4.1 算术运算符
对于基本的数值类型,包括各种整型、浮点型、有理数型、复数型等,表4-1中的运算符除了一些特殊计算,其他均是支持的。
表4-1 算术运算符
表中列举的都是一些常规的运算符,除了被除号。提供被除号运算符的目的是为了能够更广泛地支持数学中的表达方式,使得在表达数学公式时能够更为方便,这也是Julia独具匠心的设计。另外,除法除了使用斜杠(/)表达外,还可以使用÷这种传统的数学符号,这是非常有意思的。
在这些运算符中,只有两个是一元运算符,即运算操作只涉及一个值或变量。例如:
julia> +d 3.0 julia> +y 15//8
一元加号不会对原值做出改变,而一元减号则会反转原值的正负表达:
julia> -a -50 julia> - -a # 两次换符号(中间有空格) 50 julia> -x # 复数的实部与虚部值,都被反转符号 -3 - 2im
注意 还有,对于复数来说,如果使用一元减号,实部与虚部会被同时改变。
再看基本的二元加法操作,代码如下:
julia> a + b # Int64 + Int32 52 julia> typeof(ans) Int64 julia> b + c # Int32 + Float32 4.5f0 julia> typeof(ans) Float32 julia> a + c # Int64 + Float32 52.5f0 julia> typeof(ans) Float32
其中涉及的两个值均有着不同的类型,而结果一般是两者中“较大”的那个类型。所谓较大,指该类型的表达能力比另外一个强。如上例中,整型没有小数点,所以无法准确地表达浮点数;但反之,浮点型可以精确表达整数,所以,当整型与浮点型相加时结果会是浮点类型。
下面是操作数中有复数或有理数的一些例子:
julia> a - y # Int64 - Rational 385//8 # Rational julia> d + y # Float64 + Rational 4.875 # Float64 julia> d - x # Float64 - Complex 0.0 - 2.0im # Complex julia> x + y # Complex + Rational 39//8 + 2//1*im # 复数的实部与虚部的类型均是有理数型
可见,这些基本运算符对复数型及有理数型有着自然的支持。而且,结果类型的选择同样遵循“较大原则”,即选择表现能力强的类型。不难理解,复数型比有理数型的表现力更强,而有理数型是无法表达复数的。
对于较大原则,一般而言,有理数型优于整型,浮点型优于有理数型,复数型优于浮点型。但当复数与有理数进行运算时,结果却是Complex{Rational{Int64}}型。看起来复杂,实际就是复数型,只不过其实部与虚部的类型是Rational{Int64}这个有理数型而已。
我们再看以下乘除法的例子:
julia> a * b # Int64 * Int32 100 # Int64 julia> a * c # Int64 * Float32 125.0f0 # Float32 julia> a * y # Int64 * Rational 375//4 # Rational julia> a /x # Int64 / Complex{Int64} 11.538461538461538 - 7.6923076923076925im julia> typeof(ans) Complex{Float64}
结果类型同样遵循着“较大原则”。其中最后的例子稍显特别,虽然操作数的类型分别是Int64和Complex{Int64},都是以整型为基础的,但结果类型却是Complex{Float64}。实际上,这并没有突破“较大原则”,但类型参数却发生了变化,不再以整型为基础,这是因为运算符是除法,所以会自动采用浮点类型。比如:
julia> a/b # Int64 / Int32 25.0 julia> typeof(ans) Float64
这个例子中两个操作数均是整型,且能够整除,但结果并没有保持整型,同样采用了浮点类型。这点与C++等语言是不同的。
不过,在除法运算符中,斜杠的除号/与数学除号÷在对整数进行计算时,有着显著的差异,这点需要特别注意。例如:
julia> x = Int64(12); julia> x ÷ 2 6 julia> typeof(ans) Int64 # 仍为整型 julia> x / 2 6.5 julia> typeof(ans) Float64 # 自动为浮点型
另外,因为特殊浮点值—无穷值的存在,所以在Julia中如果出现除数为零的情况,是可以顺利执行的,例如:
julia> c/0 # Float32 / 0 Inf32 julia> y/0 # Rational / 0 1//0 julia> x/0 # Complex / 0 Inf + Inf*im
但对于求余数的操作,除数是不允许为零的,例如:
julia> a % 0 ERROR: DivideError: integer division error
不难理解,这是因为除数为0时的求余数运算,在数学上也是无法解释的。
不过,求余操作并不仅限于整型,例如:
julia> c % b # Float32 % Int32 0.5f0 julia> d % c # Float64 % Float32 0.5 julia> y % d # Rational{Int64} % Float64 1.875
但是,求余不适用于复数。
在算术运算符中,还有一种幂运算,同样适用于多种数值类型,例如:
julia> 2^5 # Int64 32 julia> 2.1^5 # Float64 40.84101000000001 julia> (2//3)^5 # Rational{Int64},注意圆括号不可少(优先级的缘故) 32//243 # 仍为原类型 julia> (2+3im)^5 # Complex{Int64} 122 - 597im julia> (2+3im)^4 # Complex{Int64} -119 - 120im julia> 3im^5 # Complex{Int64} 0 + 3im # 值未发生变化
当然复数的幂有些特别,但仍遵循着数学定义。
令人惊讶的是,幂运算中还支持指数为小数或复数等其他类型,例如:
julia> 2.1^1.5 # Float64 3.043189116699782 julia> (2//3)^1.5 # Rational{Int64} 0.5443310539518174 julia> (2+3im)^1.5 # Complex{Int64} 0.6603660276815664 + 6.814402636366297im julia> 2.1^(2+3im) # 指数为复数 -2.6864471968673858 + 3.497299166277224im julia> (2+3im)^(3//2) # 指数为有理数型 0.6603660276815664 + 6.814402636366297im julia> (2+3im)^(2+3im) # Complex{Int64} 0.6075666647314786 - 0.3087560180979021im
另外,指数也可以是负数,例如:
julia> 4.0^-2 # Float64 0.0625 julia> (2//3)^-2 # Rational{Int64} 9//4 julia> (2.0+3.0im)^-2 # Complex{Float64} -0.029585798816568053 - 0.07100591715976332im
与求幂相对的,运算符√和3√可分别用于开平方和开立方(求立方根)。其中的3√适用于负数,但√不适用于负实数,如果要进行操作,负数需以复数的形式提供。例如:
julia> √(-2.0+0im) 0.0 + 1.4142135623730951im
因为负数的根是复数,所以也要求对负数求根时必须输入复数(虚部为0值)。