Help us understand the problem. What is going on with this article?

JavaScriptのfloatで正確な比較を行う

More than 1 year has passed since last update.

TLにこんなツイートが回ってきました

Yep. JavaScriptに限らず浮動小数点数の丸め誤差の問題はあります。
しかし、仕様通りですが、便利かと言えば便利ではありませんね?

こんにちはAST

こんなときは、ASTで変換してやればいいです。
Babelで仕様とか色々大切なものを歪めてあげましょう。

akameco/babel-plugin-float-equal: Babel plugin for float equal

$ npm install --save-dev babel-plugin-float-equal 
{
  plugins: ["float-equal"]
}
// before
0.1 + 0.2 === 0.3
// => false


// after
0.1 + 0.2 === 0.3
// => true

Babelを使って、===で比較されていた場合、問答無用で以下のコードへ変換してやります。
Number.EPSILONは2.220446049250313e-16です。
いわゆる許容する誤差です。

0.1 + 0.2 === 0.3

           

typeof (0.1 + 0.2) === 'number' && typeof 0.3 === 'number'
  ? Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON
  : 0.1 + 0.2 === 0.3

変数

もちろん変数に対応してなくては使い道がないですね。

var a = 0.1
var b = 0.2
a + b === 0.3
// => true

How to create Babel Plugin?

以下がプラグインの全コードです。
BinaryExpressionのときのオペレーターが===のときに、左右のnodeをtemplate関数を呼んで変換したものをpath.replaceWithを使って入れ替えてあげます。
単純ですね。

export default ({ template } /*: {template: Function} */) => {
  const builder = template(`
  (typeof LEFT === 'number' && typeof RIGHT === 'number') ? Math.abs(LEFT - RIGHT) < Number.EPSILON : LEFT === RIGHT
  `)

  return {
    name: 'float-equal',
    visitor: {
      BinaryExpression(path /*: Object */) {
        if (path.get('operator').node !== '===') {
          return
        }

        const { node: left } = path.get('left')
        const { node: right } = path.get('right')

        const ast = builder({ LEFT: left, RIGHT: right })

        path.replaceWith(ast)
        path.skip()
      }
    }
  }
}

おわりに

プロダクションで使ってもいいですか?

いいえ、プロダクションで使ってはいけません。
まあ、危険を犯すのが好きならば、どうぞご自由に。

akameco/babel-plugin-float-equal: Babel plugin for float equal

akameco
シュレーディンガーの社会人.js
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした