数学运算和初等函数

    以下支持所有的原始数值类型:

    以及对 Bool 类型的否定:

    表达式名称描述
    !x否定truefalse 互换

    除了优先级比二元操作符高以外,直接放在标识符或括号前的数字,如 2x2(x+y) 还会被视为乘法。详见。

    Julia 的类型提升系统使得混合参数类型上的代数运算也能顺其自然的工作,请参考类型提升系统来了解更多内容。

    这里是使用算术运算符的一些简单例子:

    习惯上我们会把优先运算的操作符紧邻操作数,比如 -x + 2 表示先要给 x 取反,然后再加 2

    位运算符

    所有原始整数类型都支持以下:

    表达式名称
    ~x按位取反
    x & y按位与
    x | y按位或
    x ⊻ y按位异或(逻辑异或)
    x >>> y逻辑右移
    x >> y
    x << y逻辑/算术左移

    以下是位运算符的一些示例:

    1. julia> ~123
    2. -124
    3. julia> 123 & 234
    4. 106
    5. julia> 123 | 234
    6. 251
    7. julia> 123 234
    8. 145
    9. julia> xor(123, 234)
    10. 145
    11. julia> ~UInt32(123)
    12. 0xffffff84
    13. julia> ~UInt8(123)
    14. 0x84

    每一个二元运算符和位运算符都可以给左操作数复合赋值:方法是把 = 直接放在二元运算符后面。比如,x += 3 等价于 x = x + 3

    1. julia> x = 1
    2. 1
    3. julia> x += 3
    4. 4
    5. julia> x
    6. 4

    二元运算和位运算的复合赋值操作符有下面几种:

    1. += -= *= /= \= ÷= %= ^= &= |= ⊻= >>>= >>= <<=

    Note

    复合赋值后会把变量重新绑定到左操作数上,所以变量的类型可能会改变。

    1. julia> x = 0x01; typeof(x)
    2. UInt8
    3. julia> x *= 2 # 与 x = x * 2 相同
    4. julia> typeof(x)
    5. Int64

    向量化 dot 运算符

    Julia 中,每个二元运算符都有一个 dot 运算符与之对应,例如 ^ 就有对应的 .^ 存在。这个对应的 .^ 被 Julia 自动地定义为逐元素地执行 ^ 运算。比如 [1,2,3] ^ 3 是非法的,因为数学上没有给(长宽不一样的)数组的立方下过定义。但是 [1,2,3] .^ 3 在 Julia 里是合法的,它会逐元素地执行 ^ 运算(或称向量化运算),得到 [1^3, 2^3, 3^3]。类似地,! 这样的一元运算符,也都有一个对应的 .√ 用于执行逐元素运算。

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

    具体来说,a .^ b 被解析为 dot 调用 (^).(a,b),这会执行 操作:该操作能结合数组和标量、相同大小的数组(元素之间的运算)、甚至不同形状的数组(例如行、列向量结合生成矩阵)。更进一步,就像所有向量化的 dot 调用一样,这些 dot 运算符是融合的(fused)。例如,在计算表达式 2 .* A.^2 .+ sin.(A) 时,Julia 只对 A 进行做一次循环,遍历 A 中的每个元素 a 并计算 2a^2 + sin(a)。上述表达式也可以用@. 宏简写为 @. 2A^2 + sin(A)。特别的,类似 f.(g.(x)) 的嵌套 dot 调用也是融合的,并且“相邻的”二元运算符表达式 x .+ 3 .* x.^2 可以等价转换为嵌套 dot 调用:(+).(x, (*).(3, (^).(x, 2)))

    除了 dot 运算符,我们还有 dot 复合赋值运算符,类似 a .+= b(或者 @. a += b)会被解析成 a .= a .+ b,这里的 .= 是一个融合的 in-place 运算,更多信息请查看 )。

    这个点语法,也能用在用户自定义的运算符上。例如,通过定义 ⊗(A,B) = kron(A,B) 可以为 Kronecker 积(kron)提供一个方便的中缀语法 A ⊗ B,那么配合点语法 [A,B] .⊗ [C,D] 就等价于 [A⊗C, B⊗D]

    标准的比较操作对所有原始数值类型有定义:

    下面是一些简单的例子:

    整数的比较方式是标准的按位比较,而浮点数的比较方式则遵循 。

    • 有限数的大小顺序,和我们所熟知的相同。
    • +0 等于但不大于 -0.
    • Inf 等于自身,并且大于除了 NaN 外的所有数。
    • -Inf is equal to itself and less than everything else except NaN.
    • NaN 不等于、不小于且不大于任何数值,包括它自己。

    NaN 不等于它自己这一点可能会令人感到惊奇,所以需要注意:

    1. julia> NaN == NaN
    2. false
    3. julia> NaN != NaN
    4. julia> NaN < NaN
    5. false
    6. julia> NaN > NaN
    7. false

    当你将 NaN数组 一起连用时,你就会感到头疼:

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

    为此,Julia 给这些特别的数提供了下面几个额外的测试函数。这些函数在某些情况下很有用处,比如在做 hash 比较时。

    函数测试是否满足如下性质
    xy 是完全相同的
    isfinite(x)x 是有限大的数字
    x 是(正/负)无穷大
    isnan(x)xNaN

    认为 NaN 之间是相等的:

    1. julia> isequal(NaN, NaN)
    2. true
    3. julia> isequal([1 NaN], [1 NaN])
    4. true
    5. julia> isequal(NaN, NaN32)
    6. true

    isequal 也能用来区分带符号的零:

    1. julia> -0.0 == 0.0
    2. true
    3. julia> isequal(-0.0, 0.0)
    4. false

    有符号整数、无符号整数以及浮点数之间的混合类型比较是很棘手的。开发者费了很大精力来确保 Julia 在这个问题上做的是正确的。

    对于其它类型,isequal 会默认调用 ==,所以如果你想给自己的类型定义相等,那么就只需要为 增加一个方法。如果你想定义一个你自己的相等函数,你可能需要定义一个对应的 hash 方法,用于确保 isequal(x,y) 隐含着 hash(x) == hash(y)

    与其他多数语言不同,就像 一样,Julia 允许链式比较:

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

    链式比较在写数值代码时特别方便,它使用 && 运算符比较标量,数组则用 & 进行按元素比较。比如,0 .< A .< 1 会得到一个 boolean 数组,如果 A 的元素都在 0 和 1 之间则数组元素就都是 true。

    注意链式比较的执行顺序:

    中间的表达式只会计算一次,而如果写成 v(1) < v(2) && v(2) <= v(3) 是计算了两次的。然而,链式比较中的顺序是不确定的。强烈建议不要在表达式中使用有副作用(比如 printing)的函数。如果的确需要,请使用短路运算符 &&(请参考)。

    初等函数

    Julia 提供了强大的数学函数和运算符集合。这些数学运算定义在各种合理的数值上,包括整型、浮点数、分数和复数,只要这些定义有数学意义就行。

    而且,和其它 Julia 函数一样,这些函数也能通过 点语法 f.(A) 以“向量化”的方式作用于数组和其它集合上。 比如,sin.(A) 会计算 A 中每个元素的 sin 值。

    运算符的优先级与结合性

    分类运算符结合性
    语法. followed by ::左结合
    幂运算^右结合
    一元运算符+ - √右结合
    移位运算<< >> >>>左结合
    除法//左结合
    乘法 / % & \ ÷左结合[2]
    加法+ - | ⊻左结合
    语法: ..左结合
    语法|>左结合
    语法<|右结合
    比较> < >= <= == === != !== <:无结合性
    流程控制&& followed by || followed by ?右结合
    Pair 操作=>右结合
    赋值= += -= = /= //= \= ^= ÷= %= |= &= ⊻= <<= >>= >>>=右结合

    要看全部 Julia 运算符的优先级关系,可以看这个文件的最上面部分:src/julia-parser.scm

    ,例如 2x 中的 2,它的优先级比二元运算符高,因此会当作乘法,并且它的优先级也比 ^ 高。

    你也可以通过内置函数 Base.operator_precedence 查看任何给定运算符的优先级数值,数值越大优先级越高:

    1. julia> Base.operator_precedence(:+), Base.operator_precedence(:*), Base.operator_precedence(:.)
    2. (11, 12, 17)
    3. julia> Base.operator_precedence(:sin), Base.operator_precedence(:+=), Base.operator_precedence(:(=)) # (Note the necessary parens on `:(=)`)
    4. (0, 1, 1)

    另外,内置函数 Base.operator_associativity 可以返回运算符结合性的符号表示:

    1. julia> Base.operator_associativity(:-), Base.operator_associativity(:+), Base.operator_associativity(:^)
    2. (:left, :none, :right)
    3. julia> Base.operator_associativity(:⊗), Base.operator_associativity(:sin), Base.operator_associativity(:→)
    4. (:left, :none, :right)

    注意诸如 :sin 这样的符号返回优先级 0,此值代表无效的运算符或非最低优先级运算符。类似地,它们的结合性被认为是 :none

    Julia 支持三种数值转换,它们在处理不精确转换上有所不同。

    • T(x)convert(T,x) 都会把 x 转换为 T类型。

      • 如果 T 是浮点类型,转换的结果就是最近的可表示值, 可能会是正负无穷大。
      • 如果 T 为整数类型,当 x 不能由 T 类型表示时,会抛出 InexactError
    • x % T 将整数 x 转换为整型 T,与 x2^n 的结果一致,其中 nT 的位数。换句话说,在二进制表示下被截掉了一部分。

    • 舍入函数 接收一个 T 类型的可选参数。比如,round(Int,x)Int(round(x)) 的简写版。

    下面的例子展示了不同的形式

    1. julia> Int8(127)
    2. 127
    3. julia> Int8(128)
    4. ERROR: InexactError: trunc(Int8, 128)
    5. Stacktrace:
    6. [...]
    7. julia> Int8(127.0)
    8. 127
    9. julia> Int8(3.14)
    10. ERROR: InexactError: Int8(3.14)
    11. Stacktrace:
    12. [...]
    13. julia> Int8(128.0)
    14. ERROR: InexactError: Int8(128.0)
    15. Stacktrace:
    16. [...]
    17. julia> 127 % Int8
    18. 127
    19. julia> 128 % Int8
    20. -128
    21. julia> round(Int8,127.4)
    22. 127
    23. julia> round(Int8,127.6)
    24. ERROR: InexactError: trunc(Int8, 128.0)
    25. [...]

    请参考一节来定义你自己的类型转换和提升规则。

    除法函数

    函数描述
    div(x,y), x÷y截断除法;商向零近似
    向下取整除法;商向 -Inf 近似
    cld(x,y)向上取整除法;商向 +Inf 近似
    取余;满足 x == div(x,y)y + rem(x,y);符号与 x 一致
    mod(x,y)取模;满足 x == fld(x,y)y + mod(x,y);符号与 y 一致
    偏移 1 的 mod;若 y>0,则返回 r∈(0,y],若 y<0,则 r∈[y,0) 且满足 mod(r, y) == mod(x, y)
    mod2pi(x)以 2pi 为基取模;0 <= mod2pi(x) < 2pi
    返回 (div(x,y),rem(x,y))
    fldmod(x,y)返回 (fld(x,y),mod(x,y))
    x, y,… 的最大公约数
    lcm(x,y…)x, y,… 的最小公倍数
    函数描述
    x 的模
    abs2(x)x 的模的平方
    表示 x 的符号,返回 -1,0,或 +1
    signbit(x)表示符号位是 true 或 false
    返回一个数,其值等于 x 的模,符号与 y 一致
    flipsign(x,y)返回一个数,其值等于 x 的模,符号与 x*y 一致

    幂、对数与平方根

    想大概了解一下为什么诸如 、expm1和 函数是必要和有用的,可以看一下 John D. Cook 关于这些主题的两篇优秀博文:expm1, log1p, erfc, 和 。

    所有标准的三角函数和双曲函数也都已经定义了:

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

    所有这些函数都是单参数函数,不过 atan 也可以接收两个参数 来表示传统的 函数。

    另外,sinpi(x) 和 分别用来对 sin(pi*x) 和 进行更精确的计算。

    要计算角度而非弧度的三角函数,以 d 做后缀。 比如,sind(x) 计算 x 的 sine 值,其中 x 是一个角度值。 下面是角度变量的三角函数完整列表:

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

    特殊函数

    • The operators +, ++ and * are non-associative. a + b + c is parsed as +(a, b, c) not +(+(a, b), c). However, the fallback methods for +(a, b, c, d...) and both default to left-associative evaluation.