- ベストアンサー
乗算した時に数値が変わってしまいます
計算のプログラムを組んでいます。 そこの途中で以下のような計算があります。 var x01 = ( 1 + x0 + eval(c.form7.value) / 100) var x02 = x01 * 100 x0=1.06 form7=24 つまりx01=2.3です。 これは実際に表示して確認しました。 しかし、x02=299.9999...になっています。 単純に*100しただけなのですが何故なのでしょうか。 分かる方がいらっしゃいましたら是非ご教授下さい。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
[対処例] x0 = 1.06; x01 = 1 + x0 + eval(c.form7.value)/100; x02 = Math.round(x01 * 10000)/100; [備考] x02 = x01 * 1000/10 では、例えば 「x0 = 1.04」「c.form7.value = 24」や 「x0 = 1.06」「c.form7.value = 22」 の場合、意図する結果が得られないはずです。試してみてください。 小数部のある値を含んだ計算をすると、例えば x02 = 229.9999999999997 x02 = 230.0000000000005 のように、小数部の深いところで「過不足」が生じる場合があります。 対処策としては、得ようとする結果に影響が生じない、小数部の深い桁数の箇所を四捨五入しています。 JavaScriptの四捨五入(Math.round)は、小数部1桁目の四捨五入だけで、対象桁数の指定ができませんので、上記の対処例では、100倍にした値を四捨五入して整数にし、その結果を100で割って戻しています。 得ようとする計算結果が整数のみの場合は x02 = Math.round(x01 * 100); でも有効です。 小数点以下 N桁まで必要な場合は、 x02 = Math.round(x01 * 100 * 10のN乗)/10のN乗; となります。 ご参考までに。
その他の回答 (3)
- yamada_28
- ベストアンサー率43% (21/48)
いろいろ調べてみた結果、コンピュータの内部で計算するときに2進数に変換してから計算されることによる「誤差」だそうです。 「javascript 演算 誤差」でぐぐったら結構ヒットしましたのでお知らせしておきますね。対処方法もあるようです。 対処方法例 http://www.interq.or.jp/japan/satoshi0/sample/syosu/ 追伸:OS、ブラウザ毎の検証結果もありました。 http://www.openspc2.org/JavaScript/gosa/
お礼
回答ありがとうございます。 自分でも検索したのですが、検索ワードが悪かったのか求める結果が得られませんでした。 わざわざ調べて頂いてありがとうございました。 凄く勉強になりました。
- arakororin
- ベストアンサー率39% (80/205)
私の環境で試してみたところ、 x01=2.3 x02=229.9999999999997 でした。 99x02=299.9999... にはならないと思います。 仮に、x02=229.9999999999997 との書き間違いであるのならばそれは正しいです。 浮動小数点数を使用しているための 桁落ちによる誤差です。
お礼
回答ありがとう御座います。 今確認してみた所 x01=2.3 x02=229.99999999999997 でした。 私の確認ミスでした、申し訳ありません。 arakororinさんの回答を参考に調べてみた所 var x01 = ( 1 + x0 + eval(c.form7.value) / 100); var x02 = x01 * 1000 / 10; とすることで x01=2.3 x02=230 を得ることが出来ました。 しかしこれはブラウザの環境によって違ってくる可能性があるとのことなのですが、そこの所はどうなのでしょうか?
- yamada_28
- ベストアンサー率43% (21/48)
var x01 = ( 1 + x0 + eval(c.form7.value) / 100) ここでx01の値はどうなってます?2.9999...出ないでしょうか? var x01 = ( 1 + x0 + (eval(c.form7.value) / 100)) ↑こう書いてみるとか、括弧の位置を変えて試してみたらどうでしょう?あとは、まとめて式を書かないで、2つに分けてx01を求める形にしてみるとか。 ここから独り言。evalって初めて見ました。なので調べてみました。文字列から数値への変換、文字列で示された計算式の計算に有効な関数のようですね。evalはずして見たらどうなんでしょ?
お礼
回答ありがとう御座います。 yamada_28さんの仰る通りやってみましたがどちらもダメでした。 x01は必ず2.3になるようです。
お礼
回答ありがとうございます。 とりあえずcriketさんの仰る通りに変更し、問題なく動作するようになった、と思います(汗)。 どのような条件化において「過不足」が発生するのか分からないので、出来るだけ多くのパターンで動作確認してみようと思います。 Math関数については知っていた(以前勉強した)ことだったのですが、Math.floorばかり使っていたので忘れていました。 現在作っているプログラムは切り捨ても混ざっているので大変そうですが頑張ってみます。 ありがとうございました。