Julia语言程序设计
上QQ阅读APP看书,第一时间看更新

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。