When this floating point calculation is executed in boost::thread
, it gives different result than when executed in std::thread
or in main thread.
void print_number()
{
double a = 5.66;
double b = 0.0000001;
double c = 500.4444;
double d = 0.13423;
double v = std::sin(d) * std::exp(0.4 * a + b) / std::pow(c, 2.3);
printf("%llX\n%0.25f\n", *reinterpret_cast<unsigned long long*>(&v), v);
}
This seems to happen because boost::thread
is by default using 53-bit internal precision for floating point math, while the main thread is using 64-bit precision. If status of FPU unit is reset with _fpreset()
after the boost::thread
has been created, the result is the same as in the main thread.
I am using Embarcadero C++ Builder 10.1 (compiler bcc32c version 3.3.1) and Boost 1.55.0. My environment is Windows 7, and I am building for 32-bit Windows target.
#include <tchar.h>
#include <thread>
#include <boost/thread.hpp>
#include <cstdio>
#include <cmath>
#include <cfloat>
namespace boost { void tss_cleanup_implemented() {} }
void print_number()
{
double a = 5.66;
double b = 0.0000001;
double c = 500.4444;
double d = 0.13423;
double v = std::sin(d) * std::exp(0.4 * a + b) / std::pow(c, 2.3);
// Edit:
// Avoiding the undefined behaviour by a reinterpret_cast, as
// mentioned in some answers and comments.
unsigned long long x;
memcpy(&x, &v, sizeof(x));
printf("%llX\n%0.25f\n", x, v);
}
void print_number_2()
{
// Reset FPU precision to default
_fpreset();
print_number();
}
int _tmain(int argc, _TCHAR* argv[])
{
print_number();
std::thread t1(&print_number);
t1.join();
boost::thread t2(&print_number);
t2.join();
boost::thread t3(&print_number_2);
t3.join();
getchar();
return 0;
}
3EAABB3194A6E99A
0.0000007966525939409087744
3EAABB3194A6E99A
0.0000007966525939409087744
3EAABB3194A6E999
0.0000007966525939409087488
3EAABB3194A6E99A
0.0000007966525939409087744
This: *reinterpret_cast<unsigned long long*>(&v)
is undefined behaviour as v
is not unsigned_long_long
. If you want to copy the binary representation of a double
to an integral type, use memcpy()
. Note that, even with memcpy()
, it's implementation defined how the binary representation will look like, but you're guaranteed that you can 'load back what you've saved'. Nothing more AFAIK.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With