3.7 任意精度算术
不论是浮点型还是整型,遇到“超大”的数值时,都会面临越界溢出的问题。例如:
julia> x = typemax(Int64) 9223372036854775807 # Int64能表达的最大正数值 julia> x + 1 -9223372036854775808 julia> x + 1 == typemin(Int64) # 对其+1操作后,变成了最小负数值 true
其中,x已是Int64能够表达的最大数值,一旦对其+1便出现“反转”的情况,变成了Int64的最小数值。若不能跟踪这种异常,未采取恰当的处置,便会引发不可预料的重大错误。
为了应对这种情况,实现任意精度的计算(Arbitrary Precision Arithmetic),Julia语言封装了GNU的多精度算术库[1]和多精度浮点计算库[2],提供了BigInt和BigFloat两个类型。其中BigInt是Integer类型的一种,而BigFloat是浮点型AbstractFloat(浮点数抽象类型)的一种。
当使用BigInt类型时,处理上例中变量x的情况,不会再出现溢出问题,例如:
julia> BigInt(typemax(Int64)) + 1 9223372036854775808
可见,取得了累加后的正确值。当然,对于更大的整数值同样如此,例如:
julia> parse(BigInt, "123456789012345678901234567890") + 1 123456789012345678901234567891
其中的parse()函数用于将字符串转为数值类型,在字符串学习时会详细介绍。
对于浮点数,BigFloat同样可以解决表达范围越界的问题:
julia> BigFloat(2.0^66) / 3 2.459565876494606882133333333333333333333333333333333333333333333333333333333344e+19 julia> parse(BigFloat, "1.23456789012345678901") 1.234567890123456789010000000000000000000000000000000000000000000000000000000004
或者,可采用big()函数将不同类型的“超大”数值转为BigInt或BigFloat类型,例如:
julia> big(typemax(Int64)) 9223372036854775807 julia> big(2.0^66) 7.3786976294838206464e+19
采用BigFloat后,在epsilon值方面也有着更好的提升,例如:
julia> eps(Float64) 2.220446049250313e-16 julia> eps(BigFloat) 1.727233711018888925077270372560079914223200072887256277004740694033718360632485e-77
可见,BigFloat的epsilon值显然要比Float64类型的小得多。
另外,在代码中以字面值的方式输入非常大(通常也会比较长)的数值时,可以使用Julia特有的下划线分割方式,以便于视觉上的划分。例如:
julia> 988_765.000_1234_05 988765.000123405
其中的下划线位置并没有明确的限制,而且同样适用于整型,且与数制无关。例如:
julia> 10_000_000 10000000 julia> 0xdeaf_beef 0xdeafbeef julia> 0b1011_0010 0xb2
可见非常直观方便。
[1] 多精度算术库(GNU Multiple Precision Arithmetic Library,GMP),参见 https://gmplib.org。
[2] 多精度浮点计算库(Multiple-Precision Floating-point computations with correct Rounding,MPFR),参见http://www.mpfr.org。