// Clairvoire@gmail.com \(v ` >`)_v // feel free to use as you see fit, attribution appreciated but not required, not fit for any purpose // returns TRUE if the printed version of a float is being approximated when we limit the print // to a certain number of decimal places, as defined by `decimalPlaceLimit`, // returns FALSE if the printed version is 100% accurate to the float itself. // NOTE: This WILL return true for values like 0.1, which ARE approximated at extremely // small fractional parts in floats: 0.1 is actually 0.100000000000000005551115... // truth table: // f( val, dec ) -> ret // ----------------------- // f( 0.5, 3 ) -> 0 // f( 0.25, 3 ) -> 0 // f( 0.125, 3 ) -> 0 // f( 0.0625, 3 ) -> 1 bool isFloatRoundingApprox(float value, uint32_t decimalPlaceLimit) { // 0.0 is special, it's the only value for which our assumption about the exponent kind of backfires // 1.0 and 0.5 are... not special, these are just kind of common, may as well make quick outs for them if(value == 0.f || value == 1.f || (value == 0.5f && decimalPlaceLimit > 0)) return false; uint32_t bits = *(uint32_t*)(&value); uint32_t exponent = (bits>>23)&0xFF; uint32_t mantissa = bits&0x7FFFFF; uint32_t msb; // msb is treated as lsb in the preprocessor'd section #ifdef _MSC_VER { unsigned long result; // has to be this type _BitScanForward(&result, mantissa); msb = result; } #elif __GNUC__ #pragma message ("branch untested, if it works, feel free to delete this!") msb = __builtin_ffs(mantissa); #else #pragma message ("branch untested, if it works, feel free to delete this!") #pragma message ("using an unoptimized fallback") msb = 0; // treat as lsb until the end for (uint32_t i = 0; i < 23; ++i) { if((mantissa>>i)&1u) break; ++msb; } msb = (msb + 1) % 23; // 0 to 22 lsb #endif msb = (23 - msb); if(msb == 23) msb = 0; // takes advantage of a property of I noticed (that hopefully is true?) regarding float representation, // where: // [index of the most set bit in the mantissa] - ([exponent] - 127) // defines how many digits "deep" into the fractional part we travel // we can use this to DIRECTLY gather if our decimal point is being rounded due to the fact that... // once we reach into any depth of the fractional part, it can NEVER be zero (this isn't true for zero itself tho) int32_t depth = int32_t(msb) - (int32_t(exponent) - 127); return depth > int32_t(decimalPlaceLimit); }