Math.Floorによる小数点第三位以下の切り捨てについて

小数点第5位程度まである数(必ず正)を小数点以下第二位までで表示させたいと思い、
下記の処理を行っています。
小数点第三位以下は切り捨てです。
75.46000を処理した場合、値が75.46となることを期待しましたが75.45と出てしまいます。
考えられる原因をご教授いただければ幸いです。

代入アクティビティ
右辺値:(Math.Floor(75.46000*100)/100).ToString("#.00") ←("#.00")は不要かなとも思いますが
左辺値:String型変数

75.46000の他の数で同様の処理を行った場合は期待する通り小数点第三位以下を切り捨てた数が表示されました。
一例ですが結果は下記の通りです。

元の数→表示される数
7.07290→7.07
30.87000 →30.87
23.10090 →23.10

よろしくお願いします。

こんにちは

これはDouble型やFloat型といった浮動小数点表現で起こる問題です。
これらの数値は小数も含めて2のべき乗の和で表現しているため、厳密に75.46という数字を表現できないことに起因しています。

具体的には以下はduoble型の75.46という数字を17桁目まで表示する式ですが、

75.46.toString("G17")

これの結果は

75.459999999999994

になります。

通常double型の精度は15桁程度なので、通常はこれでも問題ないのですが、これを100倍
したときに上記17桁目の最後の4が影響してき、結果として75.46よりも小さいと判断され75.45になります。

この誤差を許容できない場合はDecimal型で処理することを検討してください

例えば上記は

(Math.Floor(75.46000D*100)/100).toString()

のようにすると解消されると思います。

3 Likes

ピリオドの位置を求めて、そっから2桁持ってくれば?と数値の根本を無視して、文字列として処理しましょう!

と回答しようとした私。。。恥ずかしいなぁm(__)m

今回のケースは切り捨てなのと、最終的に文字列が必要のようですので、文字列操作もアリと思います。
個人的には以下のような正規表現を使うのが手っ取り早いと思います。

System.Text.RegularExpressions.Regex.Match(75.46000.toString("#.00000"),"\d+\.\d{2}").Value
1 Like

詳しくご解説いただきありがとうございました。
大変参考になりました。
Decimal型にしたところ期待する値を出力できました。
(75.46000という値も実際はエクセルから取得したDouble型の変数なので
Convert.ToDecimalも使って処理しています)

3 Likes