Haskell中Ratio Word8类型有理数相加结果异常原因咨询
问题:Ratio Word8 加法结果不符合预期
先看这段GHCi会话:
ghci> import Data.Ratio ghci> import Data.Word ghci> 128 % 3 + 127 % 3 :: Ratio Word8 253 % 9
为什么结果是253 % 9,而不是255 % 3(化简后为85 % 1)?移除类型约束时,结果是符合预期的:
ghci> 128 % 3 + 127 % 3 85 % 1
已知128+127::Word8结果为255,并没有溢出;使用分母2时结果符合模256算术逻辑,但分母为3时分母变成9,这让人困惑。
原因分析
核心问题出在Ratio Word8的加法实现逻辑,以及Word8的溢出特性:
Ratio加法的通分逻辑
Ratio类型的加法会先执行通分操作:对于a % b + c % d,计算方式是(a*d + c*b) % (b*d),之后再尝试用分子分母的最大公约数约分。这里所有计算都在Ratio的底层类型(也就是Word8)中进行。具体计算过程中的溢出
回到例子:128%3 + 127%3- 通分后分母是
3*3=9 - 分子部分需要计算
128*3 + 127*3:128*3作为Word8计算:128*3=384,超过Word8的最大值255,溢出后结果为384 - 256 = 128127*3=381,同样溢出,结果为381 - 256 = 125- 溢出后的分子相加:
128 + 125 = 253
- 最后检查约分:253和9的最大公约数是1(253=11×23,9=3×3),无法约分,所以最终结果是
253%9
- 通分后分母是
分母2时的特殊情况
当分母为2时,比如x%2 + y%2,通分后分母是4,分子是x*2 + y*2。如果x和y的和在Word8范围内,分子会是2*(x+y),和分母4约分后得到(x+y)%2,看起来符合模256逻辑,但这只是约分后的巧合,本质还是通分过程在Word8下执行。无类型约束时的正确结果
移除类型约束后,GHC默认使用Integer作为Ratio的底层类型。Integer是任意精度整数,不会发生溢出,所以分子计算为128*3 + 127*3 = (128+127)*3 = 255*3,分母是9,约分后得到255/3=85,即85%1。
内容的提问来源于stack exchange,提问作者Mark Seemann
相关产品推荐
相关产品推荐

