Rational numbers是分数,由一个整数分子除以一个整数分母构成。
例如,我们可以把2//3存成精确的分数,而不是近似的Float64值0.6666...。
这样做的好处是,除了整数溢出这种极端情况,有理数都能保持精确,避免浮点数常常无法避免的舍入误差。
有理数是一种相当简单的数值类型,用法基本符合你的预期。由于从早期版本开始它就是 Julia 的标准类型,大多数函数都会像接受整数和浮点数那样,接受它作为输入。
创建很简单,只要在两个整数之间使用//即可。
julia> 3//4
3//4
julia> a = 3; b = 4;
julia> a//b
3//4
公因数会自动约去,把分数化成“最简形式”:能准确表示该分数的最小整数,并且分母非负。
julia> 5//15
1//3
julia> 5//-15
-1//3
常用的arithmetic operators + - * / ^ %都能用于有理数,效果与其他数值类型基本相同。
表达式中可以包含整数和其他Rational,结果仍是Rational。如果表达式中含有float,结果就是float,精度也会随之(可能)损失。
如果需要float,用float()函数把有理数转换一下即可。通常的做法是:用有理数在漫长的计算过程中保持精度,最后再转换成浮点数。
julia> 3//4 + 1//3 # addition
13//12
julia> 3//4 * 1//3 # multiplication
1//4
julia> 3//4 / 1//3 # division
9//4
julia> 3//4 ^ 2 # exponentiation
3//16
julia> 3//4 + 5 # rational and int => rational
23//4
julia> 3//4 + 5.3 # rational and float => float
6.05
julia> float(3//4) # casting
0.75
在 Julia 中,有理数就是数字。编译器通常会按需转换类型。
不过要注意,比较只在分数具有有限小数表示时才成立:
julia> 3//4 == 0.75
true
julia> 3//4 < 0.74
false
除此之外,比较时应先把Rational转换成Float:
julia> 1//3 == 1/3
false
julia> float(1//3) == 1/3
true
数学函数可以接受有理数作为输入,但可能返回浮点数结果:
julia> sqrt(9//16)
0.75
一家研究机构发现,部分初级研究员在分析中一直使用不太理想的方法。 其中一种做法是:在继续计算之前,先把离散概率直接转成浮点数(也就是实数)。
资深研究员更愿意在计算中使用有理数,这样精度可能更高。他们想知道,初级研究员的这些不良做法是否影响了研究的结果。
研究分为两类:
资深研究员请你编写一些函数,帮他们判断使用浮点数做的分析中是否存在舍入误差;如果存在误差,还要给出精确的有理数结果。
rationalize(successes, trials) 函数接收两个数组:successes 和 trials。
对于下标 i,successes[i] 表示在 trials[i] 次试验中成功的次数。
该函数返回一个数组,其中的元素是成功次数除以试验次数所得的有理数,顺序与输入数组一致。
julia> rationalize([1, 2, 3], [4, 5, 6])
3-element Vector{Rational{Int64}}:
1//4
2//5
1//2
同样,probabilities(successes, trials) 函数接收两个数组:successes 和 trials。
它返回一个浮点数数组,其中的元素是成功次数除以试验次数,顺序与输入数组一致。
julia> probabilities([1, 2, 3], [4, 5, 6])
3-element Vector{Float64}:
0.25
0.4
0.5
checkmean(successes, trials) 接收两个数组:successes 和 trials。
它会比较实数概率的平均值与有理数概率的平均值。
checkmean 返回 true
checkmean 返回有理数概率。julia> successes, trials = [9, 4, 7, 8, 6], [22, 22, 11, 17, 12];
julia> checkmean(successes, trials)
true
julia> successes, trials = [6, 5, 9, 8, 9], [21, 19, 13, 25, 22];
julia> checkmean(successes, trials)
1873629//4754750
checkprob(successes, trials) 接收两个数组:successes 和 trials。
它会比较浮点数概率的总概率与有理数概率的总概率。
checkprob 返回 true
checkprob 返回有理数概率。julia> successes, trials = [2, 9, 4, 4, 5], [15, 11, 17, 19, 15];
julia> checkprob(successes, trials)
true
julia> successes, trials = [9, 8, 5, 4, 3], [22, 14, 19, 25, 18];
julia> checkprob(sucesses, trials)
12//7315