在线计算或两行之间的区别

发布于 2025-01-21 10:47:05 字数 1108 浏览 0 评论 0原文

这是我在C ++中的代码。我正在使用GCC版本11.2.0的G ++ -11。

#include<iostream> 
#include<vector> 
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;


int main()
{
    string t="90071992547409929007199254740993";
    //separateNumbers(t);
    unsigned long long stringNum=0;
    for (int j=16;j<32;j++)
    {
        stringNum += (t[j]-'0')*pow(10,32-j-1);
        
    }
    cout << stringNum;
    
    return 0;
}

我希望将最后16位数字作为数字获得的简单代码提供9929007199254740992,而不是9929007199254740993。

但是,代码的更改

#include<iostream> 
#include<vector> 
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;


int main()
{
    string t="90071992547409929007199254740993";
    //separateNumbers(t);
    unsigned long long stringNum=0;
    for (int j=16;j<32;j++)
    {
        unsigned long long temp = (t[j]-'0')*pow(10,32-j-1);
        stringNum += temp;
        
    }
    cout << stringNum;
    
    return 0;
}

给出了所需的结果,90077199254740993。我们如何解释两个代码之间的区别?

Here is my code in C++. I'm using g++-11 with gcc version 11.2.0.

#include<iostream> 
#include<vector> 
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;


int main()
{
    string t="90071992547409929007199254740993";
    //separateNumbers(t);
    unsigned long long stringNum=0;
    for (int j=16;j<32;j++)
    {
        stringNum += (t[j]-'0')*pow(10,32-j-1);
        
    }
    cout << stringNum;
    
    return 0;
}

This simple code, which I expected to get the last 16 digits as a number, gives 9929007199254740992, not 9929007199254740993.

However, the change of code

#include<iostream> 
#include<vector> 
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;


int main()
{
    string t="90071992547409929007199254740993";
    //separateNumbers(t);
    unsigned long long stringNum=0;
    for (int j=16;j<32;j++)
    {
        unsigned long long temp = (t[j]-'0')*pow(10,32-j-1);
        stringNum += temp;
        
    }
    cout << stringNum;
    
    return 0;
}

gives the desired result, 9007199254740993. How can we explain such a difference between two codes?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

叹倦 2025-01-28 10:47:05

区别在于将浮点算术与整数混合在一起。

对于感兴趣的人来说,更多信息:

差异在您的循环的最后一次迭代中表现出来。
第一种情况中,您有:

stringNum += (t[j]-'0')*pow(10,32-j-1);

等效于:

stringNum = stringNum + (t[j]-'0')*pow(10,32-j-1);

pow返回double,因此Expresion (t [j [J ] - '0')*POW(10,32-J-1)将为double以及:stringnum +(t [j] - ' - ' 0')*POW(10,32-J-1)
您期望的值(9007199254740993)无法用double表示。最接近的值是:9007199254740992。当将其分配回Integer Stringnum时,它一直保持 9007199254740992
您可以在此处看到有关此问题的更多信息:浮点数学损坏了?

如果尝试以下行,您还可以轻松地看到这一点(您的编译器还将给出警告关于可能丢失精度的):

double d = 9007199254740993;
std::cout.precision(17);
std::cout << d << std::endl;

哪个打印:9007199254740992

第二种情况下您将最后一个数字的值分配给temp

unsigned long long temp = (t[j]-'0')*pow(10,32-j-1);

(t [j] - '0')*POW(10,32-J -1)double带值3,可以在double中表现出来。然后将其分配到整数temp,也是3。
执行时:

stringNum += temp;

使用整数算术并获得正确的结果: 9007199254740993

As mentioned in @PaulMcKenzie's comment, the source of the difference is mixing floating-point arithmetics with integers.

Some more info for those who are interested:

The difference manifests in the last iteration of your loop.
In the first case, you have:

stringNum += (t[j]-'0')*pow(10,32-j-1);

which is equivalent to:

stringNum = stringNum + (t[j]-'0')*pow(10,32-j-1);

pow returns a double, and so the expresion (t[j]-'0')*pow(10,32-j-1) will be of type double, as well as: stringNum + (t[j]-'0')*pow(10,32-j-1).
The value you expect (9007199254740993) cannot be represented in a double. The closest value is: 9007199254740992. When assigned back to integer stringNum it stays 9007199254740992.
You can see more about this issue here: Is floating point math broken?.

You can also see this easily if you try the following lines (your compiler will also give a warning about the possible loss of precision):

double d = 9007199254740993;
std::cout.precision(17);
std::cout << d << std::endl;

Which prints: 9007199254740992.

In the second case you assign the value for the last digit to temp:

unsigned long long temp = (t[j]-'0')*pow(10,32-j-1);

(t[j]-'0')*pow(10,32-j-1) is a double with value 3, which incidently can be represented in a double. Then it gets assigned into an integer temp which is also 3.
When you execute:

stringNum += temp;

You use integer arithmetic and get the correct result: 9007199254740993.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文