ホームページ >ウェブフロントエンド >jsチュートリアル >number()。tofixed()丸めエラー:壊れているが修正可能

number()。tofixed()丸めエラー:壊れているが修正可能

Jennifer Aniston
Jennifer Anistonオリジナル
2025-02-15 10:02:12180ブラウズ

Number().toFixed() Rounding Errors: Broken But Fixable

この記事は、もともとDavid Kayeのブログ

に掲載されました

試したすべてのJavaScript環境(Chrome、Firefox、Internet Explorer、Brave、node.js)でnumber()。tofixed()で丸めエラーを見つけました。驚くべきことに、修正は非常に簡単です。読み続けます...

キーポイント

  • javascriptの数字()。tofixed()関数は、複数の環境(Chrome、Firefox、Internet Explorer、Brave、およびnode.js)で丸めエラーを持っています。このエラーは一貫性がなく、10進数の最後の数の数が5であり、トリムの長さが小数部で1つずつ減少し、異なる整数値が適用されると発生します。
  • 値に小数が含まれている場合、このエラーは、変更する値の文字列バージョンの最後に「1」を追加することで修正できます。このソリューションでは、低レベルのバイナリまたはフローティングポイント操作の再審査は必要ありません。
  • tofixed()関数は、すべての実装が変更されるまでポリフィルを使用してオーバーライドできます。ただし、誰もがこのアプローチに満足しているわけではありません。 PolyFillには、プロトタイプ。tofixed関数が含まれ、結果の長さがゼロかどうかを確認します。

ウォームアップ

intl.numberformat#format()と同じ関数を実行するデジタルフォーマット関数を変更すると、tofixed()でこのバージョンで丸めエラーが見つかりました。

<code class="language-javascript">(1.015).toFixed(2) // 返回 "1.01" 而不是 "1.02"</code>

障害のあるテストは、ここに42行目にあります。 2017年12月まで見つかりませんでした。これにより、他の問題を確認するようになりました。

この質問についての私のツイートを参照してください:

  • エラーアラート
  • intl.numberformat
  • と比較します
  • 要約
  • polyfill

エラーレポート

tofixed()を使用する場合、エラー報告の長い履歴があります。

  • chrome
  • firefox
  • firefox、
  • も参照してください
  • インターネットエクスプローラー

この問題に関するスタックフローの問題の短い例をいくつか紹介します。

    例1
  • 例2
通常、これらは

aa値のエラーを指摘していますが、エラーの結果を返す値の範囲やパターンはありません(少なくとも私はそれを見つけませんでした、私は何かを逃したかもしれません)。これにより、プログラマーは小さな問題に焦点を合わせ、より大きなパターンが表示されません。私はこれを責めません。

パターンを見つけます

入力に基づく予期しない結果は、入力の共有モードから発生する必要があります。したがって、number()。tofixed()の仕様を確認する代わりに、各シリーズのエラーがどこに表示されるかを決定するために、一連の値でテストすることに焦点を当てました。

テスト関数

次のテスト関数を作成して、1からmaxvalueまでの一連の整数でtofixed()操作を実行し、各整数に.005などの小数を追加しました。 tofixed()の固定(数字)パラメーターは、小数値の長さに基づいて計算されます。

<code class="language-javascript">(1.015).toFixed(2) // 返回 "1.01" 而不是 "1.02"</code>

使用法

次の例では、整数1〜128で操作を実行し、各整数に10進数.015を追加し、「予期しない」結果の結果を返します。各結果には、指定、予想、および実際のフィールドが含まれます。ここでは、その配列を使用して各アイテムを印刷します。

<code class="language-javascript">function test({fraction, maxValue}) {
  fraction = fraction.toString()
  var fixLength = fraction.split('.')[1].length - 1

  var last = Number(fraction.charAt(fraction.length - 1))
  var fixDigit = Number(fraction.charAt(fraction.length - 2))

  last >= 5 && (fixDigit = fixDigit + 1)

  var expectedFraction = fraction.replace(/[\d]{2,2}$/, fixDigit)

  return Array(maxValue).fill(0)
    .map(function(ignoreValue, index) {
      return index + 1
    })
    .filter(function(integer) {
      var number = integer + Number(fraction)
      var actual = number.toFixed(fixLength)
      var expected = Number(number + '1').toFixed(fixLength)

      return expected != actual
    })
    .map(function(integer) {
      var number = Number(integer) + Number(fraction)
      return {
        given: number.toString(),
        expected: (Number(integer.toFixed(0)) + Number(expectedFraction)).toString(),
        actual: number.toFixed(fixLength)
      }
    })
}</code>

output

この状況では、6つの予期しない結果があります。

<code class="language-javascript">test({ fraction: .015, maxValue: 128 })
  .forEach(function(item) {
    console.log(item)
  })</code>

発見このエラーには3つの部分が含まれていることがわかりました

小数部の最後の重要な数字は5(.015および.01500が同じ結果を生成する必要があります)。

    トリム長は、1つの小数部のみで縮小する必要があります。
  1. 異なる整数値が適用されている場合、エラーは一貫して発生します。
  2. 一貫性がありませんか?
たとえば、

整数1〜128の場合、(値).tofixed(2)は5で終了する3つの小数点以下の場所を使用して、次の結果が得られます。 .005で終わるツイスト番号は常に失敗します(!!) .015で終わるツイスト数は、1、次に4〜7、次に128

で失敗します .025で終わるツイスト数は、1、2、3、および16〜63

で失敗します .035で終わるツイスト数が1で失敗し、その後32〜128

.045で終わるツイスト数が1〜15、その後128
    .055で終わるツイスト数が1で、4〜63
  • .065で終わるツイスト数は、1、2、3、次に8〜15、次に32〜128
  • で失敗します .075で終わるツイスト数は1、次に8〜31、次に128
  • で失敗します .085で終了するねじれた数字は1から7、その後64〜127(!!)
  • .095で終わるツイスト数は、1、次に4〜7、16〜128
  • で失敗します
  • 私よりもバイナリと浮遊点数学について多くを知っている人は、根本原因を推測できるかもしれません。私はこれを演習として読者に任せます。
  • tofixed()
  • を修正しました
  • が1進数を超える
  • は、たとえば(1.0151)。テストとポリフィルの両方が、この知識を正しさのチェックに使用します。
  • これは、すべてのtofixed()実装に簡単な修正があることを意味します。値に小数が含まれている場合、変更する値の文字列バージョンの最後に「1」を追加します。これは「仕様に準拠している」わけではないかもしれませんが、バイナリまたはフローティングポイント操作の低レベルを再検討することなく、期待される結果が得られることを意味します。
  • polyfill

すべての実装が変更される前に、これを行う意思がある場合(誰もが望んでいるわけではありません)、次のポリフィルでtofixed()をオーバーライドできます。

次に、テストをもう一度実行し、結果の長さがゼロかどうかを確認します。

またはこの記事を開始する最初の変換を実行するだけです。

お読みいただきありがとうございます!

JavaScriptのnumber.tofixed()Method

のFAQ(FAQ) javascriptのnumber.tofixed()メソッドの目的は何ですか?

JavaScriptのnumber.tofixed()メソッドは、固定点表記を使用して数値をフォーマットするために使用されます。指数表現を使用しない数字の文字列表現を返し、小数点以降に指定された数字数を正確に持っています。必要に応じて、数値は丸くなり、結果文字列には長さの後の小数点があります。

JavaScriptがバイナリフローティングポイント番号を処理する方法により、number.tofixed()メソッドが不正確な結果を提供する場合があります。 JavaScriptは、すべての小数を正確に表すことができないバイナリフローティングポイント番号を使用します。この不正確さは、number.tofixed()メソッドを使用して特定の10進数に丸められている場合、予期しない結果につながる可能性があります。

number.tofixed()メソッドで丸めエラーを修正する方法は?

number.tofixed()メソッドで丸めエラーを修正する1つの方法は、カスタム丸め関数を使用することです。この関数は、JavaScriptのデジタル処理の特性を考慮し、より正確な結果を提供できます。たとえば、数値に10のパワーを掛け、最寄りの整数に丸めて、同じパワー10で分割する関数を使用できます。

非数値でnumber.tofixed()メソッドを使用できますか?

いいえ、number.tofixed()メソッドは数値でのみ使用できます。非数値でそれを使用しようとすると、JavaScriptはtypeRrorを投げます。数値ではない値でこのメソッドを使用する必要がある場合は、最初に値が数字であるかどうかを確認する必要があります。

通常、

number.tofixed()メソッドとその他の丸めメソッドのパフォーマンスの違いは無視できます。ただし、多くの操作を行っている場合、カスタム丸め関数を使用すると、number.tofixed()メソッドを使用するよりもわずかに高速になる場合があります。

number.tofixed()メソッドを使用して、20以上の小数点に丸めてもいいですか?

いいえ、number.tofixed()メソッドは、最大20桁の場所にしか丸められません。 20以上の小数の場所に丸めようとすると、JavaScriptは範囲を投げます。

マイナス数に対処する方法は?

number.tofixed()メソッドは、正の数値を扱うのと同じように負の数字を処理します。指定された小数の小数の数の絶対値を丸め、否定的な符号を追加します。

すべてのJavaScript環境でnumber.tofixed()メソッドを使用できますか?

はい、number.tofixed()メソッドはJavaScriptの標準部分であり、すべてのJavaScript環境で利用できるはずです。ただし、JavaScriptエンジンが異なるため、数値が異なるため、結果はすべての環境でまったく同じではない場合があります。

number.tofixed()メソッドに引数を渡さないとどうなりますか?

引数をnumber.tofixed()メソッドに渡さない場合、デフォルトでは10小数点に丸められます。これは、数字を最も近い整数に丸めることを意味します。

多数のnumber.tofixed()メソッドを使用できますか?

はい、多数のnumber.tofixed()メソッドを使用できます。ただし、JavaScriptは最大2^53〜1までの数値のみを正確に表すことができることを忘れないでください。この数値よりも大きい番号でnumber.tofixed()メソッドを使用しようとすると、正確な結果が得られない場合があります。

以上がnumber()。tofixed()丸めエラー:壊れているが修正可能の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。