| /** | |
| * This file has no copyright assigned and is placed in the Public Domain. | |
| * This file is part of the mingw-w64 runtime package. | |
| * No warranty is given; refer to the file DISCLAIMER.PD within this package. | |
| */ | |
| long double frexpl(long double value, int* exp); | |
| #if defined(_ARM_) || defined(__arm__) || defined(_ARM64_) || defined(__aarch64__) | |
| double frexp(double value, int* exp); | |
| /* On ARM `long double` is 64 bits. */ | |
| long double frexpl(long double value, int* exp) | |
| { | |
| return frexp(value, exp); | |
| } | |
| #elif defined(_AMD64_) || defined(__x86_64__) || defined(_X86_) || defined(__i386__) | |
| #include <stdint.h> | |
| /* https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format */ | |
| typedef union x87reg_ { | |
| struct __attribute__((__packed__)) { | |
| uint64_t f64; | |
| uint16_t exp : 15; | |
| uint16_t sgn : 1; | |
| }; | |
| long double f; | |
| } x87reg; | |
| long double frexpl(long double value, int* exp) | |
| { | |
| int n; | |
| x87reg reg; | |
| reg.f = value; | |
| if(reg.exp == 0x7FFF) { | |
| /* The value is an infinity or NaN. | |
| * Store zero in `*exp`. Return the value as is. */ | |
| *exp = 0; | |
| return reg.f; | |
| } | |
| if(reg.exp != 0) { | |
| /* The value is normalized. | |
| * Extract and zero out the exponent. */ | |
| *exp = reg.exp - 0x3FFE; | |
| reg.exp = 0x3FFE; | |
| return reg.f; | |
| } | |
| if(reg.f64 == 0) { | |
| /* The value is zero. | |
| * Store zero in `*exp`. Return the value as is. | |
| * Note the signness. */ | |
| *exp = 0; | |
| return reg.f; | |
| } | |
| /* The value is denormalized. | |
| * Extract the exponent, normalize the value, then zero out | |
| * the exponent. Note that x87 uses an explicit leading bit. */ | |
| n = __builtin_clzll(reg.f64); | |
| reg.f64 <<= n; | |
| *exp = 1 - 0x3FFE - n; | |
| reg.exp = 0x3FFE; | |
| return reg.f; | |
| } | |
| #else | |
| #error Please add `frexpl()` implementation for this platform. | |
| #endif |