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.
Working example:
#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;
}
Output:
3EAABB3194A6E99A
0.0000007966525939409087744
3EAABB3194A6E99A
0.0000007966525939409087744
3EAABB3194A6E999
0.0000007966525939409087488
3EAABB3194A6E99A
0.0000007966525939409087744
Question:
- Why does this happen? Isn't a new thread supposed to inherit floating point environment from the parent thread?
- Is this a bug in the compiler or in Boost, or are my expectations wrong?
_fpreset()
makes the difference. I assume thatboost::thread
doesn't do it, andstd::thread
does. – Farman#define BOOST_THREAD_USE_LIB
before#include <boost/thread.hpp>
. I assume this was defined externally? – Farman_fpreset()
, which is a C++Builder specific thing, and thestd
library was obviously modified to make that call. See my answer. – Farmanprint_number()
function to usememcpy()
to stop the complaints about undefined behaviour, since that was irrelevant to the question. – Farman