从无符号长整型转换为双精度,反之亦然,更改值 [英] Cast from unsigned long long to double and vice versa changes the value

查看:1700
本文介绍了从无符号长整型转换为双精度,反之亦然,更改值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编写C ++代码时,我突然意识到我的数字不正确地从 double 转换为 unsigned long long



具体来说,我使用以下代码:

  define _CRT_SECURE_NO_WARNINGS 

#include< iostream>
#include< limits>
using namespace std;

int main()
{
unsigned long long ull = numeric_limits< unsigned long long> :: max();
double d = static_cast< double>(ull);
unsigned long long ull2 = static_cast< unsigned long long>(d);
cout<< ull<< endl<< d<< endl<< ull2< endl
return 0;
}

Ideone live示例



在我的计算机上执行此代码时,我有以下输出:

  18446744073709551615 
1.84467e + 019
9223372036854775808
按任意键继续。 。 。



我希望第一个和第三个数字是完全一样的(就像在Ideone上),因为我是确保 long double 占用10个字节,并在其中8个中存储尾数。我会理解,如果第三个数字被截断相比第一个 - 只是为了我的错误的浮点数格式。但是这里的值是两次不同!



所以,主要的问题是:为什么?



一些细节:我在Windows 7上使用Visual Studio 2013,为x86编译,并且 sizeof(long double )== 8

解决方案

18446744073709551615 double (在IEEE754中)中不能完全表示。这不是意料之外的,因为64位浮点显然不能表示64位中可表示的所有整数。



根据C ++标准,实现定义是否使用下一个最高或次低的 double 值。显然在你的系统上,它选择下一个最高值,似乎 1.8446744073709552e19 。您可以通过输出具有更多精确位数的双精度来确认。



请注意,这大于原始数字。



将此double转换为整数时,行为由[conv.fpint] / 1覆盖:


可以将浮点类型转换为整数类型的prvalue。转换截断;即,舍弃小数部分。


因此,此代码有潜在的可能性,因此行为未定义导致未定义的行为。当发生未定义的行为时,任何事情都可能发生,包括(但不限于)虚假输出。






发布了 long double ,而不是 double 。在我的gcc, long double case行为正确,但在OP的MSVC它给了相同的错误。这可以通过gcc使用80位 long double 来解释,但MSVC使用64位 long double p>

When writing a C++ code I suddenly realised that my numbers are incorrectly casted from double to unsigned long long.

To be specific, I use the following code:

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <limits>
using namespace std;

int main()
{
  unsigned long long ull = numeric_limits<unsigned long long>::max();
  double d = static_cast<double>(ull);
  unsigned long long ull2 = static_cast<unsigned long long>(d);
  cout << ull << endl << d << endl << ull2 << endl;
  return 0;
}

Ideone live example.

When this code is executed on my computer, I have the following output:

18446744073709551615
1.84467e+019
9223372036854775808
Press any key to continue . . .

I expected the first and third numbers to be exactly the same (just like on Ideone) because I was sure that long double took 10 bytes, and stored the mantissa in 8 of them. I would understand if the third number were truncated compared to first one - just for the case I'm wrong with the floating-point numbers format. But here the values are twice different!

So, the main question is: why? And how can I predict such situations?

Some details: I use Visual Studio 2013 on Windows 7, compile for x86, and sizeof(long double) == 8 for my system.

解决方案

18446744073709551615 is not exactly representible in double (in IEEE754). This is not unexpected, as a 64-bit floating point obviously cannot represent all integers that are representible in 64 bits.

According to the C++ Standard, it is implementation-defined whether the next-highest or next-lowest double value is used. Apparently on your system, it selects the next highest value, which seems to be 1.8446744073709552e19. You could confirm this by outputting the double with more digits of precision.

Note that this is larger than the original number.

When you convert this double to integer, the behaviour is covered by [conv.fpint]/1:

A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.

So this code potentially causes undefined behaviour. When undefined behaviour has occurred, anything can happen, including (but not limited to) bogus output.


The question was originally posted with long double, rather than double. On my gcc, the long double case behaves correctly, but on OP's MSVC it gave the same error. This could be explained by gcc using 80-bit long double, but MSVC using 64-bit long double.

这篇关于从无符号长整型转换为双精度,反之亦然,更改值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆