提问人:TheDoctor Bombastic 提问时间:10/18/2020 最后编辑:ggorlenTheDoctor Bombastic 更新时间:10/18/2020 访问量:593
在 C 中添加两个大双数会得到不正确的结果
Adding two large double numbers in C gives an incorrect result
问:
我想问你一个问题,关于在 C 语言中将两个大数字相加。
假设有两个数字是双倍的:1.31E+42 和 1.399E+43。
如果我在Excel中进行添加,结果是153000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000这应该是正确的。
如果我用 C 语言进行添加,结果15299999999999999804719125983728080953278464。
差异是相当巨大的。有谁知道如何在 C 语言中将双倍的大数相加或相乘时获得正确的结果?
我必须添加另一个重要信息。一件事是把它打印出来。我知道可以按照你们的建议打印号码。但我也需要它作为另一部作品的价值。具体来说,这是一项分析两个圆的任务——它们的交点和/或接触(如果它们接触外部或内部,或者如果有交点)。https://www.bbc.co.uk/bitesize/guides/z9pssbk/revision/4如果两个圆的中心之间的距离 (V) 等于它们的半径之和(外部触摸)或它们半径之差(内部触摸),则两个圆将接触。因此,我必须对外部触摸进行加法,然后比较它们中心V之间的距离是否与它们的半径之和相同。因此,这不仅仅是打印出值。
第一圈:
Sx = -3.2E+41, Sy = -3.31E+42, R = 1.31E+42
第二圈:
Sx = 1.354E+43, Sy = 3.17E+42, R = 1.399E+43
在 C 语言中,它们中心之间的距离为:
V = 15300000000000002280599204554488630751526912.000000
它们的半径之和是 C 语言:
SumR =15299999999999999804719125983728080953278464.000000
根据参考,他们应该从外部触摸,因此,如果我执行以下条件,我会得到没有外部触摸的信息。
if (fabs(V - SumR) < 0.001)
printf("There is an external touch")
else
printf("No external touch")
答:
如果需要处理大数字,则应使用任意精度算术(也称为 bignums)库,例如 GMPlib。
如果您想使用浮点数,请花时间阅读浮点指南和 IEEE 754 来了解它们。它们不遵循实数的直观属性(例如,大多数运算都不是关联的)。
当然,阅读 Modern C 和这个 C 参考网站,然后是 C11 草案标准 n1570。
浮点运算近似于实数算术。在将十进制数转换为二进制浮点数或进行浮点运算时,通常不应期望使用实数运算会得到的结果。
此答案假定您的 C 实现使用 IEEE-754 binary64 格式,并使用四舍五入到最接近的平数来执行算术运算,包括从十进制到 .double
double
binary64 格式有一个符号、一个 53 位有效数(数字的“分数部分”)和一个 11 位指数。
此格式不能表示 1.31•1042。它可以表示的最接近的值是 1310000000000000060347708657386176332693504。当 C 源文本包含 时,编译器会将其转换为 1310000000000000060347708657386176332693504。如果我们用十六进制来表示有效数,它是 1.E137CED6DF0D116•2139。您可以看到最初的“1”和另外 13 位十六进制数字(每个 4 位)组成 53 位。1.31e42
格式也不能表示 1.399•1043。它可以表示的最接近的值是 13989999999999999899113922237014438982975488。当 C 源文本包含 时,编译器会将其转换为 13989999999999999899113922237014438982975488。使用十六进制,这是 1.4131D470653E916•21431.399e43
当这些相加时,普通的数学结果是不可表示的。生成的结果是最接近的可表示数字,即 15299999999999999804719125983728080953278464。使用十六进制,这是 1.5F45515DD32F616•2143。
这是浮点运算所预期的正确结果。获得符合您目的的“正确”结果取决于您想要完成的任务。出于许多目的,使用浮点获得近似结果就足够了,并且人们只需理解结果是近似的。如果需要确切的结果,则必须使用替代格式和软件。
评论
15299999999999900000000000000000000000000000.00
上一个:如何找到浮点数的最短表示形式
下一个:近似值从双精度到单精度的转换
评论
printf(“delta %f\n”, 153000000 15299999999999999804719125983728080953278464
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000double