數學運算和基本函數

Julia 提供了所有數值基本類型中基本算術和位元運算子的完整集合,並提供標準數學函數的全面集合的可攜式、有效率的實作。

算術運算子

以下算術運算子支援所有基本數值類型

表達式名稱說明
+x單元正號恆等運算
-x單元負號將值對應到其加法逆元
x + y二元正號執行加法
x - y二元負號執行減法
x * y乘號執行乘法
x / y除號執行除法
x ÷ y整數除法x / y,取整
x \ y反除法等於 y / x
x ^ y冪次x 提升到 y 次方
x % y餘數等於 rem(x,y)

直接置於識別碼或括號之前的數字字面值,例如 2x2(x+y),視為乘法,但優先權高於其他二元運算。有關詳細資訊,請參閱 數字字面值係數

Julia 的提升系統讓混合參數類型的算術運算自然而然地「正常運作」。有關提升系統的詳細資訊,請參閱 轉換與提升

÷ 符號可以透過在 REPL 或 Julia IDE 中輸入 \div<tab> 方便地輸入。有關更多資訊,請參閱 Unicode 輸入手冊

以下是一些使用算術運算子的簡單範例

julia> 1 + 2 + 3
6

julia> 1 - 2
-1

julia> 3*2/12
0.5

(依慣例,我們傾向於將運算子間距縮小,如果它們在其他鄰近運算子之前套用。例如,我們通常會寫成 -x + 2 來反映首先對 x 進行否定,然後將 2 加到該結果中。)

在乘法中使用時,false 會作為一個強零

julia> NaN * false
0.0

julia> false * Inf
0.0

這對於防止已知為零的數量中 NaN 值的傳播很有用。請參閱 Knuth (1992) 以了解動機。

布林運算子

下列 布林運算子 支援 Bool 類型

表達式名稱
!x否定
x && y短路與
x || y短路或

否定會將 true 變更為 false,反之亦然。短路運算說明於連結的頁面中。

請注意,Bool 是整數類型,且所有通常的提升規則和數字運算子也定義在其中。

位元運算子

下列 位元運算子 支援所有原始整數類型

表達式名稱
~x位元非
x & y位元與
x | y位元或
x ⊻ y位元異或(互斥或)
x ⊼ y位元非與(非與)
x ⊽ y位元非或(非或)
x >>> y邏輯位移右移
x >> y算術位移右移
x << y邏輯/算術位移左移

以下是位元運算子的一些範例

julia> ~123
-124

julia> 123 & 234
106

julia> 123 | 234
251

julia> 123 ⊻ 234
145

julia> xor(123, 234)
145

julia> nand(123, 123)
-124

julia> 123 ⊼ 123
-124

julia> nor(123, 124)
-128

julia> 123 ⊽ 124
-128

julia> ~UInt32(123)
0xffffff84

julia> ~UInt8(123)
0x84

更新運算子

每個二進制算術和位元運算子也都有更新版本,會將運算結果指派回其左運算元。二進制運算子的更新版本是將 = 放在運算子之後。例如,寫成 x += 3 等同於寫成 x = x + 3

julia> x = 1
1

julia> x += 3
4

julia> x
4

所有二進制算術和位元運算子的更新版本為

+=  -=  *=  /=  \=  ÷=  %=  ^=  &=  |=  ⊻=  >>>=  >>=  <<=
注意

更新運算子會重新繫結左手邊的變數。因此,變數的類型可能會改變。

julia> x = 0x01; typeof(x)
UInt8

julia> x *= 2 # Same as x = x * 2
2

julia> typeof(x)
Int64

向量化「點」運算子

對於每個二進制運算,例如 ^,都有對應的「點」運算 .^,會自動定義為對陣列執行逐元素 ^。例如,[1,2,3] ^ 3 沒有定義,因為對(非正方形)陣列「立方」沒有標準的數學意義,但 [1,2,3] .^ 3 定義為計算逐元素(或「向量化」)結果 [1^3, 2^3, 3^3]。對於一元運算,例如 !,也有對應的 .√,會逐元素套用運算子。

julia> [1,2,3] .^ 3
3-element Vector{Int64}:
  1
  8
 27

更具體地說,a .^ b 會被解析為 「點」呼叫 (^).(a,b),它會執行 廣播 操作:它可以組合陣列和純量、相同大小的陣列(逐元素執行操作),甚至不同形狀的陣列(例如,組合行向量和列向量以產生矩陣)。此外,與所有向量化「點呼叫」一樣,這些「點運算子」都是融合的。例如,如果你計算陣列 A2 .* A.^2 .+ sin.(A)(或等效地使用 @. 巨集計算 @. 2A^2 + sin(A)),它會對 A 執行單一迴圈,為 A 的每個元素 a 計算 2a^2 + sin(a)。特別是,像 f.(g.(x)) 這樣的巢狀點呼叫會被融合,而像 x .+ 3 .* x.^2 這樣的「相鄰」二元運算子等同於巢狀點呼叫 (+).(x, (*).(3, (^).(x, 2)))

此外,像 a .+= b(或 @. a += b)這樣的「點」更新運算子會被解析為 a .= a .+ b,其中 .= 是融合的原地賦值運算(請參閱 點語法文件)。

請注意,點語法也適用於使用者定義的運算子。例如,如果你定義 ⊗(A,B) = kron(A,B) 以提供克羅內克積(kron)的方便中綴語法 A ⊗ B,則 [A,B] .⊗ [C,D] 將計算 [A⊗C, B⊗D],而無需額外的編碼。

將點運算子與數字文字結合可能會產生歧義。例如,不清楚 1.+x 是表示 1. + x 還是 1 .+ x。因此,此語法不被允許,並且在這種情況下必須在運算子周圍使用空格。

數值比較

所有原始數值類型都定義了標準比較運算

運算子名稱
==相等
!=, 不相等
<小於
<=, 小於或等於
>大於
>=, 大於或等於

以下是一些簡單範例

julia> 1 == 1
true

julia> 1 == 2
false

julia> 1 != 2
true

julia> 1 == 1.0
true

julia> 1 < 2
true

julia> 1.0 > 3
false

julia> 1 >= 1.0
true

julia> -1 <= 1
true

julia> -1 <= -1
true

julia> -1 <= -2
false

julia> 3 < -0.5
false

整數的比較方式為標準方式,也就是比較位元。浮點數的比較方式則依據 IEEE 754 標準

  • 有限數值以一般方式排序。
  • 正零等於負零,但不大於負零。
  • Inf 等於自身,且大於所有其他值,除了 NaN
  • -Inf 等於自身,且小於所有其他值,除了 NaN
  • NaN 不等於、不小於、也不大於任何值,包括自身。

最後一點可能令人驚訝,因此值得注意

julia> NaN == NaN
false

julia> NaN != NaN
true

julia> NaN < NaN
false

julia> NaN > NaN
false

且在使用 陣列 時可能會造成頭痛

julia> [1 NaN] == [1 NaN]
false

Julia 提供其他函式來測試數值的特殊值,這在雜湊金鑰比較等情況下會很有用

函式測試是否
isequal(x, y)xy 相同
isfinite(x)x 是有限數值
isinf(x)x 是無限大
isnan(x)x 不是數字

isequalNaN 為彼此相等

julia> isequal(NaN, NaN)
true

julia> isequal([1 NaN], [1 NaN])
true

julia> isequal(NaN, NaN32)
true

isequal 也可用於區分有號零

julia> -0.0 == 0.0
true

julia> isequal(-0.0, 0.0)
false

有號整數、無號整數和浮點數之間的混合型比較可能會很棘手。Julia 已非常小心地確保正確執行這些比較。

對於其他類型,isequal 預設會呼叫 ==,因此如果您想要為自己的類型定義相等性,則只需新增一個 == 方法。如果您定義自己的相等性函數,則您可能應該定義一個對應的 hash 方法,以確保 isequal(x,y) 暗示 hash(x) == hash(y)

鏈結比較

與大多數語言不同,在 Python 的顯著例外 中,比較可以任意鏈結

julia> 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
true

在數值程式碼中,鏈結比較通常非常方便。鏈結比較使用 && 算子進行純量比較,並使用 & 算子進行逐元素比較,這允許它們在陣列上執行。例如,0 .< A .< 1 會產生一個布林陣列,其中 A 的對應元素在 0 和 1 之間的項目為 true。

請注意鏈結比較的評估行為

julia> v(x) = (println(x); x)
v (generic function with 1 method)

julia> v(1) < v(2) <= v(3)
2
1
3
true

julia> v(1) > v(2) <= v(3)
2
1
false

中間表達式只會評估一次,而不是像表達式寫成 v(1) < v(2) && v(2) <= v(3) 時評估兩次。但是,鏈結比較中評估的順序是未定義的。強烈建議不要在鏈結比較中使用具有副作用(例如列印)的表達式。如果需要副作用,則應明確使用短路 && 算子(請參閱 短路評估)。

基本函數

Julia 提供全面的數學函數和運算子集合。這些數學運算定義在廣泛的數值範圍內,包括整數、浮點數、有理數和複數,只要這些定義有意義。

此外,這些函數(就像任何 Julia 函數一樣)可以使用 點語法 f.(A) 以「向量化」方式應用於陣列和其他集合,例如 sin.(A) 將計算陣列 A 中每個元素的正弦值。

運算子優先順序和結合性

Julia 應用以下運算順序和結合性,從優先順序最高到最低

類別運算子結合性
語法. 後接 ::
指數^
單元+ - √[1]
位元移位<< >> >>>
分數//
乘法* / % & \ ÷[2]
加法+ - | ⊻[2]
語法: ..
語法|>
語法<|
比較> < >= <= == === != !== <:非結合
控制流程&& 後接 || 後接 ?
配對=>
指定= += -= *= /= //= \= ^= ÷= %= |= &= ⊻= <<= >>= >>>=

如需取得 每個 Julia 運算子優先順序的完整清單,請參閱此檔案的頂端:src/julia-parser.scm。請注意,其中一些運算子並未定義在 Base 模組中,但可能會由標準函式庫、套件或使用者程式碼提供定義。

您也可以透過內建函數 Base.operator_precedence 找出任何給定運算子的數值優先順序,其中數字越大,優先順序越高

julia> Base.operator_precedence(:+), Base.operator_precedence(:*), Base.operator_precedence(:.)
(11, 12, 17)

julia> Base.operator_precedence(:sin), Base.operator_precedence(:+=), Base.operator_precedence(:(=))  # (Note the necessary parens on `:(=)`)
(0, 1, 1)

也可以透過呼叫內建函式 Base.operator_associativity 來找到表示運算子結合性的符號

julia> Base.operator_associativity(:-), Base.operator_associativity(:+), Base.operator_associativity(:^)
(:left, :none, :right)

julia> Base.operator_associativity(:⊗), Base.operator_associativity(:sin), Base.operator_associativity(:→)
(:left, :none, :right)

請注意,例如 :sin 等符號會傳回優先權 0。此值表示無效運算子,而非優先權最低的運算子。類似地,此類運算子會指定結合性 :none

數值文字係數,例如 2x,會視為乘法,優先權高於任何其他二元運算,但 ^ 例外,其中只有作為指數時,優先權才會比較高。

julia> x = 3; 2x^2
18

julia> x = 3; 2^2x
64

並置會解析為一元運算子,它在指數周圍具有相同的自然不對稱性:-x^y2x^y 會解析為 -(x^y)2(x^y),而 x^-yx^2y 會解析為 x^(-y)x^(2y)

數值轉換

Julia 支援三種形式的數值轉換,它們在處理不精確轉換時的方式不同。

  • 符號 T(x)convert(T,x) 會將 x 轉換為類型 T 的值。

    • 如果 T 是浮點類型,結果會是最接近的可表示值,可能是正或負無限大。
    • 如果 T 是整數類型,如果 x 無法由 T 表示,就會引發 InexactError
  • x % T 會將整數 x 轉換為整數類型 T 的值,與 x 同餘模 2^n,其中 nT 中的位元數。換句話說,二進位表示法會被截斷以符合。

  • 取捨函數 將類型 T 作為可選參數。例如,round(Int,x)Int(round(x)) 的簡寫。

以下範例顯示不同的形式。

julia> Int8(127)
127

julia> Int8(128)
ERROR: InexactError: trunc(Int8, 128)
Stacktrace:
[...]

julia> Int8(127.0)
127

julia> Int8(3.14)
ERROR: InexactError: Int8(3.14)
Stacktrace:
[...]

julia> Int8(128.0)
ERROR: InexactError: Int8(128.0)
Stacktrace:
[...]

julia> 127 % Int8
127

julia> 128 % Int8
-128

julia> round(Int8,127.4)
127

julia> round(Int8,127.6)
ERROR: InexactError: trunc(Int8, 128.0)
Stacktrace:
[...]

請參閱 轉換與提升,了解如何定義自己的轉換與提升。

取捨函數

函式說明傳回類型
round(x)x 取捨為最接近的整數typeof(x)
round(T, x)x 取捨為最接近的整數T
floor(x)x 取捨為小於或等於 -Inftypeof(x)
floor(T, x)x 取捨為小於或等於 -InfT
ceil(x)x 取捨為大於或等於 +Inftypeof(x)
ceil(T, x)x 取捨為大於或等於 +InfT
trunc(x)x 取捨為 0typeof(x)
trunc(T, x)x 取捨為 0T

除法函數

函式說明
div(x,y)x÷y截斷除法;商數取捨為 0
fld(x,y)向下取整除法;商數取捨為 -Inf
cld(x,y)向上取整除法;商數取捨為 +Inf
rem(x,y)x%y餘數;滿足 x == div(x,y)*y + rem(x,y);符號與 x 相同
mod(x,y)模數;滿足 x == fld(x,y)*y + mod(x,y);符號與 y 相同
mod1(x,y)偏移量為 1 的 mod;傳回 r∈(0,y](對於 y>0)或 r∈[y,0)(對於 y<0),其中 mod(r, y) == mod(x, y)
mod2pi(x)相對於 2pi 的模數;0 <= mod2pi(x) < 2pi
divrem(x,y)傳回 (div(x,y),rem(x,y))
fldmod(x,y)傳回 (fld(x,y),mod(x,y))
gcd(x,y...)xy... 的最大公因數
lcm(x,y...)xy... 的最小公倍數

符號和絕對值函數

函式說明
abs(x)一個正值,其大小為 x
abs2(x)x 的平方大小
sign(x)表示 x 的符號,傳回 -1、0 或 +1
signbit(x)表示符號位元是否開啟(true)或關閉(false)
copysign(x,y)一個值,其大小為 x,符號為 y
flipsign(x,y)一個值,其大小為 x,符號為 x*y

次方、對數和根號

函式說明
sqrt(x)√xx 的平方根
cbrt(x)∛xx 的立方根
hypot(x,y)直角三角形的斜邊,其他兩邊長度為 xy
exp(x)x 處的自然指數函數
expm1(x)x 接近零時,精確的 exp(x)-1
ldexp(x,n)對於 n 的整數值,有效率地計算 x*2^n
log(x)x 的自然對數
log(b,x)x 的底數 b 對數
log2(x)x 的底數 2 對數
log10(x)x 的底數 10 對數
log1p(x)x 接近零時,精確的 log(1+x)
exponent(x)x 的二進位指數
有效數字 (x)浮點數 x 的二進位有效數字 (又稱尾數)

對於為什麼 hypotexpm1log1p 等函數是必要且有用的概述,請參閱 John D. Cook 在這個主題上寫的兩篇優秀的部落格文章:expm1、log1p、erfchypot

三角函數和雙曲函數

所有標準三角函數和雙曲函數也都有定義

sin    cos    tan    cot    sec    csc
sinh   cosh   tanh   coth   sech   csch
asin   acos   atan   acot   asec   acsc
asinh  acosh  atanh  acoth  asech  acsch
sinc   cosc

這些都是單一參數函數,其中 atan 也接受兩個參數,對應傳統的 atan2 函數。

此外,sinpi(x)cospi(x) 提供更精確的 sin(pi*x)cos(pi*x) 計算。

為了使用度數而不是弧度來計算三角函數,請在函數後加上後綴 d。例如,sind(x) 計算 x 的正弦,其中 x 以度數指定。具有度數變體的三角函數完整清單如下

sind   cosd   tand   cotd   secd   cscd
asind  acosd  atand  acotd  asecd  acscd

特殊函數

套件 SpecialFunctions.jl 提供許多其他特殊數學函數。

  • 1一元運算子 +- 需要在它們的參數周圍加上明確的括號,以區別它們與運算子 ++ 等。一元運算子的其他組合以右結合性進行解析,例如,√√-a√(√(-a))
  • 2運算子 +++* 是非結合運算子。a + b + c 會被解析為 +(a, b, c),而不是 +(+(a, b), c)。然而,+(a, b, c, d...)*(a, b, c, d...) 的後備方法都預設為左結合運算。