- 締切済み
javascriptで浮動小数点の問題
javascriptで浮動小数点の問題を解決しつつevalをつかった電卓を作ることはできませんか? >>> //-が欲しい場合 var array2 = str.match(/-?[0-9]+\.?[0-9]*/g); for(var i = 0; i < array2.length; i++) { console.log(parseFloat(array2[i])); } な感じで数値を抜き出し 計算記号+-*/に従ってmathのメソッドを順次呼び出す関数を作成すればいいのです。 計算記号については抜き出した数値を文字列として数えれば抜き出せるはず。 このように教えてもらいましたが、正直難しすぎてさっぱりわかりません。 evalでは浮動小数点の問題は解決できないのでしょうか? 便利なライブラリなどもないでしょうか?
- みんなの回答 (21)
- 専門家の回答
みんなの回答
- amanojaku1
- ベストアンサー率54% (265/488)
>回答No.20 amanojaku1 >「加算、減算」と「乗算、除算」の整数化と小数点に戻す処理は非常に困難になります。 「加算、減算」と「乗算、除算」の混在している式では整数化と小数点に戻す処理は非常に困難になります。
- amanojaku1
- ベストアンサー率54% (265/488)
>特殊な計算を除いて一般的な計算が問題なければいいかなと思っているのですが、一度整数にして計算してから小数点を戻すだけでは一般的な計算でも誤差が大きくて使い物にならないのですか? 一般的な計算「2042/100*23450*123」でも億単位未満でも誤差がでます。 例えば「20.42/100*23450*12.3」を整数化すると、整数化した部分は上記と全く同じになり、当然 億単位未満で誤差がでます。 小数点に戻す時に数値ではなく文字で処理しないとダメです(数値だと小数点自体で誤差がでます)。 また、良く考えたら「加算、減算」と「乗算、除算」の整数化と小数点に戻す処理は非常に困難になります。 例えば「2.042*2.345+1.23」の場合「2042*2345」とすると「1000倍*1000倍」で「1.23」側は「1000000倍」しないと桁が合わなくなります。 電卓の計算:2.042*2.345+1.23=6.01849 電卓の計算:2042*2345+1230000=6018490、電卓の計算:6018490/1000000=6.01849:証明終わり 下記のように正規表現で構文を解釈し「「加算、減算」と「乗算、除算」の優先順位を無視して記述されてる順番で演算、カッコも使わない」で「bigdecimal.js」で処理した方が簡単です。 >bigdecimal.jsを使えば、evalでも簡単に誤差を修正できるならこれを使ってみます。 bigdecimal.jsはevalでは使えません。 「加算、減算」と「乗算、除算」の優先順位を無視して記述されてる順番で演算、カッコも使わないなら、正規表現で構文を解釈し「bigdecimal.js」で それほど難しくないと思われます。
- amanojaku1
- ベストアンサー率54% (265/488)
>okwebの問題ですが、どれが最新のご返信かわからないのですがこちらでしょうか? 「新着順」(添付画像の赤で囲った部分)をクリックして下さい。 >特殊な計算を除いて一般的な計算が問題なければいいかなと思っているのですが、一度整数にして計算してから小数点を戻すだけでは一般的な計算でも誤差が大きくて使い物にならないのですか? 整数の演算で下記のように誤差がでる訳ですので、(加算、減算、乗算だけなら良いのですが)除算が入ると「一度整数にして計算する」と言うアイデアには欠陥があると言う事です。 Math.round(eval(2042/100*23450*123)*100000000)/100000000=58898427.00000001
- amanojaku1
- ベストアンサー率54% (265/488)
>このようにして、整数化して計算することで、基本的に問題なく小数点の計算もできているように見えます。 > >ただ前におっしゃっていた通りこちらだと小数点の計算と10桁くらいの計算なら問題ないが何億くらいの計算になるとまた計算がおかしくなるのでしょうか? > >億単位ならほとんどだれも行わないので無視してもいいかなとも思っています。 下記は億単位未満でも誤差がでます。 やはり「bigdecimal.js」を使った方が良いかと思います。 <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift-JIS"> <!-- charset=Shift-JIS、UTF-8 --> <TITLE>test</TITLE> </head> <body> <script type="text/javascript"> <!-- document.write(eval(2042/100*23450*123)+'<br>'); document.write(Math.round(eval(2042/100*23450*123)*100000000)/100000000+'<br>'); --> </script> </body> </html>
- amanojaku1
- ベストアンサー率54% (265/488)
>結局「bigdecimal.js」でも「1/3*3=」とかだと誤差がでます。 目標が電卓レベルなら「bigdecimal.js」は桁数が多いと思われるので下記のような手法で丸めても良いと思います。 >2042/125*375=6125.999999999999 >↑この場合"9"が12個ありますが、余裕を持たせて"9"が8個以上あったら8個目の"9"を四捨五入するとか。 >2042/666*375*777=893375.0000000001 >↑この場合"0"が9個ありますが、余裕を持たせて"0"が8個以上あったら9個目以降の数字を切り捨てるとか。
- amanojaku1
- ベストアンサー率54% (265/488)
>回答No.15 amanojaku1 結局「bigdecimal.js」でも「1/3*3=」とかだと誤差がでます。
- amanojaku1
- ベストアンサー率54% (265/488)
>回答No.14 amanojaku1 「加算、減算」と「乗算、除算」の優先順位を無視して記述されてる順番で演算、カッコも使わないなら、正規表現で構文を解釈し「bigdecimal.js」で それほど難しくないと思われます。
- amanojaku1
- ベストアンサー率54% (265/488)
>結局JSでは何をやっても小数点以下が多い計算を正確に出すことは不可能なことに変わりはないのですね。 「bigdecimal.js」とか10進演算ライブラリを使うしかないでしょう。
- amanojaku1
- ベストアンサー率54% (265/488)
>回答No.12 amanojaku1 もちろん、その方法でも、誤差が大きくて それで対応できないほど誤差が大きいとダメなんですが。
お礼
>>>> 2042/125*375=6125.999999999999 ↑この場合"9"が12個ありますが、余裕を持たせて"9"が8個以上あったら8個目の"9"を四捨五入するとか。 2042/666*375*777=893375.0000000001 ↑この場合"0"が9個ありますが、余裕を持たせて"0"が8個以上あったら9個目以降の数字を切り捨てるとか。 結局JSでは何をやっても小数点以下が多い計算を正確に出すことは不可能なことに変わりはないのですね。
- amanojaku1
- ベストアンサー率54% (265/488)
>そしてもう一つ別の電卓を作ってそちらではそのままこの問題を放置するという二つのバージョンを作るしかないかなと思ったのですが、これでまず問題ないと思っていいでしょうか? 1度文字列に変換して正規表現も利用して四捨五入すると良いでしょう。 2042/125*375=6125.999999999999 ↑この場合"9"が12個ありますが、余裕を持たせて"9"が8個以上あったら8個目の"9"を四捨五入するとか。 2042/666*375*777=893375.0000000001 ↑この場合"0"が9個ありますが、余裕を持たせて"0"が8個以上あったら9個目以降の数字を切り捨てるとか。
お礼
okwebの問題ですが、どれが最新のご返信かわからないのですがこちらでしょうか? 特殊な計算を除いて一般的な計算が問題なければいいかなと思っているのですが、一度整数にして計算してから小数点を戻すだけでは一般的な計算でも誤差が大きくて使い物にならないのですか?
補足
>> 下記は億単位未満でも誤差がでます。 やはり「bigdecimal.js」を使った方が良いかと思います。 私のやり方だと普通の計算でも誤差が出るのでしょうか? bigdecimal.jsを使えば、evalでも簡単に誤差を修正できるならこれを使ってみます。