次のコードを検討してください。
_for (var i=0;i<3;i++){
var num = i + 0.50;
var output = num + " " + Math.round(num) + " " + num.toFixed(0);
alert(output);
}
_
でOpera 9.63私は得る:
0.5 1
1.5 2 2
2.5 3 2
FF 3.03では次のようになります:
0.5 1 1
1.5 2 2
2.5 3
In IE 7私は得る:
0.5 1
1.5 2 2
2.5 3
太字の結果に注意してください。なぜこの矛盾が存在するのですか?これはtoFixed(0)
を避けるべきだということですか?数値を最も近い整数に丸める正しい方法は何ですか?
編集:編集に回答するには、_Math.round
_を使用します。また、Number
オブジェクトのプロトタイプを作成して、その構文を希望する場合に入札させることもできます。
_Number.prototype.round = function() {
return Math.round(this);
}
var num = 3.5;
alert(num.round())
_
私はこれまでNumber.toFixed()
を使用したことはありません(ほとんどのJSライブラリが toInt()
メソッドを提供しているためです)が、結果から判断すると、一貫したMath
メソッド(round
、floor
、ceil
)を使用し、ブラウザ間の一貫性が目的の場合はtoFixed
ために。
FFはtoFixedで正しいことをしていると思います。なぜなら、以下のステップ10に「このようなnが2つある場合は、大きい方のnを選択する」と書かれているからです。
そして Grant Wagner が言ったように:Math.ceil(x)またはMath.floor(x)x.toFixed()の代わりに。
以下はすべて ECMAScript言語仕様 からのものです。
15.7.4.5
Number.prototype.toFixed (fractionDigits)
小数点の後に
fractionDigits
桁の固定小数点表記で表される数値を含む文字列を返します。fractionDigits
が未定義の場合、_0
_が想定されます。具体的には、次の手順を実行します。
f
をToInteger(fractionDigits)
とする。 (fractionDigits
が未定義の場合、このステップは値_0
_を生成します)。- _
f < 0
_または_f > 20
_の場合、RangeError
例外をスローします。x
をこの数値にします。x
がNaN
の場合、文字列_"NaN"
_を返します。s
を空の文字列にします。- _
x ≥ 0
_の場合、手順9に進みます。- Sを_
"-"
_としましょう。- _
x = –x
_としましょう。- _
x ≥ 10^21
_の場合は、m = ToString(x)
にしてステップ20に進みます。n
を、_n ÷ 10^f – x
_の正確な数学的値が可能な限りゼロに近い整数とする。そのようなn
が2つある場合は、大きいn
を選択します。- _
n = 0
_の場合、m
を文字列_"0"
_にします。それ以外の場合は、m
をn
の10進表現の数字で構成される文字列にします(先頭にゼロを付けずに)。- _
f = 0
_の場合、ステップ20に進みます。k
をm
の文字数とします。- _
k > f
_の場合、手順18に進みます。z
を、文字_f+1–k
_の_'0'
_オカレンスで構成される文字列とします。m
を文字列z
とm
の連結にします。- _
k = f + 1
_としましょう。a
をm
の最初の_k–f
_文字とし、b
をf
の残りのm
文字とします。m
を3つの文字列a
、_"."
_、およびb
の連結とします。- 文字列
s
とm
の連結を返します。
length
メソッドのtoFixed
プロパティは_1
_です。
toFixed
メソッドが複数の引数で呼び出された場合、動作は未定義です(セクション15を参照)。実装では、
toFixed
の値に対してfractionDigits
の動作を_0
_未満または_20
_より大きい値に拡張できます。この場合、toFixed
はそのような値に対してRangeError
を必ずしもスローしません。[〜#〜] note [〜#〜]
toFixed
の出力は、一部の値に対してtoString
よりも正確な場合がありますtoString
は、数値を隣接する数値と区別するのに十分な有効数字のみを出力するためです。たとえば、_(1000000000000000128).toString()
_は_"1000000000000000100"
_を返し、_(1000000000000000128).toFixed(0)
_は_"1000000000000000128"
_を返します。
2つの元の問題/質問に対処するには:
ここでの問題は、これらは常に同じ結果をもたらすべきであるという誤解にあります。実際、それらは異なるルールによって管理されています。たとえば、負の数を見てください。 _Math.round
_ は "round half up" をルールとして使用するため、Math.round(-1.5)
が_-1
_に評価されることがわかりますMath.round(1.5)
は_2
_と評価されます。
一方、_Number.prototype.toFixed
_は、基本的に "ゼロから離れた半分" と同等のものを、 仕様のステップ6 に従って使用します。これは本質的に、負の値を正の数として扱い、最後に負の符号を追加し直すことを意味します。したがって、_(-1.5).toFixed(0) === "-2"
_と_(1.5).toFixed(0) === "2"
_は、すべての仕様に準拠したブラウザーで真のステートメントです。これらの値は数値ではなく文字列であることに注意してください。さらに、-1.5.toFixed(0)
と-(1.5).toFixed(0)
は、演算子の優先順位により_=== -2
_(数字)であることに注意してください。
最新のブラウザ—または、少なくともこの記事の執筆時点でサポートが期待されるもの IEを除く—すべての仕様を正しく実装する必要があります。 ( Reneeのコメント によれば、Operaで指摘したtoFixed
の問題は、おそらくChromeと同じJSエンジンを使用し始めてから修正されました。 。)すべてのブラウザで仕様が一貫して実装されていたとしても、仕様で定義された動作、特にtoFixed
丸めについては、「単なる致命的な」JS開発者にとっては少し直感的ではない可能性があります。真の数学的精度を期待してください。例としてV8 JSエンジンに提出された Javascript toFixed Not Rounding および この「意図したとおりに動作する」バグ を参照してください。
要するに、これらは、2つの異なる戻り値型と丸めのための2つの異なるルールセットを持つ2つの異なる関数です。
他の人が示唆しているように、「特定のユースケースに合った関数を使用してください」と言いたいと思います(toFixed
の特殊性、特にIEの誤った実装に注意してください)。 個人的には、他の人が述べたように、_ 編集:...ただし、戻って説明を読んだ後、ユースケース(整数に丸める)は、適切な名前の_Math.round/ceil/floor
_の明示的な組み合わせを推奨することにもっと傾倒するでしょう。Math.round
_関数を確実に呼び出します。
toFixed()は文字列値を返します。 JavaScriptから:決定版ガイド
数値を、小数点以下の指定された桁数を含む文字列に変換します。
Math.round()は整数を返します。
明らかに、toFixed()はお金をより多く使用するようです。たとえば、
'$' + 12.34253.toFixed(2)= '$ 12.34'
toFixed()が適切に丸められていないように見えることは非常に残念です!
toFixed(0)
の代わりに、必要に応じてMath.ceil()
またはMath.floor()
を使用します。
一貫性のない回答が得られている場合は、間違いなくそのように見えます。
Usin toFixed(0)を使用する目的は、10進数を整数に変換することだけであると推測できます。その時点でMath.floor()をお勧めします。 この質問 でこれを行う最善の方法についてもう少し議論があります。