#include <iostream>
#include <math.h>
#define FP_UNSUPPORTED FP_NAN
/* 7.12.3.1 */
/*
Return values for fpclassify.
These are based on Intel x87 fpu condition codes
in the high byte of status word and differ from
the return values for MS IEEE 754 extension _fpclass()
*/
/*
#define FP_NAN 0x0100
#define FP_NORMAL 0x0400
#define FP_INFINITE (FP_NAN | FP_NORMAL)
#define FP_ZERO 0x4000
#define FP_SUBNORMAL (FP_NORMAL | FP_ZERO)
// 0x0200 is signbit mask
*/
/*__CRT_INLINE int __cdecl my_fpclassifyl(long double x)
{
__mingw_fp_types_t hlp;
unsigned int e;
hlp.ld = &x;
e = hlp.ldt->lh.sign_exponent & 0x7fff;
unsigned int h = hlp.ldt->lh.high;
if (!e)
{
if (!(hlp.ldt->lh.low | h))
return FP_ZERO;
else if (!(h & 0x80000000))
return FP_SUBNORMAL;
}
else if (e == 0x7fff)
return (((hlp.ldt->lh.high & 0x7fffffff) | hlp.ldt->lh.low) == 0 ?
FP_INFINITE : FP_NAN);
return ((h & 0x80000000) == 0) ? FP_NAN : FP_NORMAL;
}*/
template<class T>
void printVal(T val, const char* format)
{
printf(format, val);
}
typedef union my__mingw_ldbl_type_t
{
long double x;
struct {
unsigned int low, high;
int sign_exponent : 16;
int res1 : 16;
int res0 : 32;
} lh;
} my__mingw_ldbl_type_t;
int myclassify(long double ld)
{
my__mingw_ldbl_type_t lds = *(my__mingw_ldbl_type_t*)&ld;
//https://e...content-available-to-author-only...a.org/wiki/Extended_precision#x86_extended_precision_format
auto bit63 = (lds.lh.high & 0x80000000) != 0;
switch (lds.lh.sign_exponent & 0x7fff) //Exponent
{
case 0: //Exponent: All Zeros
{
if (!bit63) //Bit 63: Zero
{
if (lds.lh.low == 0 && (lds.lh.high & 0x7fffffff) == 0) //Bits 62-0: Zero
{
return FP_ZERO; //Zero. The sign bit gives the sign of the zero.
}
else //Bits 62-0: Non-zero
{
return FP_SUBNORMAL; //Denormal. The value is (−1)^s * m * 2^(−16382)
}
}
else //Bit 63: One
{
return FP_SUBNORMAL; //Pseudo Denormal. The 80387 and later properly interpret this value but will not generate it. The value is (−1)^s * m * 2^(−16382)
}
}
case 0x7fff: //Exponent: All Ones
{
auto bit62 = (lds.lh.high & 0x40000000) != 0;
auto bit61to0_zero = (lds.lh.high & 0x3fffffff) == 0 && lds.lh.low == 0;
if (!bit63 && !bit62) //Bits 63,62: 00
{
if (bit61to0_zero) //Bits 61-0: Zero
{
return FP_UNSUPPORTED; //Pseudo-Infinity. The sign bit gives the sign of the infinity. The 8087 and 80287 treat this as Infinity. The 80387 and later treat this as an invalid operand.
}
else //Bits 61-0: Non-zero
{
return FP_UNSUPPORTED; //Pseudo Not a Number. The sign bit is meaningless. The 8087 and 80287 treat this as a Signaling Not a Number. The 80387 and later treat this as an invalid operand.
}
}
else if (!bit63 && bit62) //Bits 63,62: 01
{
//Bits 61-0: Anything
return FP_UNSUPPORTED; //Pseudo Not a Number. The sign bit is meaningless. The 8087 and 80287 treat this as a Signaling Not a Number. The 80387 and later treat this as an invalid operand.
}
else if (bit63 && !bit62) //Bits 63,62: 10
{
if (bit61to0_zero) //Bits 61-0: Zero
{
return FP_INFINITE; //Infinity. The sign bit gives the sign of the infinity. The 8087 and 80287 treat this as a Signaling Not a Number. The 8087 and 80287 coprocessors used the pseudo-infinity representation for infinities.
}
else //Bits 61-0: Non-zero
{
return FP_NAN; //Signalling Not a Number, the sign bit is meaningless.
}
}
else if (bit63 && bit62) //Bits 63,62: 11
{
if (bit61to0_zero) //Bits 61-0: Zero
{
return FP_NAN; //Floating-point Indefinite, the result of invalid calculations such as square root of a negative number, logarithm of a negative number, 0/0, infinity / infinity, infinity times 0, and others when the processor has been configured to not generate exceptions for invalid operands. The sign bit is meaningless. This is a special case of a Quiet Not a Number.
}
else //Bits 61-0: Non-zero
{
return FP_NAN; //Quiet Not a Number, the sign bit is meaningless. The 8087 and 80287 treat this as a Signaling Not a Number.
}
}
}
default: //Exponent: All other values
{
if (!bit63) //Bit 63: Zero
{
return FP_UNSUPPORTED; //Unnormal. Only generated on the 8087 and 80287. The 80387 and later treat this as an invalid operand. The value is (−1)^s * m * 2^(e−16383)
}
else //Bit 63: One
{
return FP_NORMAL; //Normalized value. The value is (−1)^s * m * 2^(e−16383)
}
}
}
}
#include <string.h>
# define fufu(x) __builtin_fpclassify (FP_NAN, FP_INFINITE, \
FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x)
int main()
{
long double ld;
unsigned char data[10] = {0x5b, 0x01, 0x04, 0x5e, 0x85, 0x00, 0x00, 0x00, 0xd8, 0x59};
memcpy(&ld, data, 10);
my__mingw_ldbl_type_t fuck = *(my__mingw_ldbl_type_t*)&ld;
printVal(fuck.lh.low, "lh.low: 0x%08X\n");
printVal(fuck.lh.high, "lh.high: 0x%08X\n");
printVal(fuck.lh.sign_exponent, "lh.sign_exponent: 0x%04X\n");
printVal(fuck.lh.res0, "lh.res0: 0x%04X\n");
printVal(fuck.lh.res1, "lh.res1: 0x%08X\n");
memset(&fuck, 0, sizeof(fuck));
fuck.lh.low = 0xffffffff;
for(unsigned int sign_exponent = 0; sign_exponent < 65536; sign_exponent++)
{
for(unsigned int high = 0; high < 256; high++)
{
fuck.lh.sign_exponent = sign_exponent;
fuck.lh.high = high;
auto builtin = fufu(fuck.x);
auto my = myclassify(fuck.x);
if(builtin != my)
{
printf("FUCK, sign_exponent: 0x%X, high: 0x%X, 0x%X!=0x%X\n", sign_exponent, high, builtin, my);
return 0;
}
}
}
puts("YAY");
return 0;
}