Rename IEEE 754 from_f64_to_u{16,32} functions
diff --git a/internal/cgen/base/floatconv-submodule-code.c b/internal/cgen/base/floatconv-submodule-code.c
index 0e9f8a2..603d180 100644
--- a/internal/cgen/base/floatconv-submodule-code.c
+++ b/internal/cgen/base/floatconv-submodule-code.c
@@ -17,7 +17,7 @@
// ---------------- IEEE 754 Floating Point
WUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u16 //
-wuffs_base__ieee_754_bit_representation__from_f64_to_u16(double f) {
+wuffs_base__ieee_754_bit_representation__from_f64_to_u16_truncate(double f) {
uint64_t u = 0;
if (sizeof(uint64_t) == sizeof(double)) {
memcpy(&u, &f, sizeof(uint64_t));
@@ -81,7 +81,7 @@
}
WUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u32 //
-wuffs_base__ieee_754_bit_representation__from_f64_to_u32(double f) {
+wuffs_base__ieee_754_bit_representation__from_f64_to_u32_truncate(double f) {
uint64_t u = 0;
if (sizeof(uint64_t) == sizeof(double)) {
memcpy(&u, &f, sizeof(uint64_t));
diff --git a/internal/cgen/base/strconv-public.h b/internal/cgen/base/strconv-public.h
index 2e2215f..8fce7a1 100644
--- a/internal/cgen/base/strconv-public.h
+++ b/internal/cgen/base/strconv-public.h
@@ -108,12 +108,18 @@
// - -inf and 0xFC00, 0xFF80_0000 or 0xFFF0_0000_0000_0000.
//
// Converting from f64 to shorter formats (f16 or f32, represented in C as
-// uint16_t and uint32_t) may be lossy. Converting finite numbers truncate,
-// producing equal or smaller (closer-to-zero) finite numbers. Converting
-// infinities or NaNs produces infinities or NaNs and always report no loss,
-// even though there a multiple NaN representations so that round-tripping a
-// f64 NaN may produce a different 64 bits. Nonetheless, a NaN's "quiet vs
-// signaling" bit is preserved.
+// uint16_t and uint32_t) may be lossy. Such functions have names that look
+// like etc_truncate, as converting finite numbers produce equal or smaller
+// (closer-to-zero) finite numbers. For example, 1048576.0 is a perfectly valid
+// f64 number, but converting it to a f16 (with truncation) produces 65504.0,
+// the largest finite f16 number. Truncating a f64-typed value d to f32 does
+// not always produce the same result as the C-style cast ((float)d), as
+// casting can convert from finite numbers to infinite ones.
+//
+// Converting infinities or NaNs produces infinities or NaNs and always report
+// no loss, even though there a multiple NaN representations so that round-
+// tripping a f64-typed NaN may produce a different 64 bits. Nonetheless, the
+// etc_truncate functions preserve a NaN's "quiet vs signaling" bit.
//
// See https://en.wikipedia.org/wiki/Double-precision_floating-point_format
@@ -128,10 +134,10 @@
} wuffs_base__lossy_value_u32;
WUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u16 //
-wuffs_base__ieee_754_bit_representation__from_f64_to_u16(double f);
+wuffs_base__ieee_754_bit_representation__from_f64_to_u16_truncate(double f);
WUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u32 //
-wuffs_base__ieee_754_bit_representation__from_f64_to_u32(double f);
+wuffs_base__ieee_754_bit_representation__from_f64_to_u32_truncate(double f);
static inline uint64_t //
wuffs_base__ieee_754_bit_representation__from_f64_to_u64(double f) {
diff --git a/internal/cgen/data/data.go b/internal/cgen/data/data.go
index 6c9ece2..46320e0 100644
--- a/internal/cgen/data/data.go
+++ b/internal/cgen/data/data.go
@@ -29,11 +29,11 @@
""
const BaseFloatConvSubmoduleCodeC = "" +
- "// ---------------- IEEE 754 Floating Point\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u16 //\nwuffs_base__ieee_754_bit_representation__from_f64_to_u16(double f) {\n uint64_t u = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&u, &f, sizeof(uint64_t));\n }\n uint16_t neg = ((uint16_t)(u >> 63)) << 15;\n u &= 0x7FFFFFFFFFFFFFFF;\n uint64_t exp = u >> 52;\n uint64_t man = u & 0x000FFFFFFFFFFFFF;\n\n if (exp == 0x7FF) {\n if (man == 0) { // Infinity.\n wuffs_base__lossy_value_u16 ret;\n ret.value = neg | 0x7C00;\n ret.lossy = false;\n return ret;\n }\n // NaN. Shift the 52 mantissa bits to 10 mantissa bits, keeping the most\n // significant mantissa bit (quiet vs signaling NaNs). Also set the low 9\n // bits of ret.value so that the 10-bit mantissa is non-zero.\n wuffs_base__lossy_value_u16 ret;\n ret.value = neg | 0x7DFF | ((uint16_t)(man >> 42));\n ret.lossy = false;\n return ret;\n\n } else if (exp > 0x40E) { // Truncate to the largest finite f16.\n wuffs_" +
- "base__lossy_value_u16 ret;\n ret.value = neg | 0x7BFF;\n ret.lossy = true;\n return ret;\n\n } else if (exp <= 0x3E6) { // Truncate to zero.\n wuffs_base__lossy_value_u16 ret;\n ret.value = neg;\n ret.lossy = (u != 0);\n return ret;\n\n } else if (exp <= 0x3F0) { // Normal f64, subnormal f16.\n // Convert from a 53-bit mantissa (after realizing the implicit bit) to a\n // 10-bit mantissa and then adjust for the exponent.\n man |= 0x0010000000000000;\n uint32_t shift = 1051 - exp; // 1051 = 0x3F0 + 53 - 10.\n uint64_t shifted_man = man >> shift;\n wuffs_base__lossy_value_u16 ret;\n ret.value = neg | ((uint16_t)shifted_man);\n ret.lossy = (shifted_man << shift) != man;\n return ret;\n }\n\n // Normal f64, normal f16.\n\n // Re-bias from 1023 to 15 and shift above f16's 10 mantissa bits.\n exp = (exp - 1008) << 10; // 1008 = 1023 - 15 = 0x3FF - 0xF.\n\n // Convert from a 52-bit mantissa (excluding the implicit bit) to a 10-bit\n // mantissa (again excluding the implicit bit). We lo" +
- "se some information if\n // any of the bottom 42 bits are non-zero.\n wuffs_base__lossy_value_u16 ret;\n ret.value = neg | ((uint16_t)exp) | ((uint16_t)(man >> 42));\n ret.lossy = (man << 22) != 0;\n return ret;\n}\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u32 //\nwuffs_base__ieee_754_bit_representation__from_f64_to_u32(double f) {\n uint64_t u = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&u, &f, sizeof(uint64_t));\n }\n uint32_t neg = ((uint32_t)(u >> 63)) << 31;\n u &= 0x7FFFFFFFFFFFFFFF;\n uint64_t exp = u >> 52;\n uint64_t man = u & 0x000FFFFFFFFFFFFF;\n\n if (exp == 0x7FF) {\n if (man == 0) { // Infinity.\n wuffs_base__lossy_value_u32 ret;\n ret.value = neg | 0x7F800000;\n ret.lossy = false;\n return ret;\n }\n // NaN. Shift the 52 mantissa bits to 23 mantissa bits, keeping the most\n // significant mantissa bit (quiet vs signaling NaNs). Also set the low 22\n // bits of ret.value so that the 23-bit mantissa is non-zero.\n wuffs_base__lossy_value_u32 ret;" +
- "\n ret.value = neg | 0x7FBFFFFF | ((uint32_t)(man >> 29));\n ret.lossy = false;\n return ret;\n\n } else if (exp > 0x47E) { // Truncate to the largest finite f32.\n wuffs_base__lossy_value_u32 ret;\n ret.value = neg | 0x7F7FFFFF;\n ret.lossy = true;\n return ret;\n\n } else if (exp <= 0x369) { // Truncate to zero.\n wuffs_base__lossy_value_u32 ret;\n ret.value = neg;\n ret.lossy = (u != 0);\n return ret;\n\n } else if (exp <= 0x380) { // Normal f64, subnormal f32.\n // Convert from a 53-bit mantissa (after realizing the implicit bit) to a\n // 23-bit mantissa and then adjust for the exponent.\n man |= 0x0010000000000000;\n uint32_t shift = 926 - exp; // 926 = 0x380 + 53 - 23.\n uint64_t shifted_man = man >> shift;\n wuffs_base__lossy_value_u32 ret;\n ret.value = neg | ((uint32_t)shifted_man);\n ret.lossy = (shifted_man << shift) != man;\n return ret;\n }\n\n // Normal f64, normal f32.\n\n // Re-bias from 1023 to 127 and shift above f32's 23 mantissa bits.\n exp = (exp - " +
- "896) << 23; // 896 = 1023 - 127 = 0x3FF - 0x7F.\n\n // Convert from a 52-bit mantissa (excluding the implicit bit) to a 23-bit\n // mantissa (again excluding the implicit bit). We lose some information if\n // any of the bottom 29 bits are non-zero.\n wuffs_base__lossy_value_u32 ret;\n ret.value = neg | ((uint32_t)exp) | ((uint32_t)(man >> 29));\n ret.lossy = (man << 35) != 0;\n return ret;\n}\n\n" +
+ "// ---------------- IEEE 754 Floating Point\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u16 //\nwuffs_base__ieee_754_bit_representation__from_f64_to_u16_truncate(double f) {\n uint64_t u = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&u, &f, sizeof(uint64_t));\n }\n uint16_t neg = ((uint16_t)(u >> 63)) << 15;\n u &= 0x7FFFFFFFFFFFFFFF;\n uint64_t exp = u >> 52;\n uint64_t man = u & 0x000FFFFFFFFFFFFF;\n\n if (exp == 0x7FF) {\n if (man == 0) { // Infinity.\n wuffs_base__lossy_value_u16 ret;\n ret.value = neg | 0x7C00;\n ret.lossy = false;\n return ret;\n }\n // NaN. Shift the 52 mantissa bits to 10 mantissa bits, keeping the most\n // significant mantissa bit (quiet vs signaling NaNs). Also set the low 9\n // bits of ret.value so that the 10-bit mantissa is non-zero.\n wuffs_base__lossy_value_u16 ret;\n ret.value = neg | 0x7DFF | ((uint16_t)(man >> 42));\n ret.lossy = false;\n return ret;\n\n } else if (exp > 0x40E) { // Truncate to the largest finite f16.\n " +
+ " wuffs_base__lossy_value_u16 ret;\n ret.value = neg | 0x7BFF;\n ret.lossy = true;\n return ret;\n\n } else if (exp <= 0x3E6) { // Truncate to zero.\n wuffs_base__lossy_value_u16 ret;\n ret.value = neg;\n ret.lossy = (u != 0);\n return ret;\n\n } else if (exp <= 0x3F0) { // Normal f64, subnormal f16.\n // Convert from a 53-bit mantissa (after realizing the implicit bit) to a\n // 10-bit mantissa and then adjust for the exponent.\n man |= 0x0010000000000000;\n uint32_t shift = 1051 - exp; // 1051 = 0x3F0 + 53 - 10.\n uint64_t shifted_man = man >> shift;\n wuffs_base__lossy_value_u16 ret;\n ret.value = neg | ((uint16_t)shifted_man);\n ret.lossy = (shifted_man << shift) != man;\n return ret;\n }\n\n // Normal f64, normal f16.\n\n // Re-bias from 1023 to 15 and shift above f16's 10 mantissa bits.\n exp = (exp - 1008) << 10; // 1008 = 1023 - 15 = 0x3FF - 0xF.\n\n // Convert from a 52-bit mantissa (excluding the implicit bit) to a 10-bit\n // mantissa (again excluding the implicit bi" +
+ "t). We lose some information if\n // any of the bottom 42 bits are non-zero.\n wuffs_base__lossy_value_u16 ret;\n ret.value = neg | ((uint16_t)exp) | ((uint16_t)(man >> 42));\n ret.lossy = (man << 22) != 0;\n return ret;\n}\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u32 //\nwuffs_base__ieee_754_bit_representation__from_f64_to_u32_truncate(double f) {\n uint64_t u = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&u, &f, sizeof(uint64_t));\n }\n uint32_t neg = ((uint32_t)(u >> 63)) << 31;\n u &= 0x7FFFFFFFFFFFFFFF;\n uint64_t exp = u >> 52;\n uint64_t man = u & 0x000FFFFFFFFFFFFF;\n\n if (exp == 0x7FF) {\n if (man == 0) { // Infinity.\n wuffs_base__lossy_value_u32 ret;\n ret.value = neg | 0x7F800000;\n ret.lossy = false;\n return ret;\n }\n // NaN. Shift the 52 mantissa bits to 23 mantissa bits, keeping the most\n // significant mantissa bit (quiet vs signaling NaNs). Also set the low 22\n // bits of ret.value so that the 23-bit mantissa is non-zero.\n wuffs_base__lo" +
+ "ssy_value_u32 ret;\n ret.value = neg | 0x7FBFFFFF | ((uint32_t)(man >> 29));\n ret.lossy = false;\n return ret;\n\n } else if (exp > 0x47E) { // Truncate to the largest finite f32.\n wuffs_base__lossy_value_u32 ret;\n ret.value = neg | 0x7F7FFFFF;\n ret.lossy = true;\n return ret;\n\n } else if (exp <= 0x369) { // Truncate to zero.\n wuffs_base__lossy_value_u32 ret;\n ret.value = neg;\n ret.lossy = (u != 0);\n return ret;\n\n } else if (exp <= 0x380) { // Normal f64, subnormal f32.\n // Convert from a 53-bit mantissa (after realizing the implicit bit) to a\n // 23-bit mantissa and then adjust for the exponent.\n man |= 0x0010000000000000;\n uint32_t shift = 926 - exp; // 926 = 0x380 + 53 - 23.\n uint64_t shifted_man = man >> shift;\n wuffs_base__lossy_value_u32 ret;\n ret.value = neg | ((uint32_t)shifted_man);\n ret.lossy = (shifted_man << shift) != man;\n return ret;\n }\n\n // Normal f64, normal f32.\n\n // Re-bias from 1023 to 127 and shift above f32's 23 mantissa bit" +
+ "s.\n exp = (exp - 896) << 23; // 896 = 1023 - 127 = 0x3FF - 0x7F.\n\n // Convert from a 52-bit mantissa (excluding the implicit bit) to a 23-bit\n // mantissa (again excluding the implicit bit). We lose some information if\n // any of the bottom 29 bits are non-zero.\n wuffs_base__lossy_value_u32 ret;\n ret.value = neg | ((uint32_t)exp) | ((uint32_t)(man >> 29));\n ret.lossy = (man << 35) != 0;\n return ret;\n}\n\n" +
"" +
"// --------\n\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE 2047\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION 800\n\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL is the largest N\n// such that ((10 << N) < (1 << 64)).\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL 60\n\n// wuffs_base__private_implementation__high_prec_dec (abbreviated as HPD) is a\n// fixed precision floating point decimal number, augmented with ±infinity\n// values, but it cannot represent NaN (Not a Number).\n//\n// \"High precision\" means that the mantissa holds 800 decimal digits. 800 is\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION.\n//\n// An HPD isn't for general purpose arithmetic, only for conversions to and\n// from IEEE 754 double-precision floating point, where the largest and\n// smallest positive, finite values are approximately 1.8e+308 and 4.9e-324.\n// HPD exponents above +2047 mean infinity, below -2047 mean zero. The ±2047\n// bounds are further a" +
"way from zero than ±(324 + 800), where 800 and 2047 is\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION and\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.\n//\n// digits[.. num_digits] are the number's digits in big-endian order. The\n// uint8_t values are in the range [0 ..= 9], not ['0' ..= '9'], where e.g. '7'\n// is the ASCII value 0x37.\n//\n// decimal_point is the index (within digits) of the decimal point. It may be\n// negative or be larger than num_digits, in which case the explicit digits are\n// padded with implicit zeroes.\n//\n// For example, if num_digits is 3 and digits is \"\\x07\\x08\\x09\":\n// - A decimal_point of -2 means \".00789\"\n// - A decimal_point of -1 means \".0789\"\n// - A decimal_point of +0 means \".789\"\n// - A decimal_point of +1 means \"7.89\"\n// - A decimal_point of +2 means \"78.9\"\n// - A decimal_point of +3 means \"789.\"\n// - A decimal_point of +4 means \"7890.\"\n// - A decimal_point of +5 means \"78900.\"\n//\n// As above, a decimal_point higher than +2047" +
@@ -521,10 +521,10 @@
"XX__DECIMAL_SEPARATOR_IS_A_COMMA \\\n ((uint32_t)0x00001000)\n\n// WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ETC means whether to never\n// (EXPONENT_ABSENT, equivalent to printf's \"%f\") or to always\n// (EXPONENT_PRESENT, equivalent to printf's \"%e\") render a floating point\n// number as \"1.23e+05\" instead of \"123000\".\n//\n// Having both bits set is the same has having neither bit set, where the\n// notation used depends on whether the exponent is sufficiently large: \"0.5\"\n// is preferred over \"5e-01\" but \"5e-09\" is preferred over \"0.000000005\".\n#define WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT ((uint32_t)0x00002000)\n#define WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT ((uint32_t)0x00004000)\n\n// WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION means to render the\n// smallest number of digits so that parsing the resultant string will recover\n// the same double-precision floating point number.\n//\n// For example, double-precision cannot distinguish between 0.3 and\n// 0.2999999999999999888977697537484345957636" +
"83319091796875, so when this bit\n// is set, rendering the latter will produce \"0.3\" but rendering\n// 0.3000000000000000444089209850062616169452667236328125 will produce\n// \"0.30000000000000004\".\n#define WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION \\\n ((uint32_t)0x00008000)\n\n" +
"" +
- "// ---------------- IEEE 754 Floating Point\n\n// wuffs_base__ieee_754_bit_representation__etc converts between a double\n// precision numerical value and its IEEE 754 representations:\n// - 16-bit: 1 sign bit, 5 exponent bits, 10 explicit significand bits.\n// - 32-bit: 1 sign bit, 8 exponent bits, 23 explicit significand bits.\n// - 64-bit: 1 sign bit, 11 exponent bits, 52 explicit significand bits.\n//\n// For example, it converts between:\n// - +1.0 and 0x3C00, 0x3F80_0000 or 0x3FF0_0000_0000_0000.\n// - +5.5 and 0x4580, 0x40B0_0000 or 0x4016_0000_0000_0000.\n// - -inf and 0xFC00, 0xFF80_0000 or 0xFFF0_0000_0000_0000.\n//\n// Converting from f64 to shorter formats (f16 or f32, represented in C as\n// uint16_t and uint32_t) may be lossy. Converting finite numbers truncate,\n// producing equal or smaller (closer-to-zero) finite numbers. Converting\n// infinities or NaNs produces infinities or NaNs and always report no loss,\n// even though there a multiple NaN representations so that round-tripping a\n// f64 NaN m" +
- "ay produce a different 64 bits. Nonetheless, a NaN's \"quiet vs\n// signaling\" bit is preserved.\n//\n// See https://en.wikipedia.org/wiki/Double-precision_floating-point_format\n\ntypedef struct {\n uint16_t value;\n bool lossy;\n} wuffs_base__lossy_value_u16;\n\ntypedef struct {\n uint32_t value;\n bool lossy;\n} wuffs_base__lossy_value_u32;\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u16 //\nwuffs_base__ieee_754_bit_representation__from_f64_to_u16(double f);\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u32 //\nwuffs_base__ieee_754_bit_representation__from_f64_to_u32(double f);\n\nstatic inline uint64_t //\nwuffs_base__ieee_754_bit_representation__from_f64_to_u64(double f) {\n uint64_t u = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&u, &f, sizeof(uint64_t));\n }\n return u;\n}\n\nstatic inline double //\nwuffs_base__ieee_754_bit_representation__from_u16_to_f64(uint16_t u) {\n uint64_t v = ((uint64_t)(u & 0x8000)) << 48;\n\n do {\n uint64_t exp = (u >> 10) & 0x1F;\n uint64_t man = u & 0x3FF;\n " +
- " if (exp == 0x1F) { // Infinity or NaN.\n exp = 2047;\n } else if (exp != 0) { // Normal.\n exp += 1008; // 1008 = 1023 - 15, the difference in biases.\n } else if (man != 0) { // Subnormal but non-zero.\n uint32_t clz = wuffs_base__count_leading_zeroes_u64(man);\n exp = 1062 - clz; // 1062 = 1008 + 64 - 10.\n man = 0x3FF & (man << (clz - 53));\n } else { // Zero.\n break;\n }\n v |= (exp << 52) | (man << 42);\n } while (0);\n\n double f = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&f, &v, sizeof(uint64_t));\n }\n return f;\n}\n\nstatic inline double //\nwuffs_base__ieee_754_bit_representation__from_u32_to_f64(uint32_t u) {\n float f = 0;\n if (sizeof(uint32_t) == sizeof(float)) {\n memcpy(&f, &u, sizeof(uint32_t));\n }\n return (double)f;\n}\n\nstatic inline double //\nwuffs_base__ieee_754_bit_representation__from_u64_to_f64(uint64_t u) {\n double f = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&f, &u, sizeof(uint64_t));\n }\n return f;" +
- "\n}\n\n" +
+ "// ---------------- IEEE 754 Floating Point\n\n// wuffs_base__ieee_754_bit_representation__etc converts between a double\n// precision numerical value and its IEEE 754 representations:\n// - 16-bit: 1 sign bit, 5 exponent bits, 10 explicit significand bits.\n// - 32-bit: 1 sign bit, 8 exponent bits, 23 explicit significand bits.\n// - 64-bit: 1 sign bit, 11 exponent bits, 52 explicit significand bits.\n//\n// For example, it converts between:\n// - +1.0 and 0x3C00, 0x3F80_0000 or 0x3FF0_0000_0000_0000.\n// - +5.5 and 0x4580, 0x40B0_0000 or 0x4016_0000_0000_0000.\n// - -inf and 0xFC00, 0xFF80_0000 or 0xFFF0_0000_0000_0000.\n//\n// Converting from f64 to shorter formats (f16 or f32, represented in C as\n// uint16_t and uint32_t) may be lossy. Such functions have names that look\n// like etc_truncate, as converting finite numbers produce equal or smaller\n// (closer-to-zero) finite numbers. For example, 1048576.0 is a perfectly valid\n// f64 number, but converting it to a f16 (with truncation) produces 65504.0,\n// the" +
+ " largest finite f16 number. Truncating a f64-typed value d to f32 does\n// not always produce the same result as the C-style cast ((float)d), as\n// casting can convert from finite numbers to infinite ones.\n//\n// Converting infinities or NaNs produces infinities or NaNs and always report\n// no loss, even though there a multiple NaN representations so that round-\n// tripping a f64-typed NaN may produce a different 64 bits. Nonetheless, the\n// etc_truncate functions preserve a NaN's \"quiet vs signaling\" bit.\n//\n// See https://en.wikipedia.org/wiki/Double-precision_floating-point_format\n\ntypedef struct {\n uint16_t value;\n bool lossy;\n} wuffs_base__lossy_value_u16;\n\ntypedef struct {\n uint32_t value;\n bool lossy;\n} wuffs_base__lossy_value_u32;\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u16 //\nwuffs_base__ieee_754_bit_representation__from_f64_to_u16_truncate(double f);\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u32 //\nwuffs_base__ieee_754_bit_representation__from_f64_to_u32_truncate(double f);\n\nst" +
+ "atic inline uint64_t //\nwuffs_base__ieee_754_bit_representation__from_f64_to_u64(double f) {\n uint64_t u = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&u, &f, sizeof(uint64_t));\n }\n return u;\n}\n\nstatic inline double //\nwuffs_base__ieee_754_bit_representation__from_u16_to_f64(uint16_t u) {\n uint64_t v = ((uint64_t)(u & 0x8000)) << 48;\n\n do {\n uint64_t exp = (u >> 10) & 0x1F;\n uint64_t man = u & 0x3FF;\n if (exp == 0x1F) { // Infinity or NaN.\n exp = 2047;\n } else if (exp != 0) { // Normal.\n exp += 1008; // 1008 = 1023 - 15, the difference in biases.\n } else if (man != 0) { // Subnormal but non-zero.\n uint32_t clz = wuffs_base__count_leading_zeroes_u64(man);\n exp = 1062 - clz; // 1062 = 1008 + 64 - 10.\n man = 0x3FF & (man << (clz - 53));\n } else { // Zero.\n break;\n }\n v |= (exp << 52) | (man << 42);\n } while (0);\n\n double f = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&f, &v, sizeof(uint64_t));\n }\n return f" +
+ ";\n}\n\nstatic inline double //\nwuffs_base__ieee_754_bit_representation__from_u32_to_f64(uint32_t u) {\n float f = 0;\n if (sizeof(uint32_t) == sizeof(float)) {\n memcpy(&f, &u, sizeof(uint32_t));\n }\n return (double)f;\n}\n\nstatic inline double //\nwuffs_base__ieee_754_bit_representation__from_u64_to_f64(uint64_t u) {\n double f = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&f, &u, sizeof(uint64_t));\n }\n return f;\n}\n\n" +
"" +
"// ---------------- Parsing and Rendering Numbers\n\n// wuffs_base__parse_number_f64 parses the floating point number in s. For\n// example, if s contains the bytes \"1.5\" then it will return the double 1.5.\n//\n// It returns an error if s does not contain a floating point number.\n//\n// It does not necessarily return an error if the conversion is lossy, e.g. if\n// s is \"0.3\", which double-precision floating point cannot represent exactly.\n//\n// Similarly, the returned value may be infinite (and no error returned) even\n// if s was not \"inf\", when the input is nominally finite but sufficiently\n// larger than DBL_MAX, about 1.8e+308.\n//\n// It is similar to the C standard library's strtod function, but:\n// - Errors are returned in-band (in a result type), not out-of-band (errno).\n// - It takes a slice (a pointer and length), not a NUL-terminated C string.\n// - It does not take an optional endptr argument. It does not allow a partial\n// parse: it returns an error unless all of s is consumed.\n// - It does not all" +
"ow whitespace, leading or otherwise.\n// - It does not allow hexadecimal floating point numbers.\n// - It is not affected by i18n / l10n settings such as environment variables.\n//\n// The options argument can change these, but by default, it:\n// - Allows \"inf\", \"+Infinity\" and \"-NAN\", case insensitive. Similarly,\n// without an explicit opt-out, it would successfully parse \"1e999\" as\n// infinity, even though it overflows double-precision floating point.\n// - Rejects underscores. With an explicit opt-in, \"_3.141_592\" would\n// successfully parse as an approximation to π.\n// - Rejects unnecessary leading zeroes: \"00\", \"0644\" and \"00.7\".\n// - Uses a dot '1.5' instead of a comma '1,5' for the decimal separator.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// function requires the WUFFS_CONFIG__MODULE__BASE__FLOATCONV sub-module, not\n// just WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC wuffs_base__result_f64 //\nwuffs_base__parse_number_f64(wuffs_base__" +
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index cfa53e5..7a6e37f 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -4027,12 +4027,18 @@
// - -inf and 0xFC00, 0xFF80_0000 or 0xFFF0_0000_0000_0000.
//
// Converting from f64 to shorter formats (f16 or f32, represented in C as
-// uint16_t and uint32_t) may be lossy. Converting finite numbers truncate,
-// producing equal or smaller (closer-to-zero) finite numbers. Converting
-// infinities or NaNs produces infinities or NaNs and always report no loss,
-// even though there a multiple NaN representations so that round-tripping a
-// f64 NaN may produce a different 64 bits. Nonetheless, a NaN's "quiet vs
-// signaling" bit is preserved.
+// uint16_t and uint32_t) may be lossy. Such functions have names that look
+// like etc_truncate, as converting finite numbers produce equal or smaller
+// (closer-to-zero) finite numbers. For example, 1048576.0 is a perfectly valid
+// f64 number, but converting it to a f16 (with truncation) produces 65504.0,
+// the largest finite f16 number. Truncating a f64-typed value d to f32 does
+// not always produce the same result as the C-style cast ((float)d), as
+// casting can convert from finite numbers to infinite ones.
+//
+// Converting infinities or NaNs produces infinities or NaNs and always report
+// no loss, even though there a multiple NaN representations so that round-
+// tripping a f64-typed NaN may produce a different 64 bits. Nonetheless, the
+// etc_truncate functions preserve a NaN's "quiet vs signaling" bit.
//
// See https://en.wikipedia.org/wiki/Double-precision_floating-point_format
@@ -4047,10 +4053,10 @@
} wuffs_base__lossy_value_u32;
WUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u16 //
-wuffs_base__ieee_754_bit_representation__from_f64_to_u16(double f);
+wuffs_base__ieee_754_bit_representation__from_f64_to_u16_truncate(double f);
WUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u32 //
-wuffs_base__ieee_754_bit_representation__from_f64_to_u32(double f);
+wuffs_base__ieee_754_bit_representation__from_f64_to_u32_truncate(double f);
static inline uint64_t //
wuffs_base__ieee_754_bit_representation__from_f64_to_u64(double f) {
@@ -9959,7 +9965,7 @@
// ---------------- IEEE 754 Floating Point
WUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u16 //
-wuffs_base__ieee_754_bit_representation__from_f64_to_u16(double f) {
+wuffs_base__ieee_754_bit_representation__from_f64_to_u16_truncate(double f) {
uint64_t u = 0;
if (sizeof(uint64_t) == sizeof(double)) {
memcpy(&u, &f, sizeof(uint64_t));
@@ -10023,7 +10029,7 @@
}
WUFFS_BASE__MAYBE_STATIC wuffs_base__lossy_value_u32 //
-wuffs_base__ieee_754_bit_representation__from_f64_to_u32(double f) {
+wuffs_base__ieee_754_bit_representation__from_f64_to_u32_truncate(double f) {
uint64_t u = 0;
if (sizeof(uint64_t) == sizeof(double)) {
memcpy(&u, &f, sizeof(uint64_t));
diff --git a/test/c/std/json.c b/test/c/std/json.c
index 7385ae5..9f6101d 100644
--- a/test/c/std/json.c
+++ b/test/c/std/json.c
@@ -526,7 +526,7 @@
continue;
}
wuffs_base__lossy_value_u16 lv =
- wuffs_base__ieee_754_bit_representation__from_f64_to_u16(
+ wuffs_base__ieee_754_bit_representation__from_f64_to_u16_truncate(
wuffs_base__ieee_754_bit_representation__from_u64_to_f64(
want_u64 ^ ((uint64_t)noise)));
if (lv.value != test_cases[tc].u16_bits) {
@@ -648,7 +648,7 @@
continue;
}
wuffs_base__lossy_value_u32 lv =
- wuffs_base__ieee_754_bit_representation__from_f64_to_u32(
+ wuffs_base__ieee_754_bit_representation__from_f64_to_u32_truncate(
wuffs_base__ieee_754_bit_representation__from_u64_to_f64(
want_u64 ^ ((uint64_t)noise)));
if (lv.value != test_cases[tc].u32_bits) {