数学运算和初等函数

Julia 为它所有的基础数值类型,提供了整套的基础算术和位运算,也提供了一套高效、可移植的标准数学函数。

算术运算符

以下 算术运算符 支持所有的基本算术类型:

表达式 名称 描述
+x 一元加法运算符 全等操作
-x 一元减法运算符 将值变为其相反数
x + y 二元加法运算符 执行加法
x - y 二元减法运算符 执行减法
x * y 乘法运算符 执行乘法
x / y 除法运算符 执行除法
x ÷ y 整除 取 x / y 的整数部分
x \ y 反向除法 等价于 y / x
x ^ y 幂操作符 xy 次幂
x % y 取余 等价于 rem(x,y)

以及对 Bool 类型的否定:

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

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

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

  1. julia> 1 + 2 + 3
  2. 6
  3. julia> 1 - 2
  4. -1
  5. julia> 3*2/12
  6. 0.5

习惯上我们会把优先运算的操作符紧邻操作数,比如 -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 # Same as x = x * 2
  4. 2
  5. julia> typeof(x)
  6. Int64

矢量化 "dot" 运算符

对于每一个二元运算符,比如 ^ ,都有一个“dot”运算符 .^ 与之对应,它会对数组元素一一执行 ^ 运算。比如 [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" call (^).(a,b),进而会执行 @ref Broadcasting">broadcast 操作: it can combine arrays and scalars, arrays of the same size (performing the operation elementwise), and even arrays of different shapes (e.g. combining row and column vectors to produce a matrix). Moreover, like all vectorized "dot calls," these "dot operators" are fusing. For example, if you compute 2 . A.^2 .+ sin.(A) (or equivalently @. 2A^2 + sin(A), using the @__dot__">@. macro) for an array A, it performs a single loop over A, computing 2a^2 + sin(a) for each element of A. In particular, nested dot calls like f.(g.(x)) are fused, and "adjacent" binary operators like x .+ 3 . x.^2 are equivalent to nested dot calls (+).(x, (*).(3, (^).(x, 2))).

Furthermore, "dotted" updating operators like a .+= b (or @. a += b) are parsed as a .= a .+ b, where .= is a fused in-place assignment operation (see the dot syntax documentation).

Note the dot syntax is also applicable to user-defined operators. For example, if you define ⊗(A,B) = kron(A,B) to give a convenient infix syntax A ⊗ B for Kronecker products (kron), then [A,B] .⊗ [C,D] will compute [A⊗C, B⊗D] with no additional coding.

Combining dot operators with numeric literals can be ambiguous. For example, it is not clear whether 1.+x means 1. + x or 1 .+ x. Therefore this syntax is disallowed, and spaces must be used around the operator in such cases.

数值比较

Standard comparison operations are defined for all the primitive numeric types:

Operator 名称
== 相等
!=, 不等
< 小于
<=, 小于等于
> 大于
>=, 大于等于

下面是一些简单的例子:

  1. julia> 1 == 1
  2. true
  3. julia> 1 == 2
  4. false
  5. julia> 1 != 2
  6. true
  7. julia> 1 == 1.0
  8. true
  9. julia> 1 < 2
  10. true
  11. julia> 1.0 > 3
  12. false
  13. julia> 1 >= 1.0
  14. true
  15. julia> -1 <= 1
  16. true
  17. julia> -1 <= -1
  18. true
  19. julia> -1 <= -2
  20. false
  21. julia> 3 < -0.5
  22. false

Integers are compared in the standard manner – by comparison of bits. Floating-point numbers are compared according to the IEEE 754 standard:

  • Finite numbers are ordered in the usual manner.
  • Positive zero is equal but not greater than negative zero.
  • Inf is equal to itself and greater than everything else except NaN.
  • -Inf is equal to itself and less then everything else except NaN.
  • NaN is not equal to, not less than, and not greater than anything, including itself.
    The last point is potentially surprising and thus worth noting:
  1. julia> NaN == NaN
  2. false
  3. julia> NaN != NaN
  4. true
  5. julia> NaN < NaN
  6. false
  7. julia> NaN > NaN
  8. false

and can cause especial headaches with arrays:

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

Julia provides additional functions to test numbers for special values, which can be useful in situations like hash key comparisons:

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

isequal 认为 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

Mixed-type comparisons between signed integers, unsigned integers, and floats can be tricky. A great deal of care has been taken to ensure that Julia does them correctly.

For other types, isequal defaults to calling ==, so if you want to define equality for your own types then you only need to add a == method. If you define your own equality function, you should probably define a corresponding hash method to ensure that isequal(x,y) implies hash(x) == hash(y).

链式比较

Unlike most languages, with the notable exception of Python, comparisons can be arbitrarily chained:

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

Chaining comparisons is often quite convenient in numerical code. Chained comparisons use the && operator for scalar comparisons, and the & operator for elementwise comparisons, which allows them to work on arrays. For example, 0 .< A .< 1 gives a boolean array whose entries are true where the corresponding elements of A are between 0 and 1.

Note the evaluation behavior of chained comparisons:

  1. julia> v(x) = (println(x); x)
  2. v (generic function with 1 method)
  3. julia> v(1) < v(2) <= v(3)
  4. 2
  5. 1
  6. 3
  7. true
  8. julia> v(1) > v(2) <= v(3)
  9. 2
  10. 1
  11. false

The middle expression is only evaluated once, rather than twice as it would be if the expression were written as v(1) < v(2) && v(2) <= v(3). However, the order of evaluations in a chained comparison is undefined. It is strongly recommended not to use expressions with side effects (such as printing) in chained comparisons. If side effects are required, the short-circuit && operator should be used explicitly (see @ref">Short-Circuit Evaluation).

初等函数

Julia provides a comprehensive collection of mathematical functions and operators. These mathematical operations are defined over as broad a class of numerical values as permit sensible definitions, including integers, floating-point numbers, rationals, and complex numbers, wherever such definitions make sense.

Moreover, these functions (like any Julia function) can be applied in "vectorized" fashion to arrays and other collections with the dot syntax f.(A), e.g. sin.(A) will compute the sine of each element of an array A.

运算符的优先级与结合性

Julia applies the following order and associativity of operations, from highest precedence to lowest:

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

[1]
The unary operators + and - require explicit parentheses around their argument to disambiguate them from the operator ++, etc. Other compositions of unary operators are parsed with right-associativity, e. g., √√-a as √(√(-a)).

[2]
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 (a, b, c, d…) both default to left-associative evaluation.

For a complete list of every Julia operator's precedence, see the top of this file: src/julia-parser.scm

You can also find the numerical precedence for any given operator via the built-in function Base.operator_precedence, where higher numbers take precedence:

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

A symbol representing the operator associativity can also be found by calling the built-in function 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)

Note that symbols such as :sin return precedence 0. This value represents invalid operators and not operators of lowest precedence. Similarly, such operators are assigned associativity :none.

数值转换

Julia supports three forms of numerical conversion, which differ in their handling of inexact conversions.

  • The notation T(x) or convert(T,x) converts x to a value of type T.

    • If T is a floating-point type, the result is the nearest representable value, which could be positive or negative infinity.
    • 如果 T 为整数类型,当 x 不为 T 类型时,会触发 InexactError
  • x % T converts an integer x to a value of integer type T congruent to x modulo 2^n, where n is the number of bits in T. In other words, the binary representation is truncated to fit.

  • The @ref">Rounding functions take a type T as an optional argument. For example, round(Int,x) is a shorthand for Int(round(x)).

The following examples show the different forms.

  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(Int8, 3.14)
  11. Stacktrace:
  12. [...]
  13. julia> Int8(128.0)
  14. ERROR: InexactError: Int8(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. Stacktrace:
  26. [...]

See Conversion and Promotion for how to define your own conversions and promotions.

舍入函数

函数 描述 返回类型
round(x) x 舍到最接近的整数 typeof(x)
round(T, x) x 舍到最接近的整数 T
floor(x) x 舍到-Inf typeof(x)
floor(T, x) x 舍到-Inf T
ceil(x) round x towards +Inf typeof(x)
ceil(T, x) round x towards +Inf T
trunc(x) round x towards zero typeof(x)
trunc(T, x) round x towards zero T

除法函数

函数 描述
div(x,y), x÷y truncated division; quotient rounded towards zero
fld(x,y) floored division; quotient rounded towards -Inf
cld(x,y) ceiling division; quotient rounded towards +Inf
rem(x,y) remainder; satisfies x == div(x,y)*y + rem(x,y); sign matches x
mod(x,y) modulus; satisfies x == fld(x,y)*y + mod(x,y); sign matches y
mod1(x,y) mod with offset 1; returns r∈(0,y] for y>0 or r∈[y,0) for y<0, where mod(r, y) == mod(x, y)
mod2pi(x) modulus with respect to 2pi; 0 <= mod2pi(x) < 2pi
divrem(x,y) returns (div(x,y),rem(x,y))
fldmod(x,y) returns (fld(x,y),mod(x,y))
gcd(x,y…) greatest positive common divisor of x, y,…
lcm(x,y…) least positive common multiple of x, y,…

符号和绝对值函数

函数 描述
abs(x) a positive value with the magnitude of x
abs2(x) the squared magnitude of x
sign(x) indicates the sign of x, returning -1, 0, or +1
signbit(x) indicates whether the sign bit is on (true) or off (false)
copysign(x,y) a value with the magnitude of x and the sign of y
flipsign(x,y) a value with the magnitude of x and the sign of x*y

幂、对数与平方根

函数 描述
sqrt(x), √x square root of x
cbrt(x), ∛x cube root of x
hypot(x,y) hypotenuse of right-angled triangle with other sides of length x and y
exp(x) natural exponential function at x
expm1(x) accurate exp(x)-1 for x near zero
ldexp(x,n) x*2^n computed efficiently for integer values of n
log(x) natural logarithm of x
log(b,x) base b logarithm of x
log2(x) base 2 logarithm of x
log10(x) base 10 logarithm of x
log1p(x) accurate log(1+x) for x near zero
exponent(x) binary exponent of x
significand(x) binary significand (a.k.a. mantissa) of a floating-point number x

For an overview of why functions like hypot, expm1, and log1p are necessary and useful, see John D. Cook's excellent pair of blog posts on the subject: expm1, log1p, erfc, and hypot.

三角和双曲函数

All the standard trigonometric and hyperbolic functions are also defined:

  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

These are all single-argument functions, with atan also accepting two arguments corresponding to a traditional atan2 function.

Additionally, sinpi(x) and cospi(x) are provided for more accurate computations of sin(pi*x) and cos(pi*x) respectively.

In order to compute trigonometric functions with degrees instead of radians, suffix the function with d. For example, sind(x) computes the sine of x where x is specified in degrees. The complete list of trigonometric functions with degree variants is:

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

特殊函数

SpecialFunctions.jl 提供了许多其他的特殊数学函数。

原文: https://juliacn.github.io/JuliaZH.jl/latest/manual/mathematical-operations/