Skip to content

Instantly share code, notes, and snippets.

@lrhn
Created July 1, 2019 13:33
Show Gist options
  • Save lrhn/1cad1a8696babf33485a783e124386a2 to your computer and use it in GitHub Desktop.
Save lrhn/1cad1a8696babf33485a783e124386a2 to your computer and use it in GitHub Desktop.
Function returning the ULP of a double number - the value of its least signfiicant bit position.
import "dart:typed_data";
final _ulpBuffer = ByteData(8);
/// The unit of least precision for a [double] number.
///
/// A double number has 53 bits of precision. The unit of least precision (ULP)
/// is the value of the least of those bits.
/// The returned ULP is always positive.
double ulp(double d) {
var buffer = _ulpBuffer;
buffer.setFloat64(0, d, Endian.little);
// 11 bits of mantissa stored at bits 52..62.
int mantissa = (buffer.getUint16(6, Endian.little) >> 4) & 0x7FF;
if (mantissa == 0x3ff) return d.abs(); // NaN or Infinity
if (mantissa == 0) {
// Input is denormal, ULP is minimal double value.
return double.minPositive;
}
// Otherwise, the lowest bit is 52 bits below the highest bit.
buffer.setFloat64(0, 0.0, Endian.host); // Clear buffer.
if (mantissa <= 52) {
// Result is denormal.
int bit = mantissa - 1;
buffer.setUint8(bit >> 3, 1 << (bit & 7));
} else {
buffer.setUint16(6, (mantissa - 52) << 4, Endian.little);
}
return buffer.getFloat64(0, Endian.little);
}
// Sanity check
main() {
print(ulp(0.0));
for (double d = double.minPositive; d < double.infinity; d *= 2) {
var u = ulp(d);
print("$d: $u");
if (d + u == d) print("NOT RIGHT");
if (d + (u / 2) != d && d + (u/2) != d+ u) {
print("NOT WAT?");
}
}
print(ulp(double.infinity));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment