这种计算大数的方式如何工作?

use*_*028 4 c++ largenumber stringstream

通常,要处理超出C++中long long范围的整数,您必须将它们表示为字符串并以这种方式对它们执行操作.但是,我在互联网上发现这个代码似乎像魔术一样.它计算两个幂的总和(没有2 ^ 0),即使它不能存储在很长的长度中.

#include <iostream>  
#include <cmath>  
#include <iomanip>  
#include <sstream>  
using namespace std;

int main() {
    int n;
    stringstream ss;
    cin >> n;

    ss << fixed << setprecision(0) << pow(2, n + 1) - 2;

    if (n >= 54) {
        string a = ss.str();

        a[a.size() - 1] = ((a[a.size() - 1] - 48) - 2) + 48;

        cout << a;
        return 0;
    }

    cout << ss.str();

}
Run Code Online (Sandbox Code Playgroud)

它是如何工作的?它适用于涉及大量的任何操作吗?如果n的值非常大(我试过1024)它只打印"inf".可以这种方式计算的数字范围的上限是多少?

以下部分到底做了什么以及它为什么这样做?

a[a.size() - 1] = ((a[a.size() - 1] - 48) - 2) + 48;
Run Code Online (Sandbox Code Playgroud)

eer*_*ika 6

它适用于涉及大量的任何操作吗?

您可以使用浮点执行与浮点相同的操作.但每次计算都涉及错误,并非所有整数都可以表示.


可以这种方式计算的数字范围的上限是多少?

取决于处理器使用的双精度浮点类型.

您可以找到最高可表示的数字std::numeric_limits<double>::max().但是,这些高数字的精度非常差.并非所有整数都可以表示为此数字.连续可表示整数的最大值是std::pow(std::numeric_limits<double>::radix, std::numeric_limits<double>::digits).


以下部分到底做了什么以及它为什么这样做?

a[a.size() - 1] = ((a[a.size() - 1] - 48) - 2) + 48;
Run Code Online (Sandbox Code Playgroud)

这可以简化为

a[a.size() - 1] -= 2;
Run Code Online (Sandbox Code Playgroud)

它只是从最后一个(最低)数字中扣除2.它依赖于数学事实,即2的幂不是0或1模10(除了2 0),在这种情况下,最后一个数字将变为非数字字符.

这也依赖于事实pow(2, n + 1) - 2 == pow(2, n + 1)n >= 54.该代码假定浮点如下无处不二进制IEEE-754格式,其中std::pow(std::numeric_limits<double>::radix, std::numeric_limits<double>::digits)std::pow(2, 54).当n大于或等于54时,计算结果std::pow(2, 54 + 1)变得如此之大,如果从中扣除一个小数字2,则最接近的可表示结果与您开始时的结果相同.计算的准确度误差等于较小的操作数!这个计算根本不能用浮点数来执行.这就是为什么之后用数字字符摆弄它固定的原因.

2的所有幂(直到极限)都是可表示的,因此功率计算本身从不会出现任何精度误差.

  • 虽然2的所有幂都是可表示的,但是不能保证*流*它将产生完全准确的所有数字.您需要希望您的流媒体库质量足够高. (2认同)