ど素人から毛を生やす。<延>

数値を割ったり掛けたりして照合したいときにご注意。「2.3」の罠。

Web > javascript > Web > Other 2015年3月5日(最終更新:10年以上前)

2015年3月5日に作成されたページです。
情報が古かったり、僕が今以上のど素人だった頃の記事だったりする可能性があります。

どもです。

jQueryで「小数点第3位以下が入力されている場合、エラーを返す」というプログラムを作りました。

ソースは以下の通り。


var figure = parseFloat( 照合する数値 );
var figureB = Math.floor( figure * 100 )/100;
if( figure == figureB ){
小数点第2位以上の入力
}else{
小数点第3位以下の入力有り
}

照合する数に*100で小数点以下を切り捨て、再度/100で小数点第2位までの数が取得できます。
これと元の数が同じなら、その数字は小数点第2位以上。同じでなければ第3位以下があることになります。

間違いを起こしようのない簡単なプログラムのハズでした。
実際、ちゃんと正しく動作していました。

2.3を入力したとき以外は。

(´・ω・`)なんでやねん。

2.3は「浮動小数点」で対処できない数字

Consoleで調べてみたところ、どうやらfigureBの方が2.29になってしまっているようです。

その原因ですが、2.3は「浮動小数点」という数値の処理形式で対処できない数らしいです。
「浮動小数点」というのは、いわば数値の圧縮形式で(.btm→.pngみたいな感じ)で、桁数を累乗によって扱うもの。これによって膨大な桁の数値も少ないバイト数で扱えるのだそうで。
(例:123000=1.23E+6 ←1.23*10の6乗という意味)

で、この「浮動小数点」という圧縮形式は、実は可逆圧縮に見せかけた非可逆圧縮形式らしい。
jpegで保存したときに画像が元のbtmから若干変わるように、浮動小数点の数を掛け算して普通(固定小数点)の数に直したときに若干ズレる可能性があるそうです。
その「若干ズレる」に該当する数が2.3であると…。

釈然としないけど、これがプログラムの世界での仕様らしい。
で、回避法としては「 任意精度数学関数または gmp 関数」を使うと良いらしいのですが…。

そーいうのは複雑な判定しているときの話。
今回はシンプルなプログラムなので対処法もシンプルに行きましょう。

このトラブル、数がずれる場合は
○.99999...○○ となるか(本来の数より0.000...いくつか小さくなる)、
○.00000...○○ となるか(本来の数より0.000...いくつか大きくなる)
の2パターンっぽいです。

それなら、切り捨て(floor)じゃなくて四捨五入(round)をすれば良いわけだ。


var figure = parseFloat( 照合する数値 );
var figureB = Math.round( figure * 100 )/100;
if( figure == figureB ){
小数点第2位以上の入力
}else{
小数点第3位以下の入力有り
}

で、今回は解決。
うっかりやらかし易そうなトラブルなので、よーく覚えておかなければ…


参考サイト:【PHP】浮動小数点数

あ。小数点○桁までにする指示ってあったんだ。

処理したい数.toFixed(小数点以下の桁数)
って便利な指示があったんですね。
入力した数値未満の数は、四捨五入されるそうです。

それなら、わざわざ浮動小数点にわたわたせずとも、


var figure = parseFloat( 照合する数値 );
var figureB = figure.toFixed(2)
if( figure == figureB ){
小数点第2位以上の入力
}else{
小数点第3位以下の入力有り
}

にすれば、この問題は回避できますね。

この記事は役に立ちましたか?
  • _(:3」∠)_ 面白かった (0)
  • (・∀・) 参考になった (0)
  • (`・ω・´) 役に立った (0)