• 締切済み

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では浮動小数点の問題は解決できないのでしょうか? 便利なライブラリなどもないでしょうか?

みんなの回答

回答No.11

>回答No.10 amanojaku1 また、桁数が少ない整数演算でも除算があると誤差が出る場合があります(下記は その実例です)。 これは浮動小数を整数で演算すると言うアイデアの致命的な欠陥と言えます。 (浮動小数を整数で演算しないで)「丸める」のが現実的な解決法でしょう。 ただし、(人間から見て見た目が良い感じでも)「丸める」のも誤差であると言う認識が必要です。 <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift-JIS"> <TITLE>test</TITLE> </head> <body> <script type="text/javascript"> <!-- a=2042; a=a/100; a=a*150; alert(a+"\n"); // --> </script> </body> </html>

mousugusokoni
質問者

お礼

JSで作った電卓で浮動小数点の問題を解決するのは実質不可能であれば、一つは小数点はすべて四捨五入する。 そしてもう一つ別の電卓を作ってそちらではそのままこの問題を放置するという二つのバージョンを作るしかないかなと思ったのですが、これでまず問題ないと思っていいでしょうか? あくまで一般論です。

回答No.10

>https://qiita.com/k_moto/items/0b576a3351b77fb0aa98 >上記の整数化の処理を導入すれば、ライブラリを使わなくて、evalでも浮動小数点の問題を解決した計算ができるようになると考えてよいでしょうか? いえ、evalのセキュリティ対策の正規表現を浮動小数点の四則演算に対応させるだけなので、浮動小数点の誤差には なんら影響しません。 そのサイトの方法は、前提として「桁数が少ない場合」に可能ですが、桁数が多い場合は不可能です。 浮動小数がDouble(倍精度)でも、整数の桁が多いと結局 誤差が生じます。 下記は その実例です、下記の桁数だと整数(実態は浮動小数)で誤差が生じるのですから、浮動小数を整数で演算すると言うアイデア自体の意味がありません。 下記を実行すると文字列と整数(実態は浮動小数)の値が違うのが確認できると思います。 <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift-JIS"> <TITLE>test</TITLE> </head> <body> <script type="text/javascript"> <!-- alert("76287755398823936\n"+ 76287755398823936+"\n"); // --> </script> </body> </html>

  • b0a0a
  • ベストアンサー率49% (156/313)
回答No.9

>>難しすぎて自分ではどう作ればいいかさっぱりわかりません。 何事もまず一番単純化した流れを考えて、そこから広げていけばできます。 ただしこの手の問題で厄介なのが、GUI部分をどうしたいかでやや流れも変わってくることです。 ですのでとりあえずGoogle検索のような途中式が表示されるものではない一般的な電卓のような表示を考えましょう。 そしてまず演算キーは+だけを考えます。 +が押されたら、どういう挙動をすれば良いですか? もしそれ以前に1 + 2と入力しての+であれば、3と表示しないといけません。 となると、2つ前の数値と、1つ前の演算子を覚えておけば、あと現在の数値を使って演算が可能ですね つまり、+が押されたら数値を記録して、+が押されたことも記録する 記録されている演算子の種類で場合分けをして、記録されている数値2つを使って演算する という流れで実現できます そしてここで重要なのが、最初に1 +と入力したときの+のときの処理です。 このときはまだ2つ前の数値と1つ前の演算子がありません。 ただ、こういうケースを例外として場合分けするのはあまりオススメしません。 コードが複雑化しないように、できる限り共通の処理が使えるように工夫しましょう。 今回の場合、何も入力がない状態で、0 +から始まってるとすれば良いのです。 そうすれば1 + の段階でも、0 + 1で+が押されたときとみなせますから、例外処理を考えたり書かなくて済みます。 JSではこのように、その柔軟さを生かしてできるだけ手抜きをするよう心がけましょう。 そうすることで本当に大事な部分に集中できます。

  • b0a0a
  • ベストアンサー率49% (156/313)
回答No.8

四捨五入についてはまあやっても良いかもしれませんが、別にやらなくても良いと思いますよ >>恐らく~の下記の部分を自分の計算に導入するのが一番でしょうか? 質問者さんが勉強したいのならば、そういったのを良く参考にして自分で作って見る方が良いでしょう ただ完成形が欲しいのであれば見かけも含んだライブラリを探して丸ごと置くだけでよいのでは? まあこういったのは確かに始めてやると難しいでしょうが、要するにパーサーを作るということであり JavaScriptの実行環境が別の言語で作られているように、 あなたはごく限られた数式というオリジナル言語を、JavaScriptで実装していることになるのです この分野を極めれば自分の好きな言語を定義たり実行環境を作るということもできるということです あ、そう言えば最近この手の問題を言語レベルで取り組んでいるものの話を聞いたことがあります 色々なやり方のヒントくらいは得られるかもしれません https://turingcomplete.fm/17

mousugusokoni
質問者

お礼

mathjsの導入を頑張ったのですが、evalがないので不可能ということがわかりました。 eval可能なものがあれば教えてください。 evalを使わないと乗算などもすべて 自分で作らないといけないのですよね。難しすぎて自分ではどう作ればいいかさっぱりわかりません。

mousugusokoni
質問者

補足

JSで作った電卓で浮動小数点の問題を解決するのは実質不可能であれば、一つは小数点はすべて四捨五入する。 そしてもう一つ別の電卓を作ってそちらではそのままこの問題を放置するという二つのバージョンを作るしかないかなと思ったのですが、これでまず問題ないと思っていいでしょうか? あくまで一般論です。

回答No.7

>回答No.6 amanojaku1 少し修正します。 <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift-JIS"> <TITLE>test</TITLE> </head> <body> <input type="text" name="gakunen" value="" onKeyPress="Calculator(this.value, event.keyCode)"> <script type="text/javascript"> <!-- function Calculator(a, kcode){ var r; if (!(13==kcode)){return;} // ↑「13:Enterキー」でない場合は「return」 r = a; r = r.replace(/([^0-9\.\-\/\*\+\(\)eE ]+)/g, ' '); r = r.replace(/[ \+\-]*([\+\-])/g, '$1'); r = r.replace(/([eE]+)/g, 'e'); r = r.replace(/([eE][^\+\-0-9]+)/g, ' '); r = r.replace(/(\.+)/g, '.'); // r = r.replace(/([0-9]+\.?|[0-9]*\.[0-9]+)([eE][\+\-]?[0-9]+)/g, '$1$2'); r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.]+[eE][\+\-]?[0-9]+|\()/g, '$1$2$3'); r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.]+[eE][\+\-]?[0-9]+|\()/g, '$1$2'); r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2'); r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1'); r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.]+[eE][\+\-]?[0-9]+|\()/g, '$1$2'); r = r.replace(/([ ]+)/g, ' ');try{ alert(r+' = '+eval(r)); }catch(ex){ alert(ex.message+' : '+r); } } // --> </script> </body> </html>

mousugusokoni
質問者

お礼

ありがとうございます。 r = r.replace(/([^0-9\.\-\/\*\+\(\)eE ]+)/g, ' '); を見ていると乗算なども入っていそうなので、提示した機能は入ったうえでかつ小数点の問題を解決する整数化を行っても問題ないエスケープ処理にしていただいたという認識でよいでしょうか? これに変えてから https://qiita.com/k_moto/items/0b576a3351b77fb0aa98 上記の整数化の処理を導入すれば、ライブラリを使わなくて、evalでも浮動小数点の問題を解決した計算ができるようになると考えてよいでしょうか?

回答No.6

>ご回答ありがとうございます。 >おっしゃる通りそちらと同じです。 >回答No.4 amanojaku1 セキュリティ対策の正規表現を浮動小数点の四則演算に対応させるには下記のようにして下さい。 <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift-JIS"> <TITLE>test</TITLE> </head> <body> <input type="text" name="gakunen" value="" onKeyPress="Calculator(this.value, event.keyCode)"> <script type="text/javascript"> <!-- function Calculator(a, kcode){ var r; if (!(13==kcode)){return;} // ↑「13:Enterキー」でない場合は「return」 r = a; r = r.replace(/([^0-9\.\-\/\*\+\(\)eE ]+)/g, ' '); r = r.replace(/(\.+)/g, '.'); r = r.replace(/([\+\-]*\+)/g, '+'); r = r.replace(/([\+\-]*\-)/g, '-'); r = r.replace(/([eE]+)/g, 'e'); r = r.replace(/([eE][^\+\-0-9]+)/g, ' '); // r = r.replace(/([0-9]+\.?|[0-9]*\.[0-9]+)([eE][\+\-]?[0-9]+)/g, '$1$2'); r = r.replace(/([\*\/])[ \+\-\*\/]*([\+\-])[ ]*([0-9\.]+[eE][\+\-]?[0-9]+|\()/g, '$1$2$3'); r = r.replace(/[\+\-][ \+\-\*\/]*([\+\-])[ ]*([0-9\.]+[eE][\+\-]?[0-9]+|\()/g, '$1$2'); r = r.replace(/(^|\()[ \+\-\*\/]*([\+\-])/g, '$1$2'); r = r.replace(/(^|\()[ \+\-\*\/]*[\*\/]/g, '$1'); r = r.replace(/([\+\-\*\/])[ \+\-\*\/]*[\*\/][ ]*([0-9\.]+[eE][\+\-]?[0-9]+|\()/g, '$1$2'); r = r.replace(/([ ]+)/g, ' ');try{ alert(r+' = '+eval(r)); }catch(ex){ alert(ex.message+' : '+r); } } // --> </script> </body> </html>

  • mitoneko
  • ベストアンサー率58% (469/798)
回答No.5

 「浮動小数点の問題」とは、2進浮動小数点演算における誤差の話でしょうか?それなら、本質的に、無理です。  浮動小数点で演算を行っている限り、10進と2進の基数の違うに伴う演算誤差が発生するのは本質的な問題で、これを工夫無しに解消することは出来ません。  そして、evalは、浮動小数点演算を工夫無しに使用します。その結果を、評価するためには、入力された数式をプログラム上で理解する必要があり、そのためには、入力された数式をパース(構文解析)する必要があります。  既存ライブラリーの利用ならmath.js(http://techc.omorita.com/topics/mathjs/)を使えば、かなり解消できるかしら?

回答No.4

>回答No.3 amanojaku1 >ただし、evalの場合、セキュリティ上の問題があるので、想定外の文字がある場合はエラーにする必要があります(詳細は下記ページ参照)。 > >https://okwave.jp/qa/q9369932.html ↑これはエラー・チェックではなく、手抜きして想定外の文字を削除しているだけです。 この正規表現は整数の四則演算しか想定してないので、浮動小数点演算に対応させるには少し変更が必要です。

mousugusokoni
質問者

お礼

ご回答ありがとうございます。 おっしゃる通りそちらと同じです。 こちらでセキュリティ面はまず問題ないですが、浮動小数点の問題を解決するために、一度整数にしてから計算するとこのエスケープ処理では計算がうまくいかなくなるということでしょうか

回答No.3

>回答No.2 amanojaku1 >evalで普通に浮動小数点演算できますが? ただし、evalの場合、セキュリティ上の問題があるので、想定外の文字がある場合はエラーにする必要があります(詳細は下記ページ参照)。 https://okwave.jp/qa/q9369932.html

mousugusokoni
質問者

お礼

https://codepen.io/anon/pen/NzdzJB このようにして、整数化して計算することで、基本的に問題なく小数点の計算もできているように見えます。 ただ前におっしゃっていた通りこちらだと小数点の計算と10桁くらいの計算なら問題ないが何億くらいの計算になるとまた計算がおかしくなるのでしょうか? 億単位ならほとんどだれも行わないので無視してもいいかなとも思っています。

回答No.2

>javascriptで浮動小数点の問題を解決しつつevalをつかった evalで普通に浮動小数点演算できますが?(下記参照) <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift-JIS"> <TITLE>test</TITLE> </head> <body> <script type="text/javascript"> <!-- v=eval("0.5*1.23e1"); console.log(v); --> </script> </body> </html>

関連するQ&A

  • 浮動小数点について

    独学でプログラミングの勉強をしています。Wiki等で調べたりしましたが、 下記テキストの質問の計算が全く分かりません。 分かりやすく説明して頂けるとありがたいです。 宜しくお願い致します。 質問: 二つの浮動小数点の数字があり、SEEMMMM(S=符号付数値、E=指数、M=仮数)の形式で表示されています。 指数はエクセス数50、仮数は符号付数値、小数点は右の仮数に表示されます。 0 53 1110 0 50 3020 二つの数字を加算し、正しく表示された浮動小数点形式と実数をすべての計算式も含め表しなさい。

  • 浮動小数点について

    当方、浮動小数点を勉強しているのですが、 テキストの解説を読んでも理解が出来ません。 正規化とか指数と仮数の意味が分かりません。 そこで質問なのですが、浮動小数点の計算方法を教えて下さい。 IEEE形式の浮動小数点も教えて頂けると助かります。 また、下記の問題について解説して下さい。 数値を16ビットの浮動小数点表示法で表現する。 形式は図に示す通りである。10進数0.375を正規化した表現は、どれか。 ここでの正規化は、仮数部の有効数字よりも上位の0が無くなるように、 指数部を調節する操作である。 (図は添付します) 何故「E」の値が「1111」になるのでしょうか。 お手数ですが、ご教授お願いします。 尚、特に分かり易いホームページがあったら、 そのURLを記載して頂いても結構です。 以上、よろしくお願い致します。

  • 浮動小数点について

    32ビットの浮動小数点(符号1ビット指数8ビット仮数23ビット)で最小値を求めるにはどういう計算をすればいいのでしょうか?また調べた数値だと最小値 1.175494351E-38 最大値3.402823466E+38のところ±3.40282347E+38 ~ ±1.40239846E-45のところがあるのですがどちらが正しいのでしょうか?

  • iアプリで浮動小数点を使いたい

    iアプリで確立を計算したいのですが、浮動小数点が使えないので困っています。 整数演算で浮動小数点を扱うクラスを自作するしかないのでしょうか? 使えそうなクラスなど、ご存知でしたら教えてください。

    • ベストアンサー
    • Java
  • 『浮動小数点』について

    最近、ふと『浮動小数点』について疑問を持ちました。 それは『浮動小数点』がどんな場合に役立つのか?という事です。 C言語では標準で『float』型と『double』型がありますよね。 私は昔、C言語を始めたころにテスト・プログラムなどで使った経験しかなく その後に『電卓ソフト』を作ろうとしたときに『誤差』が原因で役に立たない ことを知りました。『誤差』があることは知っていましたが…。 そこで質問。内容は『浮動小数点』はどんな場面で利用されているかです。 実際の『ソフトウェア開発』や趣味でフリーソフトを作った場合も含み、あと こんな場面で役に立つのではという事を知りたいのです。 アンケートみたいになりますが、『アンケート』カテゴリでは、あまり回答などが 集まらないと思い『C/C++』カテゴリのこちらで質問としました。 よろしくお願いします。

  • 浮動小数点の計算について

    Javaで0.1+0.2を計算すると0.30000000000000004になったり、10.0-9.9を計算すると、0.09999999999999964になったりするのはなぜですか? 参考書では。 「浮動小数点数を使った計算では、一見正確な値が計算されてるように見えてもほとんど場合内部では少しだけ誤差を含んだ値を持ってると、考えた方がいいでしょう。どのような計算を行った時にどの程度の誤差が出るのかは難しい話題になるのでこの本では詳しく説明しませんが、例えば100.0-99.99のように同じぐらいの数同士で引き算を行うと誤差が現れやすくなります。」 と書いてありました。 この本ではこれだけで説明が終わりました。 なぜ浮動小数点で計算を行うと誤差が出るのか詳しく教えていただけると助かります。

    • ベストアンサー
    • Java
  • 浮動小数点変換

    (1)次の数値をIEEE754単精度形式で正規化された浮動小数点に変換し、結果を8桁の16進数で表記しなさい。 (a)0.5 0.5を二進数で表すと0.1 0.1*2^0であるから 0 00000000 10000000000000000000000 (b)1.0 1.0を二進数で表すと1.0 0.1*2^1であるから 0 10000000 10000000000000000000000 (c)1.25 1.25を二進数で表すと1.010 0.101*2^1であるから 0 10000000 10100000000000000000000 浮動小数点への変換、あってますでしょうか? また結果を8桁の16進数で表記とありますが 0.5だったら16進数で表すと0.9?これを8桁*16^なんとか乗で表すということでしょうか?

  • 浮動小数点形式の問題

    数値を32ビット浮動小数点形式で表す。指数部は2を基数とし、負数は2の補数で表現する。10進数0.375をこの2を基数とした浮動小数点形式で正規化したものはどれか。ただし結果は16進数で表現する。 答え:7FC00000 という問題です。 まず0.375を2進数に 0.011 正規化 0.11 * 2^-1 指数部-1を2進数で求める -0000 0001 ->1111 1111 仮数部符号は正の数なので0 0111 1111 ???? ???? ???? ???? ???? ???? と・・・ ここの部分からわかりません・・・ (なぜか手持ちの参考書には省略してあり・・・) 7Fの部分はこれで間違いないでしょうか? またそのあとのC00000 はどうやって導くのか教えてください。 お願いいたします

  • 「浮動小数点表示」と「丸め」について

    数値解析についての質問です。 「23.49を有効数字4桁の浮動小数点表示で書け」という問題があるときは 0.2349 * 10^2 と答えるのが正しいのでしょうか。 つまり「浮動小数点表示で答えよ」とあれば、 0.○○○... * 10^○の形で書けば良いのでしょうか。 また、数値の丸めの仕方に関する質問なのですが、教科書に以下のような記述がありました。 k+1桁以降の数を切り捨てる a.この切り捨てられた数が第k桁の単位の半分より小さいときは、第k桁の数はそのままにする。 b.もし半分より多きときには第k桁の数に1を加える c.この切り捨てられた数が第k桁のちょうど半分のときには最も近い偶数に丸める とあるのですが、その後の記述で 「1.2535をそれぞれ小数点以下3桁、2桁、1桁で丸めると、1.254,1.25,1.3が得られる」また「小数第3位以下の情報なしで、1.25を1桁で丸めると1.2になる」とあるのですが、 後者が1.2になるのは理解できるのですが、最初の規則に則ると前者も1.2になるように思うのですが、何故1.3になるのでしょうか。 以上の規則に則った上で以下の問題に答えてみました。 問.-89.216618, 500000, -0.002213675を丸めて有効数字5桁の浮動小数点表示で書け 僕の答え -0.89217 * 10^2 0.50000 * 10^6 -0.22137 * 10^-2 というのは合っていますでしょうか。 質問が多くて大変恐縮ですが、解説、ご指摘をお願いします。 よろしくお願いします。

  • 32ビットの浮動小数点について

    32ビットの浮動小数点(符号1ビット指数8ビット仮数23ビット)で非正規表現をもとめるには例えば(符号0指数0仮数1.01101)はどういう計算をすれば良いのでしょうか?

専門家に質問してみよう