gpt4 book ai didi

c++ - double 到 long 的转换不正确

转载 作者:可可西里 更新时间:2023-11-01 15:27:46 26 4
gpt4 key购买 nike

这主要是对 this other question 的跟进,那是一个奇怪的从 long 到 double 的转换,然后再返回到 long 以获得大值。

我已经知道将 float 转换为整数类型会截断,如果截断后的值无法用目标类型表示,则行为未定义:

4.9 Floating-integral conversions [conv.fpint]

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 berepresented in the destination type.

但这里是我的代码来演示这个问题,假设是一个小端架构,其中 long long 和 long double 都使用 64 位:

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
unsigned long long ull = 0xf000000000000000;
long double d = static_cast<long double>(ull);
// dump the IEE-754 number for a little endian system
unsigned char * pt = reinterpret_cast<unsigned char *>(&d);
for (int i = sizeof(d) -1; i>= 0; i--) {
cout << hex << setw(2) << setfill('0') << static_cast<unsigned int>(pt[i]);
}
cout << endl;
unsigned long long ull2 = static_cast<unsigned long long>(d);
cout << ull << endl << d << endl << ull2 << endl;
return 0;
}

输出是(在旧的 XP 32 机器上使用 MSVC 2008 32 位):

43ee000000000000
f000000000000000
1.72938e+019
8000000000000000

值的解释:

  • 0xf000000000000000 是十进制的 17293822569102704640,因此转换为 double 是正确的。
  • 43ee000000000000 :尾数部分是 e000000000000 添加隐含的 1 它正确地表示 4 位 1 后跟 0 - 去除 3ff 偏差后指数为 43e 它给出二进制1.111 263 的表示因此 0xf000000000000000 或 17293822569102704640 ( ref )
  • 的精确表示

由于该值可以表示为 unsigned long long,我预计它转换为 unsigned long long 会给出原始值,而 MSVC 会给出 0x8000000000000000 或 9223372036854775808

问题是:该转换是由另一个问题的已接受答案所建议的未定义行为引起的,还是它真的是一个 MSVC 错误?

(注意:在 FreeBSD 10.1 机器上的 CLang 编译器上的相同代码给出了正确的结果)

作为引用,我可以找到生成的代码:

  unsigned long long ull2 = static_cast<unsigned long long>(d);
0041159E fld qword ptr [d]
004115A1 call @ILT+490(__ftol2) (4111EFh)
004115A6 mov dword ptr [ull2],eax
004115A9 mov dword ptr [ebp-40h],edx

_ftol2 的代码似乎是(在执行时从调试器获得):

00411C66  push        ebp  
00411C67 mov ebp,esp
00411C69 sub esp,20h
00411C6C and esp,0FFFFFFF0h
00411C6F fld st(0)
00411C71 fst dword ptr [esp+18h]
00411C75 fistp qword ptr [esp+10h]
00411C79 fild qword ptr [esp+10h]
00411C7D mov edx,dword ptr [esp+18h]
00411C81 mov eax,dword ptr [esp+10h]
00411C85 test eax,eax
00411C87 je integer_QnaN_or_zero (411CC5h)
00411C89 fsubp st(1),st
00411C8B test edx,edx
00411C8D jns positive (411CADh)
00411C8F fstp dword ptr [esp]
00411C92 mov ecx,dword ptr [esp]
00411C95 xor ecx,80000000h
00411C9B add ecx,7FFFFFFFh
00411CA1 adc eax,0
00411CA4 mov edx,dword ptr [esp+14h]
00411CA8 adc edx,0
00411CAB jmp localexit (411CD9h)
00411CAD fstp dword ptr [esp]
00411CB0 mov ecx,dword ptr [esp]
00411CB3 add ecx,7FFFFFFFh
00411CB9 sbb eax,0
00411CBC mov edx,dword ptr [esp+14h]
00411CC0 sbb edx,0
00411CC3 jmp localexit (411CD9h)
00411CC5 mov edx,dword ptr [esp+14h]
00411CC9 test edx,7FFFFFFFh
00411CCF jne arg_is_not_integer_QnaN (411C89h)
00411CD1 fstp dword ptr [esp+18h]
00411CD5 fstp dword ptr [esp+18h]
00411CD9 leave
00411CDA ret

最佳答案

这里主要是整理评论提问。

看来旧的 MSVC 版本过去常常错误地处理 64 位整数到 64 位 double 的转换。

2008 以下的版本中存在该错误。

MSCV 2010 在 32 位模式下错误,在 64 位模式下正确

所有从 2012 开始的版本都是正确的。

关于c++ - double 到 long 的转换不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33829101/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com