<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC] # 兩個既定的事實 1. 在JS中能否表示的數字的絕對值范圍是5e-324 ~ 1.7976931348623157e+308,這一點可以通過`Number.MAX_VALUE`和`Number.MIN_VALUE`來得到證實 2. 在JS中能夠表示的最大安全整數的范圍是:-9007199254740991 ~ 9007199254740991,這一點可以通過`Number.MIN_SAFE_INTEGER`和`Number.MAX_SAFE_INTEGER`來求證 # 兩個存在的問題 1. 在四則運算中存在精度丟失的問題,比如: `01 + 0.2 //0.30000000000000004` 2. 超過最大安全整數的運算是不安全的,比如:`9007199254740991 + 2 // 9007199254740992` # 存儲 1. 把這個浮點數轉成對應的二進制數,并用科學計數法表示 2. 把這個數值通過[IEEE 754](https://link.juejin.im?target=https%3A%2F%2Fzh.wikipedia.org%2Fwiki%2FIEEE_754)標準表示成真正會在計算機中存儲的值 我們知道,JS中的Number類型使用的是雙精度浮點型,也就是其他語言中的double類型。而雙精度浮點數使用64 bit來進行存儲,結構圖如下: ![](https://user-gold-cdn.xitu.io/2018/1/30/16144bd12f9b3376?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 也就是說一個Number類型的數字在內存中會被表示成:`s x m x 2^e`這樣的格式。 在[ES規范](https://link.juejin.im?target=http%3A%2F%2Fes5.github.io%2F%23x8.5)中規定e的范圍在-1074 ~ 971,而m最大能表示的最大數是52個1,最小能表示的是1,這里需要注意: 二進制的第一位有效數字必定是1,因此這個1不會被存儲,可以節省一個存儲位,因此尾數部分可以存儲的范圍是1 ~ 2^(52+1) **也就是說Number能表示的最大數字絕對值范圍是 2^-1074 ~ 2^(53+971)** # 精度丟失 前面提到,計算機中存儲小數是先轉換成二進制進行存儲的,我們來看一下0.1和0.2轉換成二進制的結果: ~~~ (0.1)10 => (00011001100110011001(1001)...)2 (0.2)10 => (00110011001100110011(0011)...)2 ~~~ 可以發現,0.1和0.2轉成二進制之后都是一個無限循環的數,前面提到尾數位只能存儲最多53位有效數字,這時候就必須來進行四舍五入了,而這個取舍的規則就是在IEEE 754中定義的,0.1最終能被存儲的有效數字是 ~~~ 0001(1001)(1001)(1001)(1001)(1001)(1001)(1001)(1001)(1001)(1001)(1001)(1001)101 + (0011)(0011)(0011)(0011)(0011)(0011)(0011)(0011)(0011)(0011)(0011)(0011)(0011)01 = 0100(1100)(1100)(1100)(1100)(1100)(1100)(1100)(1100)(1100)(1100)(1100)(1100)111 復制代碼 ~~~ > 這里注意,53位的存儲位指的是能存53位有效數字,因此前置的0不算,要往后再取到53位有效數字為止。 最終的這個二進制數轉成十進制就是0.30000000000000004(不信的話可以找一個在線進制轉換工具試一下。 # 最大安全整數 最大安全整數9007199254740991對應的二進制數如圖: ![](https://box.kancloud.cn/1e9daad47daf0b9464906dbd9acc2407_690x67.png) 53位有效數字都存儲滿了之后,想要表示更大的數字,就只能往指數數加一位,這時候尾數因為沒有多余的存儲空間,因此只能補0。 ![](https://box.kancloud.cn/a9c98087f6842de5577ee9c34882d375_636x281.png) 如圖所有,在指數位為53的情況下,最后一位尾數位為0的數字可以被精確表示,而最后一位尾數為為1的數字都不能被精確表示。也就是可以被精確表示和不能被精確表示的比例是`1:1`。 同理,當指數為54的時候,只有最后兩位尾數為00的可以被精確表示,也就是可以被精確表示和不能被精確表示的比例是`1:3`,當有效位數達到`x(x>53)`的時候,可以被精確表示和不能被精確表示的比例將是`1 : 2^(x-53) - 1`。 可以預見的是,在指數越來越高的時候,這個指數會成指數增長,因此在Number.MAX\_SAFE\_INTEGER ~ Number.MAX\_VALUE之間可以被精確表示的整數可以說是鳳毛麟角。 ### 總結 可以發現,不管是浮點數計算的計算結果錯誤和大整數的計算結果錯誤,最終都可以歸結到JS的精度只有53位(尾數只能存儲53位的有效數字)。那么我們在日常工作中碰到這兩個問題該如何解決呢? 大而全的解決方案就是使用[mathjs](https://link.juejin.im/?target=https%3A%2F%2Fgithub.com%2Fjosdejong%2Fmathjs),看一下mathjs的輸出: ~~~ math.config({ number: 'BigNumber', precision: 64 }); console.log(math.format(math.eval('0.1 + 0.2'))); // '0.3' console.log(math.format(math.eval('0.23 \* 0.34 \* 0.92'))); // '0.071944' console.log(math.format(math.eval('9007199254740991 + 2'))); // '9.007199254740993e+15' ~~~ 其實平時在遇到整型溢出的情況是非常少的,大部分場景是浮點數的計算,如果不想因為一些簡單的計算引入mathjs的話,也可以自己來實現運算函數(需要考慮數字是否越界和當數字被表示成科學計數法的場景),如果懶得自己實現的話,可以使用這個1k都不到的[number-precision](https://link.juejin.im?target=https%3A%2F%2Fgithub.com%2Fnefe%2Fnumber-precision),這個工具庫API簡潔很多,已經可以解決浮點數的計算問題了(看了代碼,對于超出Number.MAX\_SAFE\_INTEGER的數字的處理方式是拋出warning)。 # 參考資料 * [從0.1+0.2=0.30000000000000004再看JS中的Number類型](https://juejin.im/post/5a6fce10f265da3e261c3c71)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看