Created
January 17, 2021 23:02
-
-
Save rversteegen/9865ad0dfa734981d3f41ab968d7cf58 to your computer and use it in GitHub Desktop.
Code snippet to put the x87 FPU into double precision mode for portability
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/////////////////////// Put x87 FPU in double-precision mode ////////////////// | |
// For cross-platform portability, force x87 floating-point calculations to be | |
// done with intermediate results stored in double precision (53 bit mantissa) | |
// instead of extended double precision (64 bit mantissa) registers. We change | |
// the x87 control register to accomplish this. But it only affects the | |
// mantissa, not the exponent, so does not remove all inconsistencies. | |
// | |
// See http://yosefk.com/blog/consistency-how-to-defeat-the-purpose-of-ieee-floating-point.html | |
// and http://christian-seiler.de/projekte/fpmath/ | |
// Indirectly include features.h (for glibc detection), which might not exist | |
#include <limits.h> | |
// Check for x86 or amd64, for Visual C++, GCC | |
#if defined(_M_IX86) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__) | |
#if defined(_MSC_VER) || defined(_WIN32) | |
// Windows, either Visual C++ or MinGW. Note, Windows defaults to double-precision, | |
// but MinGW switches on extended precision | |
#include <float.h> | |
// Unfortunately at least some MinGW versions (4.8.1) ship with a copy of | |
// gcc with a float.h which shadows the MinGW float.h header | |
#ifndef _PC_53 | |
#define _PC_53 0x00010000 | |
#define _MCW_PC 0x00030000 | |
_CRTIMP unsigned int __cdecl __MINGW_NOTHROW _controlfp (unsigned int unNew, unsigned int unMask); | |
#endif | |
void disable_extended_precision() { | |
_controlfp(_PC_53, _MCW_PC); | |
} | |
#elif defined(__gnu_linux__) || defined(__GNU_LIBRARY__) || defined(__GLIBC__) | |
// For glibc | |
#include <fpu_control.h> | |
void disable_extended_precision() { | |
fpu_control_t cw; | |
_FPU_GETCW(cw); | |
cw = (cw & ~_FPU_EXTENDED) | _FPU_DOUBLE; | |
_FPU_SETCW(cw); | |
} | |
#else | |
// Mac: apparently no macro provided to switch the precision, but apparently not | |
// needed on Macs because SSE is used for everything when possible? | |
// According to one source, all BSD*s use double precision by default, although | |
// they did not always, so don't know if this is still true either. | |
void disable_extended_precision() {} | |
#endif | |
#else | |
// Not x86 | |
void disable_extended_precision() {} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment