PHPExcelを使うとroundの結果がおかしくなる

2017年09月14日
投稿者:嶋崎聖
カテゴリ:PHP タグ:

鈴木商店の嶋崎です。こんにちは。

PHPExcelを使っていておかしな現象に遭遇したので報告と共有です。

現象としてはタイトルどおり、PHPExcelでテンプレートExcelファイルを読み込むとroundが返す値がおかしくなると言うものです。
例えば集計して割合表示とかやりますよね?

それではやってみましょう。

環境

PHP5.6.31

下準備

Githubから最新リリースをダウンロード

https://github.com/PHPOffice/PHPExcel/releases

執筆時、1.8.1でした。

実証

  • サンプルコード

結果

88.9
88.90000000000001

なんということでしょう。丸められていません。

原因

どういうことかというと以下をご覧ください。
PHPExcel_Calculationのコンストラクタです。

  • PHP_INT_SIZEが「4」を返さない。つまり64bit環境です。
  • ini_get('precision')ですが、デフォルトは「14」です。

つまり、64bit環境で、precisionを変更していない状態でPHPExcelを使うと、
強制的にprecisionが「16」に変更されます。
precisionが「14」よりも大きい状態でroundを使うとちょいちょい期待しない結果になるのは有名な話ですね。

どうすればいいか?

開発バージョンを使う

実はこの問題PHPExcel側も認識していて、1.8ブランチの最新ソースではprecisionの変更は行われていません。
ただ、テストが済んでないらしく、最新リリースには取り込まれていません。また、取り込まれる予定もなさそうです。

https://github.com/PHPOffice/PHPExcel/issues/237

使用は自己責任で。

PHPExcelの初期化を遅らせる

PHPExcelを使わない限り、precisionは変更されません。
先にroundしてからPHPExcelを使えばこの問題は回避できます。
とは言え、処理の呼び出し順で結果が変わるのは開発者に優しくありません。
PHPExcelの使用箇所が少なければこの問題で回避するのも手です。

roundを使わない

代わりにsprintfを使います。
sprintfprecisionの影響を受けないため、PHPExcelが何しても大丈夫です。
おそらくはこれが順当な対策ではないかと思います。
ちなみに、今回はこの方法を採用しました。

他には計算をExcel側でやらせる、力技ではini_setをコメントアウトしてしまう、といった案も考えられなくは無いです。

同じような問題に遭遇した方が「PHPExcel round」でググってこのページが解決になれば幸いです。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です