小数の値が等しいかどうかassertするJavaScriptテストコード
JavaScriptコードのテストを書いてて、小数の値が正しいかどうかテストしたくなった。でも 1/3
とか無限小数になるので、期待値をどう書けばいいかわからない。
なので、多少の誤差はあってもいいので、小数の値がだいたい等しいかどうか確認するコードを書いた。こんな感じ。
// ぴったり等しいことを確認する function assertEqual(actual, expected) { var msg = "is" + ((actual === expected) ? " " : " NOT ") + "equal to"; print(actual, msg, expected, "in ==="); } // ちょっとぐらいの誤差は許して等しいことを確認する function assertEqualFloat(actual, expected) { var equalFloat = function(actual, expected, accuracy) { // 期待した値に対する許容誤差の範囲 if (!accuracy) { // デフォルト値として +-1% の誤差は許容する accuracy = 0.01; } var upperLimit, lowerLimit; if (expected >= 0) { upperLimit = expected * (1 + accuracy); lowerLimit = expected * (1 - accuracy); } else { upperLimit = expected * (1 - accuracy); lowerLimit = expected * (1 + accuracy); } return actual <= upperLimit && actual >= lowerLimit; }; var msg = "is" + (equalFloat(actual, expected) ? " " : " NOT ") + "equal to"; print(actual, msg, expected, "in equalFloat"); }
print
ってのはRhinoの関数で、その名の通り文字列として出力する。
で、こいつを使ってテストしてみた。
var actualNums = [10/3, -(10/3), 0.0001/3, 0]; var expectedNums = [3.3333, -3.3333, 0.00003333, 0]; for (var i = 0; i < actualNums.length; i++) { assertEqual(actualNums[i], expectedNums[i]); assertEqualFloat(actualNums[i], expectedNums[i]); print(""); }
結果は以下。
% rhino equalFloat.js 3.3333333333333335 is NOT equal to 3.3333 in === 3.3333333333333335 is equal to 3.3333 in equalFloat -3.3333333333333335 is NOT equal to -3.3333 in === -3.3333333333333335 is equal to -3.3333 in equalFloat 0.000033333333333333335 is NOT equal to 0.00003333 in === 0.000033333333333333335 is equal to 0.00003333 in equalFloat 0 is equal to 0 in === 0 is equal to 0 in equalFloat
うん、いい感じ。
ちなみにこいつはrhinounitの eqFloat
関数を参考にした(rhinounitのAPI一覧)。でもそれにはバグがあって負の数の時はうまく動かなかったので、ちょっと直した。
動作はRhinoで確認したけど、print
以外は普通のブラウザでも動くと思うよ。