Math
功能 Number
屬性Math
方法Number.parseInt()
和新的整數文字Number
屬性
Number.EPSILON
Number.isInteger(number)
Math
功能
您現在可以使用二進位和八進位表示法指定整數
> 0xFF // ES5: hexadecimal
255
> 0b11 // ES6: binary
3
> 0o10 // ES6: octal
8
Number
屬性 全域物件Number
獲得了一些新的屬性
Number.EPSILON
用於比較浮點數,並容許捨入誤差。Number.isInteger(num)
檢查num
是否為整數(沒有小數部分的數字)
> Number.isInteger(1.05)
false
> Number.isInteger(1)
true
> Number.isInteger(-3.1)
false
> Number.isInteger(-3)
true
Number.isSafeInteger(number)
Number.MIN_SAFE_INTEGER
Number.MAX_SAFE_INTEGER
Number.isNaN(num)
檢查num
是否為值NaN
。與全域函式isNaN()
相反,它不會強制將其參數轉換為數字,因此對於非數字而言更安全
> isNaN('???')
true
> Number.isNaN('???')
false
Number
的另外三個方法大多等同於具有相同名稱的全域函式:Number.isFinite
、Number.parseFloat
、Number.parseInt
。Math
方法 全域物件 Math
有新的方法,用於數值、三角函數和位元運算。我們來看四個範例。
Math.sign()
傳回數字的符號
> Math.sign(-8)
-1
> Math.sign(0)
0
> Math.sign(3)
1
Math.trunc()
移掉數字的小數部分
> Math.trunc(3.1)
3
> Math.trunc(3.9)
3
> Math.trunc(-3.1)
-3
> Math.trunc(-3.9)
-3
Math.log10()
計算以 10 為底的對數
> Math.log10(100)
2
Math.hypot()
計算其參數平方和的平方根(畢氏定理)
> Math.hypot(3, 4)
5
ECMAScript 5 已經有十六進位整數文字
> 0x9
9
> 0xA
10
> 0x10
16
> 0xFF
255
ECMAScript 6 帶來兩種新的整數文字
0b
或 0B
> 0b11
3
> 0b100
4
0o
或 0O
(那是零後面跟著大寫字母 O;第一個變體比較安全)
> 0o7
7
> 0o10
8
請記住,Number
方法 toString(radix)
可用於查看非 10 進位的數字
> 255..toString(16)
'ff'
> 4..toString(2)
'100'
> 8..toString(8)
'10'
(需要雙點,這樣存取屬性的點才不會和十進位點搞混。)
在 Node.js 檔案系統模組中,幾個函數有參數 mode
。它的值用於指定檔案權限,透過一種從 Unix 遺留下來的編碼
這表示權限可以用 9 個位元表示(3 個類別,每個類別有 3 個權限)
使用者 | 群組 | 所有人 | |
---|---|---|---|
權限 | r, w, x | r, w, x | r, w, x |
位元 | 8, 7, 6 | 5, 4, 3 | 2, 1, 0 |
單一類別使用者的權限儲存在 3 個位元中
位元 | 權限 | 八進位數字 |
---|---|---|
000 | ––– | 0 |
001 | ––x | 1 |
010 | –w– | 2 |
011 | –wx | 3 |
100 | r–– | 4 |
101 | r–x | 5 |
110 | rw– | 6 |
111 | rwx | 7 |
這表示八進制數字是所有權限的緊湊表示,您只需要 3 個數字,每個使用者類別一個數字。兩個範例
Number.parseInt()
和新的整數文字 Number.parseInt()
(執行與全域函式 parseInt()
相同的動作)具有下列簽章
Number
.
parseInt
(
string
,
radix
?
)
Number.parseInt()
:十六進位數字文字 Number.parseInt()
提供對十六進位文字符表示法的特殊支援,如果
radix
遺失或為 0,則移除 string
的字首 0x
(或 0X
)。然後將 radix
設為 16。原則上,您絕不應省略 radix
。radix
為 16。例如
> Number.parseInt('0xFF')
255
> Number.parseInt('0xFF', 0)
255
> Number.parseInt('0xFF', 16)
255
在所有其他情況下,只會分析數字直到第一個非數字
> Number.parseInt('0xFF', 10)
0
> Number.parseInt('0xFF', 17)
0
Number.parseInt()
:二進位和八進位數字文字 不過,Number.parseInt()
沒有對二進位或八進位文字提供特殊支援!
> Number.parseInt('0b111')
0
> Number.parseInt('0b111', 2)
0
> Number.parseInt('111', 2)
7
> Number.parseInt('0o10')
0
> Number.parseInt('0o10', 8)
0
> Number.parseInt('10', 8)
8
如果您想要分析這些類型的文字,您需要使用 Number()
> Number('0b111')
7
> Number('0o10')
8
Number.parseInt()
對於具有不同基底的數字運作良好,只要沒有特殊字首,且有提供參數 radix
> Number.parseInt('111', 2)
7
> Number.parseInt('10', 8)
8
Number
屬性 本節說明建構函式 Number
在 ECMAScript 6 中新增的屬性。
四個與數字相關的函式已作為全域函式提供,並已新增至 Number
作為方法:isFinite
和 isNaN
、parseFloat
和 parseInt
。它們的運作方式幾乎與其全域對應函式相同,但 isFinite
和 isNaN
不再強制其引數為數字,這對 isNaN
來說特別重要。下列小節說明所有詳細資料。
Number.isFinite(number)
Number.isFinite(number)
判斷 number
是否為實際數字(既不是 Infinity
也不是 -Infinity
也不是 NaN
)
> Number.isFinite(Infinity)
false
> Number.isFinite(-Infinity)
false
> Number.isFinite(NaN)
false
> Number.isFinite(123)
true
此方法的優點是它不會強制參數為數字(而全域函數會)
> Number.isFinite('123')
false
> isFinite('123')
true
Number.isNaN(number)
Number.isNaN(number)
檢查 number
是否為 NaN
值。
ES5 進行此檢查的一種方法是透過 !==
> const x = NaN;
> x !== x
true
更具描述性的方法是透過全域函數 isNaN()
> const x = NaN;
> isNaN(x)
true
不過,此函數會強制非數字轉換為數字,如果結果為 NaN
則傳回 true
(通常不是您要的結果)
> isNaN('???')
true
新方法 Number.isNaN()
沒有這個問題,因為它不會強制參數轉換為數字
> Number.isNaN('???')
false
Number.parseFloat
和 Number.parseInt
以下兩個方法的運作方式與同名的全域函數完全相同。它們新增至 Number
是為了完整性;現在所有與數字相關的函數都可以在這裡找到。
Number.EPSILON
特別是對於小數,四捨五入誤差可能會成為 JavaScript 中的問題3。例如,0.1 和 0.2 無法精確表示,如果您將它們加起來並與 0.3 比較(也無法精確表示),就會發現這一點。
> 0.1 + 0.2 === 0.3
false
Number.EPSILON
在比較浮點數時指定合理的誤差範圍。它提供了一種比較浮點數值的更好方法,如下列函數所示。
function
epsEqu
(
x
,
y
)
{
return
Math
.
abs
(
x
-
y
)
<
Number
.
EPSILON
;
}
console
.
log
(
epsEqu
(
0.1
+
0.2
,
0.3
));
// true
Number.isInteger(number)
JavaScript 只有浮點數(雙精度)。因此,整數只是沒有小數部分的浮點數。
Number.isInteger(number)
如果 number
是數字且沒有小數部分,則傳回 true
。
> Number.isInteger(-17)
true
> Number.isInteger(33)
true
> Number.isInteger(33.1)
false
> Number.isInteger('33')
false
> Number.isInteger(NaN)
false
> Number.isInteger(Infinity)
false
JavaScript 數字只有足夠的儲存空間來表示 53 位元有號整數。也就是說,範圍為 −253 < i < 253 的整數 i 是 安全的。其具體含義將在稍後說明。下列屬性有助於判斷 JavaScript 整數是否安全
Number.isSafeInteger(number)
Number.MIN_SAFE_INTEGER
Number.MAX_SAFE_INTEGER
安全整數 的概念集中在數學整數在 JavaScript 中的表示方式上。在範圍 (−253, 253)(不包括下限和上限)中,JavaScript 整數是 安全的:它們與其表示的數學整數之間存在一對一的對應關係。
超出此範圍,JavaScript 整數是不 安全的:兩個或多個數學整數表示為同一個 JavaScript 整數。例如,從 253 開始,JavaScript 只能表示每個數學整數的第二個
> Math.pow(2, 53)
9007199254740992
> 9007199254740992
9007199254740992
> 9007199254740993
9007199254740992
> 9007199254740994
9007199254740994
> 9007199254740995
9007199254740996
> 9007199254740996
9007199254740996
> 9007199254740997
9007199254740996
因此,安全的 JavaScript 整數是一個明確表示單一數學整數的整數。
Number
屬性 指定安全整數下限和上限的兩個靜態 Number
屬性可定義如下
Number
.
MAX_SAFE_INTEGER
=
Math
.
pow
(
2
,
53
)
-
1
;
Number
.
MIN_SAFE_INTEGER
=
-
Number
.
MAX_SAFE_INTEGER
;
Number.isSafeInteger()
判斷 JavaScript 數字是否為安全整數,可定義如下
Number
.
isSafeInteger
=
function
(
n
)
{
return
(
typeof
n
===
'number'
&&
Math
.
round
(
n
)
===
n
&&
Number
.
MIN_SAFE_INTEGER
<=
n
&&
n
<=
Number
.
MAX_SAFE_INTEGER
);
}
對於給定的值 n
,此函數首先檢查 n
是否為數字和整數。如果兩個檢查都成功,則 n
大於或等於 MIN_SAFE_INTEGER
且小於或等於 MAX_SAFE_INTEGER
,則 n
是安全的。
我們如何確保使用整數進行運算的結果是正確的?例如,下列結果明顯不正確
> 9007199254740990 + 3
9007199254740992
我們有兩個安全的運算元,但結果不安全
> Number.isSafeInteger(9007199254740990)
true
> Number.isSafeInteger(3)
true
> Number.isSafeInteger(9007199254740992)
false
下列結果也不正確
> 9007199254740995 - 10
9007199254740986
這次,結果是安全的,但其中一個運算元不是
> Number.isSafeInteger(9007199254740995)
false
> Number.isSafeInteger(10)
true
> Number.isSafeInteger(9007199254740986)
true
因此,只有當所有運算元和結果都是安全的,應用整數運算子 op
的結果才保證正確。更正式地說
isSafeInteger
(
a
)
&&
isSafeInteger
(
b
)
&&
isSafeInteger
(
a
op
b
)
暗示 a op b
是正確的結果。
Math
功能 在 ECMAScript 6 中,全域物件 Math
有好幾個新方法。
Math.sign(x)
Math.sign(x)
回傳
-1
如果 x
是負數(包括 -Infinity
)。0
如果 x
是零4。+1
如果 x
是正數(包括 Infinity
)。NaN
如果 x
是 NaN
或不是數字。範例
> Math.sign(-8)
-1
> Math.sign(3)
1
> Math.sign(0)
0
> Math.sign(NaN)
NaN
> Math.sign(-Infinity)
-1
> Math.sign(Infinity)
1
Math.trunc(x)
Math.trunc(x)
移除了 x
的小數部分。補充其他捨入方法 Math.floor()
、Math.ceil()
和 Math.round()
。
> Math.trunc(3.1)
3
> Math.trunc(3.9)
3
> Math.trunc(-3.1)
-3
> Math.trunc(-3.9)
-3
你可以像這樣實作 Math.trunc()
function
trunc
(
x
)
{
return
Math
.
sign
(
x
)
*
Math
.
floor
(
Math
.
abs
(
x
));
}
Math.cbrt(x)
Math.cbrt(x)
回傳 x
的立方根(∛x)。
> Math.cbrt(8)
2
如果小數出現在零之後,可以更精確地表示。我將使用小數來示範(JavaScript 的數字在內部以 2 為底儲存,但相同的推理適用)。
以 10 為底的浮點數在內部表示為 尾數 × 10指數。尾數 在小數點之前有一個位數,而指數會根據需要「移動」小數點。這表示如果你將小數轉換為內部表示,小數點之前的一個零會導致比小數點之前的一個一更小的尾數。例如
就精確度而言,這裡重要的數量是尾數的容量,以有效位數衡量。這就是為什麼 (A) 比 (B) 給你更高的精確度。
此外,JavaScript 會以更高的精度表示接近零的數字(例如小數)。
Math.expm1(x)
Math.expm1(x)
傳回 Math.exp(x)-1
。Math.log1p()
的反函數。
因此,只要 Math.exp()
的結果接近 1,這個方法就會提供更高的精度。您可以在以下互動中看到兩者之間的差異
> Math.expm1(1e-10)
1.00000000005e-10
> Math.exp(1e-10)-1
1.000000082740371e-10
前者是更好的結果,您可以使用一個函式庫(例如 decimal.js)來驗證,該函式庫提供具有任意精度的浮點數(「bigfloat」)
>
var
Decimal
=
require
(
'decimal.js'
)
.
config
(
{
precision
:
50
}
);
>
new
Decimal
(
1e-10
)
.
exp
()
.
minus
(
1
)
.
toString
()
'1.000000000050000000001666666666708333333e-10'
Math.log1p(x)
Math.log1p(x)
傳回 Math.log(1 + x)
。Math.expm1()
的反函數。
因此,這個方法讓您可以使用更高的精度指定接近 1 的參數。以下範例說明了原因。
以下兩個 log()
呼叫會產生相同的結果
> Math.log(1 + 1e-16)
0
> Math.log(1 + 0)
0
相反地,log1p()
會產生不同的結果
> Math.log1p(1e-16)
1e-16
> Math.log1p(0)
0
Math.log1p()
精度較高的原因是 1 + 1e-16
的正確結果比 1e-16
有更多有效數字
> 1 + 1e-16 === 1
true
> 1e-16 === 0
false
Math.log2(x)
Math.log2(x)
計算以 2 為底數的對數。
> Math.log2(8)
3
Math.log10(x)
Math.log10(x)
計算以 10 為底數的對數。
> Math.log10(100)
2
Emscripten 開創了一種編碼風格,後來被 asm.js 採用:虛擬機器(想想位元組碼)的操作以 JavaScript 的靜態子集表示。JavaScript 引擎可以有效地執行該子集:如果它是從 C++ 編譯的結果,則執行速度約為原生速度的 70%。
以下 Math
方法主要是為了支援 asm.js 和類似的編譯策略而新增的,它們對其他應用程式沒有那麼有用。
Math.fround(x)
Math.fround(x)
將 x
四捨五入為 32 位元浮點值 (float
)。asm.js 使用它來告知引擎在內部使用 float
值。
Math.imul(x, y)
Math.imul(x, y)
將兩個 32 位元整數 x
和 y
相乘,並傳回結果的低 32 位元。這是唯一無法透過使用 JavaScript 運算子並將結果強制轉換回 32 位元的 32 位元基本數學運算。例如,idiv
可實作如下
function
idiv
(
x
,
y
)
{
return
(
x
/
y
)
|
0
;
}
相反地,將兩個大型 32 位元整數相乘可能會產生一個非常大的雙精度浮點數,以致於低位元會遺失。
Math.clz32(x)
x
中的開頭零位元數。
> Math.clz32(0b01000000000000000000000000000000)
1
> Math.clz32(0b00100000000000000000000000000000)
2
> Math.clz32(2)
30
> Math.clz32(1)
31
為什麼這很有趣?引用 Miro Samek 的「快速、確定性且可攜式計算開頭零」
計算整數中的開頭零在許多 DSP 演算法中都是一項重要的運算,例如音訊或視訊處理中範例的正規化,以及在即時排程器中快速找出優先順序最高的準備執行任務。
Math.sinh(x)
x
的雙曲正弦。Math.cosh(x)
x
的雙曲餘弦。Math.tanh(x)
x
的雙曲正切。Math.asinh(x)
x
的反雙曲正弦。Math.acosh(x)
x
的反雙曲餘弦。Math.atanh(x)
x
的反雙曲正切。Math.hypot(...values)
> Math.hypot(3, 4)
5
JavaScript 整數的範圍為 53 位元。當需要 64 位元整數時,這會造成問題。例如:在它的 JSON API 中,當推文 ID 變得太大時,Twitter 必須從整數切換為字串。
目前,解決此限制的唯一方法是使用高精度數字(大整數或大浮點數)的函式庫。其中一個函式庫是 decimal.js。
支援 JavaScript 中較大整數的計畫已經存在,但可能需要一段時間才能實現。