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.
I actually get errors when I start doing calculations with the doubles, so it's not only a printing issue. (e.g. 1510763846 and 1510763847 both give 1510763904)
It's also very weird that the double can just be added to and then come out correct (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. I'm sure I'm compiling the Lua lib with double
as the lua_Number
type, not float
.
std::cout << sizeof(t1) << ", " << sizeof(d2) << std::endl;
Outputs
8, 8
I'm using VS 2012 with target MachineX86, toolkit v110_xp. Floating point model "Precise (/fp:precise)"
Addendum
With the help of people who replied and this article Why are doubles added incorrectly in a specific Visual Studio 2008 project?, 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". That is why a uint64_t conversion to a double behaves as if it's a float.
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:
- Android NDK
- boost::math
- boost::numeric
- DirectX (We're using June 2010)
- FMod (non-EX)
- Pyro particle engine
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:
- having to call _fpreset() each and every time a possible conversion occurs (think about the function parameters)
- having to worry about a library's thread changing the floating point precision in between my _fpreset() and the conversion?
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?
float
instead ofdouble
. – Supranationalassert
is actually triggered; i.e., he didn’t accidentally changeNDEBUG
or something.\ – Supranational#include
directives for<iostream>
(which you need) and<time.h>
(which you don't use). You also need#include
headers for<cassert>
and<cstdint>
. I suggest you update your question to show a complete self-contained program that we can copy-and-paste and run unmodified on our own systems. minimal reproducible example – Calvert<iostream>
itself includes<cassert>
and<cstdint>
on the OP’s machine, so it’s hard to notice the missing headers. – Supranational