3.4 有理数型
有理数与无理数相对,也是实数集合的子集,可以简单地认为是分子与分母均为整数的分数。
在Julia中直接提供了这种数值的表达方式,其原型(其中涉及的抽象类型、类型参数化等概念会在后续章节中详述)为:
Rational{T <: Integer} <: Real
其中,Rational是有理数的类型名;Integer是Julia中定义的抽象类型(后文介绍),用于限定分子与分母都必须是上文中Int8、Int16等具体整数类型的一种;Real是抽象类型,表达的是Rational同浮点型、无理数型一样,都是实数的一种。
Rational类型是Julia中特有的,以“分子//分母”格式表达。其中双斜线并非是运算符,而是表达有理数结构的特定操作符。例如:
julia> 2//3 # 分子与分母都是Int64类型 2//3 julia> typeof(ans) Rational{Int64} julia> Int8(2)//Int32(7) # 分子是Int8类型,而分母是Int32类型 2//7 julia> typeof(ans) Rational{Int32} # 类型被统一为Int32
可见,分子与分母为不同整型时,Julia会通过必要的隐式转换,将两者的类型进行统一。而且创建的Rational数值在Julia内部会被约分为标准形式,确保分母不为负数,例如:
julia> UInt32(2)//Int8(10) 1//5 julia> 5//25 # 被约分 1//5 julia> 1//-2 # 负号被放于分子上 -1//2 julia> -2//4 -1//2
如此一来,数学意义上相等的有理数,在语言内部的表达便是唯一的。
由于对无穷值的支持,所以在Rational对象中允许分母为0,但不允许分子和分母同时为0,例如:
julia> 5//0 1//0 julia> -3//0 -1//0 julia> typeof(ans) Rational{Int64} julia> 0//0 ERROR: ArgumentError: invalid rational: zero(Int64)//zero(Int64)
其中,前两个除零有理数定义成功,且都被约分为同一形式;但后一个因为分子和分母都为0,所以创建失败。
显然,如果分子或分母中任意一个为浮点值,创建Rational数值对象也会失败,例如:
julia> 1.2//3 ERROR: MethodError: no method matching //(::Float64, ::Int64) julia> 2//3.1 ERROR: MethodError: no method matching //(::Int64, ::Float64)
因为Rational的声明中限定了分子、分母的类型必须是整型的一种。
当然,Rational类型的有理数值均可转换到浮点值,例如:
julia> Float64(3//2) 1.5 julia> Float64(-4//-12) 0.3333333333333333 julia> Float64(5//0) Inf # 分母为0的正有理数,对应正无穷 julia> Float64(-3//0) -Inf # 分母为0的负有理数,对应负无穷
同时,浮点值也能够转换到Rational数值,例如:
julia> Rational(1.5) 3//2 julia> Rational(0.33333333333333) 6004799503160601//18014398509481984 julia> Rational(-2.5) -5//2 julia> Rational(Inf) 1//0 julia> Rational(-Inf) -1//0
其中,为何0.33333333333333转换的结果不是1//3而是由一大串数字构成的Rational类型对象,有兴趣的读者可以研究下。
如果要获得Rational对象的分子、分母部分,可以分别通过numerator()和denominator()函数实现,例如:
julia> numerator(2//3) 2 julia> denominator(2//3) 3