首页 > 解决方案 > 超过 10^10 限制时 pow 函数的精度损失?

问题描述

做我的第一个 uni 作业,并遇到了这个问题:

任务:求所有 n 个元素的总和,其中 n 是数字中数字的个数(n=1,表示 1、2、3...例如 8、9,答案为 45)

问题:我写的代码已经正确地得到了所有测试答案,直到 10 的 9 次方,但是当它达到 10 的 10 次方时,答案开始出错,这真的很接近我应该得到的,但不完全存在(例如,我的输出 = 49499999995499995136,预期结果 = 49499999995500000000)

真的很感激一些帮助/见解,我猜这与变量类型有关,但不太确定可能的解决方案..

#include <iostream>
#include <cmath>
#include <iomanip>

using namespace std;

int main()
{
    int n;
    double ats = 0, maxi, mini;
    cin >> n;
    maxi = pow(10, n) - 1;
    mini = pow(10, n-1) - 1;
    ats = (maxi * (maxi + 1)) / 2 - (mini * (mini + 1)) / 2;
    cout << setprecision(0) << fixed << ats;
}

标签: c++c++11

解决方案


我认为您正在将浮点数拉伸到超出其精度的范围。让我解释:

C pow() 函数将双精度数作为参数。您正在传递整数,编译器正在添加代码以在它们到达 pow() 之前将它们转换为双精度数。(无论如何,当您获得返回值时,您将其存储为双精度值,因为您以这种方式声明它)。

正是因为点“浮动”,所以浮点数被称为这种方式。在 double 中,有一个符号位,一些位用于尾数,一些位用于指数。在二进制中,提升到 2 的幂相当于将小数点向右移动(如果提升到负数,则向左移动)。所以基本上指数是用二进制表示小数点在哪里。对双精度数使用这种内存表示的最大优势是,对于接近 0 的数字,您可以获得很多精度,而随着数字变大,精度会逐渐降低。

最后一件事正是发生在你身上的事情。您的号码太大而无法准确存储。所以它被四舍五入到最接近的二的幂之和(二的幂是二进制中右边全为零的数字)。

快速实验:在浏览器中按 F12,打开 javascript 控制台并输入 49499999995499995136。就我而言,在 chrome 中,我重现了同样的问题。

如果你真的真的很想用这么大的数字精确,那么你可以试试这些库中的一些,但这对于学生程序来说太高级了,你不需要它。如果用户输入的数字太大,只需添加一个 if 块并打印一条错误消息(教授们喜欢这个,这实际上是非常正确的)。


推荐阅读