Python使用math.pow计算大数平方和取模结果异常排查
问题描述
我有如下代码片段:
import math number_of_lists, M = list(map(int, input().split(" "))) print(sum([math.pow(max(list(map(int, input().split(" ")))), 2) for i in range(number_of_lists)]) % M)
我需要处理量级非常大的数值,计算得到的最终结果和谷歌计算器的计算结果不一致。如果将程序求和得到的最终值替换为谷歌计算器算出的正确值,程序就能返回正确答案,希望了解该问题的出现原因。我已经尝试过将数据类型转换为float,但没有效果;也查询过是否存在支持更大数值范围的数据类型,但了解到Python的int类型本身支持任意精度大整数,应该可以承载当前计算的数值量级。
以下是测试用示例输入:
7 671 7 5678403 6770488 5713245 6503478 7774748 5900452 531896 7 7728332 501199 9141815 7341382 7238970 8282671 3037527 7 7763981 7041667 3521352 9616160 7322888 5685405 6017382 7 7278231 1143649 6460915 8159948 2436146 1238439 9869216 7 1422820 9424407 4982886 7101222 8711246 696130 6121051 7 6485993 6596581 9169298 4214325 7097779 827465 4072058 7 6853100 9110135 9625936 7133432 8668153 5663640 6749591
上述示例输入对应的正确返回结果应为670,但当前程序的返回值为53。
抱歉代码写得比较紧凑,我只是尝试用尽可能少的代码行数完成题目。
对应练习题目链接:Maximize It 练习题目
问题根因
核心错误出在math.pow()函数的使用上:
math.pow()的返回值固定为双精度浮点数(float类型),双精度浮点数最多仅能保留15~17位十进制有效数字,超出范围的整数会直接丢失精度,计算结果必然存在偏差。- Python的int类型确实支持任意精度大整数,但
math.pow接收参数时会自动把传入的整数转为float再运算,从类型转换这一步开始精度就已经丢失,这也是你之前手动转float没有效果的原因。 - 测试用例里的最大数值为9869216,它的平方是97399424454656,已经远超过双精度浮点数能精确表示的整数上限2^53(约9e15),平方计算阶段就出现了误差,最后取模的结果自然错误。
修复方案
不要用math.pow计算整数幂,直接使用Python原生的整数幂运算符**做计算,全程保持int类型运算,不会产生任何精度损失,修改后的代码如下:
number_of_lists, M = map(int, input().split()) print(sum(max(map(int, input().split()))**2 for _ in range(number_of_lists)) % M)
运行这段代码处理给出的测试样例,即可得到正确结果670。
内容的提问来源于stack exchange,提问作者Marky
相关产品推荐
相关产品推荐

