Julia 基本运算符
运算符是一种告诉编译器执行特定的数学或逻辑操作的符号,如: 3+2=5。
Julia 语言内置了丰富的运算符,支持的运算有:
- 算术运算符
- 布尔运算符
- 关系运算符
- 位运算符
- 赋值运算符
- 向量化 "点" 运算符
算术运算符
下表显示了 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) |
实例
6
julia> 1 - 2
-1
julia> 3*2/12
0.5
julia> 2+20-5
17
julia> 50*2/10
10.0
julia> 23%2
1
julia> 2^4
16
# 整除符号 ÷ 可以在 REPL 中用 \div + Tab 输入
julia> 7 ÷ 2
3
# 与大多数语言不同,Julia 的整数除法 1/0 不会报错,而是返回 Inf
julia> 1/0
Inf
注意:
2x这种数字紧跟变量的写法也代表乘法(数字字面量系数),优先级比普通乘除更高,详见数据类型章节。
布尔运算符
下表显示了 Julia 的布尔运算符:
| 表达式 | 名称 |
|---|---|
!x | 否定 |
x && y | 短路与,子表达式 y 仅当 x 为 true 的时候才会被执行 |
x || y | 短路或,子表达式 y 仅在 x 为 false 的时候才会被执行 |
实例
false
julia> !false
true
julia> true && (x = (1, 2, 3))
(1, 2, 3)
julia> false && (x = (1, 2, 3))
false
julia> false || (x = (1, 2, 3))
(1, 2, 3)
关系运算符
下表显示了 Julia 的关系运算符:
| 操作符 | 名称 |
|---|---|
== | 相等 |
!=, ≠ | 不等 |
< | 小于 |
<=, ≤ | 小于等于 |
> | 大于 |
>=, ≥ | 大于等于 |
实例
true
julia> 100 == 101
false
julia> 100 != 101
true
julia> 100 == 100.0
true
julia> 100 < 500
true
julia> 100 > 500
false
julia> 100 >= 100.0
true
julia> -100 <= -500
false
链式比较
Julia 允许链式比较,这在写数值代码时特别方便:
实例
true
# 数组上的链式比较用 .< 等点运算符,得到布尔数组
julia> A = [0.5, 1.5, 0.8];
julia> 0 .< A .< 1
3-element BitVector:
1
0
1
标量链式比较内部使用 && 运算符,数组版本则使用按位 & 运算。
注意链式比较的执行顺序,中间表达式只计算一次,但求值顺序未定义,因此不要在链式比较中使用有副作用的表达式:
实例
M (generic function with 1 method)
julia> M(1) < M(2) <= M(3)
2
1
3
true
julia> M(1) > M(2) <= M(3)
2
1
false
位运算符
下表显示了 Julia 的位运算符:
| 表达式 | 名称 |
|---|---|
~x | 按位取反 |
x & y | 按位与 |
x | y | 按位或 |
x ⊻ y | 按位异或(也可写作 xor(x,y)) |
x ⊼ y | 按位与非(也可写作 nand(x,y)) |
x ⊽ y | 按位或非(也可写作 nor(x,y)) |
x >>> y | 逻辑右移(左边补 0) |
x >> y | 算术右移(保持符号位) |
x << y | 左移 |
实例
-124
julia> 123 & 234
106
julia> 123 | 234
251
julia> 123 ⊻ 234
145
julia> xor(123, 234)
145
julia> nand(123, 123)
-124
julia> nor(123, 124)
-128
julia> ~UInt32(123)
0xffffff84
julia> ~UInt8(123)
0x84
赋值运算符
每一个二元算术运算符和位运算符都可以给左操作数复合赋值,方法是把 = 直接放在二元运算符后面。比如,x += 3 等价于 x = x + 3。
下表显示了 Julia 全部的赋值运算符:
| 运算符 | 描述 | 实例 |
|---|---|---|
| = | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | C = A + B 将把 A + B 的值赋给 C |
| += | 加且赋值运算符 | C += A 相当于 C = C + A |
| -= | 减且赋值运算符 | C -= A 相当于 C = C - A |
| *= | 乘且赋值运算符 | C *= A 相当于 C = C * A |
| /= | 除且赋值运算符 | C /= A 相当于 C = C / A |
| \= | 反向除且赋值运算符 | C \= A 相当于 C = C \ A |
| ÷= | 整除且赋值运算符 | C ÷= A 相当于 C = C ÷ A |
| %= | 取余且赋值运算符 | C %= A 相当于 C = C % A |
| ^= | 幂且赋值运算符 | C ^= 2 相当于 C = C ^ 2 |
| //= | 有理数除且赋值运算符 | C //= A 相当于 C = C // A |
| <<= | 左移且赋值运算符 | C <<= 2 相当于 C = C << 2 |
| >>= | 算术右移且赋值运算符 | C >>= 2 相当于 C = C >> 2 |
| >>>= | 逻辑右移且赋值运算符 | C >>>= 2 相当于 C = C >>> 2 |
| &= | 按位与且赋值运算符 | C &= 2 相当于 C = C & 2 |
| |= | 按位或且赋值运算符 | C |= 2 相当于 C = C | 2 |
| ⊻= | 按位异或且赋值运算符 | C ⊻= 2 相当于 C = C ⊻ 2 |
注意:在 Julia 中
^是幂运算符而不是异或,所以x ^= 2是求平方;按位异或要用⊻(或 xor 函数)。这与 C 语言正好相反。
实例
1
julia> x += 3
4
julia> x ^= 2
16
julia> x
16
注意:更新运算符会把新值重新绑定给左侧变量,因此变量类型可能改变。例如
x = 0x01(UInt8 类型)执行x *= 2后类型变成 Int64。
向量化 "点" 运算符
Julia 中,每个二元运算符都有一个 "点" 运算符与之对应,例如 ^ 就有对应的 .^ 存在。这个对应的 .^ 被 Julia 自动地定义为逐元素地执行 ^ 运算。
比如 [1,2,3] ^ 3 是非法的,因为数学上没有给数组的立方下过定义。但是 [1,2,3] .^ 3 是合法的,它会逐元素地执行 ^ 运算(或称向量化运算):
实例
3-element Vector{Int64}:
1
8
27
类似地,! 或 √ 这样的一元运算符,也有对应的 .√ 用于执行逐元素运算。
点运算还有一个重要特性:融合(fusing)。嵌套的点运算会被合并成单次循环执行,不会产生临时数组,因此性能很好:
实例
# 下面整条表达式只循环一次,等价于对每个元素计算 2a^2 + sin(a)
julia> Y = 2 .* A.^2 .+ sin.(A)
3-element Vector{Float64}:
2.8414709848078967
8.909297426825682
18.141120008059865
# @. 宏可以把表达式里的所有运算都加上点
julia> Y = @. 2A^2 + sin(A)
3-element Vector{Float64}:
2.8414709848078967
8.909297426825682
18.141120008059865
除了点运算符,我们还有逐点赋值运算符,类似 a .+= b(或者 @. a += b)会被解析成 a .= a .+ b,表示原地修改数组 a。
注意:写
1 .+ x时点号两侧的空格是必须的,1.+x会被当成1. + x(浮点数 1.0 加 x)而导致歧义错误。
运算符的优先级与结合性
运算符的优先级确定表达式中项的组合。例如 x = 7 + 3 * 2,在这里,x 被赋值为 13,而不是 20,因为运算符 * 具有比 + 更高的优先级。
下表将按运算符优先级从高到低列出各个运算符:
| 分类 | 运算符 | 结合性 |
|---|---|---|
| 字段访问 | . | 左结合 |
| 幂运算 | ^ | 右结合 |
| 一元运算符 | + - ! ~ √ ∛ | 右结合 |
| 移位运算 | << >> >>> | 左结合 |
| 分数 | // | 左结合 |
| 乘法 | * / ÷ % & \ | 左结合 |
| 加法 | + - | ⊻ | 左结合 |
| 范围与省略 | : .. | 左结合 |
| 管道 | |>,<| | 左结合 / 右结合 |
| 比较 | > < >= <= == === != !== <: | 可链式(无固定结合性) |
| 流程控制 | && 然后 || | 右结合 |
| 三元条件 | ?: | 右结合 |
| Pair 操作 | => | 右结合 |
| 赋值 | = += -= *= /= //= ^= ÷= %= |= &= ⊻= <<= >>= >>>= | 右结合 |
我们也可以通过内置函数 Base.operator_precedence 查看任何给定运算符的优先级数值,数值越大优先级越高:
实例
(11, 12, 17)
julia> Base.operator_precedence(:sin), Base.operator_precedence(:+=), Base.operator_precedence(:(=)) # (注意:等号前后必须有括号 `:(=)`)
(0, 1, 1)
另外,内置函数 Base.operator_associativity 可以返回运算符结合性的符号表示:
实例
(:left, :none, :right)
julia> Base.operator_associativity(:⊗), Base.operator_associativity(:sin), Base.operator_associativity(:→)
(:left, :none, :right)
