在C ++中将2个大数相乘会导致错误的结果

时间:2018-08-17 04:41:33

标签: c++

有2个大整数。当我乘以它时,结果总是错误的,即使我使用了long double并且结果应该在long double的有效范围内:

long double f = 1000000000 * 99999;

我调试了,结果是如此奇怪: -723552768.00000000 。我错过了什么吗?我该如何倍数?

谢谢!

5 个答案:

答案 0 :(得分:4)

根据C ++标准:

  

4一个不带后缀的浮点常量的类型为double。如果以   字母f或F,其类型为float。如果以字母L或L结尾,   的类型为long double

auto fl = 1000000000.L * 99999.L;
std::cout << fl << "\n";

long double fl = 1000000000L * 99999.L;
std::cout <<"\n"<< fl << "\n";

答案 1 :(得分:2)

在C ++中,数字文字默认为int。因此,表达式1000000000 * 99999被视为两个int的乘积,因此*运算符返回的结果为int。仅在乘法发生之后将此int转换为long double变量f。根据您的平台,int的范围通常是-2147483648至2147483647(或4个字节)。但是,1000000000 x 99999的乘积为9.9999 x 10 ^ 13,不在此范围内,因此由于int变量不足以容纳该值而发生溢出。

为避免这种情况,应将*运算符所操作的至少一个数字声明为后缀为long double.l的{​​{1}}文字,如下所示:

.L

在上面的表达式中,*运算符将返回一个long double f = 1000000000.L * 99999 ,其大小足以容纳分配给long double的结果乘积。

答案 2 :(得分:1)

同意@feiXiang。您基本上是将两个整数相乘。要进行正确的计算,您必须将大数定义为long double。请参见下面的代码:

 #include <iostream>

using namespace std;

int main()
{
    long double a = 1000000000;
    long double b = 99999;
    long double f = a * b;
    cout<<f;

    return 0;
}

输出:

  

9.9999e + 13

答案 3 :(得分:1)

实际上,您可以通过以下方式调用未定义的行为:

long double f = 1000000000 * 99999;

首先,求值1000000000 * 99999,它是两个int对象的乘积。将两个int对象相乘始终是int。由于int的大小不足以表示结果(很可能是32位),因此高位丢失了。

由于带符号整数类型的溢出是未定义的,因此您刚刚触发了未定义的行为。但是在这种情况下,即使是UB,也可以解释发生了什么。

计算仅保留最低的32位,应为(1000000000 * 99999) modulo (2**32) == 3571414528。但是对于int,此值太大。由于在PC上,int负数由二进制补码表示,因此每次2**31<= result < 2**32时,我们必须减去2 ** 32。这给出了-723552768

现在,最后一步是:

long double f = -723552768

这就是您所看到的。

要解决此问题,请像这样使用long long

long double f = 1000000000LL * 99999;

double

long double f = 1000000000.0 * 99999;

答案 4 :(得分:0)

1000000000 99999 是整数,那么1000000000 * 99999的结果将是一个整数,然后将其分配给变量,结果超出范围整数。

您应确保结果是长双首:

long double f = (long double) 1000000000 * 99999;

long double f = 1000000000LL * 99999;