落とし穴最近、仕事で商品の割引価格を計算すると、いつも1セントの価格差が出てしまいます。お金が絡む問題はより敏感です。調査した結果、最終的にJSのネイティブtoFixedメソッドの問題であることが判明しました。 まあ、これはどういうルールですか? 。 。 (⊙お⊙) 充填方法問題を急いで調べないでください。問題を見つけたので、まずはバグを修正してください。ネイティブ メソッドが機能しない場合は、自分で書いてください。数分しかかかりません、ハハハ! /** * 小数点以下の桁数を保持し、自動的にゼロを埋め、切り上げます* @param num: 値* @param digit: 小数点以下の桁数* @returns 文字列 */ 関数 myFixed(数値, 桁数) { if(Object.is(parseFloat(num), NaN)) { return console.log(`受信値: ${num} は数値ではありません`); } num = parseFloat(num); (Math.round((num + Number.EPSILON) * Math.pow(10, digit)) / Math.pow(10, digit)).toFixed(digit) を返します。 } 何の穴ですか?さて、バグが修正されたので、toFixed の秘密を探ってみましょう。 えーっと…まずは、えーっと…百度で、百度プログラミングエンジニアを対象に検索してみましょう。案の定、たくさんの結果が出てきます。典型的な問題のようです。 少し理解してみると、toFixed メソッドで使用される丸めは、私たちが理解している文字通りの丸めではないことがわかりました。 toFixed メソッドは、「偶数への丸め」と呼ばれる奇妙な方法を使用します。これは銀行家のアルゴリズムとしても知られています。これはどういう意味ですか? 完全な文: 「最も近い 5 に切り上げます。5 の後の数が 0 でない場合は、1 を加えます。5 の後の数が 0 の場合は、それが奇数か偶数かを検討します。5 の前の数が偶数の場合は、それを破棄します。5 の前の数が奇数の場合は、1 を加えます。」 一般的な意味は、捨てられた数字の値が ≤4 の場合は捨て、≥6 の場合は加算し、=5 の場合は 5 の後の数字に応じて決定し、5 の後に 0 以外の数字がある場合は 5 を 1 に丸め、5 の後に有効な数字がない場合は、2 つのケースに分けられます。5 の前の数字が偶数の場合は 5 を丸めて加算せず、5 の前の数字が奇数の場合は 5 を 1 に丸めます。 このルールに従って、ブラウザでさらにいくつかのテストを実行しましたが、まだ適切ではないと感じました。 // 5 の前の数字は偶数なので、切り捨てられませんか? console.log(1.00000065.toFixed(7)); // 1.0000007 エラー console.log(1.000000065.toFixed(8)); // 1.00000007 エラー // 5 の前の数字は奇数なので、1 増加しませんか? console.log(1.00000015.toFixed(7)); // 1.0000001 エラー console.log(1.000000015.toFixed(8)); // 1.00000001 エラー これはなぜでしょうか?本当に混乱します。 。 。 (︶︿︶) さらに調査を進めた結果、ようやく結果が得られました。では、このメソッドの ECMAScript 仕様の定義を見てみましょう。仕様に戻るのが最も信頼できる方法である場合もあります。 上の図はtoFixedメソッド全体の定義ですが、翻訳版です。多少の違いはありますが、大きな違いはありません。上のリンクをクリックして元のテキストを表示することもできます。図の赤いボックス部分に主に焦点を当て、数式を使用して破棄された値を計算します。 次の 2 つの例を取り上げ、テストしてみましょう。 console.log(1.0000005.toFixed(6)); // 1.000001 正解 console.log(1.00000005.toFixed(7)); // 1.0000000 間違い まず、赤いボックスの条件によれば、x<10^21、1.0000005、1.00000005 はどちらも 10^21 未満なので、式 n / 10^ - x を直接使用できます。 まず、x=1.0000005 を式に代入して状況を確認しましょう。 // n1と仮定 var n1 = 1000000; var x = 1.0000005; var f = 6; console.log((n1 / Math.pow(10, f) - x)); // -5.00000000069889e-7 // n2と仮定 var n2 = 1000001; var x = 1.0000005; var f = 6; console.log((n2 / Math.pow(10, f) - x)); // 4.9999999998478444e-7 結果から、n1=1000001 の場合、結果は 0 に最も近い値であることがわかります。 console.log(1.0000005.toFixed(6)); // 1.000001が正しい 式に x=1.00000005 を代入してもう一度試してみましょう。 // n1と仮定 var n1 = 10000000; var x = 1.00000005; var f = 7; console.log((n1 / Math.pow(10,f) - x)); // -4.99999999918171056e-8 // n2と仮定 var n2 = 10000001; var x = 1.00000005; var f = 7; console.log((n2 / Math.pow(10,f) - x)); // 5.000000014021566e-8 結果から、n2=10000001 の場合、結果は 0 に最も近い値であることがわかります。 console.log(1.00000005.toFixed(7)); // 1.0000000 エラー ああ...ここに来て、自分が大きな穴を掘ってしまったことに今気づきました。なぜこんなにたくさんのゼロを使わなければならないのでしょうか。数えると目が回ります。 。 。 一般的に、上記の例は、仕様で定義されている式を使用して結果を計算する方法を説明するだけです。仕様を理解できる場合は、直接代入しても問題ありません。 要約するJS の toFixed() メソッドの丸め精度問題についての記事はこれで終わりです。JS toFixed() の丸め精度問題についての詳細は、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
コンテキストの定義と目的コンテキストは、コンポーネント ツリーにプロパティを明示的に渡すことなく、コ...
各ブラウザの select タグのプロパティと各ブラウザのサポートが多少異なるため、各ブラウザでの選...
1. 背景通常、外部サービスを提供する必要がある Docker コンテナの場合、起動時に -p コマ...
目次序文1. GMT GMTとはGMTの歴史2. UTC UTCとはUTC は次の 2 つの部分で構...
目次無イメージの創造と混乱Noneオブジェクトをクリーンアップする方法トリムミラーコンテナで使用され...
<br />前の記事:Webデザインチュートリアル(6):デザインへの情熱を持ち続けまし...
MySQL x64 はインストーラーを提供していません、インストーラーを提供していません、インストー...
この記事では、参考までに、簡単な虫眼鏡効果を実現するためのVueの具体的なコードを紹介します。具体的...
この記事では、テキストクロックを実装するためのキャンバスの具体的なコードを例として紹介します。具体的...
目次ノードのバージョンが一致しない、ノードをアップグレードまたはダウングレードするnvm を使用して...
序文長い間、MySQL のアプリケーションおよび学習環境は MySQL 5.6 以前のバージョンであ...
JavaScript を使用して Web ページ クロックを実装します。効果は次の図に示されています...
ReactとはReact は、効率的で高速なユーザー インターフェイスを構築するためのシンプルな J...
1. pipとは何かpip は、Python パッケージの検索、ダウンロード、インストール、アンイ...
MySQLをアンインストールする1. コントロールパネルで、MySQLのすべてのコンポーネントをア...