| author | |
| committer | |
| log | 31791ae15bfa8590cb235ce9d7c87a97d5136eef |
| tree | bf981a8a7b4afbb4edc63e9d44fcac20fd555d3b |
| parent | afdc41cfd61db23f545d9239b61695e2ae991713 |
Symmetry with parse_float and to hide the implementation from the user.
Additionally, we expose the entire namespace and provide some aliases so
everything is available to a user.
Closes #193664 files changed, 1150 insertions(+), 1147 deletions(-)
CMakeLists.txt+1-1| ... | ... | @@ -235,7 +235,7 @@ set(ZIG_STAGE2_SOURCES |
| 235 | 235 | "${CMAKE_SOURCE_DIR}/lib/std/elf.zig" |
| 236 | 236 | "${CMAKE_SOURCE_DIR}/lib/std/fifo.zig" |
| 237 | 237 | "${CMAKE_SOURCE_DIR}/lib/std/fmt.zig" |
| 238 | "${CMAKE_SOURCE_DIR}/lib/std/fmt/ryu128.zig" | |
| 238 | "${CMAKE_SOURCE_DIR}/lib/std/fmt/format_float.zig" | |
| 239 | 239 | "${CMAKE_SOURCE_DIR}/lib/std/fmt/parse_float.zig" |
| 240 | 240 | "${CMAKE_SOURCE_DIR}/lib/std/fs.zig" |
| 241 | 241 | "${CMAKE_SOURCE_DIR}/lib/std/fs/AtomicFile.zig" |
lib/std/fmt.zig+10-7| ... | ... | @@ -9,7 +9,6 @@ const assert = std.debug.assert; |
| 9 | 9 | const mem = std.mem; |
| 10 | 10 | const unicode = std.unicode; |
| 11 | 11 | const meta = std.meta; |
| 12 | const ryu128 = @import("fmt/ryu128.zig"); | |
| 13 | 12 | const lossyCast = std.math.lossyCast; |
| 14 | 13 | const expectFmt = std.testing.expectFmt; |
| 15 | 14 | |
| ... | ... | @@ -757,21 +756,25 @@ pub fn formatIntValue( |
| 757 | 756 | return formatInt(int_value, base, case, options, writer); |
| 758 | 757 | } |
| 759 | 758 | |
| 759 | pub const format_float = @import("fmt/format_float.zig"); | |
| 760 | pub const formatFloat = format_float.formatFloat; | |
| 761 | pub const FormatFloatError = format_float.FormatError; | |
| 762 | ||
| 760 | 763 | fn formatFloatValue( |
| 761 | 764 | value: anytype, |
| 762 | 765 | comptime fmt: []const u8, |
| 763 | 766 | options: FormatOptions, |
| 764 | 767 | writer: anytype, |
| 765 | 768 | ) !void { |
| 766 | var buf: [ryu128.bufferSize(.decimal, f64)]u8 = undefined; | |
| 769 | var buf: [format_float.bufferSize(.decimal, f64)]u8 = undefined; | |
| 767 | 770 | |
| 768 | 771 | if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) { |
| 769 | const s = ryu128.format(&buf, value, .{ .mode = .scientific, .precision = options.precision }) catch |err| switch (err) { | |
| 772 | const s = formatFloat(&buf, value, .{ .mode = .scientific, .precision = options.precision }) catch |err| switch (err) { | |
| 770 | 773 | error.BufferTooSmall => "(float)", |
| 771 | 774 | }; |
| 772 | 775 | return formatBuf(s, options, writer); |
| 773 | 776 | } else if (comptime std.mem.eql(u8, fmt, "d")) { |
| 774 | const s = ryu128.format(&buf, value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) { | |
| 777 | const s = formatFloat(&buf, value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) { | |
| 775 | 778 | error.BufferTooSmall => "(float)", |
| 776 | 779 | }; |
| 777 | 780 | return formatBuf(s, options, writer); |
| ... | ... | @@ -787,7 +790,7 @@ fn formatFloatValue( |
| 787 | 790 | } |
| 788 | 791 | |
| 789 | 792 | test { |
| 790 | _ = &ryu128; | |
| 793 | _ = &format_float; | |
| 791 | 794 | } |
| 792 | 795 | |
| 793 | 796 | pub const Case = enum { lower, upper }; |
| ... | ... | @@ -890,7 +893,7 @@ fn formatSizeImpl(comptime base: comptime_int) type { |
| 890 | 893 | return formatBuf("0B", options, writer); |
| 891 | 894 | } |
| 892 | 895 | // The worst case in terms of space needed is 32 bytes + 3 for the suffix. |
| 893 | var buf: [ryu128.min_buffer_size + 3]u8 = undefined; | |
| 896 | var buf: [format_float.min_buffer_size + 3]u8 = undefined; | |
| 894 | 897 | |
| 895 | 898 | const mags_si = " kMGTPEZY"; |
| 896 | 899 | const mags_iec = " KMGTPEZY"; |
| ... | ... | @@ -908,7 +911,7 @@ fn formatSizeImpl(comptime base: comptime_int) type { |
| 908 | 911 | else => unreachable, |
| 909 | 912 | }; |
| 910 | 913 | |
| 911 | const s = ryu128.format(&buf, new_value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) { | |
| 914 | const s = formatFloat(&buf, new_value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) { | |
| 912 | 915 | error.BufferTooSmall => unreachable, |
| 913 | 916 | }; |
| 914 | 917 |
lib/std/fmt/format_float.zig created+1139| ... | ... | @@ -0,0 +1,1139 @@ |
| 1 | //! This file implements the ryu floating point conversion algorithm: | |
| 2 | //! https://dl.acm.org/doi/pdf/10.1145/3360595 | |
| 3 | ||
| 4 | const std = @import("std"); | |
| 5 | const expectFmt = std.testing.expectFmt; | |
| 6 | ||
| 7 | const special_exponent = 0x7fffffff; | |
| 8 | ||
| 9 | /// Any buffer used for `format` must be at least this large. This is asserted. A runtime check will | |
| 10 | /// additionally be performed if more bytes are required. | |
| 11 | pub const min_buffer_size = 53; | |
| 12 | ||
| 13 | /// Returns the minimum buffer size needed to print every float of a specific type and format. | |
| 14 | pub fn bufferSize(comptime mode: Format, comptime T: type) comptime_int { | |
| 15 | comptime std.debug.assert(@typeInfo(T) == .Float); | |
| 16 | return switch (mode) { | |
| 17 | .scientific => 53, | |
| 18 | // Based on minimum subnormal values. | |
| 19 | .decimal => switch (@bitSizeOf(T)) { | |
| 20 | 16 => @max(15, min_buffer_size), | |
| 21 | 32 => 55, | |
| 22 | 64 => 347, | |
| 23 | 80 => 4996, | |
| 24 | 128 => 5011, | |
| 25 | else => unreachable, | |
| 26 | }, | |
| 27 | }; | |
| 28 | } | |
| 29 | ||
| 30 | pub const FormatError = error{ | |
| 31 | BufferTooSmall, | |
| 32 | }; | |
| 33 | ||
| 34 | pub const Format = enum { | |
| 35 | scientific, | |
| 36 | decimal, | |
| 37 | }; | |
| 38 | ||
| 39 | pub const FormatOptions = struct { | |
| 40 | mode: Format = .scientific, | |
| 41 | precision: ?usize = null, | |
| 42 | }; | |
| 43 | ||
| 44 | /// Format a floating-point value and write it to buffer. Returns a slice to the buffer containing | |
| 45 | /// the string representation. | |
| 46 | /// | |
| 47 | /// Full precision is the default. Any full precision float can be reparsed with std.fmt.parseFloat | |
| 48 | /// unambiguously. | |
| 49 | /// | |
| 50 | /// Scientific mode is recommended generally as the output is more compact and any type can be | |
| 51 | /// written in full precision using a buffer of only `min_buffer_size`. | |
| 52 | /// | |
| 53 | /// When printing full precision decimals, use `bufferSize` to get the required space. It is | |
| 54 | /// recommended to bound decimal output with a fixed precision to reduce the required buffer size. | |
| 55 | pub fn formatFloat(buf: []u8, v_: anytype, options: FormatOptions) FormatError![]const u8 { | |
| 56 | const v = switch (@TypeOf(v_)) { | |
| 57 | // comptime_float internally is a f128; this preserves precision. | |
| 58 | comptime_float => @as(f128, v_), | |
| 59 | else => v_, | |
| 60 | }; | |
| 61 | ||
| 62 | const T = @TypeOf(v); | |
| 63 | comptime std.debug.assert(@typeInfo(T) == .Float); | |
| 64 | const I = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } }); | |
| 65 | ||
| 66 | const has_explicit_leading_bit = std.math.floatMantissaBits(T) - std.math.floatFractionalBits(T) != 0; | |
| 67 | const d = binaryToDecimal(@as(I, @bitCast(v)), std.math.floatMantissaBits(T), std.math.floatExponentBits(T), has_explicit_leading_bit); | |
| 68 | ||
| 69 | return switch (options.mode) { | |
| 70 | .scientific => formatScientific(buf, d, options.precision), | |
| 71 | .decimal => formatDecimal(buf, d, options.precision), | |
| 72 | }; | |
| 73 | } | |
| 74 | ||
| 75 | pub const FloatDecimal128 = struct { | |
| 76 | mantissa: u128, | |
| 77 | exponent: i32, | |
| 78 | sign: bool, | |
| 79 | }; | |
| 80 | ||
| 81 | fn copySpecialStr(buf: []u8, f: FloatDecimal128) []const u8 { | |
| 82 | if (f.sign) { | |
| 83 | buf[0] = '-'; | |
| 84 | } | |
| 85 | const offset: usize = @intFromBool(f.sign); | |
| 86 | if (f.mantissa != 0) { | |
| 87 | @memcpy(buf[offset..][0..3], "nan"); | |
| 88 | return buf[0 .. 3 + offset]; | |
| 89 | } | |
| 90 | @memcpy(buf[offset..][0..3], "inf"); | |
| 91 | return buf[0 .. 3 + offset]; | |
| 92 | } | |
| 93 | ||
| 94 | fn writeDecimal(buf: []u8, value: anytype, count: usize) void { | |
| 95 | var i: usize = 0; | |
| 96 | ||
| 97 | while (i + 2 < count) : (i += 2) { | |
| 98 | const c: u8 = @intCast(value.* % 100); | |
| 99 | value.* /= 100; | |
| 100 | const d = std.fmt.digits2(c); | |
| 101 | buf[count - i - 1] = d[1]; | |
| 102 | buf[count - i - 2] = d[0]; | |
| 103 | } | |
| 104 | ||
| 105 | while (i < count) : (i += 1) { | |
| 106 | const c: u8 = @intCast(value.* % 10); | |
| 107 | value.* /= 10; | |
| 108 | buf[count - i - 1] = '0' + c; | |
| 109 | } | |
| 110 | } | |
| 111 | ||
| 112 | fn isPowerOf10(n_: u128) bool { | |
| 113 | var n = n_; | |
| 114 | while (n != 0) : (n /= 10) { | |
| 115 | if (n % 10 != 0) return false; | |
| 116 | } | |
| 117 | return true; | |
| 118 | } | |
| 119 | ||
| 120 | const RoundMode = enum { | |
| 121 | /// 1234.56 = precision 2 | |
| 122 | decimal, | |
| 123 | /// 1.23456e3 = precision 5 | |
| 124 | scientific, | |
| 125 | }; | |
| 126 | ||
| 127 | fn round(f: FloatDecimal128, mode: RoundMode, precision: usize) FloatDecimal128 { | |
| 128 | var round_digit: usize = 0; | |
| 129 | var output = f.mantissa; | |
| 130 | var exp = f.exponent; | |
| 131 | const olength = decimalLength(output); | |
| 132 | ||
| 133 | switch (mode) { | |
| 134 | .decimal => { | |
| 135 | if (f.exponent > 0) { | |
| 136 | round_digit = (olength - 1) + precision + @as(usize, @intCast(f.exponent)); | |
| 137 | } else { | |
| 138 | const min_exp_required = @as(usize, @intCast(-f.exponent)); | |
| 139 | if (precision + olength > min_exp_required) { | |
| 140 | round_digit = precision + olength - min_exp_required; | |
| 141 | } | |
| 142 | } | |
| 143 | }, | |
| 144 | .scientific => { | |
| 145 | round_digit = 1 + precision; | |
| 146 | }, | |
| 147 | } | |
| 148 | ||
| 149 | if (round_digit < olength) { | |
| 150 | var nlength = olength; | |
| 151 | for (round_digit + 1..olength) |_| { | |
| 152 | output /= 10; | |
| 153 | exp += 1; | |
| 154 | nlength -= 1; | |
| 155 | } | |
| 156 | ||
| 157 | if (output % 10 >= 5) { | |
| 158 | output /= 10; | |
| 159 | output += 1; | |
| 160 | exp += 1; | |
| 161 | ||
| 162 | // e.g. 9999 -> 10000 | |
| 163 | if (isPowerOf10(output)) { | |
| 164 | output /= 10; | |
| 165 | exp += 1; | |
| 166 | } | |
| 167 | } | |
| 168 | } | |
| 169 | ||
| 170 | return .{ | |
| 171 | .mantissa = output, | |
| 172 | .exponent = exp, | |
| 173 | .sign = f.sign, | |
| 174 | }; | |
| 175 | } | |
| 176 | ||
| 177 | /// Write a FloatDecimal128 to a buffer in scientific form. | |
| 178 | /// | |
| 179 | /// The buffer provided must be greater than `min_buffer_size` in length. If no precision is | |
| 180 | /// specified, this function will never return an error. If a precision is specified, up to | |
| 181 | /// `8 + precision` bytes will be written to the buffer. An error will be returned if the content | |
| 182 | /// will not fit. | |
| 183 | /// | |
| 184 | /// It is recommended to bound decimal formatting with an exact precision. | |
| 185 | pub fn formatScientific(buf: []u8, f_: FloatDecimal128, precision: ?usize) FormatError![]const u8 { | |
| 186 | std.debug.assert(buf.len >= min_buffer_size); | |
| 187 | var f = f_; | |
| 188 | ||
| 189 | if (f.exponent == special_exponent) { | |
| 190 | return copySpecialStr(buf, f); | |
| 191 | } | |
| 192 | ||
| 193 | if (precision) |prec| { | |
| 194 | f = round(f, .scientific, prec); | |
| 195 | } | |
| 196 | ||
| 197 | var output = f.mantissa; | |
| 198 | const olength = decimalLength(output); | |
| 199 | ||
| 200 | if (precision) |prec| { | |
| 201 | // fixed bound: sign(1) + leading_digit(1) + point(1) + exp_sign(1) + exp_max(4) | |
| 202 | const req_bytes = 8 + prec; | |
| 203 | if (buf.len < req_bytes) { | |
| 204 | return error.BufferTooSmall; | |
| 205 | } | |
| 206 | } | |
| 207 | ||
| 208 | // Step 5: Print the scientific representation | |
| 209 | var index: usize = 0; | |
| 210 | if (f.sign) { | |
| 211 | buf[index] = '-'; | |
| 212 | index += 1; | |
| 213 | } | |
| 214 | ||
| 215 | // 1.12345 | |
| 216 | writeDecimal(buf[index + 2 ..], &output, olength - 1); | |
| 217 | buf[index] = '0' + @as(u8, @intCast(output % 10)); | |
| 218 | buf[index + 1] = '.'; | |
| 219 | index += 2; | |
| 220 | const dp_index = index; | |
| 221 | if (olength > 1) index += olength - 1 else index -= 1; | |
| 222 | ||
| 223 | if (precision) |prec| { | |
| 224 | index += @intFromBool(olength == 1); | |
| 225 | if (prec > olength - 1) { | |
| 226 | const len = prec - (olength - 1); | |
| 227 | @memset(buf[index..][0..len], '0'); | |
| 228 | index += len; | |
| 229 | } else { | |
| 230 | index = dp_index + prec - @intFromBool(prec == 0); | |
| 231 | } | |
| 232 | } | |
| 233 | ||
| 234 | // e100 | |
| 235 | buf[index] = 'e'; | |
| 236 | index += 1; | |
| 237 | var exp = f.exponent + @as(i32, @intCast(olength)) - 1; | |
| 238 | if (exp < 0) { | |
| 239 | buf[index] = '-'; | |
| 240 | index += 1; | |
| 241 | exp = -exp; | |
| 242 | } | |
| 243 | var uexp: u32 = @intCast(exp); | |
| 244 | const elength = decimalLength(uexp); | |
| 245 | writeDecimal(buf[index..], &uexp, elength); | |
| 246 | index += elength; | |
| 247 | ||
| 248 | return buf[0..index]; | |
| 249 | } | |
| 250 | ||
| 251 | /// Write a FloatDecimal128 to a buffer in decimal form. | |
| 252 | /// | |
| 253 | /// The buffer provided must be greater than `min_buffer_size` bytes in length. If no precision is | |
| 254 | /// specified, this may still return an error. If precision is specified, `2 + precision` bytes will | |
| 255 | /// always be written. | |
| 256 | pub fn formatDecimal(buf: []u8, f_: FloatDecimal128, precision: ?usize) FormatError![]const u8 { | |
| 257 | std.debug.assert(buf.len >= min_buffer_size); | |
| 258 | var f = f_; | |
| 259 | ||
| 260 | if (f.exponent == special_exponent) { | |
| 261 | return copySpecialStr(buf, f); | |
| 262 | } | |
| 263 | ||
| 264 | if (precision) |prec| { | |
| 265 | f = round(f, .decimal, prec); | |
| 266 | } | |
| 267 | ||
| 268 | var output = f.mantissa; | |
| 269 | const olength = decimalLength(output); | |
| 270 | ||
| 271 | // fixed bound: leading_digit(1) + point(1) | |
| 272 | const req_bytes = if (f.exponent >= 0) | |
| 273 | 2 + @abs(f.exponent) + olength + (precision orelse 0) | |
| 274 | else | |
| 275 | 2 + @max(@abs(f.exponent) + olength, precision orelse 0); | |
| 276 | if (buf.len < req_bytes) { | |
| 277 | return error.BufferTooSmall; | |
| 278 | } | |
| 279 | ||
| 280 | // Step 5: Print the decimal representation | |
| 281 | var index: usize = 0; | |
| 282 | if (f.sign) { | |
| 283 | buf[index] = '-'; | |
| 284 | index += 1; | |
| 285 | } | |
| 286 | ||
| 287 | const dp_offset = f.exponent + cast_i32(olength); | |
| 288 | if (dp_offset <= 0) { | |
| 289 | // 0.000001234 | |
| 290 | buf[index] = '0'; | |
| 291 | buf[index + 1] = '.'; | |
| 292 | index += 2; | |
| 293 | const dp_index = index; | |
| 294 | ||
| 295 | const dp_poffset: u32 = @intCast(-dp_offset); | |
| 296 | @memset(buf[index..][0..dp_poffset], '0'); | |
| 297 | index += dp_poffset; | |
| 298 | writeDecimal(buf[index..], &output, olength); | |
| 299 | index += olength; | |
| 300 | ||
| 301 | if (precision) |prec| { | |
| 302 | const dp_written = index - dp_index; | |
| 303 | if (prec > dp_written) { | |
| 304 | @memset(buf[index..][0 .. prec - dp_written], '0'); | |
| 305 | } | |
| 306 | index = dp_index + prec - @intFromBool(prec == 0); | |
| 307 | } | |
| 308 | } else { | |
| 309 | // 123456000 | |
| 310 | const dp_uoffset: usize = @intCast(dp_offset); | |
| 311 | if (dp_uoffset >= olength) { | |
| 312 | writeDecimal(buf[index..], &output, olength); | |
| 313 | index += olength; | |
| 314 | @memset(buf[index..][0 .. dp_uoffset - olength], '0'); | |
| 315 | index += dp_uoffset - olength; | |
| 316 | ||
| 317 | if (precision) |prec| { | |
| 318 | if (prec != 0) { | |
| 319 | buf[index] = '.'; | |
| 320 | index += 1; | |
| 321 | @memset(buf[index..][0..prec], '0'); | |
| 322 | index += prec; | |
| 323 | } | |
| 324 | } | |
| 325 | } else { | |
| 326 | // 12345.6789 | |
| 327 | writeDecimal(buf[index + dp_uoffset + 1 ..], &output, olength - dp_uoffset); | |
| 328 | buf[index + dp_uoffset] = '.'; | |
| 329 | const dp_index = index + dp_uoffset + 1; | |
| 330 | writeDecimal(buf[index..], &output, dp_uoffset); | |
| 331 | index += olength + 1; | |
| 332 | ||
| 333 | if (precision) |prec| { | |
| 334 | const dp_written = olength - dp_uoffset; | |
| 335 | if (prec > dp_written) { | |
| 336 | @memset(buf[index..][0 .. prec - dp_written], '0'); | |
| 337 | } | |
| 338 | index = dp_index + prec - @intFromBool(prec == 0); | |
| 339 | } | |
| 340 | } | |
| 341 | } | |
| 342 | ||
| 343 | return buf[0..index]; | |
| 344 | } | |
| 345 | ||
| 346 | fn cast_i32(v: anytype) i32 { | |
| 347 | return @intCast(v); | |
| 348 | } | |
| 349 | ||
| 350 | /// Convert a binary float representation to decimal. | |
| 351 | pub fn binaryToDecimal(bits: u128, mantissa_bits: u7, exponent_bits: u5, explicit_leading_bit: bool) FloatDecimal128 { | |
| 352 | const bias = (@as(u32, 1) << (exponent_bits - 1)) - 1; | |
| 353 | const ieee_sign = ((bits >> (mantissa_bits + exponent_bits)) & 1) != 0; | |
| 354 | const ieee_mantissa = bits & ((@as(u128, 1) << mantissa_bits) - 1); | |
| 355 | const ieee_exponent: u32 = @intCast((bits >> mantissa_bits) & ((@as(u128, 1) << exponent_bits) - 1)); | |
| 356 | ||
| 357 | if (ieee_exponent == 0 and ieee_mantissa == 0) { | |
| 358 | return .{ | |
| 359 | .mantissa = 0, | |
| 360 | .exponent = 0, | |
| 361 | .sign = ieee_sign, | |
| 362 | }; | |
| 363 | } | |
| 364 | if (ieee_exponent == ((@as(u32, 1) << exponent_bits) - 1)) { | |
| 365 | return .{ | |
| 366 | .mantissa = if (explicit_leading_bit) ieee_mantissa & ((@as(u128, 1) << (mantissa_bits - 1)) - 1) else ieee_mantissa, | |
| 367 | .exponent = 0x7fffffff, | |
| 368 | .sign = ieee_sign, | |
| 369 | }; | |
| 370 | } | |
| 371 | ||
| 372 | var e2: i32 = undefined; | |
| 373 | var m2: u128 = undefined; | |
| 374 | if (explicit_leading_bit) { | |
| 375 | if (ieee_exponent == 0) { | |
| 376 | e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2; | |
| 377 | } else { | |
| 378 | e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2; | |
| 379 | } | |
| 380 | m2 = ieee_mantissa; | |
| 381 | } else { | |
| 382 | if (ieee_exponent == 0) { | |
| 383 | e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) - 2; | |
| 384 | m2 = ieee_mantissa; | |
| 385 | } else { | |
| 386 | e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) - 2; | |
| 387 | m2 = (@as(u128, 1) << mantissa_bits) | ieee_mantissa; | |
| 388 | } | |
| 389 | } | |
| 390 | const even = (m2 & 1) == 0; | |
| 391 | const accept_bounds = even; | |
| 392 | ||
| 393 | // Step 2: Determine the interval of legal decimal representations. | |
| 394 | const mv = 4 * m2; | |
| 395 | const mm_shift: u1 = @intFromBool((ieee_mantissa != if (explicit_leading_bit) (@as(u128, 1) << (mantissa_bits - 1)) else 0) or (ieee_exponent == 0)); | |
| 396 | ||
| 397 | // Step 3: Convert to a decimal power base using 128-bit arithmetic. | |
| 398 | var vr: u128 = undefined; | |
| 399 | var vp: u128 = undefined; | |
| 400 | var vm: u128 = undefined; | |
| 401 | var e10: i32 = undefined; | |
| 402 | var vm_is_trailing_zeros = false; | |
| 403 | var vr_is_trailing_zeros = false; | |
| 404 | if (e2 >= 0) { | |
| 405 | const q: u32 = log10Pow2(@intCast(e2)) - @intFromBool(e2 > 3); | |
| 406 | e10 = cast_i32(q); | |
| 407 | const k: i32 = @intCast(FLOAT_128_POW5_INV_BITCOUNT + pow5Bits(q) - 1); | |
| 408 | const i: u32 = @intCast(-e2 + cast_i32(q) + k); | |
| 409 | ||
| 410 | const pow5 = computeInvPow5(q); | |
| 411 | vr = mulShift(4 * m2, &pow5, i); | |
| 412 | vp = mulShift(4 * m2 + 2, &pow5, i); | |
| 413 | vm = mulShift(4 * m2 - 1 - mm_shift, &pow5, i); | |
| 414 | ||
| 415 | if (q <= 55) { | |
| 416 | if (mv % 5 == 0) { | |
| 417 | vr_is_trailing_zeros = multipleOfPowerOf5(mv, q -% 1); | |
| 418 | } else if (accept_bounds) { | |
| 419 | vm_is_trailing_zeros = multipleOfPowerOf5(mv - 1 - mm_shift, q); | |
| 420 | } else { | |
| 421 | vp -= @intFromBool(multipleOfPowerOf5(mv + 2, q)); | |
| 422 | } | |
| 423 | } | |
| 424 | } else { | |
| 425 | const q: u32 = log10Pow5(@intCast(-e2)) - @intFromBool(-e2 > 1); | |
| 426 | e10 = cast_i32(q) + e2; | |
| 427 | const i: i32 = -e2 - cast_i32(q); | |
| 428 | const k: i32 = cast_i32(pow5Bits(@intCast(i))) - FLOAT_128_POW5_BITCOUNT; | |
| 429 | const j: u32 = @intCast(cast_i32(q) - k); | |
| 430 | ||
| 431 | const pow5 = computePow5(@intCast(i)); | |
| 432 | vr = mulShift(4 * m2, &pow5, j); | |
| 433 | vp = mulShift(4 * m2 + 2, &pow5, j); | |
| 434 | vm = mulShift(4 * m2 - 1 - mm_shift, &pow5, j); | |
| 435 | ||
| 436 | if (q <= 1) { | |
| 437 | vr_is_trailing_zeros = true; | |
| 438 | if (accept_bounds) { | |
| 439 | vm_is_trailing_zeros = mm_shift == 1; | |
| 440 | } else { | |
| 441 | vp -= 1; | |
| 442 | } | |
| 443 | } else if (q < 127) { | |
| 444 | vr_is_trailing_zeros = multipleOfPowerOf2(mv, q - 1); | |
| 445 | } | |
| 446 | } | |
| 447 | ||
| 448 | // Step 4: Find the shortest decimal representation in the interval of legal representations. | |
| 449 | var removed: u32 = 0; | |
| 450 | var last_removed_digit: u8 = 0; | |
| 451 | ||
| 452 | while (vp / 10 > vm / 10) { | |
| 453 | vm_is_trailing_zeros = vm_is_trailing_zeros and vm % 10 == 0; | |
| 454 | vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0; | |
| 455 | last_removed_digit = @intCast(vr % 10); | |
| 456 | vr /= 10; | |
| 457 | vp /= 10; | |
| 458 | vm /= 10; | |
| 459 | removed += 1; | |
| 460 | } | |
| 461 | ||
| 462 | if (vm_is_trailing_zeros) { | |
| 463 | while (vm % 10 == 0) { | |
| 464 | vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0; | |
| 465 | last_removed_digit = @intCast(vr % 10); | |
| 466 | vr /= 10; | |
| 467 | vp /= 10; | |
| 468 | vm /= 10; | |
| 469 | removed += 1; | |
| 470 | } | |
| 471 | } | |
| 472 | ||
| 473 | if (vr_is_trailing_zeros and (last_removed_digit == 5) and (vr % 2 == 0)) { | |
| 474 | last_removed_digit = 4; | |
| 475 | } | |
| 476 | ||
| 477 | return .{ | |
| 478 | .mantissa = vr + @intFromBool((vr == vm and (!accept_bounds or !vm_is_trailing_zeros)) or last_removed_digit >= 5), | |
| 479 | .exponent = e10 + cast_i32(removed), | |
| 480 | .sign = ieee_sign, | |
| 481 | }; | |
| 482 | } | |
| 483 | ||
| 484 | fn decimalLength(v: u128) u32 { | |
| 485 | const LARGEST_POW10 = (@as(u128, 5421010862427522170) << 64) | 687399551400673280; | |
| 486 | var p10 = LARGEST_POW10; | |
| 487 | var i: u32 = 39; | |
| 488 | while (i > 0) : (i -= 1) { | |
| 489 | if (v >= p10) return i; | |
| 490 | p10 /= 10; | |
| 491 | } | |
| 492 | return 1; | |
| 493 | } | |
| 494 | ||
| 495 | // floor(log_10(2^e)) | |
| 496 | fn log10Pow2(e: u32) u32 { | |
| 497 | std.debug.assert(e <= 1 << 15); | |
| 498 | return @intCast((@as(u64, @intCast(e)) * 169464822037455) >> 49); | |
| 499 | } | |
| 500 | ||
| 501 | // floor(log_10(5^e)) | |
| 502 | fn log10Pow5(e: u32) u32 { | |
| 503 | std.debug.assert(e <= 1 << 15); | |
| 504 | return @intCast((@as(u64, @intCast(e)) * 196742565691928) >> 48); | |
| 505 | } | |
| 506 | ||
| 507 | // if (e == 0) 1 else ceil(log_2(5^e)) | |
| 508 | fn pow5Bits(e: u32) u32 { | |
| 509 | std.debug.assert(e <= 1 << 15); | |
| 510 | return @intCast(((@as(u64, @intCast(e)) * 163391164108059) >> 46) + 1); | |
| 511 | } | |
| 512 | ||
| 513 | fn pow5Factor(value_: u128) u32 { | |
| 514 | var count: u32 = 0; | |
| 515 | var value = value_; | |
| 516 | while (value > 0) : ({ | |
| 517 | count += 1; | |
| 518 | value /= 5; | |
| 519 | }) { | |
| 520 | if (value % 5 != 0) return count; | |
| 521 | } | |
| 522 | return 0; | |
| 523 | } | |
| 524 | ||
| 525 | fn multipleOfPowerOf5(value: u128, p: u32) bool { | |
| 526 | return pow5Factor(value) >= p; | |
| 527 | } | |
| 528 | ||
| 529 | fn multipleOfPowerOf2(value: u128, p: u32) bool { | |
| 530 | return (value & ((@as(u128, 1) << @as(u7, @intCast(p))) - 1)) == 0; | |
| 531 | } | |
| 532 | ||
| 533 | fn computeInvPow5(i: u32) [4]u64 { | |
| 534 | const base = (i + POW5_TABLE_SIZE - 1) / POW5_TABLE_SIZE; | |
| 535 | const base2 = base * POW5_TABLE_SIZE; | |
| 536 | const mul = &GENERIC_POW5_INV_SPLIT[base]; // 1 / 5^base2 | |
| 537 | if (i == base2) { | |
| 538 | return .{ mul[0] + 1, mul[1], mul[2], mul[3] }; | |
| 539 | } else { | |
| 540 | const offset = base2 - i; | |
| 541 | const m = &GENERIC_POW5_TABLE[offset]; // 5^offset | |
| 542 | const delta = pow5Bits(base2) - pow5Bits(i); | |
| 543 | ||
| 544 | const shift: u6 = @intCast(2 * (i % 32)); | |
| 545 | const corr: u32 = @intCast(((POW5_INV_ERRORS[i / 32] >> shift) & 3) + 1); | |
| 546 | return mul_128_256_shift(m, mul, delta, corr); | |
| 547 | } | |
| 548 | } | |
| 549 | ||
| 550 | fn computePow5(i: u32) [4]u64 { | |
| 551 | const base = i / POW5_TABLE_SIZE; | |
| 552 | const base2 = base * POW5_TABLE_SIZE; | |
| 553 | const mul = &GENERIC_POW5_SPLIT[base]; | |
| 554 | if (i == base2) { | |
| 555 | return mul.*; | |
| 556 | } else { | |
| 557 | const offset = i - base2; | |
| 558 | const m = &GENERIC_POW5_TABLE[offset]; | |
| 559 | const delta = pow5Bits(i) - pow5Bits(base2); | |
| 560 | ||
| 561 | const shift: u6 = @intCast(2 * (i % 32)); | |
| 562 | const corr: u32 = @intCast((POW5_ERRORS[i / 32] >> shift) & 3); | |
| 563 | return mul_128_256_shift(m, mul, delta, corr); | |
| 564 | } | |
| 565 | } | |
| 566 | ||
| 567 | fn mulShift(m: u128, mul: *const [4]u64, j: u32) u128 { | |
| 568 | std.debug.assert(j > 128); | |
| 569 | const a: [2]u64 = .{ @truncate(m), @truncate(m >> 64) }; | |
| 570 | const r = mul_128_256_shift(&a, mul, j, 0); | |
| 571 | return (@as(u128, r[1]) << 64) | r[0]; | |
| 572 | } | |
| 573 | ||
| 574 | fn mul_128_256_shift(a: *const [2]u64, b: *const [4]u64, shift: u32, corr: u32) [4]u64 { | |
| 575 | std.debug.assert(shift > 0); | |
| 576 | std.debug.assert(shift < 256); | |
| 577 | ||
| 578 | const b00 = @as(u128, a[0]) * b[0]; | |
| 579 | const b01 = @as(u128, a[0]) * b[1]; | |
| 580 | const b02 = @as(u128, a[0]) * b[2]; | |
| 581 | const b03 = @as(u128, a[0]) * b[3]; | |
| 582 | const b10 = @as(u128, a[1]) * b[0]; | |
| 583 | const b11 = @as(u128, a[1]) * b[1]; | |
| 584 | const b12 = @as(u128, a[1]) * b[2]; | |
| 585 | const b13 = @as(u128, a[1]) * b[3]; | |
| 586 | ||
| 587 | const s0 = b00; | |
| 588 | const s1 = b01 +% b10; | |
| 589 | const c1: u128 = @intFromBool(s1 < b01); | |
| 590 | const s2 = b02 +% b11; | |
| 591 | const c2: u128 = @intFromBool(s2 < b02); | |
| 592 | const s3 = b03 +% b12; | |
| 593 | const c3: u128 = @intFromBool(s3 < b03); | |
| 594 | ||
| 595 | const p0 = s0 +% (s1 << 64); | |
| 596 | const d0: u128 = @intFromBool(p0 < b00); | |
| 597 | const q1 = s2 +% (s1 >> 64) +% (s3 << 64); | |
| 598 | const d1: u128 = @intFromBool(q1 < s2); | |
| 599 | const p1 = q1 +% (c1 << 64) +% d0; | |
| 600 | const d2: u128 = @intFromBool(p1 < q1); | |
| 601 | const p2 = b13 +% (s3 >> 64) +% c2 +% (c3 << 64) +% d1 +% d2; | |
| 602 | ||
| 603 | var r0: u128 = undefined; | |
| 604 | var r1: u128 = undefined; | |
| 605 | if (shift < 128) { | |
| 606 | const cshift: u7 = @intCast(shift); | |
| 607 | const sshift: u7 = @intCast(128 - shift); | |
| 608 | r0 = corr +% ((p0 >> cshift) | (p1 << sshift)); | |
| 609 | r1 = ((p1 >> cshift) | (p2 << sshift)) +% @intFromBool(r0 < corr); | |
| 610 | } else if (shift == 128) { | |
| 611 | r0 = corr +% p1; | |
| 612 | r1 = p2 +% @intFromBool(r0 < corr); | |
| 613 | } else { | |
| 614 | const ashift: u7 = @intCast(shift - 128); | |
| 615 | const sshift: u7 = @intCast(256 - shift); | |
| 616 | r0 = corr +% ((p1 >> ashift) | (p2 << sshift)); | |
| 617 | r1 = (p2 >> ashift) +% @intFromBool(r0 < corr); | |
| 618 | } | |
| 619 | ||
| 620 | return .{ @truncate(r0), @truncate(r0 >> 64), @truncate(r1), @truncate(r1 >> 64) }; | |
| 621 | } | |
| 622 | ||
| 623 | // zig fmt: off | |
| 624 | // | |
| 625 | // 4.5KiB of tables. | |
| 626 | ||
| 627 | const FLOAT_128_POW5_INV_BITCOUNT = 249; | |
| 628 | const FLOAT_128_POW5_BITCOUNT = 249; | |
| 629 | const POW5_TABLE_SIZE = 56; | |
| 630 | ||
| 631 | const GENERIC_POW5_TABLE: [POW5_TABLE_SIZE][2]u64 = .{ | |
| 632 | .{ 1, 0 }, | |
| 633 | .{ 5, 0 }, | |
| 634 | .{ 25, 0 }, | |
| 635 | .{ 125, 0 }, | |
| 636 | .{ 625, 0 }, | |
| 637 | .{ 3125, 0 }, | |
| 638 | .{ 15625, 0 }, | |
| 639 | .{ 78125, 0 }, | |
| 640 | .{ 390625, 0 }, | |
| 641 | .{ 1953125, 0 }, | |
| 642 | .{ 9765625, 0 }, | |
| 643 | .{ 48828125, 0 }, | |
| 644 | .{ 244140625, 0 }, | |
| 645 | .{ 1220703125, 0 }, | |
| 646 | .{ 6103515625, 0 }, | |
| 647 | .{ 30517578125, 0 }, | |
| 648 | .{ 152587890625, 0 }, | |
| 649 | .{ 762939453125, 0 }, | |
| 650 | .{ 3814697265625, 0 }, | |
| 651 | .{ 19073486328125, 0 }, | |
| 652 | .{ 95367431640625, 0 }, | |
| 653 | .{ 476837158203125, 0 }, | |
| 654 | .{ 2384185791015625, 0 }, | |
| 655 | .{ 11920928955078125, 0 }, | |
| 656 | .{ 59604644775390625, 0 }, | |
| 657 | .{ 298023223876953125, 0 }, | |
| 658 | .{ 1490116119384765625, 0 }, | |
| 659 | .{ 7450580596923828125, 0 }, | |
| 660 | .{ 359414837200037393, 2 }, | |
| 661 | .{ 1797074186000186965, 10 }, | |
| 662 | .{ 8985370930000934825, 50 }, | |
| 663 | .{ 8033366502585570893, 252 }, | |
| 664 | .{ 3273344365508751233, 1262 }, | |
| 665 | .{ 16366721827543756165, 6310 }, | |
| 666 | .{ 8046632842880574361, 31554 }, | |
| 667 | .{ 3339676066983768573, 157772 }, | |
| 668 | .{ 16698380334918842865, 788860 }, | |
| 669 | .{ 9704925379756007861, 3944304 }, | |
| 670 | .{ 11631138751360936073, 19721522 }, | |
| 671 | .{ 2815461535676025517, 98607613 }, | |
| 672 | .{ 14077307678380127585, 493038065 }, | |
| 673 | .{ 15046306170771983077, 2465190328 }, | |
| 674 | .{ 1444554559021708921, 12325951644 }, | |
| 675 | .{ 7222772795108544605, 61629758220 }, | |
| 676 | .{ 17667119901833171409, 308148791101 }, | |
| 677 | .{ 14548623214327650581, 1540743955509 }, | |
| 678 | .{ 17402883850509598057, 7703719777548 }, | |
| 679 | .{ 13227442957709783821, 38518598887744 }, | |
| 680 | .{ 10796982567420264257, 192592994438723 }, | |
| 681 | .{ 17091424689682218053, 962964972193617 }, | |
| 682 | .{ 11670147153572883801, 4814824860968089 }, | |
| 683 | .{ 3010503546735764157, 24074124304840448 }, | |
| 684 | .{ 15052517733678820785, 120370621524202240 }, | |
| 685 | .{ 1475612373555897461, 601853107621011204 }, | |
| 686 | .{ 7378061867779487305, 3009265538105056020 }, | |
| 687 | .{ 18443565265187884909, 15046327690525280101 }, | |
| 688 | }; | |
| 689 | ||
| 690 | const GENERIC_POW5_SPLIT: [89][4]u64 = .{ | |
| 691 | .{ 0, 0, 0, 72057594037927936 }, | |
| 692 | .{ 0, 5206161169240293376, 4575641699882439235, 73468396926392969 }, | |
| 693 | .{ 3360510775605221349, 6983200512169538081, 4325643253124434363, 74906821675075173 }, | |
| 694 | .{ 11917660854915489451, 9652941469841108803, 946308467778435600, 76373409087490117 }, | |
| 695 | .{ 1994853395185689235, 16102657350889591545, 6847013871814915412, 77868710555449746 }, | |
| 696 | .{ 958415760277438274, 15059347134713823592, 7329070255463483331, 79393288266368765 }, | |
| 697 | .{ 2065144883315240188, 7145278325844925976, 14718454754511147343, 80947715414629833 }, | |
| 698 | .{ 8980391188862868935, 13709057401304208685, 8230434828742694591, 82532576417087045 }, | |
| 699 | .{ 432148644612782575, 7960151582448466064, 12056089168559840552, 84148467132788711 }, | |
| 700 | .{ 484109300864744403, 15010663910730448582, 16824949663447227068, 85795995087002057 }, | |
| 701 | .{ 14793711725276144220, 16494403799991899904, 10145107106505865967, 87475779699624060 }, | |
| 702 | .{ 15427548291869817042, 12330588654550505203, 13980791795114552342, 89188452518064298 }, | |
| 703 | .{ 9979404135116626552, 13477446383271537499, 14459862802511591337, 90934657454687378 }, | |
| 704 | .{ 12385121150303452775, 9097130814231585614, 6523855782339765207, 92715051028904201 }, | |
| 705 | .{ 1822931022538209743, 16062974719797586441, 3619180286173516788, 94530302614003091 }, | |
| 706 | .{ 12318611738248470829, 13330752208259324507, 10986694768744162601, 96381094688813589 }, | |
| 707 | .{ 13684493829640282333, 7674802078297225834, 15208116197624593182, 98268123094297527 }, | |
| 708 | .{ 5408877057066295332, 6470124174091971006, 15112713923117703147, 100192097295163851 }, | |
| 709 | .{ 11407083166564425062, 18189998238742408185, 4337638702446708282, 102153740646605557 }, | |
| 710 | .{ 4112405898036935485, 924624216579956435, 14251108172073737125, 104153790666259019 }, | |
| 711 | .{ 16996739107011444789, 10015944118339042475, 2395188869672266257, 106192999311487969 }, | |
| 712 | .{ 4588314690421337879, 5339991768263654604, 15441007590670620066, 108272133262096356 }, | |
| 713 | .{ 2286159977890359825, 14329706763185060248, 5980012964059367667, 110391974208576409 }, | |
| 714 | .{ 9654767503237031099, 11293544302844823188, 11739932712678287805, 112553319146000238 }, | |
| 715 | .{ 11362964448496095896, 7990659682315657680, 251480263940996374, 114756980673665505 }, | |
| 716 | .{ 1423410421096377129, 14274395557581462179, 16553482793602208894, 117003787300607788 }, | |
| 717 | .{ 2070444190619093137, 11517140404712147401, 11657844572835578076, 119294583757094535 }, | |
| 718 | .{ 7648316884775828921, 15264332483297977688, 247182277434709002, 121630231312217685 }, | |
| 719 | .{ 17410896758132241352, 10923914482914417070, 13976383996795783649, 124011608097704390 }, | |
| 720 | .{ 9542674537907272703, 3079432708831728956, 14235189590642919676, 126439609438067572 }, | |
| 721 | .{ 10364666969937261816, 8464573184892924210, 12758646866025101190, 128915148187220428 }, | |
| 722 | .{ 14720354822146013883, 11480204489231511423, 7449876034836187038, 131439155071681461 }, | |
| 723 | .{ 1692907053653558553, 17835392458598425233, 1754856712536736598, 134012579040499057 }, | |
| 724 | .{ 5620591334531458755, 11361776175667106627, 13350215315297937856, 136636387622027174 }, | |
| 725 | .{ 17455759733928092601, 10362573084069962561, 11246018728801810510, 139311567287686283 }, | |
| 726 | .{ 2465404073814044982, 17694822665274381860, 1509954037718722697, 142039123822846312 }, | |
| 727 | .{ 2152236053329638369, 11202280800589637091, 16388426812920420176, 72410041352485523 }, | |
| 728 | .{ 17319024055671609028, 10944982848661280484, 2457150158022562661, 73827744744583080 }, | |
| 729 | .{ 17511219308535248024, 5122059497846768077, 2089605804219668451, 75273205100637900 }, | |
| 730 | .{ 10082673333144031533, 14429008783411894887, 12842832230171903890, 76746965869337783 }, | |
| 731 | .{ 16196653406315961184, 10260180891682904501, 10537411930446752461, 78249581139456266 }, | |
| 732 | .{ 15084422041749743389, 234835370106753111, 16662517110286225617, 79781615848172976 }, | |
| 733 | .{ 8199644021067702606, 3787318116274991885, 7438130039325743106, 81343645993472659 }, | |
| 734 | .{ 12039493937039359765, 9773822153580393709, 5945428874398357806, 82936258850702722 }, | |
| 735 | .{ 984543865091303961, 7975107621689454830, 6556665988501773347, 84560053193370726 }, | |
| 736 | .{ 9633317878125234244, 16099592426808915028, 9706674539190598200, 86215639518264828 }, | |
| 737 | .{ 6860695058870476186, 4471839111886709592, 7828342285492709568, 87903640274981819 }, | |
| 738 | .{ 14583324717644598331, 4496120889473451238, 5290040788305728466, 89624690099949049 }, | |
| 739 | .{ 18093669366515003715, 12879506572606942994, 18005739787089675377, 91379436055028227 }, | |
| 740 | .{ 17997493966862379937, 14646222655265145582, 10265023312844161858, 93168537870790806 }, | |
| 741 | .{ 12283848109039722318, 11290258077250314935, 9878160025624946825, 94992668194556404 }, | |
| 742 | .{ 8087752761883078164, 5262596608437575693, 11093553063763274413, 96852512843287537 }, | |
| 743 | .{ 15027787746776840781, 12250273651168257752, 9290470558712181914, 98748771061435726 }, | |
| 744 | .{ 15003915578366724489, 2937334162439764327, 5404085603526796602, 100682155783835929 }, | |
| 745 | .{ 5225610465224746757, 14932114897406142027, 2774647558180708010, 102653393903748137 }, | |
| 746 | .{ 17112957703385190360, 12069082008339002412, 3901112447086388439, 104663226546146909 }, | |
| 747 | .{ 4062324464323300238, 3992768146772240329, 15757196565593695724, 106712409346361594 }, | |
| 748 | .{ 5525364615810306701, 11855206026704935156, 11344868740897365300, 108801712734172003 }, | |
| 749 | .{ 9274143661888462646, 4478365862348432381, 18010077872551661771, 110931922223466333 }, | |
| 750 | .{ 12604141221930060148, 8930937759942591500, 9382183116147201338, 113103838707570263 }, | |
| 751 | .{ 14513929377491886653, 1410646149696279084, 587092196850797612, 115318278760358235 }, | |
| 752 | .{ 2226851524999454362, 7717102471110805679, 7187441550995571734, 117576074943260147 }, | |
| 753 | .{ 5527526061344932763, 2347100676188369132, 16976241418824030445, 119878076118278875 }, | |
| 754 | .{ 6088479778147221611, 17669593130014777580, 10991124207197663546, 122225147767136307 }, | |
| 755 | .{ 11107734086759692041, 3391795220306863431, 17233960908859089158, 124618172316667879 }, | |
| 756 | .{ 7913172514655155198, 17726879005381242552, 641069866244011540, 127058049470587962 }, | |
| 757 | .{ 12596991768458713949, 15714785522479904446, 6035972567136116512, 129545696547750811 }, | |
| 758 | .{ 16901996933781815980, 4275085211437148707, 14091642539965169063, 132082048827034281 }, | |
| 759 | .{ 7524574627987869240, 15661204384239316051, 2444526454225712267, 134668059898975949 }, | |
| 760 | .{ 8199251625090479942, 6803282222165044067, 16064817666437851504, 137304702024293857 }, | |
| 761 | .{ 4453256673338111920, 15269922543084434181, 3139961729834750852, 139992966499426682 }, | |
| 762 | .{ 15841763546372731299, 3013174075437671812, 4383755396295695606, 142733864029230733 }, | |
| 763 | .{ 9771896230907310329, 4900659362437687569, 12386126719044266361, 72764212553486967 }, | |
| 764 | .{ 9420455527449565190, 1859606122611023693, 6555040298902684281, 74188850200884818 }, | |
| 765 | .{ 5146105983135678095, 2287300449992174951, 4325371679080264751, 75641380576797959 }, | |
| 766 | .{ 11019359372592553360, 8422686425957443718, 7175176077944048210, 77122349788024458 }, | |
| 767 | .{ 11005742969399620716, 4132174559240043701, 9372258443096612118, 78632314633490790 }, | |
| 768 | .{ 8887589641394725840, 8029899502466543662, 14582206497241572853, 80171842813591127 }, | |
| 769 | .{ 360247523705545899, 12568341805293354211, 14653258284762517866, 81741513143625247 }, | |
| 770 | .{ 12314272731984275834, 4740745023227177044, 6141631472368337539, 83341915771415304 }, | |
| 771 | .{ 441052047733984759, 7940090120939869826, 11750200619921094248, 84973652399183278 }, | |
| 772 | .{ 3436657868127012749, 9187006432149937667, 16389726097323041290, 86637336509772529 }, | |
| 773 | .{ 13490220260784534044, 15339072891382896702, 8846102360835316895, 88333593597298497 }, | |
| 774 | .{ 4125672032094859833, 158347675704003277, 10592598512749774447, 90063061402315272 }, | |
| 775 | .{ 12189928252974395775, 2386931199439295891, 7009030566469913276, 91826390151586454 }, | |
| 776 | .{ 9256479608339282969, 2844900158963599229, 11148388908923225596, 93624242802550437 }, | |
| 777 | .{ 11584393507658707408, 2863659090805147914, 9873421561981063551, 95457295292572042 }, | |
| 778 | .{ 13984297296943171390, 1931468383973130608, 12905719743235082319, 97326236793074198 }, | |
| 779 | .{ 5837045222254987499, 10213498696735864176, 14893951506257020749, 99231769968645227 }, | |
| 780 | }; | |
| 781 | ||
| 782 | // Unfortunately, the results are sometimes off by one or two. We use an additional | |
| 783 | // lookup table to store those cases and adjust the result. | |
| 784 | const POW5_ERRORS: [156]u64 = .{ | |
| 785 | 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x9555596400000000, | |
| 786 | 0x65a6569525565555, 0x4415551445449655, 0x5105015504144541, 0x65a69969a6965964, | |
| 787 | 0x5054955969959656, 0x5105154515554145, 0x4055511051591555, 0x5500514455550115, | |
| 788 | 0x0041140014145515, 0x1005440545511051, 0x0014405450411004, 0x0414440010500000, | |
| 789 | 0x0044000440010040, 0x5551155000004001, 0x4554555454544114, 0x5150045544005441, | |
| 790 | 0x0001111400054501, 0x6550955555554554, 0x1504159645559559, 0x4105055141454545, | |
| 791 | 0x1411541410405454, 0x0415555044545555, 0x0014154115405550, 0x1540055040411445, | |
| 792 | 0x0000000500000000, 0x5644000000000000, 0x1155555591596555, 0x0410440054569565, | |
| 793 | 0x5145100010010005, 0x0555041405500150, 0x4141450455140450, 0x0000000144000140, | |
| 794 | 0x5114004001105410, 0x4444100404005504, 0x0414014410001015, 0x5145055155555015, | |
| 795 | 0x0141041444445540, 0x0000100451541414, 0x4105041104155550, 0x0500501150451145, | |
| 796 | 0x1001050000004114, 0x5551504400141045, 0x5110545410151454, 0x0100001400004040, | |
| 797 | 0x5040010111040000, 0x0140000150541100, 0x4400140400104110, 0x5011014405545004, | |
| 798 | 0x0000000044155440, 0x0000000010000000, 0x1100401444440001, 0x0040401010055111, | |
| 799 | 0x5155155551405454, 0x0444440015514411, 0x0054505054014101, 0x0451015441115511, | |
| 800 | 0x1541411401140551, 0x4155104514445110, 0x4141145450145515, 0x5451445055155050, | |
| 801 | 0x4400515554110054, 0x5111145104501151, 0x565a655455500501, 0x5565555555525955, | |
| 802 | 0x0550511500405695, 0x4415504051054544, 0x6555595965555554, 0x0100915915555655, | |
| 803 | 0x5540001510001001, 0x5450051414000544, 0x1405010555555551, 0x5555515555644155, | |
| 804 | 0x5555055595496555, 0x5451045004415000, 0x5450510144040144, 0x5554155555556455, | |
| 805 | 0x5051555495415555, 0x5555554555555545, 0x0000000010005455, 0x4000005000040000, | |
| 806 | 0x5565555555555954, 0x5554559555555505, 0x9645545495552555, 0x4000400055955564, | |
| 807 | 0x0040000000000001, 0x4004100100000000, 0x5540040440000411, 0x4565555955545644, | |
| 808 | 0x1140659549651556, 0x0100000410010000, 0x5555515400004001, 0x5955545555155255, | |
| 809 | 0x5151055545505556, 0x5051454510554515, 0x0501500050415554, 0x5044154005441005, | |
| 810 | 0x1455445450550455, 0x0010144055144545, 0x0000401100000004, 0x1050145050000010, | |
| 811 | 0x0415004554011540, 0x1000510100151150, 0x0100040400001144, 0x0000000000000000, | |
| 812 | 0x0550004400000100, 0x0151145041451151, 0x0000400400005450, 0x0000100044010004, | |
| 813 | 0x0100054100050040, 0x0504400005410010, 0x4011410445500105, 0x0000404000144411, | |
| 814 | 0x0101504404500000, 0x0000005044400400, 0x0000000014000100, 0x0404440414000000, | |
| 815 | 0x5554100410000140, 0x4555455544505555, 0x5454105055455455, 0x0115454155454015, | |
| 816 | 0x4404110000045100, 0x4400001100101501, 0x6596955956966a94, 0x0040655955665965, | |
| 817 | 0x5554144400100155, 0xa549495401011041, 0x5596555565955555, 0x5569965959549555, | |
| 818 | 0x969565a655555456, 0x0000001000000000, 0x0000000040000140, 0x0000040100000000, | |
| 819 | 0x1415454400000000, 0x5410415411454114, 0x0400040104000154, 0x0504045000000411, | |
| 820 | 0x0000001000000010, 0x5554000000001040, 0x5549155551556595, 0x1455541055515555, | |
| 821 | 0x0510555454554541, 0x9555555555540455, 0x6455456555556465, 0x4524565555654514, | |
| 822 | 0x5554655255559545, 0x9555455441155556, 0x0000000051515555, 0x0010005040000550, | |
| 823 | 0x5044044040000000, 0x1045040440010500, 0x0000400000040000, 0x0000000000000000, | |
| 824 | }; | |
| 825 | ||
| 826 | const GENERIC_POW5_INV_SPLIT: [89][4]u64 = .{ | |
| 827 | .{ 0, 0, 0, 144115188075855872 }, | |
| 828 | .{ 1573859546583440065, 2691002611772552616, 6763753280790178510, 141347765182270746 }, | |
| 829 | .{ 12960290449513840412, 12345512957918226762, 18057899791198622765, 138633484706040742 }, | |
| 830 | .{ 7615871757716765416, 9507132263365501332, 4879801712092008245, 135971326161092377 }, | |
| 831 | .{ 7869961150745287587, 5804035291554591636, 8883897266325833928, 133360288657597085 }, | |
| 832 | .{ 2942118023529634767, 15128191429820565086, 10638459445243230718, 130799390525667397 }, | |
| 833 | .{ 14188759758411913794, 5362791266439207815, 8068821289119264054, 128287668946279217 }, | |
| 834 | .{ 7183196927902545212, 1952291723540117099, 12075928209936341512, 125824179589281448 }, | |
| 835 | .{ 5672588001402349748, 17892323620748423487, 9874578446960390364, 123407996258356868 }, | |
| 836 | .{ 4442590541217566325, 4558254706293456445, 10343828952663182727, 121038210542800766 }, | |
| 837 | .{ 3005560928406962566, 2082271027139057888, 13961184524927245081, 118713931475986426 }, | |
| 838 | .{ 13299058168408384786, 17834349496131278595, 9029906103900731664, 116434285200389047 }, | |
| 839 | .{ 5414878118283973035, 13079825470227392078, 17897304791683760280, 114198414639042157 }, | |
| 840 | .{ 14609755883382484834, 14991702445765844156, 3269802549772755411, 112005479173303009 }, | |
| 841 | .{ 15967774957605076027, 2511532636717499923, 16221038267832563171, 109854654326805788 }, | |
| 842 | .{ 9269330061621627145, 3332501053426257392, 16223281189403734630, 107745131455483836 }, | |
| 843 | .{ 16739559299223642282, 1873986623300664530, 6546709159471442872, 105676117443544318 }, | |
| 844 | .{ 17116435360051202055, 1359075105581853924, 2038341371621886470, 103646834405281051 }, | |
| 845 | .{ 17144715798009627550, 3201623802661132408, 9757551605154622431, 101656519392613377 }, | |
| 846 | .{ 17580479792687825857, 6546633380567327312, 15099972427870912398, 99704424108241124 }, | |
| 847 | .{ 9726477118325522902, 14578369026754005435, 11728055595254428803, 97789814624307808 }, | |
| 848 | .{ 134593949518343635, 5715151379816901985, 1660163707976377376, 95911971106466306 }, | |
| 849 | .{ 5515914027713859358, 7124354893273815720, 5548463282858794077, 94070187543243255 }, | |
| 850 | .{ 6188403395862945512, 5681264392632320838, 15417410852121406654, 92263771480600430 }, | |
| 851 | .{ 15908890877468271457, 10398888261125597540, 4817794962769172309, 90492043761593298 }, | |
| 852 | .{ 1413077535082201005, 12675058125384151580, 7731426132303759597, 88754338271028867 }, | |
| 853 | .{ 1486733163972670293, 11369385300195092554, 11610016711694864110, 87050001685026843 }, | |
| 854 | .{ 8788596583757589684, 3978580923851924802, 9255162428306775812, 85378393225389919 }, | |
| 855 | .{ 7203518319660962120, 15044736224407683725, 2488132019818199792, 83738884418690858 }, | |
| 856 | .{ 4004175967662388707, 18236988667757575407, 15613100370957482671, 82130858859985791 }, | |
| 857 | .{ 18371903370586036463, 53497579022921640, 16465963977267203307, 80553711981064899 }, | |
| 858 | .{ 10170778323887491315, 1999668801648976001, 10209763593579456445, 79006850823153334 }, | |
| 859 | .{ 17108131712433974546, 16825784443029944237, 2078700786753338945, 77489693813976938 }, | |
| 860 | .{ 17221789422665858532, 12145427517550446164, 5391414622238668005, 76001670549108934 }, | |
| 861 | .{ 4859588996898795878, 1715798948121313204, 3950858167455137171, 74542221577515387 }, | |
| 862 | .{ 13513469241795711526, 631367850494860526, 10517278915021816160, 73110798191218799 }, | |
| 863 | .{ 11757513142672073111, 2581974932255022228, 17498959383193606459, 143413724438001539 }, | |
| 864 | .{ 14524355192525042817, 5640643347559376447, 1309659274756813016, 140659771648132296 }, | |
| 865 | .{ 2765095348461978538, 11021111021896007722, 3224303603779962366, 137958702611185230 }, | |
| 866 | .{ 12373410389187981037, 13679193545685856195, 11644609038462631561, 135309501808182158 }, | |
| 867 | .{ 12813176257562780151, 3754199046160268020, 9954691079802960722, 132711173221007413 }, | |
| 868 | .{ 17557452279667723458, 3237799193992485824, 17893947919029030695, 130162739957935629 }, | |
| 869 | .{ 14634200999559435155, 4123869946105211004, 6955301747350769239, 127663243886350468 }, | |
| 870 | .{ 2185352760627740240, 2864813346878886844, 13049218671329690184, 125211745272516185 }, | |
| 871 | .{ 6143438674322183002, 10464733336980678750, 6982925169933978309, 122807322428266620 }, | |
| 872 | .{ 1099509117817174576, 10202656147550524081, 754997032816608484, 120449071364478757 }, | |
| 873 | .{ 2410631293559367023, 17407273750261453804, 15307291918933463037, 118136105451200587 }, | |
| 874 | .{ 12224968375134586697, 1664436604907828062, 11506086230137787358, 115867555084305488 }, | |
| 875 | .{ 3495926216898000888, 18392536965197424288, 10992889188570643156, 113642567358547782 }, | |
| 876 | .{ 8744506286256259680, 3966568369496879937, 18342264969761820037, 111460305746896569 }, | |
| 877 | .{ 7689600520560455039, 5254331190877624630, 9628558080573245556, 109319949786027263 }, | |
| 878 | .{ 11862637625618819436, 3456120362318976488, 14690471063106001082, 107220694767852583 }, | |
| 879 | .{ 5697330450030126444, 12424082405392918899, 358204170751754904, 105161751436977040 }, | |
| 880 | .{ 11257457505097373622, 15373192700214208870, 671619062372033814, 103142345693961148 }, | |
| 881 | .{ 16850355018477166700, 1913910419361963966, 4550257919755970531, 101161718304283822 }, | |
| 882 | .{ 9670835567561997011, 10584031339132130638, 3060560222974851757, 99219124612893520 }, | |
| 883 | .{ 7698686577353054710, 11689292838639130817, 11806331021588878241, 97313834264240819 }, | |
| 884 | .{ 12233569599615692137, 3347791226108469959, 10333904326094451110, 95445130927687169 }, | |
| 885 | .{ 13049400362825383933, 17142621313007799680, 3790542585289224168, 93612312028186576 }, | |
| 886 | .{ 12430457242474442072, 5625077542189557960, 14765055286236672238, 91814688482138969 }, | |
| 887 | .{ 4759444137752473128, 2230562561567025078, 4954443037339580076, 90051584438315940 }, | |
| 888 | .{ 7246913525170274758, 8910297835195760709, 4015904029508858381, 88322337023761438 }, | |
| 889 | .{ 12854430245836432067, 8135139748065431455, 11548083631386317976, 86626296094571907 }, | |
| 890 | .{ 4848827254502687803, 4789491250196085625, 3988192420450664125, 84962823991462151 }, | |
| 891 | .{ 7435538409611286684, 904061756819742353, 14598026519493048444, 83331295300025028 }, | |
| 892 | .{ 11042616160352530997, 8948390828345326218, 10052651191118271927, 81731096615594853 }, | |
| 893 | .{ 11059348291563778943, 11696515766184685544, 3783210511290897367, 80161626312626082 }, | |
| 894 | .{ 7020010856491885826, 5025093219346041680, 8960210401638911765, 78622294318500592 }, | |
| 895 | .{ 17732844474490699984, 7820866704994446502, 6088373186798844243, 77112521891678506 }, | |
| 896 | .{ 688278527545590501, 3045610706602776618, 8684243536999567610, 75631741404109150 }, | |
| 897 | .{ 2734573255120657297, 3903146411440697663, 9470794821691856713, 74179396127820347 }, | |
| 898 | .{ 15996457521023071259, 4776627823451271680, 12394856457265744744, 72754940025605801 }, | |
| 899 | .{ 13492065758834518331, 7390517611012222399, 1630485387832860230, 142715675091463768 }, | |
| 900 | .{ 13665021627282055864, 9897834675523659302, 17907668136755296849, 139975126841173266 }, | |
| 901 | .{ 9603773719399446181, 10771916301484339398, 10672699855989487527, 137287204938390542 }, | |
| 902 | .{ 3630218541553511265, 8139010004241080614, 2876479648932814543, 134650898807055963 }, | |
| 903 | .{ 8318835909686377084, 9525369258927993371, 2796120270400437057, 132065217277054270 }, | |
| 904 | .{ 11190003059043290163, 12424345635599592110, 12539346395388933763, 129529188211565064 }, | |
| 905 | .{ 8701968833973242276, 820569587086330727, 2315591597351480110, 127041858141569228 }, | |
| 906 | .{ 5115113890115690487, 16906305245394587826, 9899749468931071388, 124602291907373862 }, | |
| 907 | .{ 15543535488939245974, 10945189844466391399, 3553863472349432246, 122209572307020975 }, | |
| 908 | .{ 7709257252608325038, 1191832167690640880, 15077137020234258537, 119862799751447719 }, | |
| 909 | .{ 7541333244210021737, 9790054727902174575, 5160944773155322014, 117561091926268545 }, | |
| 910 | .{ 12297384708782857832, 1281328873123467374, 4827925254630475769, 115303583460052092 }, | |
| 911 | .{ 13243237906232367265, 15873887428139547641, 3607993172301799599, 113089425598968120 }, | |
| 912 | .{ 11384616453739611114, 15184114243769211033, 13148448124803481057, 110917785887682141 }, | |
| 913 | .{ 17727970963596660683, 1196965221832671990, 14537830463956404138, 108787847856377790 }, | |
| 914 | .{ 17241367586707330931, 8880584684128262874, 11173506540726547818, 106698810713789254 }, | |
| 915 | .{ 7184427196661305643, 14332510582433188173, 14230167953789677901, 104649889046128358 }, | |
| 916 | }; | |
| 917 | ||
| 918 | const POW5_INV_ERRORS: [154]u64 = .{ | |
| 919 | 0x1144155514145504, 0x0000541555401141, 0x0000000000000000, 0x0154454000000000, | |
| 920 | 0x4114105515544440, 0x0001001111500415, 0x4041411410011000, 0x5550114515155014, | |
| 921 | 0x1404100041554551, 0x0515000450404410, 0x5054544401140004, 0x5155501005555105, | |
| 922 | 0x1144141000105515, 0x0541500000500000, 0x1104105540444140, 0x4000015055514110, | |
| 923 | 0x0054010450004005, 0x4155515404100005, 0x5155145045155555, 0x1511555515440558, | |
| 924 | 0x5558544555515555, 0x0000000000000010, 0x5004000000000050, 0x1415510100000010, | |
| 925 | 0x4545555444514500, 0x5155151555555551, 0x1441540144044554, 0x5150104045544400, | |
| 926 | 0x5450545401444040, 0x5554455045501400, 0x4655155555555145, 0x1000010055455055, | |
| 927 | 0x1000004000055004, 0x4455405104000005, 0x4500114504150545, 0x0000000014000000, | |
| 928 | 0x5450000000000000, 0x5514551511445555, 0x4111501040555451, 0x4515445500054444, | |
| 929 | 0x5101500104100441, 0x1545115155545055, 0x0000000000000000, 0x1554000000100000, | |
| 930 | 0x5555545595551555, 0x5555051851455955, 0x5555555555555559, 0x0000400011001555, | |
| 931 | 0x0000004400040000, 0x5455511555554554, 0x5614555544115445, 0x6455156145555155, | |
| 932 | 0x5455855455415455, 0x5515555144555545, 0x0114400000145155, 0x0000051000450511, | |
| 933 | 0x4455154554445100, 0x4554150141544455, 0x65955555559a5965, 0x5555555854559559, | |
| 934 | 0x9569654559616595, 0x1040044040005565, 0x1010010500011044, 0x1554015545154540, | |
| 935 | 0x4440555401545441, 0x1014441450550105, 0x4545400410504145, 0x5015111541040151, | |
| 936 | 0x5145051154000410, 0x1040001044545044, 0x4001400000151410, 0x0540000044040000, | |
| 937 | 0x0510555454411544, 0x0400054054141550, 0x1001041145001100, 0x0000000140000000, | |
| 938 | 0x0000000014100000, 0x1544005454000140, 0x4050055505445145, 0x0011511104504155, | |
| 939 | 0x5505544415045055, 0x1155154445515554, 0x0000000000004555, 0x0000000000000000, | |
| 940 | 0x5101010510400004, 0x1514045044440400, 0x5515519555515555, 0x4554545441555545, | |
| 941 | 0x1551055955551515, 0x0150000011505515, 0x0044005040400000, 0x0004001004010050, | |
| 942 | 0x0000051004450414, 0x0114001101001144, 0x0401000001000001, 0x4500010001000401, | |
| 943 | 0x0004100000005000, 0x0105000441101100, 0x0455455550454540, 0x5404050144105505, | |
| 944 | 0x4101510540555455, 0x1055541411451555, 0x5451445110115505, 0x1154110010101545, | |
| 945 | 0x1145140450054055, 0x5555565415551554, 0x1550559555555555, 0x5555541545045141, | |
| 946 | 0x4555455450500100, 0x5510454545554555, 0x1510140115045455, 0x1001050040111510, | |
| 947 | 0x5555454555555504, 0x9954155545515554, 0x6596656555555555, 0x0140410051555559, | |
| 948 | 0x0011104010001544, 0x965669659a680501, 0x5655a55955556955, 0x4015111014404514, | |
| 949 | 0x1414155554505145, 0x0540040011051404, 0x1010000000015005, 0x0010054050004410, | |
| 950 | 0x5041104014000100, 0x4440010500100001, 0x1155510504545554, 0x0450151545115541, | |
| 951 | 0x4000100400110440, 0x1004440010514440, 0x0000115050450000, 0x0545404455541500, | |
| 952 | 0x1051051555505101, 0x5505144554544144, 0x4550545555515550, 0x0015400450045445, | |
| 953 | 0x4514155400554415, 0x4555055051050151, 0x1511441450001014, 0x4544554510404414, | |
| 954 | 0x4115115545545450, 0x5500541555551555, 0x5550010544155015, 0x0144414045545500, | |
| 955 | 0x4154050001050150, 0x5550511111000145, 0x1114504055000151, 0x5104041101451040, | |
| 956 | 0x0010501401051441, 0x0010501450504401, 0x4554585440044444, 0x5155555951450455, | |
| 957 | 0x0040000400105555, 0x0000000000000001, | |
| 958 | }; | |
| 959 | ||
| 960 | // zig fmt: on | |
| 961 | ||
| 962 | fn check(comptime T: type, value: T, comptime expected: []const u8) !void { | |
| 963 | const I = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } }); | |
| 964 | ||
| 965 | var buf: [6000]u8 = undefined; | |
| 966 | const value_bits: I = @bitCast(value); | |
| 967 | const s = try formatFloat(&buf, value, .{}); | |
| 968 | try std.testing.expectEqualStrings(expected, s); | |
| 969 | ||
| 970 | if (@bitSizeOf(T) != 80) { | |
| 971 | const o = try std.fmt.parseFloat(T, s); | |
| 972 | const o_bits: I = @bitCast(o); | |
| 973 | ||
| 974 | if (std.math.isNan(value)) { | |
| 975 | try std.testing.expect(std.math.isNan(o)); | |
| 976 | } else { | |
| 977 | try std.testing.expectEqual(value_bits, o_bits); | |
| 978 | } | |
| 979 | } | |
| 980 | } | |
| 981 | ||
| 982 | test "format f32" { | |
| 983 | try check(f32, 0.0, "0e0"); | |
| 984 | try check(f32, -0.0, "-0e0"); | |
| 985 | try check(f32, 1.0, "1e0"); | |
| 986 | try check(f32, -1.0, "-1e0"); | |
| 987 | try check(f32, std.math.nan(f32), "nan"); | |
| 988 | try check(f32, std.math.inf(f32), "inf"); | |
| 989 | try check(f32, -std.math.inf(f32), "-inf"); | |
| 990 | try check(f32, 1.1754944e-38, "1.1754944e-38"); | |
| 991 | try check(f32, @bitCast(@as(u32, 0x7f7fffff)), "3.4028235e38"); | |
| 992 | try check(f32, @bitCast(@as(u32, 1)), "1e-45"); | |
| 993 | try check(f32, 3.355445E7, "3.355445e7"); | |
| 994 | try check(f32, 8.999999e9, "9e9"); | |
| 995 | try check(f32, 3.4366717e10, "3.436672e10"); | |
| 996 | try check(f32, 3.0540412e5, "3.0540412e5"); | |
| 997 | try check(f32, 8.0990312e3, "8.0990312e3"); | |
| 998 | try check(f32, 2.4414062e-4, "2.4414062e-4"); | |
| 999 | try check(f32, 2.4414062e-3, "2.4414062e-3"); | |
| 1000 | try check(f32, 4.3945312e-3, "4.3945312e-3"); | |
| 1001 | try check(f32, 6.3476562e-3, "6.3476562e-3"); | |
| 1002 | try check(f32, 4.7223665e21, "4.7223665e21"); | |
| 1003 | try check(f32, 8388608.0, "8.388608e6"); | |
| 1004 | try check(f32, 1.6777216e7, "1.6777216e7"); | |
| 1005 | try check(f32, 3.3554436e7, "3.3554436e7"); | |
| 1006 | try check(f32, 6.7131496e7, "6.7131496e7"); | |
| 1007 | try check(f32, 1.9310392e-38, "1.9310392e-38"); | |
| 1008 | try check(f32, -2.47e-43, "-2.47e-43"); | |
| 1009 | try check(f32, 1.993244e-38, "1.993244e-38"); | |
| 1010 | try check(f32, 4103.9003, "4.1039004e3"); | |
| 1011 | try check(f32, 5.3399997e9, "5.3399997e9"); | |
| 1012 | try check(f32, 6.0898e-39, "6.0898e-39"); | |
| 1013 | try check(f32, 0.0010310042, "1.0310042e-3"); | |
| 1014 | try check(f32, 2.8823261e17, "2.882326e17"); | |
| 1015 | try check(f32, 7.038531e-26, "7.038531e-26"); | |
| 1016 | try check(f32, 9.2234038e17, "9.223404e17"); | |
| 1017 | try check(f32, 6.7108872e7, "6.710887e7"); | |
| 1018 | try check(f32, 1.0e-44, "1e-44"); | |
| 1019 | try check(f32, 2.816025e14, "2.816025e14"); | |
| 1020 | try check(f32, 9.223372e18, "9.223372e18"); | |
| 1021 | try check(f32, 1.5846085e29, "1.5846086e29"); | |
| 1022 | try check(f32, 1.1811161e19, "1.1811161e19"); | |
| 1023 | try check(f32, 5.368709e18, "5.368709e18"); | |
| 1024 | try check(f32, 4.6143165e18, "4.6143166e18"); | |
| 1025 | try check(f32, 0.007812537, "7.812537e-3"); | |
| 1026 | try check(f32, 1.4e-45, "1e-45"); | |
| 1027 | try check(f32, 1.18697724e20, "1.18697725e20"); | |
| 1028 | try check(f32, 1.00014165e-36, "1.00014165e-36"); | |
| 1029 | try check(f32, 200.0, "2e2"); | |
| 1030 | try check(f32, 3.3554432e7, "3.3554432e7"); | |
| 1031 | ||
| 1032 | try check(f32, 1.0, "1e0"); | |
| 1033 | try check(f32, 1.2, "1.2e0"); | |
| 1034 | try check(f32, 1.23, "1.23e0"); | |
| 1035 | try check(f32, 1.234, "1.234e0"); | |
| 1036 | try check(f32, 1.2345, "1.2345e0"); | |
| 1037 | try check(f32, 1.23456, "1.23456e0"); | |
| 1038 | try check(f32, 1.234567, "1.234567e0"); | |
| 1039 | try check(f32, 1.2345678, "1.2345678e0"); | |
| 1040 | try check(f32, 1.23456735e-36, "1.23456735e-36"); | |
| 1041 | } | |
| 1042 | ||
| 1043 | test "format f64" { | |
| 1044 | try check(f64, 0.0, "0e0"); | |
| 1045 | try check(f64, -0.0, "-0e0"); | |
| 1046 | try check(f64, 1.0, "1e0"); | |
| 1047 | try check(f64, -1.0, "-1e0"); | |
| 1048 | try check(f64, std.math.nan(f64), "nan"); | |
| 1049 | try check(f64, std.math.inf(f64), "inf"); | |
| 1050 | try check(f64, -std.math.inf(f64), "-inf"); | |
| 1051 | try check(f64, 2.2250738585072014e-308, "2.2250738585072014e-308"); | |
| 1052 | try check(f64, @bitCast(@as(u64, 0x7fefffffffffffff)), "1.7976931348623157e308"); | |
| 1053 | try check(f64, @bitCast(@as(u64, 1)), "5e-324"); | |
| 1054 | try check(f64, 2.98023223876953125e-8, "2.9802322387695312e-8"); | |
| 1055 | try check(f64, -2.109808898695963e16, "-2.109808898695963e16"); | |
| 1056 | try check(f64, 4.940656e-318, "4.940656e-318"); | |
| 1057 | try check(f64, 1.18575755e-316, "1.18575755e-316"); | |
| 1058 | try check(f64, 2.989102097996e-312, "2.989102097996e-312"); | |
| 1059 | try check(f64, 9.0608011534336e15, "9.0608011534336e15"); | |
| 1060 | try check(f64, 4.708356024711512e18, "4.708356024711512e18"); | |
| 1061 | try check(f64, 9.409340012568248e18, "9.409340012568248e18"); | |
| 1062 | try check(f64, 1.2345678, "1.2345678e0"); | |
| 1063 | try check(f64, @bitCast(@as(u64, 0x4830f0cf064dd592)), "5.764607523034235e39"); | |
| 1064 | try check(f64, @bitCast(@as(u64, 0x4840f0cf064dd592)), "1.152921504606847e40"); | |
| 1065 | try check(f64, @bitCast(@as(u64, 0x4850f0cf064dd592)), "2.305843009213694e40"); | |
| 1066 | ||
| 1067 | try check(f64, 1, "1e0"); | |
| 1068 | try check(f64, 1.2, "1.2e0"); | |
| 1069 | try check(f64, 1.23, "1.23e0"); | |
| 1070 | try check(f64, 1.234, "1.234e0"); | |
| 1071 | try check(f64, 1.2345, "1.2345e0"); | |
| 1072 | try check(f64, 1.23456, "1.23456e0"); | |
| 1073 | try check(f64, 1.234567, "1.234567e0"); | |
| 1074 | try check(f64, 1.2345678, "1.2345678e0"); | |
| 1075 | try check(f64, 1.23456789, "1.23456789e0"); | |
| 1076 | try check(f64, 1.234567895, "1.234567895e0"); | |
| 1077 | try check(f64, 1.2345678901, "1.2345678901e0"); | |
| 1078 | try check(f64, 1.23456789012, "1.23456789012e0"); | |
| 1079 | try check(f64, 1.234567890123, "1.234567890123e0"); | |
| 1080 | try check(f64, 1.2345678901234, "1.2345678901234e0"); | |
| 1081 | try check(f64, 1.23456789012345, "1.23456789012345e0"); | |
| 1082 | try check(f64, 1.234567890123456, "1.234567890123456e0"); | |
| 1083 | try check(f64, 1.2345678901234567, "1.2345678901234567e0"); | |
| 1084 | ||
| 1085 | try check(f64, 4.294967294, "4.294967294e0"); | |
| 1086 | try check(f64, 4.294967295, "4.294967295e0"); | |
| 1087 | try check(f64, 4.294967296, "4.294967296e0"); | |
| 1088 | try check(f64, 4.294967297, "4.294967297e0"); | |
| 1089 | try check(f64, 4.294967298, "4.294967298e0"); | |
| 1090 | } | |
| 1091 | ||
| 1092 | test "format f80" { | |
| 1093 | try check(f80, 0.0, "0e0"); | |
| 1094 | try check(f80, -0.0, "-0e0"); | |
| 1095 | try check(f80, 1.0, "1e0"); | |
| 1096 | try check(f80, -1.0, "-1e0"); | |
| 1097 | try check(f80, std.math.nan(f80), "nan"); | |
| 1098 | try check(f80, std.math.inf(f80), "inf"); | |
| 1099 | try check(f80, -std.math.inf(f80), "-inf"); | |
| 1100 | ||
| 1101 | try check(f80, 2.2250738585072014e-308, "2.2250738585072014e-308"); | |
| 1102 | try check(f80, 2.98023223876953125e-8, "2.98023223876953125e-8"); | |
| 1103 | try check(f80, -2.109808898695963e16, "-2.109808898695963e16"); | |
| 1104 | try check(f80, 4.940656e-318, "4.940656e-318"); | |
| 1105 | try check(f80, 1.18575755e-316, "1.18575755e-316"); | |
| 1106 | try check(f80, 2.989102097996e-312, "2.989102097996e-312"); | |
| 1107 | try check(f80, 9.0608011534336e15, "9.0608011534336e15"); | |
| 1108 | try check(f80, 4.708356024711512e18, "4.708356024711512e18"); | |
| 1109 | try check(f80, 9.409340012568248e18, "9.409340012568248e18"); | |
| 1110 | try check(f80, 1.2345678, "1.2345678e0"); | |
| 1111 | } | |
| 1112 | ||
| 1113 | test "format f128" { | |
| 1114 | try check(f128, 0.0, "0e0"); | |
| 1115 | try check(f128, -0.0, "-0e0"); | |
| 1116 | try check(f128, 1.0, "1e0"); | |
| 1117 | try check(f128, -1.0, "-1e0"); | |
| 1118 | try check(f128, std.math.nan(f128), "nan"); | |
| 1119 | try check(f128, std.math.inf(f128), "inf"); | |
| 1120 | try check(f128, -std.math.inf(f128), "-inf"); | |
| 1121 | ||
| 1122 | try check(f128, 2.2250738585072014e-308, "2.2250738585072014e-308"); | |
| 1123 | try check(f128, 2.98023223876953125e-8, "2.98023223876953125e-8"); | |
| 1124 | try check(f128, -2.109808898695963e16, "-2.109808898695963e16"); | |
| 1125 | try check(f128, 4.940656e-318, "4.940656e-318"); | |
| 1126 | try check(f128, 1.18575755e-316, "1.18575755e-316"); | |
| 1127 | try check(f128, 2.989102097996e-312, "2.989102097996e-312"); | |
| 1128 | try check(f128, 9.0608011534336e15, "9.0608011534336e15"); | |
| 1129 | try check(f128, 4.708356024711512e18, "4.708356024711512e18"); | |
| 1130 | try check(f128, 9.409340012568248e18, "9.409340012568248e18"); | |
| 1131 | try check(f128, 1.2345678, "1.2345678e0"); | |
| 1132 | } | |
| 1133 | ||
| 1134 | test "format float to decimal with zero precision" { | |
| 1135 | try expectFmt("5", "{d:.0}", .{5}); | |
| 1136 | try expectFmt("6", "{d:.0}", .{6}); | |
| 1137 | try expectFmt("7", "{d:.0}", .{7}); | |
| 1138 | try expectFmt("8", "{d:.0}", .{8}); | |
| 1139 | } |
lib/std/fmt/ryu128.zig deleted-1139| ... | ... | @@ -1,1139 +0,0 @@ |
| 1 | //! This file implements the ryu floating point conversion algorithm: | |
| 2 | //! https://dl.acm.org/doi/pdf/10.1145/3360595 | |
| 3 | ||
| 4 | const std = @import("std"); | |
| 5 | const expectFmt = std.testing.expectFmt; | |
| 6 | ||
| 7 | const special_exponent = 0x7fffffff; | |
| 8 | ||
| 9 | /// Any buffer used for `format` must be at least this large. This is asserted. A runtime check will | |
| 10 | /// additionally be performed if more bytes are required. | |
| 11 | pub const min_buffer_size = 53; | |
| 12 | ||
| 13 | /// Returns the minimum buffer size needed to print every float of a specific type and format. | |
| 14 | pub fn bufferSize(comptime mode: Format, comptime T: type) comptime_int { | |
| 15 | comptime std.debug.assert(@typeInfo(T) == .Float); | |
| 16 | return switch (mode) { | |
| 17 | .scientific => 53, | |
| 18 | // Based on minimum subnormal values. | |
| 19 | .decimal => switch (@bitSizeOf(T)) { | |
| 20 | 16 => @max(15, min_buffer_size), | |
| 21 | 32 => 55, | |
| 22 | 64 => 347, | |
| 23 | 80 => 4996, | |
| 24 | 128 => 5011, | |
| 25 | else => unreachable, | |
| 26 | }, | |
| 27 | }; | |
| 28 | } | |
| 29 | ||
| 30 | pub const RyuError = error{ | |
| 31 | BufferTooSmall, | |
| 32 | }; | |
| 33 | ||
| 34 | pub const Format = enum { | |
| 35 | scientific, | |
| 36 | decimal, | |
| 37 | }; | |
| 38 | ||
| 39 | pub const FormatOptions = struct { | |
| 40 | mode: Format = .scientific, | |
| 41 | precision: ?usize = null, | |
| 42 | }; | |
| 43 | ||
| 44 | /// Format a floating-point value and write it to buffer. Returns a slice to the buffer containing | |
| 45 | /// the string representation. | |
| 46 | /// | |
| 47 | /// Full precision is the default. Any full precision float can be reparsed with std.fmt.parseFloat | |
| 48 | /// unambiguously. | |
| 49 | /// | |
| 50 | /// Scientific mode is recommended generally as the output is more compact and any type can be | |
| 51 | /// written in full precision using a buffer of only `min_buffer_size`. | |
| 52 | /// | |
| 53 | /// When printing full precision decimals, use `bufferSize` to get the required space. It is | |
| 54 | /// recommended to bound decimal output with a fixed precision to reduce the required buffer size. | |
| 55 | pub fn format(buf: []u8, v_: anytype, options: FormatOptions) RyuError![]const u8 { | |
| 56 | const v = switch (@TypeOf(v_)) { | |
| 57 | // comptime_float internally is a f128; this preserves precision. | |
| 58 | comptime_float => @as(f128, v_), | |
| 59 | else => v_, | |
| 60 | }; | |
| 61 | ||
| 62 | const T = @TypeOf(v); | |
| 63 | comptime std.debug.assert(@typeInfo(T) == .Float); | |
| 64 | const I = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } }); | |
| 65 | ||
| 66 | const has_explicit_leading_bit = std.math.floatMantissaBits(T) - std.math.floatFractionalBits(T) != 0; | |
| 67 | const d = binaryToDecimal(@as(I, @bitCast(v)), std.math.floatMantissaBits(T), std.math.floatExponentBits(T), has_explicit_leading_bit); | |
| 68 | ||
| 69 | return switch (options.mode) { | |
| 70 | .scientific => formatScientific(buf, d, options.precision), | |
| 71 | .decimal => formatDecimal(buf, d, options.precision), | |
| 72 | }; | |
| 73 | } | |
| 74 | ||
| 75 | pub const FloatDecimal128 = struct { | |
| 76 | mantissa: u128, | |
| 77 | exponent: i32, | |
| 78 | sign: bool, | |
| 79 | }; | |
| 80 | ||
| 81 | fn copySpecialStr(buf: []u8, f: FloatDecimal128) []const u8 { | |
| 82 | if (f.sign) { | |
| 83 | buf[0] = '-'; | |
| 84 | } | |
| 85 | const offset: usize = @intFromBool(f.sign); | |
| 86 | if (f.mantissa != 0) { | |
| 87 | @memcpy(buf[offset..][0..3], "nan"); | |
| 88 | return buf[0 .. 3 + offset]; | |
| 89 | } | |
| 90 | @memcpy(buf[offset..][0..3], "inf"); | |
| 91 | return buf[0 .. 3 + offset]; | |
| 92 | } | |
| 93 | ||
| 94 | fn writeDecimal(buf: []u8, value: anytype, count: usize) void { | |
| 95 | var i: usize = 0; | |
| 96 | ||
| 97 | while (i + 2 < count) : (i += 2) { | |
| 98 | const c: u8 = @intCast(value.* % 100); | |
| 99 | value.* /= 100; | |
| 100 | const d = std.fmt.digits2(c); | |
| 101 | buf[count - i - 1] = d[1]; | |
| 102 | buf[count - i - 2] = d[0]; | |
| 103 | } | |
| 104 | ||
| 105 | while (i < count) : (i += 1) { | |
| 106 | const c: u8 = @intCast(value.* % 10); | |
| 107 | value.* /= 10; | |
| 108 | buf[count - i - 1] = '0' + c; | |
| 109 | } | |
| 110 | } | |
| 111 | ||
| 112 | fn isPowerOf10(n_: u128) bool { | |
| 113 | var n = n_; | |
| 114 | while (n != 0) : (n /= 10) { | |
| 115 | if (n % 10 != 0) return false; | |
| 116 | } | |
| 117 | return true; | |
| 118 | } | |
| 119 | ||
| 120 | const RoundMode = enum { | |
| 121 | /// 1234.56 = precision 2 | |
| 122 | decimal, | |
| 123 | /// 1.23456e3 = precision 5 | |
| 124 | scientific, | |
| 125 | }; | |
| 126 | ||
| 127 | fn round(f: FloatDecimal128, mode: RoundMode, precision: usize) FloatDecimal128 { | |
| 128 | var round_digit: usize = 0; | |
| 129 | var output = f.mantissa; | |
| 130 | var exp = f.exponent; | |
| 131 | const olength = decimalLength(output); | |
| 132 | ||
| 133 | switch (mode) { | |
| 134 | .decimal => { | |
| 135 | if (f.exponent > 0) { | |
| 136 | round_digit = (olength - 1) + precision + @as(usize, @intCast(f.exponent)); | |
| 137 | } else { | |
| 138 | const min_exp_required = @as(usize, @intCast(-f.exponent)); | |
| 139 | if (precision + olength > min_exp_required) { | |
| 140 | round_digit = precision + olength - min_exp_required; | |
| 141 | } | |
| 142 | } | |
| 143 | }, | |
| 144 | .scientific => { | |
| 145 | round_digit = 1 + precision; | |
| 146 | }, | |
| 147 | } | |
| 148 | ||
| 149 | if (round_digit < olength) { | |
| 150 | var nlength = olength; | |
| 151 | for (round_digit + 1..olength) |_| { | |
| 152 | output /= 10; | |
| 153 | exp += 1; | |
| 154 | nlength -= 1; | |
| 155 | } | |
| 156 | ||
| 157 | if (output % 10 >= 5) { | |
| 158 | output /= 10; | |
| 159 | output += 1; | |
| 160 | exp += 1; | |
| 161 | ||
| 162 | // e.g. 9999 -> 10000 | |
| 163 | if (isPowerOf10(output)) { | |
| 164 | output /= 10; | |
| 165 | exp += 1; | |
| 166 | } | |
| 167 | } | |
| 168 | } | |
| 169 | ||
| 170 | return .{ | |
| 171 | .mantissa = output, | |
| 172 | .exponent = exp, | |
| 173 | .sign = f.sign, | |
| 174 | }; | |
| 175 | } | |
| 176 | ||
| 177 | /// Write a FloatDecimal128 to a buffer in scientific form. | |
| 178 | /// | |
| 179 | /// The buffer provided must be greater than `min_buffer_size` in length. If no precision is | |
| 180 | /// specified, this function will never return an error. If a precision is specified, up to | |
| 181 | /// `8 + precision` bytes will be written to the buffer. An error will be returned if the content | |
| 182 | /// will not fit. | |
| 183 | /// | |
| 184 | /// It is recommended to bound decimal formatting with an exact precision. | |
| 185 | pub fn formatScientific(buf: []u8, f_: FloatDecimal128, precision: ?usize) RyuError![]const u8 { | |
| 186 | std.debug.assert(buf.len >= min_buffer_size); | |
| 187 | var f = f_; | |
| 188 | ||
| 189 | if (f.exponent == special_exponent) { | |
| 190 | return copySpecialStr(buf, f); | |
| 191 | } | |
| 192 | ||
| 193 | if (precision) |prec| { | |
| 194 | f = round(f, .scientific, prec); | |
| 195 | } | |
| 196 | ||
| 197 | var output = f.mantissa; | |
| 198 | const olength = decimalLength(output); | |
| 199 | ||
| 200 | if (precision) |prec| { | |
| 201 | // fixed bound: sign(1) + leading_digit(1) + point(1) + exp_sign(1) + exp_max(4) | |
| 202 | const req_bytes = 8 + prec; | |
| 203 | if (buf.len < req_bytes) { | |
| 204 | return error.BufferTooSmall; | |
| 205 | } | |
| 206 | } | |
| 207 | ||
| 208 | // Step 5: Print the scientific representation | |
| 209 | var index: usize = 0; | |
| 210 | if (f.sign) { | |
| 211 | buf[index] = '-'; | |
| 212 | index += 1; | |
| 213 | } | |
| 214 | ||
| 215 | // 1.12345 | |
| 216 | writeDecimal(buf[index + 2 ..], &output, olength - 1); | |
| 217 | buf[index] = '0' + @as(u8, @intCast(output % 10)); | |
| 218 | buf[index + 1] = '.'; | |
| 219 | index += 2; | |
| 220 | const dp_index = index; | |
| 221 | if (olength > 1) index += olength - 1 else index -= 1; | |
| 222 | ||
| 223 | if (precision) |prec| { | |
| 224 | index += @intFromBool(olength == 1); | |
| 225 | if (prec > olength - 1) { | |
| 226 | const len = prec - (olength - 1); | |
| 227 | @memset(buf[index..][0..len], '0'); | |
| 228 | index += len; | |
| 229 | } else { | |
| 230 | index = dp_index + prec - @intFromBool(prec == 0); | |
| 231 | } | |
| 232 | } | |
| 233 | ||
| 234 | // e100 | |
| 235 | buf[index] = 'e'; | |
| 236 | index += 1; | |
| 237 | var exp = f.exponent + @as(i32, @intCast(olength)) - 1; | |
| 238 | if (exp < 0) { | |
| 239 | buf[index] = '-'; | |
| 240 | index += 1; | |
| 241 | exp = -exp; | |
| 242 | } | |
| 243 | var uexp: u32 = @intCast(exp); | |
| 244 | const elength = decimalLength(uexp); | |
| 245 | writeDecimal(buf[index..], &uexp, elength); | |
| 246 | index += elength; | |
| 247 | ||
| 248 | return buf[0..index]; | |
| 249 | } | |
| 250 | ||
| 251 | /// Write a FloatDecimal128 to a buffer in decimal form. | |
| 252 | /// | |
| 253 | /// The buffer provided must be greater than `min_buffer_size` bytes in length. If no precision is | |
| 254 | /// specified, this may still return an error. If precision is specified, `2 + precision` bytes will | |
| 255 | /// always be written. | |
| 256 | pub fn formatDecimal(buf: []u8, f_: FloatDecimal128, precision: ?usize) RyuError![]const u8 { | |
| 257 | std.debug.assert(buf.len >= min_buffer_size); | |
| 258 | var f = f_; | |
| 259 | ||
| 260 | if (f.exponent == special_exponent) { | |
| 261 | return copySpecialStr(buf, f); | |
| 262 | } | |
| 263 | ||
| 264 | if (precision) |prec| { | |
| 265 | f = round(f, .decimal, prec); | |
| 266 | } | |
| 267 | ||
| 268 | var output = f.mantissa; | |
| 269 | const olength = decimalLength(output); | |
| 270 | ||
| 271 | // fixed bound: leading_digit(1) + point(1) | |
| 272 | const req_bytes = if (f.exponent >= 0) | |
| 273 | 2 + @abs(f.exponent) + olength + (precision orelse 0) | |
| 274 | else | |
| 275 | 2 + @max(@abs(f.exponent) + olength, precision orelse 0); | |
| 276 | if (buf.len < req_bytes) { | |
| 277 | return error.BufferTooSmall; | |
| 278 | } | |
| 279 | ||
| 280 | // Step 5: Print the decimal representation | |
| 281 | var index: usize = 0; | |
| 282 | if (f.sign) { | |
| 283 | buf[index] = '-'; | |
| 284 | index += 1; | |
| 285 | } | |
| 286 | ||
| 287 | const dp_offset = f.exponent + cast_i32(olength); | |
| 288 | if (dp_offset <= 0) { | |
| 289 | // 0.000001234 | |
| 290 | buf[index] = '0'; | |
| 291 | buf[index + 1] = '.'; | |
| 292 | index += 2; | |
| 293 | const dp_index = index; | |
| 294 | ||
| 295 | const dp_poffset: u32 = @intCast(-dp_offset); | |
| 296 | @memset(buf[index..][0..dp_poffset], '0'); | |
| 297 | index += dp_poffset; | |
| 298 | writeDecimal(buf[index..], &output, olength); | |
| 299 | index += olength; | |
| 300 | ||
| 301 | if (precision) |prec| { | |
| 302 | const dp_written = index - dp_index; | |
| 303 | if (prec > dp_written) { | |
| 304 | @memset(buf[index..][0 .. prec - dp_written], '0'); | |
| 305 | } | |
| 306 | index = dp_index + prec - @intFromBool(prec == 0); | |
| 307 | } | |
| 308 | } else { | |
| 309 | // 123456000 | |
| 310 | const dp_uoffset: usize = @intCast(dp_offset); | |
| 311 | if (dp_uoffset >= olength) { | |
| 312 | writeDecimal(buf[index..], &output, olength); | |
| 313 | index += olength; | |
| 314 | @memset(buf[index..][0 .. dp_uoffset - olength], '0'); | |
| 315 | index += dp_uoffset - olength; | |
| 316 | ||
| 317 | if (precision) |prec| { | |
| 318 | if (prec != 0) { | |
| 319 | buf[index] = '.'; | |
| 320 | index += 1; | |
| 321 | @memset(buf[index..][0..prec], '0'); | |
| 322 | index += prec; | |
| 323 | } | |
| 324 | } | |
| 325 | } else { | |
| 326 | // 12345.6789 | |
| 327 | writeDecimal(buf[index + dp_uoffset + 1 ..], &output, olength - dp_uoffset); | |
| 328 | buf[index + dp_uoffset] = '.'; | |
| 329 | const dp_index = index + dp_uoffset + 1; | |
| 330 | writeDecimal(buf[index..], &output, dp_uoffset); | |
| 331 | index += olength + 1; | |
| 332 | ||
| 333 | if (precision) |prec| { | |
| 334 | const dp_written = olength - dp_uoffset; | |
| 335 | if (prec > dp_written) { | |
| 336 | @memset(buf[index..][0 .. prec - dp_written], '0'); | |
| 337 | } | |
| 338 | index = dp_index + prec - @intFromBool(prec == 0); | |
| 339 | } | |
| 340 | } | |
| 341 | } | |
| 342 | ||
| 343 | return buf[0..index]; | |
| 344 | } | |
| 345 | ||
| 346 | fn cast_i32(v: anytype) i32 { | |
| 347 | return @intCast(v); | |
| 348 | } | |
| 349 | ||
| 350 | /// Convert a binary float representation to decimal. | |
| 351 | pub fn binaryToDecimal(bits: u128, mantissa_bits: u7, exponent_bits: u5, explicit_leading_bit: bool) FloatDecimal128 { | |
| 352 | const bias = (@as(u32, 1) << (exponent_bits - 1)) - 1; | |
| 353 | const ieee_sign = ((bits >> (mantissa_bits + exponent_bits)) & 1) != 0; | |
| 354 | const ieee_mantissa = bits & ((@as(u128, 1) << mantissa_bits) - 1); | |
| 355 | const ieee_exponent: u32 = @intCast((bits >> mantissa_bits) & ((@as(u128, 1) << exponent_bits) - 1)); | |
| 356 | ||
| 357 | if (ieee_exponent == 0 and ieee_mantissa == 0) { | |
| 358 | return .{ | |
| 359 | .mantissa = 0, | |
| 360 | .exponent = 0, | |
| 361 | .sign = ieee_sign, | |
| 362 | }; | |
| 363 | } | |
| 364 | if (ieee_exponent == ((@as(u32, 1) << exponent_bits) - 1)) { | |
| 365 | return .{ | |
| 366 | .mantissa = if (explicit_leading_bit) ieee_mantissa & ((@as(u128, 1) << (mantissa_bits - 1)) - 1) else ieee_mantissa, | |
| 367 | .exponent = 0x7fffffff, | |
| 368 | .sign = ieee_sign, | |
| 369 | }; | |
| 370 | } | |
| 371 | ||
| 372 | var e2: i32 = undefined; | |
| 373 | var m2: u128 = undefined; | |
| 374 | if (explicit_leading_bit) { | |
| 375 | if (ieee_exponent == 0) { | |
| 376 | e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2; | |
| 377 | } else { | |
| 378 | e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2; | |
| 379 | } | |
| 380 | m2 = ieee_mantissa; | |
| 381 | } else { | |
| 382 | if (ieee_exponent == 0) { | |
| 383 | e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) - 2; | |
| 384 | m2 = ieee_mantissa; | |
| 385 | } else { | |
| 386 | e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) - 2; | |
| 387 | m2 = (@as(u128, 1) << mantissa_bits) | ieee_mantissa; | |
| 388 | } | |
| 389 | } | |
| 390 | const even = (m2 & 1) == 0; | |
| 391 | const accept_bounds = even; | |
| 392 | ||
| 393 | // Step 2: Determine the interval of legal decimal representations. | |
| 394 | const mv = 4 * m2; | |
| 395 | const mm_shift: u1 = @intFromBool((ieee_mantissa != if (explicit_leading_bit) (@as(u128, 1) << (mantissa_bits - 1)) else 0) or (ieee_exponent == 0)); | |
| 396 | ||
| 397 | // Step 3: Convert to a decimal power base using 128-bit arithmetic. | |
| 398 | var vr: u128 = undefined; | |
| 399 | var vp: u128 = undefined; | |
| 400 | var vm: u128 = undefined; | |
| 401 | var e10: i32 = undefined; | |
| 402 | var vm_is_trailing_zeros = false; | |
| 403 | var vr_is_trailing_zeros = false; | |
| 404 | if (e2 >= 0) { | |
| 405 | const q: u32 = log10Pow2(@intCast(e2)) - @intFromBool(e2 > 3); | |
| 406 | e10 = cast_i32(q); | |
| 407 | const k: i32 = @intCast(FLOAT_128_POW5_INV_BITCOUNT + pow5Bits(q) - 1); | |
| 408 | const i: u32 = @intCast(-e2 + cast_i32(q) + k); | |
| 409 | ||
| 410 | const pow5 = computeInvPow5(q); | |
| 411 | vr = mulShift(4 * m2, &pow5, i); | |
| 412 | vp = mulShift(4 * m2 + 2, &pow5, i); | |
| 413 | vm = mulShift(4 * m2 - 1 - mm_shift, &pow5, i); | |
| 414 | ||
| 415 | if (q <= 55) { | |
| 416 | if (mv % 5 == 0) { | |
| 417 | vr_is_trailing_zeros = multipleOfPowerOf5(mv, q -% 1); | |
| 418 | } else if (accept_bounds) { | |
| 419 | vm_is_trailing_zeros = multipleOfPowerOf5(mv - 1 - mm_shift, q); | |
| 420 | } else { | |
| 421 | vp -= @intFromBool(multipleOfPowerOf5(mv + 2, q)); | |
| 422 | } | |
| 423 | } | |
| 424 | } else { | |
| 425 | const q: u32 = log10Pow5(@intCast(-e2)) - @intFromBool(-e2 > 1); | |
| 426 | e10 = cast_i32(q) + e2; | |
| 427 | const i: i32 = -e2 - cast_i32(q); | |
| 428 | const k: i32 = cast_i32(pow5Bits(@intCast(i))) - FLOAT_128_POW5_BITCOUNT; | |
| 429 | const j: u32 = @intCast(cast_i32(q) - k); | |
| 430 | ||
| 431 | const pow5 = computePow5(@intCast(i)); | |
| 432 | vr = mulShift(4 * m2, &pow5, j); | |
| 433 | vp = mulShift(4 * m2 + 2, &pow5, j); | |
| 434 | vm = mulShift(4 * m2 - 1 - mm_shift, &pow5, j); | |
| 435 | ||
| 436 | if (q <= 1) { | |
| 437 | vr_is_trailing_zeros = true; | |
| 438 | if (accept_bounds) { | |
| 439 | vm_is_trailing_zeros = mm_shift == 1; | |
| 440 | } else { | |
| 441 | vp -= 1; | |
| 442 | } | |
| 443 | } else if (q < 127) { | |
| 444 | vr_is_trailing_zeros = multipleOfPowerOf2(mv, q - 1); | |
| 445 | } | |
| 446 | } | |
| 447 | ||
| 448 | // Step 4: Find the shortest decimal representation in the interval of legal representations. | |
| 449 | var removed: u32 = 0; | |
| 450 | var last_removed_digit: u8 = 0; | |
| 451 | ||
| 452 | while (vp / 10 > vm / 10) { | |
| 453 | vm_is_trailing_zeros = vm_is_trailing_zeros and vm % 10 == 0; | |
| 454 | vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0; | |
| 455 | last_removed_digit = @intCast(vr % 10); | |
| 456 | vr /= 10; | |
| 457 | vp /= 10; | |
| 458 | vm /= 10; | |
| 459 | removed += 1; | |
| 460 | } | |
| 461 | ||
| 462 | if (vm_is_trailing_zeros) { | |
| 463 | while (vm % 10 == 0) { | |
| 464 | vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0; | |
| 465 | last_removed_digit = @intCast(vr % 10); | |
| 466 | vr /= 10; | |
| 467 | vp /= 10; | |
| 468 | vm /= 10; | |
| 469 | removed += 1; | |
| 470 | } | |
| 471 | } | |
| 472 | ||
| 473 | if (vr_is_trailing_zeros and (last_removed_digit == 5) and (vr % 2 == 0)) { | |
| 474 | last_removed_digit = 4; | |
| 475 | } | |
| 476 | ||
| 477 | return .{ | |
| 478 | .mantissa = vr + @intFromBool((vr == vm and (!accept_bounds or !vm_is_trailing_zeros)) or last_removed_digit >= 5), | |
| 479 | .exponent = e10 + cast_i32(removed), | |
| 480 | .sign = ieee_sign, | |
| 481 | }; | |
| 482 | } | |
| 483 | ||
| 484 | fn decimalLength(v: u128) u32 { | |
| 485 | const LARGEST_POW10 = (@as(u128, 5421010862427522170) << 64) | 687399551400673280; | |
| 486 | var p10 = LARGEST_POW10; | |
| 487 | var i: u32 = 39; | |
| 488 | while (i > 0) : (i -= 1) { | |
| 489 | if (v >= p10) return i; | |
| 490 | p10 /= 10; | |
| 491 | } | |
| 492 | return 1; | |
| 493 | } | |
| 494 | ||
| 495 | // floor(log_10(2^e)) | |
| 496 | fn log10Pow2(e: u32) u32 { | |
| 497 | std.debug.assert(e <= 1 << 15); | |
| 498 | return @intCast((@as(u64, @intCast(e)) * 169464822037455) >> 49); | |
| 499 | } | |
| 500 | ||
| 501 | // floor(log_10(5^e)) | |
| 502 | fn log10Pow5(e: u32) u32 { | |
| 503 | std.debug.assert(e <= 1 << 15); | |
| 504 | return @intCast((@as(u64, @intCast(e)) * 196742565691928) >> 48); | |
| 505 | } | |
| 506 | ||
| 507 | // if (e == 0) 1 else ceil(log_2(5^e)) | |
| 508 | fn pow5Bits(e: u32) u32 { | |
| 509 | std.debug.assert(e <= 1 << 15); | |
| 510 | return @intCast(((@as(u64, @intCast(e)) * 163391164108059) >> 46) + 1); | |
| 511 | } | |
| 512 | ||
| 513 | fn pow5Factor(value_: u128) u32 { | |
| 514 | var count: u32 = 0; | |
| 515 | var value = value_; | |
| 516 | while (value > 0) : ({ | |
| 517 | count += 1; | |
| 518 | value /= 5; | |
| 519 | }) { | |
| 520 | if (value % 5 != 0) return count; | |
| 521 | } | |
| 522 | return 0; | |
| 523 | } | |
| 524 | ||
| 525 | fn multipleOfPowerOf5(value: u128, p: u32) bool { | |
| 526 | return pow5Factor(value) >= p; | |
| 527 | } | |
| 528 | ||
| 529 | fn multipleOfPowerOf2(value: u128, p: u32) bool { | |
| 530 | return (value & ((@as(u128, 1) << @as(u7, @intCast(p))) - 1)) == 0; | |
| 531 | } | |
| 532 | ||
| 533 | fn computeInvPow5(i: u32) [4]u64 { | |
| 534 | const base = (i + POW5_TABLE_SIZE - 1) / POW5_TABLE_SIZE; | |
| 535 | const base2 = base * POW5_TABLE_SIZE; | |
| 536 | const mul = &GENERIC_POW5_INV_SPLIT[base]; // 1 / 5^base2 | |
| 537 | if (i == base2) { | |
| 538 | return .{ mul[0] + 1, mul[1], mul[2], mul[3] }; | |
| 539 | } else { | |
| 540 | const offset = base2 - i; | |
| 541 | const m = &GENERIC_POW5_TABLE[offset]; // 5^offset | |
| 542 | const delta = pow5Bits(base2) - pow5Bits(i); | |
| 543 | ||
| 544 | const shift: u6 = @intCast(2 * (i % 32)); | |
| 545 | const corr: u32 = @intCast(((POW5_INV_ERRORS[i / 32] >> shift) & 3) + 1); | |
| 546 | return mul_128_256_shift(m, mul, delta, corr); | |
| 547 | } | |
| 548 | } | |
| 549 | ||
| 550 | fn computePow5(i: u32) [4]u64 { | |
| 551 | const base = i / POW5_TABLE_SIZE; | |
| 552 | const base2 = base * POW5_TABLE_SIZE; | |
| 553 | const mul = &GENERIC_POW5_SPLIT[base]; | |
| 554 | if (i == base2) { | |
| 555 | return mul.*; | |
| 556 | } else { | |
| 557 | const offset = i - base2; | |
| 558 | const m = &GENERIC_POW5_TABLE[offset]; | |
| 559 | const delta = pow5Bits(i) - pow5Bits(base2); | |
| 560 | ||
| 561 | const shift: u6 = @intCast(2 * (i % 32)); | |
| 562 | const corr: u32 = @intCast((POW5_ERRORS[i / 32] >> shift) & 3); | |
| 563 | return mul_128_256_shift(m, mul, delta, corr); | |
| 564 | } | |
| 565 | } | |
| 566 | ||
| 567 | fn mulShift(m: u128, mul: *const [4]u64, j: u32) u128 { | |
| 568 | std.debug.assert(j > 128); | |
| 569 | const a: [2]u64 = .{ @truncate(m), @truncate(m >> 64) }; | |
| 570 | const r = mul_128_256_shift(&a, mul, j, 0); | |
| 571 | return (@as(u128, r[1]) << 64) | r[0]; | |
| 572 | } | |
| 573 | ||
| 574 | fn mul_128_256_shift(a: *const [2]u64, b: *const [4]u64, shift: u32, corr: u32) [4]u64 { | |
| 575 | std.debug.assert(shift > 0); | |
| 576 | std.debug.assert(shift < 256); | |
| 577 | ||
| 578 | const b00 = @as(u128, a[0]) * b[0]; | |
| 579 | const b01 = @as(u128, a[0]) * b[1]; | |
| 580 | const b02 = @as(u128, a[0]) * b[2]; | |
| 581 | const b03 = @as(u128, a[0]) * b[3]; | |
| 582 | const b10 = @as(u128, a[1]) * b[0]; | |
| 583 | const b11 = @as(u128, a[1]) * b[1]; | |
| 584 | const b12 = @as(u128, a[1]) * b[2]; | |
| 585 | const b13 = @as(u128, a[1]) * b[3]; | |
| 586 | ||
| 587 | const s0 = b00; | |
| 588 | const s1 = b01 +% b10; | |
| 589 | const c1: u128 = @intFromBool(s1 < b01); | |
| 590 | const s2 = b02 +% b11; | |
| 591 | const c2: u128 = @intFromBool(s2 < b02); | |
| 592 | const s3 = b03 +% b12; | |
| 593 | const c3: u128 = @intFromBool(s3 < b03); | |
| 594 | ||
| 595 | const p0 = s0 +% (s1 << 64); | |
| 596 | const d0: u128 = @intFromBool(p0 < b00); | |
| 597 | const q1 = s2 +% (s1 >> 64) +% (s3 << 64); | |
| 598 | const d1: u128 = @intFromBool(q1 < s2); | |
| 599 | const p1 = q1 +% (c1 << 64) +% d0; | |
| 600 | const d2: u128 = @intFromBool(p1 < q1); | |
| 601 | const p2 = b13 +% (s3 >> 64) +% c2 +% (c3 << 64) +% d1 +% d2; | |
| 602 | ||
| 603 | var r0: u128 = undefined; | |
| 604 | var r1: u128 = undefined; | |
| 605 | if (shift < 128) { | |
| 606 | const cshift: u7 = @intCast(shift); | |
| 607 | const sshift: u7 = @intCast(128 - shift); | |
| 608 | r0 = corr +% ((p0 >> cshift) | (p1 << sshift)); | |
| 609 | r1 = ((p1 >> cshift) | (p2 << sshift)) +% @intFromBool(r0 < corr); | |
| 610 | } else if (shift == 128) { | |
| 611 | r0 = corr +% p1; | |
| 612 | r1 = p2 +% @intFromBool(r0 < corr); | |
| 613 | } else { | |
| 614 | const ashift: u7 = @intCast(shift - 128); | |
| 615 | const sshift: u7 = @intCast(256 - shift); | |
| 616 | r0 = corr +% ((p1 >> ashift) | (p2 << sshift)); | |
| 617 | r1 = (p2 >> ashift) +% @intFromBool(r0 < corr); | |
| 618 | } | |
| 619 | ||
| 620 | return .{ @truncate(r0), @truncate(r0 >> 64), @truncate(r1), @truncate(r1 >> 64) }; | |
| 621 | } | |
| 622 | ||
| 623 | // zig fmt: off | |
| 624 | // | |
| 625 | // 4.5KiB of tables. | |
| 626 | ||
| 627 | const FLOAT_128_POW5_INV_BITCOUNT = 249; | |
| 628 | const FLOAT_128_POW5_BITCOUNT = 249; | |
| 629 | const POW5_TABLE_SIZE = 56; | |
| 630 | ||
| 631 | const GENERIC_POW5_TABLE: [POW5_TABLE_SIZE][2]u64 = .{ | |
| 632 | .{ 1, 0 }, | |
| 633 | .{ 5, 0 }, | |
| 634 | .{ 25, 0 }, | |
| 635 | .{ 125, 0 }, | |
| 636 | .{ 625, 0 }, | |
| 637 | .{ 3125, 0 }, | |
| 638 | .{ 15625, 0 }, | |
| 639 | .{ 78125, 0 }, | |
| 640 | .{ 390625, 0 }, | |
| 641 | .{ 1953125, 0 }, | |
| 642 | .{ 9765625, 0 }, | |
| 643 | .{ 48828125, 0 }, | |
| 644 | .{ 244140625, 0 }, | |
| 645 | .{ 1220703125, 0 }, | |
| 646 | .{ 6103515625, 0 }, | |
| 647 | .{ 30517578125, 0 }, | |
| 648 | .{ 152587890625, 0 }, | |
| 649 | .{ 762939453125, 0 }, | |
| 650 | .{ 3814697265625, 0 }, | |
| 651 | .{ 19073486328125, 0 }, | |
| 652 | .{ 95367431640625, 0 }, | |
| 653 | .{ 476837158203125, 0 }, | |
| 654 | .{ 2384185791015625, 0 }, | |
| 655 | .{ 11920928955078125, 0 }, | |
| 656 | .{ 59604644775390625, 0 }, | |
| 657 | .{ 298023223876953125, 0 }, | |
| 658 | .{ 1490116119384765625, 0 }, | |
| 659 | .{ 7450580596923828125, 0 }, | |
| 660 | .{ 359414837200037393, 2 }, | |
| 661 | .{ 1797074186000186965, 10 }, | |
| 662 | .{ 8985370930000934825, 50 }, | |
| 663 | .{ 8033366502585570893, 252 }, | |
| 664 | .{ 3273344365508751233, 1262 }, | |
| 665 | .{ 16366721827543756165, 6310 }, | |
| 666 | .{ 8046632842880574361, 31554 }, | |
| 667 | .{ 3339676066983768573, 157772 }, | |
| 668 | .{ 16698380334918842865, 788860 }, | |
| 669 | .{ 9704925379756007861, 3944304 }, | |
| 670 | .{ 11631138751360936073, 19721522 }, | |
| 671 | .{ 2815461535676025517, 98607613 }, | |
| 672 | .{ 14077307678380127585, 493038065 }, | |
| 673 | .{ 15046306170771983077, 2465190328 }, | |
| 674 | .{ 1444554559021708921, 12325951644 }, | |
| 675 | .{ 7222772795108544605, 61629758220 }, | |
| 676 | .{ 17667119901833171409, 308148791101 }, | |
| 677 | .{ 14548623214327650581, 1540743955509 }, | |
| 678 | .{ 17402883850509598057, 7703719777548 }, | |
| 679 | .{ 13227442957709783821, 38518598887744 }, | |
| 680 | .{ 10796982567420264257, 192592994438723 }, | |
| 681 | .{ 17091424689682218053, 962964972193617 }, | |
| 682 | .{ 11670147153572883801, 4814824860968089 }, | |
| 683 | .{ 3010503546735764157, 24074124304840448 }, | |
| 684 | .{ 15052517733678820785, 120370621524202240 }, | |
| 685 | .{ 1475612373555897461, 601853107621011204 }, | |
| 686 | .{ 7378061867779487305, 3009265538105056020 }, | |
| 687 | .{ 18443565265187884909, 15046327690525280101 }, | |
| 688 | }; | |
| 689 | ||
| 690 | const GENERIC_POW5_SPLIT: [89][4]u64 = .{ | |
| 691 | .{ 0, 0, 0, 72057594037927936 }, | |
| 692 | .{ 0, 5206161169240293376, 4575641699882439235, 73468396926392969 }, | |
| 693 | .{ 3360510775605221349, 6983200512169538081, 4325643253124434363, 74906821675075173 }, | |
| 694 | .{ 11917660854915489451, 9652941469841108803, 946308467778435600, 76373409087490117 }, | |
| 695 | .{ 1994853395185689235, 16102657350889591545, 6847013871814915412, 77868710555449746 }, | |
| 696 | .{ 958415760277438274, 15059347134713823592, 7329070255463483331, 79393288266368765 }, | |
| 697 | .{ 2065144883315240188, 7145278325844925976, 14718454754511147343, 80947715414629833 }, | |
| 698 | .{ 8980391188862868935, 13709057401304208685, 8230434828742694591, 82532576417087045 }, | |
| 699 | .{ 432148644612782575, 7960151582448466064, 12056089168559840552, 84148467132788711 }, | |
| 700 | .{ 484109300864744403, 15010663910730448582, 16824949663447227068, 85795995087002057 }, | |
| 701 | .{ 14793711725276144220, 16494403799991899904, 10145107106505865967, 87475779699624060 }, | |
| 702 | .{ 15427548291869817042, 12330588654550505203, 13980791795114552342, 89188452518064298 }, | |
| 703 | .{ 9979404135116626552, 13477446383271537499, 14459862802511591337, 90934657454687378 }, | |
| 704 | .{ 12385121150303452775, 9097130814231585614, 6523855782339765207, 92715051028904201 }, | |
| 705 | .{ 1822931022538209743, 16062974719797586441, 3619180286173516788, 94530302614003091 }, | |
| 706 | .{ 12318611738248470829, 13330752208259324507, 10986694768744162601, 96381094688813589 }, | |
| 707 | .{ 13684493829640282333, 7674802078297225834, 15208116197624593182, 98268123094297527 }, | |
| 708 | .{ 5408877057066295332, 6470124174091971006, 15112713923117703147, 100192097295163851 }, | |
| 709 | .{ 11407083166564425062, 18189998238742408185, 4337638702446708282, 102153740646605557 }, | |
| 710 | .{ 4112405898036935485, 924624216579956435, 14251108172073737125, 104153790666259019 }, | |
| 711 | .{ 16996739107011444789, 10015944118339042475, 2395188869672266257, 106192999311487969 }, | |
| 712 | .{ 4588314690421337879, 5339991768263654604, 15441007590670620066, 108272133262096356 }, | |
| 713 | .{ 2286159977890359825, 14329706763185060248, 5980012964059367667, 110391974208576409 }, | |
| 714 | .{ 9654767503237031099, 11293544302844823188, 11739932712678287805, 112553319146000238 }, | |
| 715 | .{ 11362964448496095896, 7990659682315657680, 251480263940996374, 114756980673665505 }, | |
| 716 | .{ 1423410421096377129, 14274395557581462179, 16553482793602208894, 117003787300607788 }, | |
| 717 | .{ 2070444190619093137, 11517140404712147401, 11657844572835578076, 119294583757094535 }, | |
| 718 | .{ 7648316884775828921, 15264332483297977688, 247182277434709002, 121630231312217685 }, | |
| 719 | .{ 17410896758132241352, 10923914482914417070, 13976383996795783649, 124011608097704390 }, | |
| 720 | .{ 9542674537907272703, 3079432708831728956, 14235189590642919676, 126439609438067572 }, | |
| 721 | .{ 10364666969937261816, 8464573184892924210, 12758646866025101190, 128915148187220428 }, | |
| 722 | .{ 14720354822146013883, 11480204489231511423, 7449876034836187038, 131439155071681461 }, | |
| 723 | .{ 1692907053653558553, 17835392458598425233, 1754856712536736598, 134012579040499057 }, | |
| 724 | .{ 5620591334531458755, 11361776175667106627, 13350215315297937856, 136636387622027174 }, | |
| 725 | .{ 17455759733928092601, 10362573084069962561, 11246018728801810510, 139311567287686283 }, | |
| 726 | .{ 2465404073814044982, 17694822665274381860, 1509954037718722697, 142039123822846312 }, | |
| 727 | .{ 2152236053329638369, 11202280800589637091, 16388426812920420176, 72410041352485523 }, | |
| 728 | .{ 17319024055671609028, 10944982848661280484, 2457150158022562661, 73827744744583080 }, | |
| 729 | .{ 17511219308535248024, 5122059497846768077, 2089605804219668451, 75273205100637900 }, | |
| 730 | .{ 10082673333144031533, 14429008783411894887, 12842832230171903890, 76746965869337783 }, | |
| 731 | .{ 16196653406315961184, 10260180891682904501, 10537411930446752461, 78249581139456266 }, | |
| 732 | .{ 15084422041749743389, 234835370106753111, 16662517110286225617, 79781615848172976 }, | |
| 733 | .{ 8199644021067702606, 3787318116274991885, 7438130039325743106, 81343645993472659 }, | |
| 734 | .{ 12039493937039359765, 9773822153580393709, 5945428874398357806, 82936258850702722 }, | |
| 735 | .{ 984543865091303961, 7975107621689454830, 6556665988501773347, 84560053193370726 }, | |
| 736 | .{ 9633317878125234244, 16099592426808915028, 9706674539190598200, 86215639518264828 }, | |
| 737 | .{ 6860695058870476186, 4471839111886709592, 7828342285492709568, 87903640274981819 }, | |
| 738 | .{ 14583324717644598331, 4496120889473451238, 5290040788305728466, 89624690099949049 }, | |
| 739 | .{ 18093669366515003715, 12879506572606942994, 18005739787089675377, 91379436055028227 }, | |
| 740 | .{ 17997493966862379937, 14646222655265145582, 10265023312844161858, 93168537870790806 }, | |
| 741 | .{ 12283848109039722318, 11290258077250314935, 9878160025624946825, 94992668194556404 }, | |
| 742 | .{ 8087752761883078164, 5262596608437575693, 11093553063763274413, 96852512843287537 }, | |
| 743 | .{ 15027787746776840781, 12250273651168257752, 9290470558712181914, 98748771061435726 }, | |
| 744 | .{ 15003915578366724489, 2937334162439764327, 5404085603526796602, 100682155783835929 }, | |
| 745 | .{ 5225610465224746757, 14932114897406142027, 2774647558180708010, 102653393903748137 }, | |
| 746 | .{ 17112957703385190360, 12069082008339002412, 3901112447086388439, 104663226546146909 }, | |
| 747 | .{ 4062324464323300238, 3992768146772240329, 15757196565593695724, 106712409346361594 }, | |
| 748 | .{ 5525364615810306701, 11855206026704935156, 11344868740897365300, 108801712734172003 }, | |
| 749 | .{ 9274143661888462646, 4478365862348432381, 18010077872551661771, 110931922223466333 }, | |
| 750 | .{ 12604141221930060148, 8930937759942591500, 9382183116147201338, 113103838707570263 }, | |
| 751 | .{ 14513929377491886653, 1410646149696279084, 587092196850797612, 115318278760358235 }, | |
| 752 | .{ 2226851524999454362, 7717102471110805679, 7187441550995571734, 117576074943260147 }, | |
| 753 | .{ 5527526061344932763, 2347100676188369132, 16976241418824030445, 119878076118278875 }, | |
| 754 | .{ 6088479778147221611, 17669593130014777580, 10991124207197663546, 122225147767136307 }, | |
| 755 | .{ 11107734086759692041, 3391795220306863431, 17233960908859089158, 124618172316667879 }, | |
| 756 | .{ 7913172514655155198, 17726879005381242552, 641069866244011540, 127058049470587962 }, | |
| 757 | .{ 12596991768458713949, 15714785522479904446, 6035972567136116512, 129545696547750811 }, | |
| 758 | .{ 16901996933781815980, 4275085211437148707, 14091642539965169063, 132082048827034281 }, | |
| 759 | .{ 7524574627987869240, 15661204384239316051, 2444526454225712267, 134668059898975949 }, | |
| 760 | .{ 8199251625090479942, 6803282222165044067, 16064817666437851504, 137304702024293857 }, | |
| 761 | .{ 4453256673338111920, 15269922543084434181, 3139961729834750852, 139992966499426682 }, | |
| 762 | .{ 15841763546372731299, 3013174075437671812, 4383755396295695606, 142733864029230733 }, | |
| 763 | .{ 9771896230907310329, 4900659362437687569, 12386126719044266361, 72764212553486967 }, | |
| 764 | .{ 9420455527449565190, 1859606122611023693, 6555040298902684281, 74188850200884818 }, | |
| 765 | .{ 5146105983135678095, 2287300449992174951, 4325371679080264751, 75641380576797959 }, | |
| 766 | .{ 11019359372592553360, 8422686425957443718, 7175176077944048210, 77122349788024458 }, | |
| 767 | .{ 11005742969399620716, 4132174559240043701, 9372258443096612118, 78632314633490790 }, | |
| 768 | .{ 8887589641394725840, 8029899502466543662, 14582206497241572853, 80171842813591127 }, | |
| 769 | .{ 360247523705545899, 12568341805293354211, 14653258284762517866, 81741513143625247 }, | |
| 770 | .{ 12314272731984275834, 4740745023227177044, 6141631472368337539, 83341915771415304 }, | |
| 771 | .{ 441052047733984759, 7940090120939869826, 11750200619921094248, 84973652399183278 }, | |
| 772 | .{ 3436657868127012749, 9187006432149937667, 16389726097323041290, 86637336509772529 }, | |
| 773 | .{ 13490220260784534044, 15339072891382896702, 8846102360835316895, 88333593597298497 }, | |
| 774 | .{ 4125672032094859833, 158347675704003277, 10592598512749774447, 90063061402315272 }, | |
| 775 | .{ 12189928252974395775, 2386931199439295891, 7009030566469913276, 91826390151586454 }, | |
| 776 | .{ 9256479608339282969, 2844900158963599229, 11148388908923225596, 93624242802550437 }, | |
| 777 | .{ 11584393507658707408, 2863659090805147914, 9873421561981063551, 95457295292572042 }, | |
| 778 | .{ 13984297296943171390, 1931468383973130608, 12905719743235082319, 97326236793074198 }, | |
| 779 | .{ 5837045222254987499, 10213498696735864176, 14893951506257020749, 99231769968645227 }, | |
| 780 | }; | |
| 781 | ||
| 782 | // Unfortunately, the results are sometimes off by one or two. We use an additional | |
| 783 | // lookup table to store those cases and adjust the result. | |
| 784 | const POW5_ERRORS: [156]u64 = .{ | |
| 785 | 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x9555596400000000, | |
| 786 | 0x65a6569525565555, 0x4415551445449655, 0x5105015504144541, 0x65a69969a6965964, | |
| 787 | 0x5054955969959656, 0x5105154515554145, 0x4055511051591555, 0x5500514455550115, | |
| 788 | 0x0041140014145515, 0x1005440545511051, 0x0014405450411004, 0x0414440010500000, | |
| 789 | 0x0044000440010040, 0x5551155000004001, 0x4554555454544114, 0x5150045544005441, | |
| 790 | 0x0001111400054501, 0x6550955555554554, 0x1504159645559559, 0x4105055141454545, | |
| 791 | 0x1411541410405454, 0x0415555044545555, 0x0014154115405550, 0x1540055040411445, | |
| 792 | 0x0000000500000000, 0x5644000000000000, 0x1155555591596555, 0x0410440054569565, | |
| 793 | 0x5145100010010005, 0x0555041405500150, 0x4141450455140450, 0x0000000144000140, | |
| 794 | 0x5114004001105410, 0x4444100404005504, 0x0414014410001015, 0x5145055155555015, | |
| 795 | 0x0141041444445540, 0x0000100451541414, 0x4105041104155550, 0x0500501150451145, | |
| 796 | 0x1001050000004114, 0x5551504400141045, 0x5110545410151454, 0x0100001400004040, | |
| 797 | 0x5040010111040000, 0x0140000150541100, 0x4400140400104110, 0x5011014405545004, | |
| 798 | 0x0000000044155440, 0x0000000010000000, 0x1100401444440001, 0x0040401010055111, | |
| 799 | 0x5155155551405454, 0x0444440015514411, 0x0054505054014101, 0x0451015441115511, | |
| 800 | 0x1541411401140551, 0x4155104514445110, 0x4141145450145515, 0x5451445055155050, | |
| 801 | 0x4400515554110054, 0x5111145104501151, 0x565a655455500501, 0x5565555555525955, | |
| 802 | 0x0550511500405695, 0x4415504051054544, 0x6555595965555554, 0x0100915915555655, | |
| 803 | 0x5540001510001001, 0x5450051414000544, 0x1405010555555551, 0x5555515555644155, | |
| 804 | 0x5555055595496555, 0x5451045004415000, 0x5450510144040144, 0x5554155555556455, | |
| 805 | 0x5051555495415555, 0x5555554555555545, 0x0000000010005455, 0x4000005000040000, | |
| 806 | 0x5565555555555954, 0x5554559555555505, 0x9645545495552555, 0x4000400055955564, | |
| 807 | 0x0040000000000001, 0x4004100100000000, 0x5540040440000411, 0x4565555955545644, | |
| 808 | 0x1140659549651556, 0x0100000410010000, 0x5555515400004001, 0x5955545555155255, | |
| 809 | 0x5151055545505556, 0x5051454510554515, 0x0501500050415554, 0x5044154005441005, | |
| 810 | 0x1455445450550455, 0x0010144055144545, 0x0000401100000004, 0x1050145050000010, | |
| 811 | 0x0415004554011540, 0x1000510100151150, 0x0100040400001144, 0x0000000000000000, | |
| 812 | 0x0550004400000100, 0x0151145041451151, 0x0000400400005450, 0x0000100044010004, | |
| 813 | 0x0100054100050040, 0x0504400005410010, 0x4011410445500105, 0x0000404000144411, | |
| 814 | 0x0101504404500000, 0x0000005044400400, 0x0000000014000100, 0x0404440414000000, | |
| 815 | 0x5554100410000140, 0x4555455544505555, 0x5454105055455455, 0x0115454155454015, | |
| 816 | 0x4404110000045100, 0x4400001100101501, 0x6596955956966a94, 0x0040655955665965, | |
| 817 | 0x5554144400100155, 0xa549495401011041, 0x5596555565955555, 0x5569965959549555, | |
| 818 | 0x969565a655555456, 0x0000001000000000, 0x0000000040000140, 0x0000040100000000, | |
| 819 | 0x1415454400000000, 0x5410415411454114, 0x0400040104000154, 0x0504045000000411, | |
| 820 | 0x0000001000000010, 0x5554000000001040, 0x5549155551556595, 0x1455541055515555, | |
| 821 | 0x0510555454554541, 0x9555555555540455, 0x6455456555556465, 0x4524565555654514, | |
| 822 | 0x5554655255559545, 0x9555455441155556, 0x0000000051515555, 0x0010005040000550, | |
| 823 | 0x5044044040000000, 0x1045040440010500, 0x0000400000040000, 0x0000000000000000, | |
| 824 | }; | |
| 825 | ||
| 826 | const GENERIC_POW5_INV_SPLIT: [89][4]u64 = .{ | |
| 827 | .{ 0, 0, 0, 144115188075855872 }, | |
| 828 | .{ 1573859546583440065, 2691002611772552616, 6763753280790178510, 141347765182270746 }, | |
| 829 | .{ 12960290449513840412, 12345512957918226762, 18057899791198622765, 138633484706040742 }, | |
| 830 | .{ 7615871757716765416, 9507132263365501332, 4879801712092008245, 135971326161092377 }, | |
| 831 | .{ 7869961150745287587, 5804035291554591636, 8883897266325833928, 133360288657597085 }, | |
| 832 | .{ 2942118023529634767, 15128191429820565086, 10638459445243230718, 130799390525667397 }, | |
| 833 | .{ 14188759758411913794, 5362791266439207815, 8068821289119264054, 128287668946279217 }, | |
| 834 | .{ 7183196927902545212, 1952291723540117099, 12075928209936341512, 125824179589281448 }, | |
| 835 | .{ 5672588001402349748, 17892323620748423487, 9874578446960390364, 123407996258356868 }, | |
| 836 | .{ 4442590541217566325, 4558254706293456445, 10343828952663182727, 121038210542800766 }, | |
| 837 | .{ 3005560928406962566, 2082271027139057888, 13961184524927245081, 118713931475986426 }, | |
| 838 | .{ 13299058168408384786, 17834349496131278595, 9029906103900731664, 116434285200389047 }, | |
| 839 | .{ 5414878118283973035, 13079825470227392078, 17897304791683760280, 114198414639042157 }, | |
| 840 | .{ 14609755883382484834, 14991702445765844156, 3269802549772755411, 112005479173303009 }, | |
| 841 | .{ 15967774957605076027, 2511532636717499923, 16221038267832563171, 109854654326805788 }, | |
| 842 | .{ 9269330061621627145, 3332501053426257392, 16223281189403734630, 107745131455483836 }, | |
| 843 | .{ 16739559299223642282, 1873986623300664530, 6546709159471442872, 105676117443544318 }, | |
| 844 | .{ 17116435360051202055, 1359075105581853924, 2038341371621886470, 103646834405281051 }, | |
| 845 | .{ 17144715798009627550, 3201623802661132408, 9757551605154622431, 101656519392613377 }, | |
| 846 | .{ 17580479792687825857, 6546633380567327312, 15099972427870912398, 99704424108241124 }, | |
| 847 | .{ 9726477118325522902, 14578369026754005435, 11728055595254428803, 97789814624307808 }, | |
| 848 | .{ 134593949518343635, 5715151379816901985, 1660163707976377376, 95911971106466306 }, | |
| 849 | .{ 5515914027713859358, 7124354893273815720, 5548463282858794077, 94070187543243255 }, | |
| 850 | .{ 6188403395862945512, 5681264392632320838, 15417410852121406654, 92263771480600430 }, | |
| 851 | .{ 15908890877468271457, 10398888261125597540, 4817794962769172309, 90492043761593298 }, | |
| 852 | .{ 1413077535082201005, 12675058125384151580, 7731426132303759597, 88754338271028867 }, | |
| 853 | .{ 1486733163972670293, 11369385300195092554, 11610016711694864110, 87050001685026843 }, | |
| 854 | .{ 8788596583757589684, 3978580923851924802, 9255162428306775812, 85378393225389919 }, | |
| 855 | .{ 7203518319660962120, 15044736224407683725, 2488132019818199792, 83738884418690858 }, | |
| 856 | .{ 4004175967662388707, 18236988667757575407, 15613100370957482671, 82130858859985791 }, | |
| 857 | .{ 18371903370586036463, 53497579022921640, 16465963977267203307, 80553711981064899 }, | |
| 858 | .{ 10170778323887491315, 1999668801648976001, 10209763593579456445, 79006850823153334 }, | |
| 859 | .{ 17108131712433974546, 16825784443029944237, 2078700786753338945, 77489693813976938 }, | |
| 860 | .{ 17221789422665858532, 12145427517550446164, 5391414622238668005, 76001670549108934 }, | |
| 861 | .{ 4859588996898795878, 1715798948121313204, 3950858167455137171, 74542221577515387 }, | |
| 862 | .{ 13513469241795711526, 631367850494860526, 10517278915021816160, 73110798191218799 }, | |
| 863 | .{ 11757513142672073111, 2581974932255022228, 17498959383193606459, 143413724438001539 }, | |
| 864 | .{ 14524355192525042817, 5640643347559376447, 1309659274756813016, 140659771648132296 }, | |
| 865 | .{ 2765095348461978538, 11021111021896007722, 3224303603779962366, 137958702611185230 }, | |
| 866 | .{ 12373410389187981037, 13679193545685856195, 11644609038462631561, 135309501808182158 }, | |
| 867 | .{ 12813176257562780151, 3754199046160268020, 9954691079802960722, 132711173221007413 }, | |
| 868 | .{ 17557452279667723458, 3237799193992485824, 17893947919029030695, 130162739957935629 }, | |
| 869 | .{ 14634200999559435155, 4123869946105211004, 6955301747350769239, 127663243886350468 }, | |
| 870 | .{ 2185352760627740240, 2864813346878886844, 13049218671329690184, 125211745272516185 }, | |
| 871 | .{ 6143438674322183002, 10464733336980678750, 6982925169933978309, 122807322428266620 }, | |
| 872 | .{ 1099509117817174576, 10202656147550524081, 754997032816608484, 120449071364478757 }, | |
| 873 | .{ 2410631293559367023, 17407273750261453804, 15307291918933463037, 118136105451200587 }, | |
| 874 | .{ 12224968375134586697, 1664436604907828062, 11506086230137787358, 115867555084305488 }, | |
| 875 | .{ 3495926216898000888, 18392536965197424288, 10992889188570643156, 113642567358547782 }, | |
| 876 | .{ 8744506286256259680, 3966568369496879937, 18342264969761820037, 111460305746896569 }, | |
| 877 | .{ 7689600520560455039, 5254331190877624630, 9628558080573245556, 109319949786027263 }, | |
| 878 | .{ 11862637625618819436, 3456120362318976488, 14690471063106001082, 107220694767852583 }, | |
| 879 | .{ 5697330450030126444, 12424082405392918899, 358204170751754904, 105161751436977040 }, | |
| 880 | .{ 11257457505097373622, 15373192700214208870, 671619062372033814, 103142345693961148 }, | |
| 881 | .{ 16850355018477166700, 1913910419361963966, 4550257919755970531, 101161718304283822 }, | |
| 882 | .{ 9670835567561997011, 10584031339132130638, 3060560222974851757, 99219124612893520 }, | |
| 883 | .{ 7698686577353054710, 11689292838639130817, 11806331021588878241, 97313834264240819 }, | |
| 884 | .{ 12233569599615692137, 3347791226108469959, 10333904326094451110, 95445130927687169 }, | |
| 885 | .{ 13049400362825383933, 17142621313007799680, 3790542585289224168, 93612312028186576 }, | |
| 886 | .{ 12430457242474442072, 5625077542189557960, 14765055286236672238, 91814688482138969 }, | |
| 887 | .{ 4759444137752473128, 2230562561567025078, 4954443037339580076, 90051584438315940 }, | |
| 888 | .{ 7246913525170274758, 8910297835195760709, 4015904029508858381, 88322337023761438 }, | |
| 889 | .{ 12854430245836432067, 8135139748065431455, 11548083631386317976, 86626296094571907 }, | |
| 890 | .{ 4848827254502687803, 4789491250196085625, 3988192420450664125, 84962823991462151 }, | |
| 891 | .{ 7435538409611286684, 904061756819742353, 14598026519493048444, 83331295300025028 }, | |
| 892 | .{ 11042616160352530997, 8948390828345326218, 10052651191118271927, 81731096615594853 }, | |
| 893 | .{ 11059348291563778943, 11696515766184685544, 3783210511290897367, 80161626312626082 }, | |
| 894 | .{ 7020010856491885826, 5025093219346041680, 8960210401638911765, 78622294318500592 }, | |
| 895 | .{ 17732844474490699984, 7820866704994446502, 6088373186798844243, 77112521891678506 }, | |
| 896 | .{ 688278527545590501, 3045610706602776618, 8684243536999567610, 75631741404109150 }, | |
| 897 | .{ 2734573255120657297, 3903146411440697663, 9470794821691856713, 74179396127820347 }, | |
| 898 | .{ 15996457521023071259, 4776627823451271680, 12394856457265744744, 72754940025605801 }, | |
| 899 | .{ 13492065758834518331, 7390517611012222399, 1630485387832860230, 142715675091463768 }, | |
| 900 | .{ 13665021627282055864, 9897834675523659302, 17907668136755296849, 139975126841173266 }, | |
| 901 | .{ 9603773719399446181, 10771916301484339398, 10672699855989487527, 137287204938390542 }, | |
| 902 | .{ 3630218541553511265, 8139010004241080614, 2876479648932814543, 134650898807055963 }, | |
| 903 | .{ 8318835909686377084, 9525369258927993371, 2796120270400437057, 132065217277054270 }, | |
| 904 | .{ 11190003059043290163, 12424345635599592110, 12539346395388933763, 129529188211565064 }, | |
| 905 | .{ 8701968833973242276, 820569587086330727, 2315591597351480110, 127041858141569228 }, | |
| 906 | .{ 5115113890115690487, 16906305245394587826, 9899749468931071388, 124602291907373862 }, | |
| 907 | .{ 15543535488939245974, 10945189844466391399, 3553863472349432246, 122209572307020975 }, | |
| 908 | .{ 7709257252608325038, 1191832167690640880, 15077137020234258537, 119862799751447719 }, | |
| 909 | .{ 7541333244210021737, 9790054727902174575, 5160944773155322014, 117561091926268545 }, | |
| 910 | .{ 12297384708782857832, 1281328873123467374, 4827925254630475769, 115303583460052092 }, | |
| 911 | .{ 13243237906232367265, 15873887428139547641, 3607993172301799599, 113089425598968120 }, | |
| 912 | .{ 11384616453739611114, 15184114243769211033, 13148448124803481057, 110917785887682141 }, | |
| 913 | .{ 17727970963596660683, 1196965221832671990, 14537830463956404138, 108787847856377790 }, | |
| 914 | .{ 17241367586707330931, 8880584684128262874, 11173506540726547818, 106698810713789254 }, | |
| 915 | .{ 7184427196661305643, 14332510582433188173, 14230167953789677901, 104649889046128358 }, | |
| 916 | }; | |
| 917 | ||
| 918 | const POW5_INV_ERRORS: [154]u64 = .{ | |
| 919 | 0x1144155514145504, 0x0000541555401141, 0x0000000000000000, 0x0154454000000000, | |
| 920 | 0x4114105515544440, 0x0001001111500415, 0x4041411410011000, 0x5550114515155014, | |
| 921 | 0x1404100041554551, 0x0515000450404410, 0x5054544401140004, 0x5155501005555105, | |
| 922 | 0x1144141000105515, 0x0541500000500000, 0x1104105540444140, 0x4000015055514110, | |
| 923 | 0x0054010450004005, 0x4155515404100005, 0x5155145045155555, 0x1511555515440558, | |
| 924 | 0x5558544555515555, 0x0000000000000010, 0x5004000000000050, 0x1415510100000010, | |
| 925 | 0x4545555444514500, 0x5155151555555551, 0x1441540144044554, 0x5150104045544400, | |
| 926 | 0x5450545401444040, 0x5554455045501400, 0x4655155555555145, 0x1000010055455055, | |
| 927 | 0x1000004000055004, 0x4455405104000005, 0x4500114504150545, 0x0000000014000000, | |
| 928 | 0x5450000000000000, 0x5514551511445555, 0x4111501040555451, 0x4515445500054444, | |
| 929 | 0x5101500104100441, 0x1545115155545055, 0x0000000000000000, 0x1554000000100000, | |
| 930 | 0x5555545595551555, 0x5555051851455955, 0x5555555555555559, 0x0000400011001555, | |
| 931 | 0x0000004400040000, 0x5455511555554554, 0x5614555544115445, 0x6455156145555155, | |
| 932 | 0x5455855455415455, 0x5515555144555545, 0x0114400000145155, 0x0000051000450511, | |
| 933 | 0x4455154554445100, 0x4554150141544455, 0x65955555559a5965, 0x5555555854559559, | |
| 934 | 0x9569654559616595, 0x1040044040005565, 0x1010010500011044, 0x1554015545154540, | |
| 935 | 0x4440555401545441, 0x1014441450550105, 0x4545400410504145, 0x5015111541040151, | |
| 936 | 0x5145051154000410, 0x1040001044545044, 0x4001400000151410, 0x0540000044040000, | |
| 937 | 0x0510555454411544, 0x0400054054141550, 0x1001041145001100, 0x0000000140000000, | |
| 938 | 0x0000000014100000, 0x1544005454000140, 0x4050055505445145, 0x0011511104504155, | |
| 939 | 0x5505544415045055, 0x1155154445515554, 0x0000000000004555, 0x0000000000000000, | |
| 940 | 0x5101010510400004, 0x1514045044440400, 0x5515519555515555, 0x4554545441555545, | |
| 941 | 0x1551055955551515, 0x0150000011505515, 0x0044005040400000, 0x0004001004010050, | |
| 942 | 0x0000051004450414, 0x0114001101001144, 0x0401000001000001, 0x4500010001000401, | |
| 943 | 0x0004100000005000, 0x0105000441101100, 0x0455455550454540, 0x5404050144105505, | |
| 944 | 0x4101510540555455, 0x1055541411451555, 0x5451445110115505, 0x1154110010101545, | |
| 945 | 0x1145140450054055, 0x5555565415551554, 0x1550559555555555, 0x5555541545045141, | |
| 946 | 0x4555455450500100, 0x5510454545554555, 0x1510140115045455, 0x1001050040111510, | |
| 947 | 0x5555454555555504, 0x9954155545515554, 0x6596656555555555, 0x0140410051555559, | |
| 948 | 0x0011104010001544, 0x965669659a680501, 0x5655a55955556955, 0x4015111014404514, | |
| 949 | 0x1414155554505145, 0x0540040011051404, 0x1010000000015005, 0x0010054050004410, | |
| 950 | 0x5041104014000100, 0x4440010500100001, 0x1155510504545554, 0x0450151545115541, | |
| 951 | 0x4000100400110440, 0x1004440010514440, 0x0000115050450000, 0x0545404455541500, | |
| 952 | 0x1051051555505101, 0x5505144554544144, 0x4550545555515550, 0x0015400450045445, | |
| 953 | 0x4514155400554415, 0x4555055051050151, 0x1511441450001014, 0x4544554510404414, | |
| 954 | 0x4115115545545450, 0x5500541555551555, 0x5550010544155015, 0x0144414045545500, | |
| 955 | 0x4154050001050150, 0x5550511111000145, 0x1114504055000151, 0x5104041101451040, | |
| 956 | 0x0010501401051441, 0x0010501450504401, 0x4554585440044444, 0x5155555951450455, | |
| 957 | 0x0040000400105555, 0x0000000000000001, | |
| 958 | }; | |
| 959 | ||
| 960 | // zig fmt: on | |
| 961 | ||
| 962 | fn check(comptime T: type, value: T, comptime expected: []const u8) !void { | |
| 963 | const I = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } }); | |
| 964 | ||
| 965 | var buf: [6000]u8 = undefined; | |
| 966 | const value_bits: I = @bitCast(value); | |
| 967 | const s = try format(&buf, value, .{}); | |
| 968 | try std.testing.expectEqualStrings(expected, s); | |
| 969 | ||
| 970 | if (@bitSizeOf(T) != 80) { | |
| 971 | const o = try std.fmt.parseFloat(T, s); | |
| 972 | const o_bits: I = @bitCast(o); | |
| 973 | ||
| 974 | if (std.math.isNan(value)) { | |
| 975 | try std.testing.expect(std.math.isNan(o)); | |
| 976 | } else { | |
| 977 | try std.testing.expectEqual(value_bits, o_bits); | |
| 978 | } | |
| 979 | } | |
| 980 | } | |
| 981 | ||
| 982 | test "format f32" { | |
| 983 | try check(f32, 0.0, "0e0"); | |
| 984 | try check(f32, -0.0, "-0e0"); | |
| 985 | try check(f32, 1.0, "1e0"); | |
| 986 | try check(f32, -1.0, "-1e0"); | |
| 987 | try check(f32, std.math.nan(f32), "nan"); | |
| 988 | try check(f32, std.math.inf(f32), "inf"); | |
| 989 | try check(f32, -std.math.inf(f32), "-inf"); | |
| 990 | try check(f32, 1.1754944e-38, "1.1754944e-38"); | |
| 991 | try check(f32, @bitCast(@as(u32, 0x7f7fffff)), "3.4028235e38"); | |
| 992 | try check(f32, @bitCast(@as(u32, 1)), "1e-45"); | |
| 993 | try check(f32, 3.355445E7, "3.355445e7"); | |
| 994 | try check(f32, 8.999999e9, "9e9"); | |
| 995 | try check(f32, 3.4366717e10, "3.436672e10"); | |
| 996 | try check(f32, 3.0540412e5, "3.0540412e5"); | |
| 997 | try check(f32, 8.0990312e3, "8.0990312e3"); | |
| 998 | try check(f32, 2.4414062e-4, "2.4414062e-4"); | |
| 999 | try check(f32, 2.4414062e-3, "2.4414062e-3"); | |
| 1000 | try check(f32, 4.3945312e-3, "4.3945312e-3"); | |
| 1001 | try check(f32, 6.3476562e-3, "6.3476562e-3"); | |
| 1002 | try check(f32, 4.7223665e21, "4.7223665e21"); | |
| 1003 | try check(f32, 8388608.0, "8.388608e6"); | |
| 1004 | try check(f32, 1.6777216e7, "1.6777216e7"); | |
| 1005 | try check(f32, 3.3554436e7, "3.3554436e7"); | |
| 1006 | try check(f32, 6.7131496e7, "6.7131496e7"); | |
| 1007 | try check(f32, 1.9310392e-38, "1.9310392e-38"); | |
| 1008 | try check(f32, -2.47e-43, "-2.47e-43"); | |
| 1009 | try check(f32, 1.993244e-38, "1.993244e-38"); | |
| 1010 | try check(f32, 4103.9003, "4.1039004e3"); | |
| 1011 | try check(f32, 5.3399997e9, "5.3399997e9"); | |
| 1012 | try check(f32, 6.0898e-39, "6.0898e-39"); | |
| 1013 | try check(f32, 0.0010310042, "1.0310042e-3"); | |
| 1014 | try check(f32, 2.8823261e17, "2.882326e17"); | |
| 1015 | try check(f32, 7.038531e-26, "7.038531e-26"); | |
| 1016 | try check(f32, 9.2234038e17, "9.223404e17"); | |
| 1017 | try check(f32, 6.7108872e7, "6.710887e7"); | |
| 1018 | try check(f32, 1.0e-44, "1e-44"); | |
| 1019 | try check(f32, 2.816025e14, "2.816025e14"); | |
| 1020 | try check(f32, 9.223372e18, "9.223372e18"); | |
| 1021 | try check(f32, 1.5846085e29, "1.5846086e29"); | |
| 1022 | try check(f32, 1.1811161e19, "1.1811161e19"); | |
| 1023 | try check(f32, 5.368709e18, "5.368709e18"); | |
| 1024 | try check(f32, 4.6143165e18, "4.6143166e18"); | |
| 1025 | try check(f32, 0.007812537, "7.812537e-3"); | |
| 1026 | try check(f32, 1.4e-45, "1e-45"); | |
| 1027 | try check(f32, 1.18697724e20, "1.18697725e20"); | |
| 1028 | try check(f32, 1.00014165e-36, "1.00014165e-36"); | |
| 1029 | try check(f32, 200.0, "2e2"); | |
| 1030 | try check(f32, 3.3554432e7, "3.3554432e7"); | |
| 1031 | ||
| 1032 | try check(f32, 1.0, "1e0"); | |
| 1033 | try check(f32, 1.2, "1.2e0"); | |
| 1034 | try check(f32, 1.23, "1.23e0"); | |
| 1035 | try check(f32, 1.234, "1.234e0"); | |
| 1036 | try check(f32, 1.2345, "1.2345e0"); | |
| 1037 | try check(f32, 1.23456, "1.23456e0"); | |
| 1038 | try check(f32, 1.234567, "1.234567e0"); | |
| 1039 | try check(f32, 1.2345678, "1.2345678e0"); | |
| 1040 | try check(f32, 1.23456735e-36, "1.23456735e-36"); | |
| 1041 | } | |
| 1042 | ||
| 1043 | test "format f64" { | |
| 1044 | try check(f64, 0.0, "0e0"); | |
| 1045 | try check(f64, -0.0, "-0e0"); | |
| 1046 | try check(f64, 1.0, "1e0"); | |
| 1047 | try check(f64, -1.0, "-1e0"); | |
| 1048 | try check(f64, std.math.nan(f64), "nan"); | |
| 1049 | try check(f64, std.math.inf(f64), "inf"); | |
| 1050 | try check(f64, -std.math.inf(f64), "-inf"); | |
| 1051 | try check(f64, 2.2250738585072014e-308, "2.2250738585072014e-308"); | |
| 1052 | try check(f64, @bitCast(@as(u64, 0x7fefffffffffffff)), "1.7976931348623157e308"); | |
| 1053 | try check(f64, @bitCast(@as(u64, 1)), "5e-324"); | |
| 1054 | try check(f64, 2.98023223876953125e-8, "2.9802322387695312e-8"); | |
| 1055 | try check(f64, -2.109808898695963e16, "-2.109808898695963e16"); | |
| 1056 | try check(f64, 4.940656e-318, "4.940656e-318"); | |
| 1057 | try check(f64, 1.18575755e-316, "1.18575755e-316"); | |
| 1058 | try check(f64, 2.989102097996e-312, "2.989102097996e-312"); | |
| 1059 | try check(f64, 9.0608011534336e15, "9.0608011534336e15"); | |
| 1060 | try check(f64, 4.708356024711512e18, "4.708356024711512e18"); | |
| 1061 | try check(f64, 9.409340012568248e18, "9.409340012568248e18"); | |
| 1062 | try check(f64, 1.2345678, "1.2345678e0"); | |
| 1063 | try check(f64, @bitCast(@as(u64, 0x4830f0cf064dd592)), "5.764607523034235e39"); | |
| 1064 | try check(f64, @bitCast(@as(u64, 0x4840f0cf064dd592)), "1.152921504606847e40"); | |
| 1065 | try check(f64, @bitCast(@as(u64, 0x4850f0cf064dd592)), "2.305843009213694e40"); | |
| 1066 | ||
| 1067 | try check(f64, 1, "1e0"); | |
| 1068 | try check(f64, 1.2, "1.2e0"); | |
| 1069 | try check(f64, 1.23, "1.23e0"); | |
| 1070 | try check(f64, 1.234, "1.234e0"); | |
| 1071 | try check(f64, 1.2345, "1.2345e0"); | |
| 1072 | try check(f64, 1.23456, "1.23456e0"); | |
| 1073 | try check(f64, 1.234567, "1.234567e0"); | |
| 1074 | try check(f64, 1.2345678, "1.2345678e0"); | |
| 1075 | try check(f64, 1.23456789, "1.23456789e0"); | |
| 1076 | try check(f64, 1.234567895, "1.234567895e0"); | |
| 1077 | try check(f64, 1.2345678901, "1.2345678901e0"); | |
| 1078 | try check(f64, 1.23456789012, "1.23456789012e0"); | |
| 1079 | try check(f64, 1.234567890123, "1.234567890123e0"); | |
| 1080 | try check(f64, 1.2345678901234, "1.2345678901234e0"); | |
| 1081 | try check(f64, 1.23456789012345, "1.23456789012345e0"); | |
| 1082 | try check(f64, 1.234567890123456, "1.234567890123456e0"); | |
| 1083 | try check(f64, 1.2345678901234567, "1.2345678901234567e0"); | |
| 1084 | ||
| 1085 | try check(f64, 4.294967294, "4.294967294e0"); | |
| 1086 | try check(f64, 4.294967295, "4.294967295e0"); | |
| 1087 | try check(f64, 4.294967296, "4.294967296e0"); | |
| 1088 | try check(f64, 4.294967297, "4.294967297e0"); | |
| 1089 | try check(f64, 4.294967298, "4.294967298e0"); | |
| 1090 | } | |
| 1091 | ||
| 1092 | test "format f80" { | |
| 1093 | try check(f80, 0.0, "0e0"); | |
| 1094 | try check(f80, -0.0, "-0e0"); | |
| 1095 | try check(f80, 1.0, "1e0"); | |
| 1096 | try check(f80, -1.0, "-1e0"); | |
| 1097 | try check(f80, std.math.nan(f80), "nan"); | |
| 1098 | try check(f80, std.math.inf(f80), "inf"); | |
| 1099 | try check(f80, -std.math.inf(f80), "-inf"); | |
| 1100 | ||
| 1101 | try check(f80, 2.2250738585072014e-308, "2.2250738585072014e-308"); | |
| 1102 | try check(f80, 2.98023223876953125e-8, "2.98023223876953125e-8"); | |
| 1103 | try check(f80, -2.109808898695963e16, "-2.109808898695963e16"); | |
| 1104 | try check(f80, 4.940656e-318, "4.940656e-318"); | |
| 1105 | try check(f80, 1.18575755e-316, "1.18575755e-316"); | |
| 1106 | try check(f80, 2.989102097996e-312, "2.989102097996e-312"); | |
| 1107 | try check(f80, 9.0608011534336e15, "9.0608011534336e15"); | |
| 1108 | try check(f80, 4.708356024711512e18, "4.708356024711512e18"); | |
| 1109 | try check(f80, 9.409340012568248e18, "9.409340012568248e18"); | |
| 1110 | try check(f80, 1.2345678, "1.2345678e0"); | |
| 1111 | } | |
| 1112 | ||
| 1113 | test "format f128" { | |
| 1114 | try check(f128, 0.0, "0e0"); | |
| 1115 | try check(f128, -0.0, "-0e0"); | |
| 1116 | try check(f128, 1.0, "1e0"); | |
| 1117 | try check(f128, -1.0, "-1e0"); | |
| 1118 | try check(f128, std.math.nan(f128), "nan"); | |
| 1119 | try check(f128, std.math.inf(f128), "inf"); | |
| 1120 | try check(f128, -std.math.inf(f128), "-inf"); | |
| 1121 | ||
| 1122 | try check(f128, 2.2250738585072014e-308, "2.2250738585072014e-308"); | |
| 1123 | try check(f128, 2.98023223876953125e-8, "2.98023223876953125e-8"); | |
| 1124 | try check(f128, -2.109808898695963e16, "-2.109808898695963e16"); | |
| 1125 | try check(f128, 4.940656e-318, "4.940656e-318"); | |
| 1126 | try check(f128, 1.18575755e-316, "1.18575755e-316"); | |
| 1127 | try check(f128, 2.989102097996e-312, "2.989102097996e-312"); | |
| 1128 | try check(f128, 9.0608011534336e15, "9.0608011534336e15"); | |
| 1129 | try check(f128, 4.708356024711512e18, "4.708356024711512e18"); | |
| 1130 | try check(f128, 9.409340012568248e18, "9.409340012568248e18"); | |
| 1131 | try check(f128, 1.2345678, "1.2345678e0"); | |
| 1132 | } | |
| 1133 | ||
| 1134 | test "format float to decimal with zero precision" { | |
| 1135 | try expectFmt("5", "{d:.0}", .{5}); | |
| 1136 | try expectFmt("6", "{d:.0}", .{6}); | |
| 1137 | try expectFmt("7", "{d:.0}", .{7}); | |
| 1138 | try expectFmt("8", "{d:.0}", .{8}); | |
| 1139 | } |