数学运算和基本函数
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) |
直接放在标识符或括号之前的数字字面量,例如 2x
或 2(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)。
布尔运算符
表达式 | 名称 |
---|---|
!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)
,它执行 广播 运算:它可以组合数组和标量、相同大小的数组(逐元素执行运算),甚至不同形状的数组(例如,组合行向量和列向量以生成矩阵)。此外,与所有向量化的“点调用”一样,这些“点运算符”是融合的。例如,如果您计算 2 .* A.^2 .+ sin.(A)
(或等效地 @. 2A^2 + sin(A)
,使用 @.
宏)对于数组 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)
,为 Kronecker 积提供方便的中缀语法 A ⊗ B
(kron
),则 [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) | x 和 y 相同 |
isfinite(x) | x 是一个有限数 |
isinf(x) | x 是无限的 |
isnan(x) | x 不是一个数字 |
isequal
认为 NaN
相互相等
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 之间时为真。
请注意链接比较的评估行为
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^y
和 2x^y
解析为 -(x^y)
和 2(x^y)
,而 x^-y
和 x^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
同余,其中n
是T
中的位数。换句话说,二进制表示被截断以适合。舍入函数 以类型
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 舍入到 -Inf | typeof(x) |
floor(T, x) | 将 x 舍入到 -Inf | T |
ceil(x) | 将 x 舍入到 +Inf | typeof(x) |
ceil(T, x) | 将 x 舍入到 +Inf | T |
trunc(x) | 将 x 舍入到零 | typeof(x) |
trunc(T, x) | 将 x 舍入到零 | T |
除法函数
函数 | 描述 |
---|---|
div(x,y) , x÷y | 截断除法;商舍入到零 |
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) | mod 偏移 1;对于 y>0 返回 r∈(0,y] ,对于 y<0 返回 r∈[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...) | x 、y 、... 的最大公约数 |
lcm(x,y...) | x 、y 、... 的最小公倍数 |
符号和绝对值函数
函数 | 描述 |
---|---|
abs(x) | 一个具有 x 大小的正值 |
abs2(x) | x 的平方大小 |
sign(x) | 指示 x 的符号,返回 -1、0 或 +1 |
signbit(x) | 指示符号位是否打开(真)或关闭(假) |
copysign(x,y) | 一个具有 x 大小和 y 符号的值 |
flipsign(x,y) | 一个具有 x 大小和 x*y 符号的值 |
幂、对数和根
函数 | 描述 |
---|---|
sqrt(x) , √x | x 的平方根 |
cbrt(x) , ∛x | x 的立方根 |
hypot(x,y) | 直角三角形的斜边,其他边的长度为 x 和 y |
exp(x) | x 处的自然指数函数 |
expm1(x) | 对于接近零的 x ,精确的 exp(x)-1 |
ldexp(x,n) | x*2^n ,对于 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 的二进制指数 |
significand(x) | 浮点数 x 的二进制有效数(也称为尾数) |
有关为什么像 hypot
、expm1
和 log1p
这样的函数是必要且有用的概述,请参阅 John D. Cook 关于此主题的出色博文对:expm1、log1p、erfc 和 hypot。
三角函数和双曲函数
所有标准的三角函数和双曲函数也被定义。
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 提供了许多其他特殊数学函数。