Last active
August 13, 2021 07:16
-
-
Save Quackward/005f67c7e541c81edb64fa0ccf0f6749 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// [email protected] \(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); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment