简体   繁体   English

将uint64_t转换为double后出现意外结果

[英]Unexpected result after converting uint64_t to double

In the following code: 在以下代码中:

#include <iostream>

...

uint64_t t1 = 1510763846;
uint64_t t2 = 1510763847;
double d1 = (double)t1;
double d2 = (double)t2;
// d1 == t2 => evaluates to true somehow?
// t1 == d2 => evaluates to true somehow?
// d1 == d2 => evaluates to true somehow?
// t1 == t2 => evaluates to false, of course.
std::cout << std::fixed << 
        "uint64_t: " << t1 << ", " << t2 << ", " <<
        "double: " << d1 << ", " << d2 << ", " << (d2+1) << std::endl;

I get this output: 我得到这个输出:

uint64_t: 1510763846, 1510763847, double: 1510763904.000000, 1510763904.000000, 1510763905.000000

And I don't understand why. 我不明白为什么。 This answer: biggest integer that can be stored in a double says that an integral number up to 2^53 (9007199254740992) can be stored in a double without losing precision. 这个答案: 可以存储在double中的最大整数表示最多2 ^ 53(9007199254740992)的整数可以存储在一个double精度而不会丢失精度。

I actually get errors when I start doing calculations with the doubles, so it's not only a printing issue. 当我开始用双打计算时,我实际上会出错,所以这不仅仅是打印问题。 (eg 1510763846 and 1510763847 both give 1510763904) (例如1510763846和1510763847均给出1510763904)

It's also very weird that the double can just be added to and then come out correct (d2+1 == 1510763905.000000) 双倍可以添加到然后出来正确也是非常奇怪的(d2 + 1 == 1510763905.000000)

Rationale: I'm converting these numbers to doubles because I need to work with them in Lua, which only supports floating point numbers. 基本原理:我将这些数字转换为双数,因为我需要在Lua中使用它们,它只支持浮点数。 I'm sure I'm compiling the Lua lib with double as the lua_Number type, not float . 我确定我正在使用double作为lua_Number类型编译Lua lib,而不是float

std::cout << sizeof(t1) << ", " << sizeof(d2) << std::endl;

Outputs 输出

8, 8

I'm using VS 2012 with target MachineX86, toolkit v110_xp. 我正在使用VS 2012与目标MachineX86,工具包v110_xp。 Floating point model "Precise (/fp:precise)" 浮点模型“精确(/ fp:精确)”

Addendum 附录

With the help of people who replied and this article Why are doubles added incorrectly in a specific Visual Studio 2008 project? 在回复的人和本文的帮助下, 为什么在特定的Visual Studio 2008项目中错误地添加了双打? , I've been able to pinpoint the problem. ,我已经能够找出问题所在。 A library is using a function like _set_controlfp, _control87, _controlfp or __control87_2 to change the precision of my executable to "single". 库正在使用_set_controlfp,_control87,_controlfp或__control87_2等函数将可执行文件的精度更改为“single”。 That is why a uint64_t conversion to a double behaves as if it's a float. 这就是为什么uint64_t转换为double的行为就好像它是一个浮点数。

When doing a file search for the above function names and "MCW_PC", which is used for Precision Control, I found the following libraries that might have set it: 在执行文件搜索上述函数名称和“MCW_PC”(用于精确控制)时,我发现可能设置了以下库:

  • Android NDK Android NDK
  • boost::math 提高::数学
  • boost::numeric 提高::数字
  • DirectX (We're using June 2010) DirectX(我们使用2010年6月)
  • FMod (non-EX) FMod(非EX)
  • Pyro particle engine Pyro粒子引擎

Now I'd like to rephrase my question: 现在我想重新解释一下我的问题:

How do I make sure converting from a uint64_t to a double goes correctly every time, without: 如何确保每次都能正确地从uint64_t转换为double ,而不是:

  1. having to call _fpreset() each and every time a possible conversion occurs (think about the function parameters) 必须在每次发生可能的转换时调用_fpreset()(考虑函数参数)
  2. having to worry about a library's thread changing the floating point precision in between my _fpreset() and the conversion? 不得不担心库的线程在我的_fpreset()和转换之间改变浮点精度?

Naive code would be something like this: 天真的代码将是这样的:

double toDouble(uint64_t i)
{
    double d;
    do {
        _fpreset();
        d = i;
        _fpreset();
    } while (d != i);
    return d;
}

double toDouble(int64_t i)
{
    double d;
    do {
        _fpreset();
        d = i;
        _fpreset();
    } while (d != i);
    return d;
}

This solution assumes the odds of a thread messing with the Floating Point Precision twice are astronomically small. 这个解决方案假设一个线程搞乱浮点精度两次的几率是天文数字小。 Problem is, the values I'm working with, are timers that represent real-world value. 问题是,我正在使用的值是代表真实世界价值的计时器。 So I shouldn't be taking any chances. 所以我不应该冒任何风险。 Is there a silver bullet for this problem? 这个问题有灵丹妙药吗?

From ieee754 floating point conversion it looks like your implementation of double is actually float, which is of course allowed by the standard, that mandates that sizeof double >= sizeof float . 从ieee754浮点转换看起来你的double实现实际上是浮点数,当然这是标准所允许的,它规定了sizeof double >= sizeof float

The most accurate representation of 1510763846 is 1.510763904E9. 最准确的1510763846表示是1.510763904E9。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM