Unexpected result after converting uint64_t to double - c++

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?

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.
The most accurate representation of 1510763846 is 1.510763904E9.

Related

c++ half even rounding to x digits

Given a float, I want to round the result to 4 decimal places using half-even rounding, i.e., rounding to the next even number method. For example, when I have the following code snippet:
#include <iostream>
#include <iomanip>
int main(){
float x = 70.04535;
std::cout << std::fixed << std::setprecision(4) << x << std::endl;
}
The output is 70.0453, but I want to be 70.0454. I could not find anything in the standard library, is there any function to achieve this? If not, what would a custom function look like?
If you use float, you're kind of screwed here. There is no such value as 70.04535, because it's not representable in IEEE 754 binary floating point.
Easy demonstration with Python's decimal.Decimal class, which will try to reproduce the actual float (well, Python float is a C double, but it's the same principle) value out to 30 digits of precision:
>>> import decimal
>>> decimal.Decimal(70.04535)
Decimal('70.0453499999999991132426657713949680328369140625')
So your actual value doesn't end in a 5, it ends in 49999... (the closest to 70.04535 a C double can get; C float is even less precise); even banker's rounding would round it down. If this is important to your program, you need to use an equivalent C or C++ library that matches "human" (base-10) math expectations, e.g. libmpdec (which is what Python's decimal.Decimal uses under the hood).
I'm sure someone can improve this, but it gets the job done.
double round_p( double x, int p ){
double d = std::pow(10,p+1);
return ((x*d)+5)/d;
}
void main(int argc, const char**argv){
double x = 70.04535;
{
std::cout << "value " << x << " rounded " << round_p(x,4) << std::endl;
std::cout << "CHECK " << (bool)(round_p(x,4) == 70.0454) << std::endl;
}
}

Each deserialized 64 bit integer number should be converted to bit wise equivalent 64 bit floating number

I have above statement in file I am refering . Expected output is double. I could not find anything relevant to my problem.
I found this
Passing a structure through Sockets in C
but dont know if its relevant.
I am not reading that int64 value. I am getting it from other process and that is the way it is designed.
Does anyone have any theory about serialization and deserialization of ints?
There is exactly one defined way to bitwise-copy one type into another in c++ - memcpy.
template<class Out, class In, std::enable_if_t<(sizeof(In) == sizeof(Out))>* = nullptr>
Out mangle(const In& in)
{
Out result;
std::memcpy(std::addressof(result), std::addressof(in), sizeof(Out));
return result;
}
int main()
{
double a = 1.1;
auto b = mangle<std::uint64_t>(a);
auto c = mangle<double>(b);
std::cout << a << " " << std::hex << b << " " << c << std::endl;
}
example output:
1.1 3ff199999999999a 1.1
How about reading that 64-bit number and using reinterpret_cast to convert it to bitwise equivalent floating point number.
int64_t a = 121314;
double b = *reinterpret_cast<double*>(&a);
int64_t c = *reinterpret_cast<int64_t*>(&b);
assert(a==c);

Problematic output of fmod (long double, long double)

Problematic output of fmod (long double, long double)
It seems that output of fmod (long double, long double) in this test is problematocs.
Any suggestions?
g++ --version
g++ (GCC) 4.9.2
uname -srvmpio
CYGWIN_NT-6.1 1.7.34(0.285/5/3) 2015-02-04 12:12 i686 unknown unknown Cygwin
g++ test1.cpp
// No errors, no warnings
./a.exe
l1 = 4294967296
l2 = 72057594037927934
l3 = 4294967294
d1 = 4294967296
d2 = 72057594037927934
d3 = 0 // Expected 4294967294
// -------- Program test1. cpp --------
#include <iostream>
#include <iomanip>
#include <cmath>
int main (int argc, char** argv)
{
long long l1 = 4294967296;
long long l2 = 72057594037927934;
long long l3 = l2 % l1;
long double d1 = static_cast<long double>(l1);
long double d2 = static_cast<long double>(l2);
long double d3 = fmod (d2, d1);
std::cout << "l1 = " << l1 << std::endl;
std::cout << "l2 = " << l2 << std::endl;
std::cout << "l3 = " << l3 << std::endl;
std::cout << std::endl;
std::cout << "d1 = " << std::setprecision(18) << d1 << std::endl;
std::cout << "d2 = " << std::setprecision(18) << d2 << std::endl;
std::cout << "d3 = " << std::setprecision(18) << d3 << std::endl;
return 0;
}
// -----------------------
Floating point types, including long double cannot represent all integral values in their range. In practice, they are less likely to support larger magnitude values precisely.
A consequence is that converting large integral values to long double (or any floating point type) does not necessarily preserve value - the converted value is only the closest approximation possible given limits of the floating point type.
From there, if your two conversions have produced different values, it would be very lucky if the result of fmod() was exactly the value you seek.
fmod() is also not overloaded to accept long double arguments. Which means your long double values will be converted to double. The set of values a double can represent is a subset of the set that a long double can represent. Among other things, that means a smaller range of integral values that can be represented exactly.
The usual suggestion is not to do such things. If you can do required operations using integer operations (like %) then do so. And, if you use floating point, you need to allow for and manage the loss of precision associated with using floating point.

What is the difference between 0 and -0 floating point value?

This code snippet in Visual Studio 2013:
double a = 0.0;
double b = -0.0;
cout << (a == b) << " " << a << " " << b;
prints 1 0 -0. What is the difference between a and b?
C++ does not guarantee to differentiate between +0 and -0. This is a feature of each particular number representation. The IEEE 754 standard for floating point arithmetic does make this distinction, which can be used to keep sign information even when numbers go to zero. std::numeric_limits does not directly tell you if you have possible signed zeroes. But if std::numeric_limits<double>::is_iec559 is true then you can in practice assume that you have IEEE 754 representation, and thus possibly negative zero.
Noted by “gmch” in a comment, the C++11 standard library way to check the sign of a zero is to use std::copysign, or more directly using std::signbit, e.g. as follows:
#include <iostream>
#include <math.h> // copysign, signbit
using namespace std;
auto main() -> int
{
double const z1 = +0.0;
double const z2 = -0.0;
cout << boolalpha;
cout << "z1 is " << (signbit( z1 )? "negative" : "positive") << "." << endl;
cout << "z2 is " << (signbit( z2 )? "negative" : "positive") << "." << endl;
}
Without copysign or signbit, e.g. for a C++03 compiler, one way to detect a negative zero z is to check whether 1.0/z is negative infinity, e.g. by checking if it's just negative.
#include <iostream>
using namespace std;
auto main() -> int
{
double const z1 = +0.0;
double const z2 = -0.0;
cout << boolalpha;
cout << "z1 is " << (1/z1 < 0? "negative" : "positive") << "." << endl;
cout << "z2 is " << (1/z2 < 0? "negative" : "positive") << "." << endl;
}
But while this will probably work in practice on most any implementation, it's formally *Undefined Behavior.
One needs to be sure that the expression evaluation will not trap.
*) C++11 §5.6/4 “If the second operand of / or % is zero the behavior is undefined”
See http://en.m.wikipedia.org/wiki/Signed_zero
In a nutshell, it is due to the sign being stored as a stand-alone bit in IEEE 754 floating point representation. This leads to being able to have a zero exponent and fractional portions but still have the sign bit set--thus a negative zero. This is a condition that wouldn't happen for signed integers which are stored in twos-complement.

Analysis of float/double precision in 32 decimal digits

From a .c file of another guy, I saw this:
const float c = 0.70710678118654752440084436210485f;
where he wants to avoid the computation of sqrt(1/2).
Can this be really stored somehow with plain C/C++? I mean without loosing precision. It seems impossible to me.
I am using C++, but I do not believe that precision difference between this two languages are too big (if any), that' why I did not test it.
So, I wrote these few lines, to have a look at the behaviour of the code:
std::cout << "Number: 0.70710678118654752440084436210485\n";
const float f = 0.70710678118654752440084436210485f;
std::cout << "float: " << std::setprecision(32) << f << std::endl;
const double d = 0.70710678118654752440084436210485; // no f extension
std::cout << "double: " << std::setprecision(32) << d << std::endl;
const double df = 0.70710678118654752440084436210485f;
std::cout << "doublef: " << std::setprecision(32) << df << std::endl;
const long double ld = 0.70710678118654752440084436210485;
std::cout << "l double: " << std::setprecision(32) << ld << std::endl;
const long double ldl = 0.70710678118654752440084436210485l; // l suffix!
std::cout << "l doublel: " << std::setprecision(32) << ldl << std::endl;
The output is this:
* ** ***
v v v
Number: 0.70710678118654752440084436210485 // 32 decimal digits
float: 0.707106769084930419921875 // 24 >> >>
double: 0.70710678118654757273731092936941
doublef: 0.707106769084930419921875 // same as float
l double: 0.70710678118654757273731092936941 // same as double
l doublel: 0.70710678118654752438189403651592 // suffix l
where * is the last accurate digit of float, ** the last accurate digit of double and *** the last accurate digit of long double.
The output of double has 32 decimal digits, since I have set the precision of std::cout at that value.
float output has 24, as expected, as said here:
float has 24 binary bits of precision, and double has 53.
I would expect the last output to be the same with the pre-last, i.e. that the f suffix would not prevent the number from becoming a double. I think that when I write this:
const double df = 0.70710678118654752440084436210485f;
what happens is that first the number becomes a float one and then stored as a double, so after the 24th decimal digits, it has zeroes and that's why the double precision stops there.
Am I correct?
From this answer I found some relevant information:
float x = 0 has an implicit typecast from int to float.
float x = 0.0f does not have such a typecast.
float x = 0.0 has an implicit typecast from double to float.
[EDIT]
About __float128, it is not standard, thus it's out of the competition. See more here.
From the standard:
There are three floating point types: float, double, and long double.
The type double provides at least as much precision as float, and the
type long double provides at least as much precision as double. The
set of values of the type float is a subset of the set of values of
the type double; the set of values of the type double is a subset of
the set of values of the type long double. The value representation of
floating-point types is implementation-defined.
So you can see your issue with this question: the standard doesn't actually say how precise floats are.
In terms of standard implementations, you need to look at IEEE754, which means the other two answers from Irineau and Davidmh are perfectly valid approaches to the problem.
As to suffix letters to indicate type, again looking at the standard:
The type of a floating literal is double unless explicitly specified by
a suffix. The suffixes f and F specify float, the suffixes l and L specify
long double.
So your attempt to create a long double will just have the same precision as the double literal you are assigning to it unless you use the L suffix.
I understand that some of these answers may not seem satisfactory, but there is a lot of background reading to be done on the relevant standards before you can dismiss answers. This answer is already longer than intended so I won't try and explain everything here.
And as a final note: Since the precision is not clearly defined, why not have a constant that's longer than it needs to be? Seems to make sense to always define a constant that is precise enough to always be representable regardless of type.
Python's numerical library, numpy, has a very convenient float info function. All the types are the equivalent to C:
For C's float:
print numpy.finfo(numpy.float32)
Machine parameters for float32
---------------------------------------------------------------------
precision= 6 resolution= 1.0000000e-06
machep= -23 eps= 1.1920929e-07
negep = -24 epsneg= 5.9604645e-08
minexp= -126 tiny= 1.1754944e-38
maxexp= 128 max= 3.4028235e+38
nexp = 8 min= -max
---------------------------------------------------------------------
For C's double:
print numpy.finfo(numpy.float64)
Machine parameters for float64
---------------------------------------------------------------------
precision= 15 resolution= 1.0000000000000001e-15
machep= -52 eps= 2.2204460492503131e-16
negep = -53 epsneg= 1.1102230246251565e-16
minexp= -1022 tiny= 2.2250738585072014e-308
maxexp= 1024 max= 1.7976931348623157e+308
nexp = 11 min= -max
---------------------------------------------------------------------
And for C's long float:
print numpy.finfo(numpy.float128)
Machine parameters for float128
---------------------------------------------------------------------
precision= 18 resolution= 1e-18
machep= -63 eps= 1.08420217249e-19
negep = -64 epsneg= 5.42101086243e-20
minexp=-16382 tiny= 3.36210314311e-4932
maxexp= 16384 max= 1.18973149536e+4932
nexp = 15 min= -max
---------------------------------------------------------------------
So, not even long float (128 bits) will give you the 32 digits you want. But, do you really need them all?
Some compilers have an implementation of the binary128 floating point format, normalized by IEEE 754-2008. Using gcc, for example, the type is __float128. That floating point format have about 34 decimal precision (log(2^113)/log(10)).
You can use the Boost Multiprecision library, to use their wrapper float128. That implementation will either use native types, if available, or use a drop-in replacement.
Let's extend your experiment with that new non-standard type __float128, with a recent g++ (4.8):
// Compiled with g++ -Wall -lquadmath essai.cpp
#include <iostream>
#include <iomanip>
#include <quadmath.h>
#include <sstream>
std::ostream& operator<<(std::ostream& out, __float128 f) {
char buf[200];
std::ostringstream format;
format << "%." << (std::min)(190L, out.precision()) << "Qf";
quadmath_snprintf(buf, 200, format.str().c_str(), f);
out << buf;
return out;
}
int main() {
std::cout.precision(32);
std::cout << "Number: 0.70710678118654752440084436210485\n";
const float f = 0.70710678118654752440084436210485f;
std::cout << "float: " << std::setprecision(32) << f << std::endl;
const double d = 0.70710678118654752440084436210485; // no f extension
std::cout << "double: " << std::setprecision(32) << d << std::endl;
const double df = 0.70710678118654752440084436210485f;
std::cout << "doublef: " << std::setprecision(32) << df << std::endl;
const long double ld = 0.70710678118654752440084436210485;
std::cout << "l double: " << std::setprecision(32) << ld << std::endl;
const long double ldl = 0.70710678118654752440084436210485l; // l suffix!
std::cout << "l doublel: " << std::setprecision(32) << ldl << std::endl;
const __float128 f128 = 0.70710678118654752440084436210485;
const __float128 f128f = 0.70710678118654752440084436210485f; // f suffix
const __float128 f128l = 0.70710678118654752440084436210485l; // l suffix
const __float128 f128q = 0.70710678118654752440084436210485q; // q suffix
std::cout << "f128: " << f128 << std::endl;
std::cout << "f f128: " << f128f << std::endl;
std::cout << "l f128: " << f128l << std::endl;
std::cout << "q f128: " << f128q << std::endl;
}
The output is:
* ** *** ****
v v v v
Number: 0.70710678118654752440084436210485
float: 0.707106769084930419921875
double: 0.70710678118654757273731092936941
doublef: 0.707106769084930419921875
l double: 0.70710678118654757273731092936941
l doublel: 0.70710678118654752438189403651592
f128: 0.70710678118654757273731092936941
f f128: 0.70710676908493041992187500000000
l f128: 0.70710678118654752438189403651592
q f128: 0.70710678118654752440084436210485
where * is the last accurate digit of float, ** the last accurate digit of
double, *** the last accurate digit of long double, and **** is the
last accurate digit of __float128.
As said by another answer, the C++ standard does not say what is the precision of the various floating point types (like it does not says what is the size of the integral types). It only specifies minimal precision/size of those types. But the norm IEEE754 does specify all that! The FPU of all lot of architectures does implement that norm IEEE745, and the recent versions of gcc implement the type binary128 of the norm with the extension __float128.
As for the explanation of your code, or mine, an expression like 0.70710678118654752440084436210485f is a floating-point literal. It has a type, that is defined by its suffix, here f for float. And thus the value of the literal correspond to the nearest value of the given type from the given number. That explains why, for example, the precision of "doublef" is the same as for "float", in your code. In recent gcc versions, there is an extension, that allows to define floating-point literals of type __float128, with the Q suffix (Quadruple-precision).