Created
July 1, 2019 13:33
-
-
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.
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
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