• ベストアンサー

ceilでの切り上げ処理について

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型にしてみても結果は同じでした。 どのように計算すれば上手くいくのでしょうか。 アドバイスをお願い致します。

  • mm666
  • お礼率92% (58/63)

質問者が選んだベストアンサー

  • ベストアンサー
  • noah7150
  • ベストアンサー率46% (116/251)
回答No.6

2進の小数点以下は近似値でしかないのです。 2の-1乗は0.5、-2乗は0.25・・・ なので0.55をセットした段階で近似値に置き換わっていると思われます。 ただ、デバッグなのど表示では暗黙の丸目が行われていて0.55と表示されているだけでしょう 有効桁で一度丸めを行い切り上げを行うしかないのかも。 私の場合は文字列に変換してから行いましたけど

mm666
質問者

お礼

アドバイスありがとうございます。 はい、デバッグでは小数点以下第14位までしか表示されておらずに、 そこまではすべてゼロだった為になかなか気づきませんでした。 実際は"55.00000000000000700000"と、15位に"7"が入っていました。 今回丸めを行おうと思います。 でも、文字列でやったほうが正しく出来るケースも昔体験したような気がするのですが… 迷っています。 ありがとうございました。

その他の回答 (5)

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.5

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のまま誤差が無いためです

mm666
質問者

お礼

分かりやすいアドバイスありがとうございます。 何だか基本的な事を分かっていなかったように思います。 55.0を直接入れた時は大丈夫というのもやっと理解出来ました。 こうなるのは当然とやっと分かったので、 処置を考える事が出来そうです。 ありがとうございました。

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.4

浮動小数点数で0.55は循環小数になってしまうので、正確に計算することはできません。 多分他にもだめな値はあると思います。 こういった場合には、最初からすべての値を100倍して計算し、最終的な表示の際に100分の1に戻す方法がよく使われます。

mm666
質問者

お礼

アドバイスありがとうございます。 循環小数…このような結果になるのは当たり前なのですね。 分かっているようで分かっていなかったように思います。 0.55*100だけが特殊な訳ではないのですね。 プログラムとしては、小数点以下の有効桁数は6桁で、 0.55*100の小数点以下で0以外のものが発生するのが 15桁目くらいなので、その間くらいで切り捨てをしてから 処理しようかと思います。 ありがとうございました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

printf("%.20f\n", num); を入れて実行すればわかると思う.

mm666
質問者

お礼

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

  • php504
  • ベストアンサー率42% (926/2160)
回答No.2

やりたいのは切り上げですね 間違えました

mm666
質問者

お礼

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

  • php504
  • ベストアンサー率42% (926/2160)
回答No.1

計算結果をintにしたら num = (int)(num * 100);

関連するQ&A

  • 切り上げ?

    すごく簡単なことを聞いて申し訳ないのですが、6.1を切り上げすると、7になるというのがよく分かりません。 後、例えば48.48とあるとして、小数点以下切り上げとあれば、此の場合49になったりするのでしょうか? 切捨ては分かりますが、切り上げの原理が分かりません。どなたかお願いします。

  • C#.netでの切り上げ処理について

    C#.netでの切り上げ処理について C#.netでの切り上げ処理について質問です。 ある値を百単位で切上げを行いたいのですが、どのようにすればよいでしょうか? 例)「1040」→「1100」   「60」 →「100」 値は必ずint値になります。 小数の切上げの場合、Ceiling メソッドを使用するのは分かるのですが… よろしくお願いします。

  • 数値の切り上げ、切り捨てって??

     数値計算の際、たまに切り上げ、切り捨てなどという言葉 が出てくるのですがあまり理解できません。 たとえば、(小数点以下は切り上げ)のとき、値が13.6の場合 14でよろしいでしょうか? 13.4でも14になるんですよね? どうか、教えてください。よろしくお願いします。  

  • 小数点の切り上げ

    いつも参考にさせて頂いています。 javascript初心者です。 ある計算結果の数値で小数点以下が出た場合は切り上げを、 また、そうでなかった場合はそのままの数値を使うようなことを 行いたいのですがどのような条件文を作成すればいいのでしょうか? どなたか教えて下さる方がいらっしゃいましたらお願いします。

  • EXCELでの小数点第1位の切り上げについて

    現状、二つの計算を行っております。 【1つ目】セルP11(数値21)÷P10(数値22)      21÷22=0.95454545・・・ 【2つ目】セルQ11(数値20.4)÷Q10(数値21.4)      20.4÷21.4=0.953271・・・  この2つの値それぞれ「セルP13」,「セルQ13」に算出し  パーセンテージ表示にするようにしたのですが、  1つ目(セルP13)が95%、2つ目(セルQ13)が96%に  なってしまいました。  小数点第3位で調整し、同じ95%、または96%にしたいと  考えております。  切り上げを行う場合『ROUNDUP』という関数があることは  分かったのですが、計算式と組み合わせた場合、どのような式に  なるのでしょうか?  申し訳ありませんが   ●四捨五入の場合,●切り上げの場合 での  式をお教え願います。  

  • エクセルで表示のみ小数点以下切り上げに出来ますか?

    エクセルで表示のみ小数点以下を切り上げにしたいんです。 その数値を使用して他シートで計算しているため、実際は0.1であれば0.1×○○と計算し、表示を0.1のところ小数点以下切り上げで1と表示したいんです。 良い方法があったら、是非教えてください。

  • こんな処理は可能ですか?(動的な命名)

    以下のように、switchでnumの値を分岐させてその値ごとに tmp[j][i]に格納する変数を変えたいのですが、こういうことはもっと スマートにできないでしょうか? int num = (ランダムな数取得); for ( int j = 0; j < 100; j++ ){   for ( int i = 0; i < 100; i++ ){     switch ( num ){     case 1: tmp[j][i] = num1[j][i]; break;     case 2: tmp[j][i] = num2[j][i]; break;     case 3: tmp[j][i] = num3[j][i]; break;      ・      ・      ・     }   } } ーーーーーーーーーーーーーーーーーーーーーーーーーーーーー 上のコードを int num = (ランダムな数取得); char *str = "num"; strcat( str, (char *)num ); //文字列の連結 tmp[j][i] = (*str)[j][i]; 見たいな雰囲気でスマートにできるのではないかと思ったのですが・・。 動的な関数呼び出しとか##演算子とかそういうのと組み合わせてこんなことは 実現できないでしょうか?

  • 小数点切り上げって関数ですか?

    セルA2の数値の0.7掛けをB2に表示する場合は B2に=A2*0.7ですよね? で、小数点第1位を切り上げしたいのですが (ちょっと数学的にも分からないのですが、切り上げの場合って 例えば、39.1~39.9は40になって39.0は39のままですよね?) その場合、どういうふうにすればいいのでしょう?

  • 計算結果の処理について

    入力された数値に従って、計算をするというスクリプトを作成しています。 計算結果が2.27272727…と続くような場合が出てくるので、 小数点以下第何位を四捨五入するとか、第何位以下を切り捨てるといった数学関数はありますか? 調べてみても、以下3つぐらいしかありませんでした。 Math.ceil() Math.floor() Math.round() 宜しくお願いします。

  • ファイルメーカーで小数点以下の切り上げ

    ファイルメーカーで小数点以下の切り上げをするに、どのような関数を使えばよろしいでしょうか? 四捨五入と切り捨ては標準であるのですが、切り上げが見当たらず、またどのように計算を組めばよいか分からず困っています。 わずかでも小数点以下の端数が発生した場合に、整数に切り上げる処理をしたいと思っています。(例としては10.001→11) ファイルメーカーの使用バージョンは9です。

専門家に質問してみよう