Skip to content

Instantly share code, notes, and snippets.

@Quackward
Last active August 13, 2021 07:16
Show Gist options
  • Save Quackward/005f67c7e541c81edb64fa0ccf0f6749 to your computer and use it in GitHub Desktop.
Save Quackward/005f67c7e541c81edb64fa0ccf0f6749 to your computer and use it in GitHub Desktop.
// 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);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment