電子書籍の厳選無料作品が豊富!

WinXP,SDKです。

小数点以下第2位までに切り上げをしようと思ったのですが、
以下のような式の場合に0.55が0.56と求められてしまいます。

double num = 0.55;
num = num * 100; <- この時点で55.0
double tmp = ceil(num); <- この時点で56.0 ※
num = tmp / 100; <- この時点で0.56

※の所でなぜ55.0と戻ってこないのでしょうか。
これはなぜか0.55の時だけ現象が出てしまいます。
ほかの数値の場合はほぼ上手く行きます。(ダメな数値は見つけられていません)

上の式をたとえば

num = 55.0;
double tmp = ceil(num);

とした場合、正しく55.0と求められます。
おそらく100をかけているところで何らかの問題が出ていると思うのですが…
100をintやdouble型にしてみても結果は同じでした。

どのように計算すれば上手くいくのでしょうか。
アドバイスをお願い致します。

A 回答 (6件)

2進の小数点以下は近似値でしかないのです。


2の-1乗は0.5、-2乗は0.25・・・

なので0.55をセットした段階で近似値に置き換わっていると思われます。
ただ、デバッグなのど表示では暗黙の丸目が行われていて0.55と表示されているだけでしょう

有効桁で一度丸めを行い切り上げを行うしかないのかも。
私の場合は文字列に変換してから行いましたけど
    • good
    • 0
この回答へのお礼

アドバイスありがとうございます。

はい、デバッグでは小数点以下第14位までしか表示されておらずに、
そこまではすべてゼロだった為になかなか気づきませんでした。
実際は"55.00000000000000700000"と、15位に"7"が入っていました。

今回丸めを行おうと思います。
でも、文字列でやったほうが正しく出来るケースも昔体験したような気がするのですが…
迷っています。

ありがとうございました。

お礼日時:2008/10/31 16:58

0.55自体が2進表現にした場合に厳密な0.55にならないに起きる現象でしょう



double num = 0.55;
ddum *= 100.0;
double t1 = floor( num );
double t2 = num - t1;
if ( t2 == 0 ) {
  printf( "num == 55\t" );
} else {
  printf( "num != 55\t" );
}
printf( "%lf", t2 );
printf( "%.20lf", 0.55 );

num = 55.0;
double tmp = ceil(num);
で tmpが55になるのは 55を浮動小数点であらわしても55のまま誤差が無いためです
    • good
    • 0
この回答へのお礼

分かりやすいアドバイスありがとうございます。

何だか基本的な事を分かっていなかったように思います。
55.0を直接入れた時は大丈夫というのもやっと理解出来ました。

こうなるのは当然とやっと分かったので、
処置を考える事が出来そうです。

ありがとうございました。

お礼日時:2008/10/31 16:54

浮動小数点数で0.55は循環小数になってしまうので、正確に計算することはできません。


多分他にもだめな値はあると思います。

こういった場合には、最初からすべての値を100倍して計算し、最終的な表示の際に100分の1に戻す方法がよく使われます。
    • good
    • 0
この回答へのお礼

アドバイスありがとうございます。
循環小数…このような結果になるのは当たり前なのですね。
分かっているようで分かっていなかったように思います。
0.55*100だけが特殊な訳ではないのですね。

プログラムとしては、小数点以下の有効桁数は6桁で、
0.55*100の小数点以下で0以外のものが発生するのが
15桁目くらいなので、その間くらいで切り捨てをしてから
処理しようかと思います。

ありがとうございました。

お礼日時:2008/10/31 16:51

printf("%.20f\n", num);


を入れて実行すればわかると思う.
    • good
    • 0
この回答へのお礼

ありがとうございます。
下の方へお礼として書いていましたが、
かなり深いところに「7」が入っていました。
最初からやってみたらすぐにピンと来たはずなのに、
随分長いこと悩んでいました。
ありがとうございます。

お礼日時:2008/10/31 16:46

やりたいのは切り上げですね


間違えました
    • good
    • 0
この回答へのお礼

見て頂いてありがとうございました。

切り上げとか数値の問題ではないのかもしれません…
あれから色々と調べていて、
普通に
double tmp = 0.55 * 100;
などとしたものを%.20fで表示してみると、
小数点以下第15位くらいに値が入っています。
きっとこれのせいでceilが一つ上に切り上げしてくるんですね。
これは誤差と考えて、
計算式を一度100億倍位にして、切り捨て(floor)してから
ceilにかけたりしてみようかと思います。

ありがとうございました。

お礼日時:2008/10/31 16:34

計算結果をintにしたら


num = (int)(num * 100);
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!