Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
10
Help us understand the problem. What is going on with this article?

More than 3 years have passed since last update.

@akameco

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

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

10
Help us understand the problem. What is going on with this article?
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
10
Help us understand the problem. What is going on with this article?