将double类型转换为有理数形式时的精度问题求助
你碰到的这个问题,本质是二进制浮点数的固有局限性——像8.2这类十进制小数,没办法用二进制浮点数(比如double)精确存储,它在内存里其实是一个接近8.2的近似值(也就是你看到的8.19999999...),这直接导致你乘以1010后得到的分子不是精确的82000000000,自然约分后就会出错。哪怕换更大的10k也没用,因为double的有效数字只有15-17位,只要原数无法精确表示,误差会一直存在。
给你几个靠谱的解决方案:
改用十进制浮点类型处理
大部分编程语言都提供了专门针对十进制小数的精确类型,比如Java的BigDecimal、C#的decimal、Python的decimal模块。这些类型会按照十进制规则存储数值,能精确表示8.2这样的数。你可以直接用这类类型存储目标值,再转换为分数形式,或者手动计算分子分母后用gcd约分,完全不会有精度损失。通过字符串解析绕开浮点数误差
先把double值转成精确的十进制字符串(注意要禁用科学计数法,保留完整的小数部分),然后解析字符串里的整数和小数部分。比如8.2转成字符串是"8.2",整数部分是8,小数部分是2,小数位数是1,那分子就是8*10 + 2 = 82,分母是10^1=10,再约分得到41/5。这种方法直接从十进制的字面量入手,彻底避开了浮点数的精度陷阱。对浮点数近似值做修正后再处理
如果必须用double类型,那在乘以10k之后,先对结果做四舍五入取整,再去计算gcd。比如8.19999999...乘以1010后是81999999999.xxxx,四舍五入后就能得到精确的82000000000,再和10^10约分就会得到正确的分数。不过要注意选择合适的k值,确保四舍五入后能还原出原本的十进制小数。
内容的提问来源于stack exchange,提问作者Taylor

