diff --git a/NOTICE b/NOTICE index 064f7ad88..04c11c8b4 100644 --- a/NOTICE +++ b/NOTICE @@ -42,6 +42,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. File random/random.mbt is adapted from Golang's [`math/rand/v2`](https://pkg.go.dev/math/rand/v2) package. +Files `internal/strconv/strconv_eisel_lemire.mbt` and +`internal/strconv/strconv_eisel_lemire_table.mbt` are adapted from Go 1.26.2's +`internal/strconv/atofeisel.go` and generated `internal/strconv/pow10tab.go`. + License from Golang: Copyright 2009 The Go Authors. diff --git a/internal/strconv/eisel_lemire_quickcheck_test.mbt b/internal/strconv/eisel_lemire_quickcheck_test.mbt new file mode 100644 index 000000000..a62d521fa --- /dev/null +++ b/internal/strconv/eisel_lemire_quickcheck_test.mbt @@ -0,0 +1,79 @@ +// Copyright 2026 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Property tests for the Eisel-Lemire fast path. +// +// `try_eisel_lemire64` is free to reject any input, but every value it +// accepts must be the correctly rounded double — bit for bit what the +// arbitrary-precision Decimal conversion produces. The oracle reaches that +// exact path through the public parser: appending 21 mantissa zeros (with +// the exponent compensating) pushes the digit count past the 19 the fast +// paths tolerate, so `parse_double` is forced onto the Decimal slow path. + +///| +fn eisel_lemire_is_exact( + mantissa : UInt64, + exponent : Int, + negative : Bool, +) -> Bool { + let fast = @strconv.try_eisel_lemire64( + mantissa, + exponent.to_int64(), + negative, + ) + if fast.is_nan() { + // Rejection is always allowed: those inputs stay on the exact fallback. + return true + } + let sign = if negative { "-" } else { "" } + let padded = "\{sign}\{mantissa}\{repeat_char('0', 21)}e\{exponent - 21}" + parsed(padded) is Some(exact) && same_double(fast, exact) +} + +///| +/// Whatever the fast path accepts must match the exact conversion. +test "quickcheck: accepted Eisel-Lemire values are correctly rounded" { + @quickcheck.check( + (input : (UInt64, Int, Int, Bool)) => { + let (raw, shift_code, exp_code, negative) = input + // The shift spreads mantissas across every magnitude, including the + // small values a uniform UInt64 almost never produces. + let mantissa = raw >> wrap_index(shift_code, 64) + // Exponents overshoot the table range (-348..=347) on both sides so + // the bounds check is exercised alongside the conversion. + let exponent = wrap_index(exp_code, 723) - 361 + eisel_lemire_is_exact(mantissa, exponent, negative) + }, + count=20000, + ) +} + +///| +/// Mantissas next to powers of two sit on binade boundaries, where rounding +/// carries into the next exponent and halfway cases cluster; the ambiguity +/// rejection has to fire exactly there. +test "quickcheck: Eisel-Lemire stays exact near binade boundaries" { + @quickcheck.check( + (input : (Int, Int, Int, Bool)) => { + let (bit_code, delta_code, exp_code, negative) = input + let base = 1UL << wrap_index(bit_code, 64) + let delta = (wrap_index(delta_code, 9) - 4).to_int64() + // Wrapping addition is fine: any UInt64 is a valid mantissa. + let mantissa = base + delta.reinterpret_as_uint64() + let exponent = wrap_index(exp_code, 723) - 361 + eisel_lemire_is_exact(mantissa, exponent, negative) + }, + count=20000, + ) +} diff --git a/internal/strconv/parse_double_bench_test.mbt b/internal/strconv/parse_double_bench_test.mbt index d545377df..fde64d9e5 100644 --- a/internal/strconv/parse_double_bench_test.mbt +++ b/internal/strconv/parse_double_bench_test.mbt @@ -27,6 +27,12 @@ let parse_double_underscore_bench_inputs : FixedArray[String] = [ "123_456_789_012_345e-2", "876_543_210_987_654e-3", "1_234_567_890_123e+2", "7_654_321_098_765e-1", ] +///| +let parse_double_long_mantissa_bench_inputs : FixedArray[String] = [ + "-65.613616999999977", "43.420273000000009", "-65.619720000000029", "43.418052999999986", + "-65.625000000000000", "43.412101000000000", "-65.630279999999994", "43.406101000000010", +] + ///| fn parse_double_bench_sum(inputs : FixedArray[String]) -> Double { let mut sum = 0.0 @@ -51,3 +57,10 @@ test "bench parse_double underscores n=4096" (it : @bench.T) { it.keep(parse_double_bench_sum(parse_double_underscore_bench_inputs)) }) } + +///| +test "bench parse_double long mantissa n=4096" (it : @bench.T) { + it.bench(fn() { + it.keep(parse_double_bench_sum(parse_double_long_mantissa_bench_inputs)) + }) +} diff --git a/internal/strconv/strconv_double.mbt b/internal/strconv/strconv_double.mbt index 156a47328..676d87ef4 100644 --- a/internal/strconv/strconv_double.mbt +++ b/internal/strconv/strconv_double.mbt @@ -79,7 +79,18 @@ pub fn parse_double(str : StringView) -> Double raise { // Clinger's fast path (How to read floating point numbers accurately)[https://doi.org/10.1145/989393.989430] match num.try_fast_path() { Some(value) => value - None => parse_decimal_priv(str).to_double_priv() // fallback to slow path + None => { + let fast = if num.many_digits { + @double.not_a_number + } else { + try_eisel_lemire64(num.mantissa, num.exponent, num.negative) + } + if fast.is_nan() { + parse_decimal_priv(str).to_double_priv() // fallback to slow path + } else { + fast + } + } } } } diff --git a/internal/strconv/strconv_eisel_lemire.mbt b/internal/strconv/strconv_eisel_lemire.mbt new file mode 100644 index 000000000..54fa6d203 --- /dev/null +++ b/internal/strconv/strconv_eisel_lemire.mbt @@ -0,0 +1,128 @@ +// Copyright 2026 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +///| +#valtype +priv struct EiselProduct { + lo : UInt64 + hi : UInt64 +} + +///| +fn eisel_umul128(a : UInt64, b : UInt64) -> EiselProduct { + let a_lo = a & 0xffffffffUL + let a_hi = a >> 32 + let b_lo = b & 0xffffffffUL + let b_hi = b >> 32 + let x = a_lo * b_lo + let y = a_hi * b_lo + (x >> 32) + let z = a_lo * b_hi + (y & 0xffffffffUL) + let hi = a_hi * b_hi + (y >> 32) + (z >> 32) + { lo: a * b, hi } +} + +///| +fn eisel_mul_log2_10(exponent : Int) -> Int { + // floor(exponent * log2(10)) for -500 <= exponent <= 500. + (exponent * 108853) >> 15 +} + +///| +/// Attempts Eisel-Lemire conversion of `mantissa * 10^exponent`. +/// +/// A NaN result is a private failure sentinel. The algorithm deliberately +/// rejects values whose correct rounding cannot be certified; callers must +/// retain an exact Decimal fallback for those inputs. +#doc(hidden) +pub fn try_eisel_lemire64( + mantissa : UInt64, + exponent : Int64, + negative : Bool, +) -> Double { + if mantissa == 0UL { + return if negative { + 0x8000000000000000UL.reinterpret_as_double() + } else { + 0.0 + } + } + if exponent < EISEL_LEMIRE_POW10_MIN.to_int64() || + exponent > EISEL_LEMIRE_POW10_MAX.to_int64() { + return @double.not_a_number + } + let exponent = exponent.to_int() + let table_index = (exponent - EISEL_LEMIRE_POW10_MIN) * 2 + let pow_hi = eisel_lemire_pow10_table[table_index] + let pow_lo = eisel_lemire_pow10_table[table_index + 1] + let pow_exp2 = 1 + eisel_mul_log2_10(exponent) + + // Normalize the decimal mantissa so its most significant bit is set. + let leading_zeros = mantissa.clz() + let normalized = mantissa << leading_zeros + let mut result_exp2 = pow_exp2 + 63 + 1023 - leading_zeros + + let product = eisel_umul128(normalized, pow_hi) + let mut product_hi = product.hi + let mut product_lo = product.lo + + // Use the low limb of the cached power when the first product does not + // contain enough information to determine the rounded result. + if (product_hi & 0x1ffUL) == 0x1ffUL && product_lo + normalized < normalized { + let wider = eisel_umul128(normalized, pow_lo) + let mut merged_hi = product_hi + let merged_lo = product_lo + wider.hi + if merged_lo < product_lo { + merged_hi += 1UL + } + if (merged_hi & 0x1ffUL) == 0x1ffUL && + merged_lo + 1UL == 0UL && + wider.lo + normalized < normalized { + return @double.not_a_number + } + product_hi = merged_hi + product_lo = merged_lo + } + + // Keep 54 significant bits, then round down to the binary64 precision. + let top_bit = (product_hi >> 63).to_int() + let mut result_mantissa = product_hi >> (top_bit + 9) + result_exp2 -= 1 - top_bit + + // An exact halfway case needs the Decimal fallback to resolve ties safely. + if product_lo == 0UL && + (product_hi & 0x1ffUL) == 0UL && + (result_mantissa & 3UL) == 1UL { + return @double.not_a_number + } + + result_mantissa += result_mantissa & 1UL + result_mantissa = result_mantissa >> 1 + if result_mantissa >> 53 > 0UL { + result_mantissa = result_mantissa >> 1 + result_exp2 += 1 + } + + // Subnormal, overflow, and special-value boundaries remain on the exact + // fallback path. + if result_exp2 <= 0 || result_exp2 >= 0x7ff { + return @double.not_a_number + } + let exponent_bits = UInt64::extend_uint(result_exp2.reinterpret_as_uint()) << + 52 + let mut result_bits = exponent_bits | (result_mantissa & 0x000fffffffffffffUL) + if negative { + result_bits = result_bits | 0x8000000000000000UL + } + result_bits.reinterpret_as_double() +} diff --git a/internal/strconv/strconv_eisel_lemire_table.mbt b/internal/strconv/strconv_eisel_lemire_table.mbt new file mode 100644 index 000000000..82c6cc10d --- /dev/null +++ b/internal/strconv/strconv_eisel_lemire_table.mbt @@ -0,0 +1,723 @@ +// Copyright 2026 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated from Go's internal/strconv/pow10tab.go. DO NOT EDIT. + +///| +const EISEL_LEMIRE_POW10_MIN : Int = -348 + +///| +const EISEL_LEMIRE_POW10_MAX : Int = 347 + +///| +// Flat pairs of high and low UInt64 limbs. Each pair is a 128-bit mantissa +// of 10^e, scaled so that its high bit is set. +let eisel_lemire_pow10_table : ReadOnlyArray[UInt64] = [ + 0xfa8fd5a0081c0288UL, 0x1732c869cd60e453UL, // 1e-348 * 2**1284 + 0x9c99e58405118195UL, 0x0e7fbd42205c8eb4UL, // 1e-347 * 2**1280 + 0xc3c05ee50655e1faUL, 0x521fac92a873b261UL, // 1e-346 * 2**1277 + 0xf4b0769e47eb5a78UL, 0xe6a797b752909ef9UL, // 1e-345 * 2**1274 + 0x98ee4a22ecf3188bUL, 0x9028bed2939a635cUL, // 1e-344 * 2**1270 + 0xbf29dcaba82fdeaeUL, 0x7432ee873880fc33UL, // 1e-343 * 2**1267 + 0xeef453d6923bd65aUL, 0x113faa2906a13b3fUL, // 1e-342 * 2**1264 + 0x9558b4661b6565f8UL, 0x4ac7ca59a424c507UL, // 1e-341 * 2**1260 + 0xbaaee17fa23ebf76UL, 0x5d79bcf00d2df649UL, // 1e-340 * 2**1257 + 0xe95a99df8ace6f53UL, 0xf4d82c2c107973dcUL, // 1e-339 * 2**1254 + 0x91d8a02bb6c10594UL, 0x79071b9b8a4be869UL, // 1e-338 * 2**1250 + 0xb64ec836a47146f9UL, 0x9748e2826cdee284UL, // 1e-337 * 2**1247 + 0xe3e27a444d8d98b7UL, 0xfd1b1b2308169b25UL, // 1e-336 * 2**1244 + 0x8e6d8c6ab0787f72UL, 0xfe30f0f5e50e20f7UL, // 1e-335 * 2**1240 + 0xb208ef855c969f4fUL, 0xbdbd2d335e51a935UL, // 1e-334 * 2**1237 + 0xde8b2b66b3bc4723UL, 0xad2c788035e61382UL, // 1e-333 * 2**1234 + 0x8b16fb203055ac76UL, 0x4c3bcb5021afcc31UL, // 1e-332 * 2**1230 + 0xaddcb9e83c6b1793UL, 0xdf4abe242a1bbf3dUL, // 1e-331 * 2**1227 + 0xd953e8624b85dd78UL, 0xd71d6dad34a2af0dUL, // 1e-330 * 2**1224 + 0x87d4713d6f33aa6bUL, 0x8672648c40e5ad68UL, // 1e-329 * 2**1220 + 0xa9c98d8ccb009506UL, 0x680efdaf511f18c2UL, // 1e-328 * 2**1217 + 0xd43bf0effdc0ba48UL, 0x0212bd1b2566def2UL, // 1e-327 * 2**1214 + 0x84a57695fe98746dUL, 0x014bb630f7604b57UL, // 1e-326 * 2**1210 + 0xa5ced43b7e3e9188UL, 0x419ea3bd35385e2dUL, // 1e-325 * 2**1207 + 0xcf42894a5dce35eaUL, 0x52064cac828675b9UL, // 1e-324 * 2**1204 + 0x818995ce7aa0e1b2UL, 0x7343efebd1940993UL, // 1e-323 * 2**1200 + 0xa1ebfb4219491a1fUL, 0x1014ebe6c5f90bf8UL, // 1e-322 * 2**1197 + 0xca66fa129f9b60a6UL, 0xd41a26e077774ef6UL, // 1e-321 * 2**1194 + 0xfd00b897478238d0UL, 0x8920b098955522b4UL, // 1e-320 * 2**1191 + 0x9e20735e8cb16382UL, 0x55b46e5f5d5535b0UL, // 1e-319 * 2**1187 + 0xc5a890362fddbc62UL, 0xeb2189f734aa831dUL, // 1e-318 * 2**1184 + 0xf712b443bbd52b7bUL, 0xa5e9ec7501d523e4UL, // 1e-317 * 2**1181 + 0x9a6bb0aa55653b2dUL, 0x47b233c92125366eUL, // 1e-316 * 2**1177 + 0xc1069cd4eabe89f8UL, 0x999ec0bb696e840aUL, // 1e-315 * 2**1174 + 0xf148440a256e2c76UL, 0xc00670ea43ca250dUL, // 1e-314 * 2**1171 + 0x96cd2a865764dbcaUL, 0x380406926a5e5728UL, // 1e-313 * 2**1167 + 0xbc807527ed3e12bcUL, 0xc605083704f5ecf2UL, // 1e-312 * 2**1164 + 0xeba09271e88d976bUL, 0xf7864a44c633682eUL, // 1e-311 * 2**1161 + 0x93445b8731587ea3UL, 0x7ab3ee6afbe0211dUL, // 1e-310 * 2**1157 + 0xb8157268fdae9e4cUL, 0x5960ea05bad82964UL, // 1e-309 * 2**1154 + 0xe61acf033d1a45dfUL, 0x6fb92487298e33bdUL, // 1e-308 * 2**1151 + 0x8fd0c16206306babUL, 0xa5d3b6d479f8e056UL, // 1e-307 * 2**1147 + 0xb3c4f1ba87bc8696UL, 0x8f48a4899877186cUL, // 1e-306 * 2**1144 + 0xe0b62e2929aba83cUL, 0x331acdabfe94de87UL, // 1e-305 * 2**1141 + 0x8c71dcd9ba0b4925UL, 0x9ff0c08b7f1d0b14UL, // 1e-304 * 2**1137 + 0xaf8e5410288e1b6fUL, 0x07ecf0ae5ee44dd9UL, // 1e-303 * 2**1134 + 0xdb71e91432b1a24aUL, 0xc9e82cd9f69d6150UL, // 1e-302 * 2**1131 + 0x892731ac9faf056eUL, 0xbe311c083a225cd2UL, // 1e-301 * 2**1127 + 0xab70fe17c79ac6caUL, 0x6dbd630a48aaf406UL, // 1e-300 * 2**1124 + 0xd64d3d9db981787dUL, 0x092cbbccdad5b108UL, // 1e-299 * 2**1121 + 0x85f0468293f0eb4eUL, 0x25bbf56008c58ea5UL, // 1e-298 * 2**1117 + 0xa76c582338ed2621UL, 0xaf2af2b80af6f24eUL, // 1e-297 * 2**1114 + 0xd1476e2c07286faaUL, 0x1af5af660db4aee1UL, // 1e-296 * 2**1111 + 0x82cca4db847945caUL, 0x50d98d9fc890ed4dUL, // 1e-295 * 2**1107 + 0xa37fce126597973cUL, 0xe50ff107bab528a0UL, // 1e-294 * 2**1104 + 0xcc5fc196fefd7d0cUL, 0x1e53ed49a96272c8UL, // 1e-293 * 2**1101 + 0xff77b1fcbebcdc4fUL, 0x25e8e89c13bb0f7aUL, // 1e-292 * 2**1098 + 0x9faacf3df73609b1UL, 0x77b191618c54e9acUL, // 1e-291 * 2**1094 + 0xc795830d75038c1dUL, 0xd59df5b9ef6a2417UL, // 1e-290 * 2**1091 + 0xf97ae3d0d2446f25UL, 0x4b0573286b44ad1dUL, // 1e-289 * 2**1088 + 0x9becce62836ac577UL, 0x4ee367f9430aec32UL, // 1e-288 * 2**1084 + 0xc2e801fb244576d5UL, 0x229c41f793cda73fUL, // 1e-287 * 2**1081 + 0xf3a20279ed56d48aUL, 0x6b43527578c1110fUL, // 1e-286 * 2**1078 + 0x9845418c345644d6UL, 0x830a13896b78aaa9UL, // 1e-285 * 2**1074 + 0xbe5691ef416bd60cUL, 0x23cc986bc656d553UL, // 1e-284 * 2**1071 + 0xedec366b11c6cb8fUL, 0x2cbfbe86b7ec8aa8UL, // 1e-283 * 2**1068 + 0x94b3a202eb1c3f39UL, 0x7bf7d71432f3d6a9UL, // 1e-282 * 2**1064 + 0xb9e08a83a5e34f07UL, 0xdaf5ccd93fb0cc53UL, // 1e-281 * 2**1061 + 0xe858ad248f5c22c9UL, 0xd1b3400f8f9cff68UL, // 1e-280 * 2**1058 + 0x91376c36d99995beUL, 0x23100809b9c21fa1UL, // 1e-279 * 2**1054 + 0xb58547448ffffb2dUL, 0xabd40a0c2832a78aUL, // 1e-278 * 2**1051 + 0xe2e69915b3fff9f9UL, 0x16c90c8f323f516cUL, // 1e-277 * 2**1048 + 0x8dd01fad907ffc3bUL, 0xae3da7d97f6792e3UL, // 1e-276 * 2**1044 + 0xb1442798f49ffb4aUL, 0x99cd11cfdf41779cUL, // 1e-275 * 2**1041 + 0xdd95317f31c7fa1dUL, 0x40405643d711d583UL, // 1e-274 * 2**1038 + 0x8a7d3eef7f1cfc52UL, 0x482835ea666b2572UL, // 1e-273 * 2**1034 + 0xad1c8eab5ee43b66UL, 0xda3243650005eecfUL, // 1e-272 * 2**1031 + 0xd863b256369d4a40UL, 0x90bed43e40076a82UL, // 1e-271 * 2**1028 + 0x873e4f75e2224e68UL, 0x5a7744a6e804a291UL, // 1e-270 * 2**1024 + 0xa90de3535aaae202UL, 0x711515d0a205cb36UL, // 1e-269 * 2**1021 + 0xd3515c2831559a83UL, 0x0d5a5b44ca873e03UL, // 1e-268 * 2**1018 + 0x8412d9991ed58091UL, 0xe858790afe9486c2UL, // 1e-267 * 2**1014 + 0xa5178fff668ae0b6UL, 0x626e974dbe39a872UL, // 1e-266 * 2**1011 + 0xce5d73ff402d98e3UL, 0xfb0a3d212dc8128fUL, // 1e-265 * 2**1008 + 0x80fa687f881c7f8eUL, 0x7ce66634bc9d0b99UL, // 1e-264 * 2**1004 + 0xa139029f6a239f72UL, 0x1c1fffc1ebc44e80UL, // 1e-263 * 2**1001 + 0xc987434744ac874eUL, 0xa327ffb266b56220UL, // 1e-262 * 2**998 + 0xfbe9141915d7a922UL, 0x4bf1ff9f0062baa8UL, // 1e-261 * 2**995 + 0x9d71ac8fada6c9b5UL, 0x6f773fc3603db4a9UL, // 1e-260 * 2**991 + 0xc4ce17b399107c22UL, 0xcb550fb4384d21d3UL, // 1e-259 * 2**988 + 0xf6019da07f549b2bUL, 0x7e2a53a146606a48UL, // 1e-258 * 2**985 + 0x99c102844f94e0fbUL, 0x2eda7444cbfc426dUL, // 1e-257 * 2**981 + 0xc0314325637a1939UL, 0xfa911155fefb5308UL, // 1e-256 * 2**978 + 0xf03d93eebc589f88UL, 0x793555ab7eba27caUL, // 1e-255 * 2**975 + 0x96267c7535b763b5UL, 0x4bc1558b2f3458deUL, // 1e-254 * 2**971 + 0xbbb01b9283253ca2UL, 0x9eb1aaedfb016f16UL, // 1e-253 * 2**968 + 0xea9c227723ee8bcbUL, 0x465e15a979c1cadcUL, // 1e-252 * 2**965 + 0x92a1958a7675175fUL, 0x0bfacd89ec191ec9UL, // 1e-251 * 2**961 + 0xb749faed14125d36UL, 0xcef980ec671f667bUL, // 1e-250 * 2**958 + 0xe51c79a85916f484UL, 0x82b7e12780e7401aUL, // 1e-249 * 2**955 + 0x8f31cc0937ae58d2UL, 0xd1b2ecb8b0908810UL, // 1e-248 * 2**951 + 0xb2fe3f0b8599ef07UL, 0x861fa7e6dcb4aa15UL, // 1e-247 * 2**948 + 0xdfbdcece67006ac9UL, 0x67a791e093e1d49aUL, // 1e-246 * 2**945 + 0x8bd6a141006042bdUL, 0xe0c8bb2c5c6d24e0UL, // 1e-245 * 2**941 + 0xaecc49914078536dUL, 0x58fae9f773886e18UL, // 1e-244 * 2**938 + 0xda7f5bf590966848UL, 0xaf39a475506a899eUL, // 1e-243 * 2**935 + 0x888f99797a5e012dUL, 0x6d8406c952429603UL, // 1e-242 * 2**931 + 0xaab37fd7d8f58178UL, 0xc8e5087ba6d33b83UL, // 1e-241 * 2**928 + 0xd5605fcdcf32e1d6UL, 0xfb1e4a9a90880a64UL, // 1e-240 * 2**925 + 0x855c3be0a17fcd26UL, 0x5cf2eea09a55067fUL, // 1e-239 * 2**921 + 0xa6b34ad8c9dfc06fUL, 0xf42faa48c0ea481eUL, // 1e-238 * 2**918 + 0xd0601d8efc57b08bUL, 0xf13b94daf124da26UL, // 1e-237 * 2**915 + 0x823c12795db6ce57UL, 0x76c53d08d6b70858UL, // 1e-236 * 2**911 + 0xa2cb1717b52481edUL, 0x54768c4b0c64ca6eUL, // 1e-235 * 2**908 + 0xcb7ddcdda26da268UL, 0xa9942f5dcf7dfd09UL, // 1e-234 * 2**905 + 0xfe5d54150b090b02UL, 0xd3f93b35435d7c4cUL, // 1e-233 * 2**902 + 0x9efa548d26e5a6e1UL, 0xc47bc5014a1a6dafUL, // 1e-232 * 2**898 + 0xc6b8e9b0709f109aUL, 0x359ab6419ca1091bUL, // 1e-231 * 2**895 + 0xf867241c8cc6d4c0UL, 0xc30163d203c94b62UL, // 1e-230 * 2**892 + 0x9b407691d7fc44f8UL, 0x79e0de63425dcf1dUL, // 1e-229 * 2**888 + 0xc21094364dfb5636UL, 0x985915fc12f542e4UL, // 1e-228 * 2**885 + 0xf294b943e17a2bc4UL, 0x3e6f5b7b17b2939dUL, // 1e-227 * 2**882 + 0x979cf3ca6cec5b5aUL, 0xa705992ceecf9c42UL, // 1e-226 * 2**878 + 0xbd8430bd08277231UL, 0x50c6ff782a838353UL, // 1e-225 * 2**875 + 0xece53cec4a314ebdUL, 0xa4f8bf5635246428UL, // 1e-224 * 2**872 + 0x940f4613ae5ed136UL, 0x871b7795e136be99UL, // 1e-223 * 2**868 + 0xb913179899f68584UL, 0x28e2557b59846e3fUL, // 1e-222 * 2**865 + 0xe757dd7ec07426e5UL, 0x331aeada2fe589cfUL, // 1e-221 * 2**862 + 0x9096ea6f3848984fUL, 0x3ff0d2c85def7621UL, // 1e-220 * 2**858 + 0xb4bca50b065abe63UL, 0x0fed077a756b53a9UL, // 1e-219 * 2**855 + 0xe1ebce4dc7f16dfbUL, 0xd3e8495912c62894UL, // 1e-218 * 2**852 + 0x8d3360f09cf6e4bdUL, 0x64712dd7abbbd95cUL, // 1e-217 * 2**848 + 0xb080392cc4349decUL, 0xbd8d794d96aacfb3UL, // 1e-216 * 2**845 + 0xdca04777f541c567UL, 0xecf0d7a0fc5583a0UL, // 1e-215 * 2**842 + 0x89e42caaf9491b60UL, 0xf41686c49db57244UL, // 1e-214 * 2**838 + 0xac5d37d5b79b6239UL, 0x311c2875c522ced5UL, // 1e-213 * 2**835 + 0xd77485cb25823ac7UL, 0x7d633293366b828bUL, // 1e-212 * 2**832 + 0x86a8d39ef77164bcUL, 0xae5dff9c02033197UL, // 1e-211 * 2**828 + 0xa8530886b54dbdebUL, 0xd9f57f830283fdfcUL, // 1e-210 * 2**825 + 0xd267caa862a12d66UL, 0xd072df63c324fd7bUL, // 1e-209 * 2**822 + 0x8380dea93da4bc60UL, 0x4247cb9e59f71e6dUL, // 1e-208 * 2**818 + 0xa46116538d0deb78UL, 0x52d9be85f074e608UL, // 1e-207 * 2**815 + 0xcd795be870516656UL, 0x67902e276c921f8bUL, // 1e-206 * 2**812 + 0x806bd9714632dff6UL, 0x00ba1cd8a3db53b6UL, // 1e-205 * 2**808 + 0xa086cfcd97bf97f3UL, 0x80e8a40eccd228a4UL, // 1e-204 * 2**805 + 0xc8a883c0fdaf7df0UL, 0x6122cd128006b2cdUL, // 1e-203 * 2**802 + 0xfad2a4b13d1b5d6cUL, 0x796b805720085f81UL, // 1e-202 * 2**799 + 0x9cc3a6eec6311a63UL, 0xcbe3303674053bb0UL, // 1e-201 * 2**795 + 0xc3f490aa77bd60fcUL, 0xbedbfc4411068a9cUL, // 1e-200 * 2**792 + 0xf4f1b4d515acb93bUL, 0xee92fb5515482d44UL, // 1e-199 * 2**789 + 0x991711052d8bf3c5UL, 0x751bdd152d4d1c4aUL, // 1e-198 * 2**785 + 0xbf5cd54678eef0b6UL, 0xd262d45a78a0635dUL, // 1e-197 * 2**782 + 0xef340a98172aace4UL, 0x86fb897116c87c34UL, // 1e-196 * 2**779 + 0x9580869f0e7aac0eUL, 0xd45d35e6ae3d4da0UL, // 1e-195 * 2**775 + 0xbae0a846d2195712UL, 0x8974836059cca109UL, // 1e-194 * 2**772 + 0xe998d258869facd7UL, 0x2bd1a438703fc94bUL, // 1e-193 * 2**769 + 0x91ff83775423cc06UL, 0x7b6306a34627ddcfUL, // 1e-192 * 2**765 + 0xb67f6455292cbf08UL, 0x1a3bc84c17b1d542UL, // 1e-191 * 2**762 + 0xe41f3d6a7377eecaUL, 0x20caba5f1d9e4a93UL, // 1e-190 * 2**759 + 0x8e938662882af53eUL, 0x547eb47b7282ee9cUL, // 1e-189 * 2**755 + 0xb23867fb2a35b28dUL, 0xe99e619a4f23aa43UL, // 1e-188 * 2**752 + 0xdec681f9f4c31f31UL, 0x6405fa00e2ec94d4UL, // 1e-187 * 2**749 + 0x8b3c113c38f9f37eUL, 0xde83bc408dd3dd04UL, // 1e-186 * 2**745 + 0xae0b158b4738705eUL, 0x9624ab50b148d445UL, // 1e-185 * 2**742 + 0xd98ddaee19068c76UL, 0x3badd624dd9b0957UL, // 1e-184 * 2**739 + 0x87f8a8d4cfa417c9UL, 0xe54ca5d70a80e5d6UL, // 1e-183 * 2**735 + 0xa9f6d30a038d1dbcUL, 0x5e9fcf4ccd211f4cUL, // 1e-182 * 2**732 + 0xd47487cc8470652bUL, 0x7647c3200069671fUL, // 1e-181 * 2**729 + 0x84c8d4dfd2c63f3bUL, 0x29ecd9f40041e073UL, // 1e-180 * 2**725 + 0xa5fb0a17c777cf09UL, 0xf468107100525890UL, // 1e-179 * 2**722 + 0xcf79cc9db955c2ccUL, 0x7182148d4066eeb4UL, // 1e-178 * 2**719 + 0x81ac1fe293d599bfUL, 0xc6f14cd848405530UL, // 1e-177 * 2**715 + 0xa21727db38cb002fUL, 0xb8ada00e5a506a7cUL, // 1e-176 * 2**712 + 0xca9cf1d206fdc03bUL, 0xa6d90811f0e4851cUL, // 1e-175 * 2**709 + 0xfd442e4688bd304aUL, 0x908f4a166d1da663UL, // 1e-174 * 2**706 + 0x9e4a9cec15763e2eUL, 0x9a598e4e043287feUL, // 1e-173 * 2**702 + 0xc5dd44271ad3cdbaUL, 0x40eff1e1853f29fdUL, // 1e-172 * 2**699 + 0xf7549530e188c128UL, 0xd12bee59e68ef47cUL, // 1e-171 * 2**696 + 0x9a94dd3e8cf578b9UL, 0x82bb74f8301958ceUL, // 1e-170 * 2**692 + 0xc13a148e3032d6e7UL, 0xe36a52363c1faf01UL, // 1e-169 * 2**689 + 0xf18899b1bc3f8ca1UL, 0xdc44e6c3cb279ac1UL, // 1e-168 * 2**686 + 0x96f5600f15a7b7e5UL, 0x29ab103a5ef8c0b9UL, // 1e-167 * 2**682 + 0xbcb2b812db11a5deUL, 0x7415d448f6b6f0e7UL, // 1e-166 * 2**679 + 0xebdf661791d60f56UL, 0x111b495b3464ad21UL, // 1e-165 * 2**676 + 0x936b9fcebb25c995UL, 0xcab10dd900beec34UL, // 1e-164 * 2**672 + 0xb84687c269ef3bfbUL, 0x3d5d514f40eea742UL, // 1e-163 * 2**669 + 0xe65829b3046b0afaUL, 0x0cb4a5a3112a5112UL, // 1e-162 * 2**666 + 0x8ff71a0fe2c2e6dcUL, 0x47f0e785eaba72abUL, // 1e-161 * 2**662 + 0xb3f4e093db73a093UL, 0x59ed216765690f56UL, // 1e-160 * 2**659 + 0xe0f218b8d25088b8UL, 0x306869c13ec3532cUL, // 1e-159 * 2**656 + 0x8c974f7383725573UL, 0x1e414218c73a13fbUL, // 1e-158 * 2**652 + 0xafbd2350644eeacfUL, 0xe5d1929ef90898faUL, // 1e-157 * 2**649 + 0xdbac6c247d62a583UL, 0xdf45f746b74abf39UL, // 1e-156 * 2**646 + 0x894bc396ce5da772UL, 0x6b8bba8c328eb783UL, // 1e-155 * 2**642 + 0xab9eb47c81f5114fUL, 0x066ea92f3f326564UL, // 1e-154 * 2**639 + 0xd686619ba27255a2UL, 0xc80a537b0efefebdUL, // 1e-153 * 2**636 + 0x8613fd0145877585UL, 0xbd06742ce95f5f36UL, // 1e-152 * 2**632 + 0xa798fc4196e952e7UL, 0x2c48113823b73704UL, // 1e-151 * 2**629 + 0xd17f3b51fca3a7a0UL, 0xf75a15862ca504c5UL, // 1e-150 * 2**626 + 0x82ef85133de648c4UL, 0x9a984d73dbe722fbUL, // 1e-149 * 2**622 + 0xa3ab66580d5fdaf5UL, 0xc13e60d0d2e0ebbaUL, // 1e-148 * 2**619 + 0xcc963fee10b7d1b3UL, 0x318df905079926a8UL, // 1e-147 * 2**616 + 0xffbbcfe994e5c61fUL, 0xfdf17746497f7052UL, // 1e-146 * 2**613 + 0x9fd561f1fd0f9bd3UL, 0xfeb6ea8bedefa633UL, // 1e-145 * 2**609 + 0xc7caba6e7c5382c8UL, 0xfe64a52ee96b8fc0UL, // 1e-144 * 2**606 + 0xf9bd690a1b68637bUL, 0x3dfdce7aa3c673b0UL, // 1e-143 * 2**603 + 0x9c1661a651213e2dUL, 0x06bea10ca65c084eUL, // 1e-142 * 2**599 + 0xc31bfa0fe5698db8UL, 0x486e494fcff30a62UL, // 1e-141 * 2**596 + 0xf3e2f893dec3f126UL, 0x5a89dba3c3efccfaUL, // 1e-140 * 2**593 + 0x986ddb5c6b3a76b7UL, 0xf89629465a75e01cUL, // 1e-139 * 2**589 + 0xbe89523386091465UL, 0xf6bbb397f1135823UL, // 1e-138 * 2**586 + 0xee2ba6c0678b597fUL, 0x746aa07ded582e2cUL, // 1e-137 * 2**583 + 0x94db483840b717efUL, 0xa8c2a44eb4571cdcUL, // 1e-136 * 2**579 + 0xba121a4650e4ddebUL, 0x92f34d62616ce413UL, // 1e-135 * 2**576 + 0xe896a0d7e51e1566UL, 0x77b020baf9c81d17UL, // 1e-134 * 2**573 + 0x915e2486ef32cd60UL, 0x0ace1474dc1d122eUL, // 1e-133 * 2**569 + 0xb5b5ada8aaff80b8UL, 0x0d819992132456baUL, // 1e-132 * 2**566 + 0xe3231912d5bf60e6UL, 0x10e1fff697ed6c69UL, // 1e-131 * 2**563 + 0x8df5efabc5979c8fUL, 0xca8d3ffa1ef463c1UL, // 1e-130 * 2**559 + 0xb1736b96b6fd83b3UL, 0xbd308ff8a6b17cb2UL, // 1e-129 * 2**556 + 0xddd0467c64bce4a0UL, 0xac7cb3f6d05ddbdeUL, // 1e-128 * 2**553 + 0x8aa22c0dbef60ee4UL, 0x6bcdf07a423aa96bUL, // 1e-127 * 2**549 + 0xad4ab7112eb3929dUL, 0x86c16c98d2c953c6UL, // 1e-126 * 2**546 + 0xd89d64d57a607744UL, 0xe871c7bf077ba8b7UL, // 1e-125 * 2**543 + 0x87625f056c7c4a8bUL, 0x11471cd764ad4972UL, // 1e-124 * 2**539 + 0xa93af6c6c79b5d2dUL, 0xd598e40d3dd89bcfUL, // 1e-123 * 2**536 + 0xd389b47879823479UL, 0x4aff1d108d4ec2c3UL, // 1e-122 * 2**533 + 0x843610cb4bf160cbUL, 0xcedf722a585139baUL, // 1e-121 * 2**529 + 0xa54394fe1eedb8feUL, 0xc2974eb4ee658828UL, // 1e-120 * 2**526 + 0xce947a3da6a9273eUL, 0x733d226229feea32UL, // 1e-119 * 2**523 + 0x811ccc668829b887UL, 0x0806357d5a3f525fUL, // 1e-118 * 2**519 + 0xa163ff802a3426a8UL, 0xca07c2dcb0cf26f7UL, // 1e-117 * 2**516 + 0xc9bcff6034c13052UL, 0xfc89b393dd02f0b5UL, // 1e-116 * 2**513 + 0xfc2c3f3841f17c67UL, 0xbbac2078d443ace2UL, // 1e-115 * 2**510 + 0x9d9ba7832936edc0UL, 0xd54b944b84aa4c0dUL, // 1e-114 * 2**506 + 0xc5029163f384a931UL, 0x0a9e795e65d4df11UL, // 1e-113 * 2**503 + 0xf64335bcf065d37dUL, 0x4d4617b5ff4a16d5UL, // 1e-112 * 2**500 + 0x99ea0196163fa42eUL, 0x504bced1bf8e4e45UL, // 1e-111 * 2**496 + 0xc06481fb9bcf8d39UL, 0xe45ec2862f71e1d6UL, // 1e-110 * 2**493 + 0xf07da27a82c37088UL, 0x5d767327bb4e5a4cUL, // 1e-109 * 2**490 + 0x964e858c91ba2655UL, 0x3a6a07f8d510f86fUL, // 1e-108 * 2**486 + 0xbbe226efb628afeaUL, 0x890489f70a55368bUL, // 1e-107 * 2**483 + 0xeadab0aba3b2dbe5UL, 0x2b45ac74ccea842eUL, // 1e-106 * 2**480 + 0x92c8ae6b464fc96fUL, 0x3b0b8bc90012929dUL, // 1e-105 * 2**476 + 0xb77ada0617e3bbcbUL, 0x09ce6ebb40173744UL, // 1e-104 * 2**473 + 0xe55990879ddcaabdUL, 0xcc420a6a101d0515UL, // 1e-103 * 2**470 + 0x8f57fa54c2a9eab6UL, 0x9fa946824a12232dUL, // 1e-102 * 2**466 + 0xb32df8e9f3546564UL, 0x47939822dc96abf9UL, // 1e-101 * 2**463 + 0xdff9772470297ebdUL, 0x59787e2b93bc56f7UL, // 1e-100 * 2**460 + 0x8bfbea76c619ef36UL, 0x57eb4edb3c55b65aUL, // 1e-99 * 2**456 + 0xaefae51477a06b03UL, 0xede622920b6b23f1UL, // 1e-98 * 2**453 + 0xdab99e59958885c4UL, 0xe95fab368e45ecedUL, // 1e-97 * 2**450 + 0x88b402f7fd75539bUL, 0x11dbcb0218ebb414UL, // 1e-96 * 2**446 + 0xaae103b5fcd2a881UL, 0xd652bdc29f26a119UL, // 1e-95 * 2**443 + 0xd59944a37c0752a2UL, 0x4be76d3346f0495fUL, // 1e-94 * 2**440 + 0x857fcae62d8493a5UL, 0x6f70a4400c562ddbUL, // 1e-93 * 2**436 + 0xa6dfbd9fb8e5b88eUL, 0xcb4ccd500f6bb952UL, // 1e-92 * 2**433 + 0xd097ad07a71f26b2UL, 0x7e2000a41346a7a7UL, // 1e-91 * 2**430 + 0x825ecc24c873782fUL, 0x8ed400668c0c28c8UL, // 1e-90 * 2**426 + 0xa2f67f2dfa90563bUL, 0x728900802f0f32faUL, // 1e-89 * 2**423 + 0xcbb41ef979346bcaUL, 0x4f2b40a03ad2ffb9UL, // 1e-88 * 2**420 + 0xfea126b7d78186bcUL, 0xe2f610c84987bfa8UL, // 1e-87 * 2**417 + 0x9f24b832e6b0f436UL, 0x0dd9ca7d2df4d7c9UL, // 1e-86 * 2**413 + 0xc6ede63fa05d3143UL, 0x91503d1c79720dbbUL, // 1e-85 * 2**410 + 0xf8a95fcf88747d94UL, 0x75a44c6397ce912aUL, // 1e-84 * 2**407 + 0x9b69dbe1b548ce7cUL, 0xc986afbe3ee11abaUL, // 1e-83 * 2**403 + 0xc24452da229b021bUL, 0xfbe85badce996168UL, // 1e-82 * 2**400 + 0xf2d56790ab41c2a2UL, 0xfae27299423fb9c3UL, // 1e-81 * 2**397 + 0x97c560ba6b0919a5UL, 0xdccd879fc967d41aUL, // 1e-80 * 2**393 + 0xbdb6b8e905cb600fUL, 0x5400e987bbc1c920UL, // 1e-79 * 2**390 + 0xed246723473e3813UL, 0x290123e9aab23b68UL, // 1e-78 * 2**387 + 0x9436c0760c86e30bUL, 0xf9a0b6720aaf6521UL, // 1e-77 * 2**383 + 0xb94470938fa89bceUL, 0xf808e40e8d5b3e69UL, // 1e-76 * 2**380 + 0xe7958cb87392c2c2UL, 0xb60b1d1230b20e04UL, // 1e-75 * 2**377 + 0x90bd77f3483bb9b9UL, 0xb1c6f22b5e6f48c2UL, // 1e-74 * 2**373 + 0xb4ecd5f01a4aa828UL, 0x1e38aeb6360b1af3UL, // 1e-73 * 2**370 + 0xe2280b6c20dd5232UL, 0x25c6da63c38de1b0UL, // 1e-72 * 2**367 + 0x8d590723948a535fUL, 0x579c487e5a38ad0eUL, // 1e-71 * 2**363 + 0xb0af48ec79ace837UL, 0x2d835a9df0c6d851UL, // 1e-70 * 2**360 + 0xdcdb1b2798182244UL, 0xf8e431456cf88e65UL, // 1e-69 * 2**357 + 0x8a08f0f8bf0f156bUL, 0x1b8e9ecb641b58ffUL, // 1e-68 * 2**353 + 0xac8b2d36eed2dac5UL, 0xe272467e3d222f3fUL, // 1e-67 * 2**350 + 0xd7adf884aa879177UL, 0x5b0ed81dcc6abb0fUL, // 1e-66 * 2**347 + 0x86ccbb52ea94baeaUL, 0x98e947129fc2b4e9UL, // 1e-65 * 2**343 + 0xa87fea27a539e9a5UL, 0x3f2398d747b36224UL, // 1e-64 * 2**340 + 0xd29fe4b18e88640eUL, 0x8eec7f0d19a03aadUL, // 1e-63 * 2**337 + 0x83a3eeeef9153e89UL, 0x1953cf68300424acUL, // 1e-62 * 2**333 + 0xa48ceaaab75a8e2bUL, 0x5fa8c3423c052dd7UL, // 1e-61 * 2**330 + 0xcdb02555653131b6UL, 0x3792f412cb06794dUL, // 1e-60 * 2**327 + 0x808e17555f3ebf11UL, 0xe2bbd88bbee40bd0UL, // 1e-59 * 2**323 + 0xa0b19d2ab70e6ed6UL, 0x5b6aceaeae9d0ec4UL, // 1e-58 * 2**320 + 0xc8de047564d20a8bUL, 0xf245825a5a445275UL, // 1e-57 * 2**317 + 0xfb158592be068d2eUL, 0xeed6e2f0f0d56712UL, // 1e-56 * 2**314 + 0x9ced737bb6c4183dUL, 0x55464dd69685606bUL, // 1e-55 * 2**310 + 0xc428d05aa4751e4cUL, 0xaa97e14c3c26b886UL, // 1e-54 * 2**307 + 0xf53304714d9265dfUL, 0xd53dd99f4b3066a8UL, // 1e-53 * 2**304 + 0x993fe2c6d07b7fabUL, 0xe546a8038efe4029UL, // 1e-52 * 2**300 + 0xbf8fdb78849a5f96UL, 0xde98520472bdd033UL, // 1e-51 * 2**297 + 0xef73d256a5c0f77cUL, 0x963e66858f6d4440UL, // 1e-50 * 2**294 + 0x95a8637627989aadUL, 0xdde7001379a44aa8UL, // 1e-49 * 2**290 + 0xbb127c53b17ec159UL, 0x5560c018580d5d52UL, // 1e-48 * 2**287 + 0xe9d71b689dde71afUL, 0xaab8f01e6e10b4a6UL, // 1e-47 * 2**284 + 0x9226712162ab070dUL, 0xcab3961304ca70e8UL, // 1e-46 * 2**280 + 0xb6b00d69bb55c8d1UL, 0x3d607b97c5fd0d22UL, // 1e-45 * 2**277 + 0xe45c10c42a2b3b05UL, 0x8cb89a7db77c506aUL, // 1e-44 * 2**274 + 0x8eb98a7a9a5b04e3UL, 0x77f3608e92adb242UL, // 1e-43 * 2**270 + 0xb267ed1940f1c61cUL, 0x55f038b237591ed3UL, // 1e-42 * 2**267 + 0xdf01e85f912e37a3UL, 0x6b6c46dec52f6688UL, // 1e-41 * 2**264 + 0x8b61313bbabce2c6UL, 0x2323ac4b3b3da015UL, // 1e-40 * 2**260 + 0xae397d8aa96c1b77UL, 0xabec975e0a0d081aUL, // 1e-39 * 2**257 + 0xd9c7dced53c72255UL, 0x96e7bd358c904a21UL, // 1e-38 * 2**254 + 0x881cea14545c7575UL, 0x7e50d64177da2e54UL, // 1e-37 * 2**250 + 0xaa242499697392d2UL, 0xdde50bd1d5d0b9e9UL, // 1e-36 * 2**247 + 0xd4ad2dbfc3d07787UL, 0x955e4ec64b44e864UL, // 1e-35 * 2**244 + 0x84ec3c97da624ab4UL, 0xbd5af13bef0b113eUL, // 1e-34 * 2**240 + 0xa6274bbdd0fadd61UL, 0xecb1ad8aeacdd58eUL, // 1e-33 * 2**237 + 0xcfb11ead453994baUL, 0x67de18eda5814af2UL, // 1e-32 * 2**234 + 0x81ceb32c4b43fcf4UL, 0x80eacf948770ced7UL, // 1e-31 * 2**230 + 0xa2425ff75e14fc31UL, 0xa1258379a94d028dUL, // 1e-30 * 2**227 + 0xcad2f7f5359a3b3eUL, 0x096ee45813a04330UL, // 1e-29 * 2**224 + 0xfd87b5f28300ca0dUL, 0x8bca9d6e188853fcUL, // 1e-28 * 2**221 + 0x9e74d1b791e07e48UL, 0x775ea264cf55347dUL, // 1e-27 * 2**217 + 0xc612062576589ddaUL, 0x95364afe032a819dUL, // 1e-26 * 2**214 + 0xf79687aed3eec551UL, 0x3a83ddbd83f52204UL, // 1e-25 * 2**211 + 0x9abe14cd44753b52UL, 0xc4926a9672793542UL, // 1e-24 * 2**207 + 0xc16d9a0095928a27UL, 0x75b7053c0f178293UL, // 1e-23 * 2**204 + 0xf1c90080baf72cb1UL, 0x5324c68b12dd6338UL, // 1e-22 * 2**201 + 0x971da05074da7beeUL, 0xd3f6fc16ebca5e03UL, // 1e-21 * 2**197 + 0xbce5086492111aeaUL, 0x88f4bb1ca6bcf584UL, // 1e-20 * 2**194 + 0xec1e4a7db69561a5UL, 0x2b31e9e3d06c32e5UL, // 1e-19 * 2**191 + 0x9392ee8e921d5d07UL, 0x3aff322e62439fcfUL, // 1e-18 * 2**187 + 0xb877aa3236a4b449UL, 0x09befeb9fad487c2UL, // 1e-17 * 2**184 + 0xe69594bec44de15bUL, 0x4c2ebe687989a9b3UL, // 1e-16 * 2**181 + 0x901d7cf73ab0acd9UL, 0x0f9d37014bf60a10UL, // 1e-15 * 2**177 + 0xb424dc35095cd80fUL, 0x538484c19ef38c94UL, // 1e-14 * 2**174 + 0xe12e13424bb40e13UL, 0x2865a5f206b06fb9UL, // 1e-13 * 2**171 + 0x8cbccc096f5088cbUL, 0xf93f87b7442e45d3UL, // 1e-12 * 2**167 + 0xafebff0bcb24aafeUL, 0xf78f69a51539d748UL, // 1e-11 * 2**164 + 0xdbe6fecebdedd5beUL, 0xb573440e5a884d1bUL, // 1e-10 * 2**161 + 0x89705f4136b4a597UL, 0x31680a88f8953030UL, // 1e-9 * 2**157 + 0xabcc77118461cefcUL, 0xfdc20d2b36ba7c3dUL, // 1e-8 * 2**154 + 0xd6bf94d5e57a42bcUL, 0x3d32907604691b4cUL, // 1e-7 * 2**151 + 0x8637bd05af6c69b5UL, 0xa63f9a49c2c1b10fUL, // 1e-6 * 2**147 + 0xa7c5ac471b478423UL, 0x0fcf80dc33721d53UL, // 1e-5 * 2**144 + 0xd1b71758e219652bUL, 0xd3c36113404ea4a8UL, // 1e-4 * 2**141 + 0x83126e978d4fdf3bUL, 0x645a1cac083126e9UL, // 1e-3 * 2**137 + 0xa3d70a3d70a3d70aUL, 0x3d70a3d70a3d70a3UL, // 1e-2 * 2**134 + 0xccccccccccccccccUL, 0xccccccccccccccccUL, // 1e-1 * 2**131 + 0x8000000000000000UL, 0x0000000000000000UL, // 1e0 * 2**127 + 0xa000000000000000UL, 0x0000000000000000UL, // 1e1 * 2**124 + 0xc800000000000000UL, 0x0000000000000000UL, // 1e2 * 2**121 + 0xfa00000000000000UL, 0x0000000000000000UL, // 1e3 * 2**118 + 0x9c40000000000000UL, 0x0000000000000000UL, // 1e4 * 2**114 + 0xc350000000000000UL, 0x0000000000000000UL, // 1e5 * 2**111 + 0xf424000000000000UL, 0x0000000000000000UL, // 1e6 * 2**108 + 0x9896800000000000UL, 0x0000000000000000UL, // 1e7 * 2**104 + 0xbebc200000000000UL, 0x0000000000000000UL, // 1e8 * 2**101 + 0xee6b280000000000UL, 0x0000000000000000UL, // 1e9 * 2**98 + 0x9502f90000000000UL, 0x0000000000000000UL, // 1e10 * 2**94 + 0xba43b74000000000UL, 0x0000000000000000UL, // 1e11 * 2**91 + 0xe8d4a51000000000UL, 0x0000000000000000UL, // 1e12 * 2**88 + 0x9184e72a00000000UL, 0x0000000000000000UL, // 1e13 * 2**84 + 0xb5e620f480000000UL, 0x0000000000000000UL, // 1e14 * 2**81 + 0xe35fa931a0000000UL, 0x0000000000000000UL, // 1e15 * 2**78 + 0x8e1bc9bf04000000UL, 0x0000000000000000UL, // 1e16 * 2**74 + 0xb1a2bc2ec5000000UL, 0x0000000000000000UL, // 1e17 * 2**71 + 0xde0b6b3a76400000UL, 0x0000000000000000UL, // 1e18 * 2**68 + 0x8ac7230489e80000UL, 0x0000000000000000UL, // 1e19 * 2**64 + 0xad78ebc5ac620000UL, 0x0000000000000000UL, // 1e20 * 2**61 + 0xd8d726b7177a8000UL, 0x0000000000000000UL, // 1e21 * 2**58 + 0x878678326eac9000UL, 0x0000000000000000UL, // 1e22 * 2**54 + 0xa968163f0a57b400UL, 0x0000000000000000UL, // 1e23 * 2**51 + 0xd3c21bcecceda100UL, 0x0000000000000000UL, // 1e24 * 2**48 + 0x84595161401484a0UL, 0x0000000000000000UL, // 1e25 * 2**44 + 0xa56fa5b99019a5c8UL, 0x0000000000000000UL, // 1e26 * 2**41 + 0xcecb8f27f4200f3aUL, 0x0000000000000000UL, // 1e27 * 2**38 + 0x813f3978f8940984UL, 0x4000000000000000UL, // 1e28 * 2**34 + 0xa18f07d736b90be5UL, 0x5000000000000000UL, // 1e29 * 2**31 + 0xc9f2c9cd04674edeUL, 0xa400000000000000UL, // 1e30 * 2**28 + 0xfc6f7c4045812296UL, 0x4d00000000000000UL, // 1e31 * 2**25 + 0x9dc5ada82b70b59dUL, 0xf020000000000000UL, // 1e32 * 2**21 + 0xc5371912364ce305UL, 0x6c28000000000000UL, // 1e33 * 2**18 + 0xf684df56c3e01bc6UL, 0xc732000000000000UL, // 1e34 * 2**15 + 0x9a130b963a6c115cUL, 0x3c7f400000000000UL, // 1e35 * 2**11 + 0xc097ce7bc90715b3UL, 0x4b9f100000000000UL, // 1e36 * 2**8 + 0xf0bdc21abb48db20UL, 0x1e86d40000000000UL, // 1e37 * 2**5 + 0x96769950b50d88f4UL, 0x1314448000000000UL, // 1e38 * 2**1 + 0xbc143fa4e250eb31UL, 0x17d955a000000000UL, // 1e39 * 2**-2 + 0xeb194f8e1ae525fdUL, 0x5dcfab0800000000UL, // 1e40 * 2**-5 + 0x92efd1b8d0cf37beUL, 0x5aa1cae500000000UL, // 1e41 * 2**-9 + 0xb7abc627050305adUL, 0xf14a3d9e40000000UL, // 1e42 * 2**-12 + 0xe596b7b0c643c719UL, 0x6d9ccd05d0000000UL, // 1e43 * 2**-15 + 0x8f7e32ce7bea5c6fUL, 0xe4820023a2000000UL, // 1e44 * 2**-19 + 0xb35dbf821ae4f38bUL, 0xdda2802c8a800000UL, // 1e45 * 2**-22 + 0xe0352f62a19e306eUL, 0xd50b2037ad200000UL, // 1e46 * 2**-25 + 0x8c213d9da502de45UL, 0x4526f422cc340000UL, // 1e47 * 2**-29 + 0xaf298d050e4395d6UL, 0x9670b12b7f410000UL, // 1e48 * 2**-32 + 0xdaf3f04651d47b4cUL, 0x3c0cdd765f114000UL, // 1e49 * 2**-35 + 0x88d8762bf324cd0fUL, 0xa5880a69fb6ac800UL, // 1e50 * 2**-39 + 0xab0e93b6efee0053UL, 0x8eea0d047a457a00UL, // 1e51 * 2**-42 + 0xd5d238a4abe98068UL, 0x72a4904598d6d880UL, // 1e52 * 2**-45 + 0x85a36366eb71f041UL, 0x47a6da2b7f864750UL, // 1e53 * 2**-49 + 0xa70c3c40a64e6c51UL, 0x999090b65f67d924UL, // 1e54 * 2**-52 + 0xd0cf4b50cfe20765UL, 0xfff4b4e3f741cf6dUL, // 1e55 * 2**-55 + 0x82818f1281ed449fUL, 0xbff8f10e7a8921a4UL, // 1e56 * 2**-59 + 0xa321f2d7226895c7UL, 0xaff72d52192b6a0dUL, // 1e57 * 2**-62 + 0xcbea6f8ceb02bb39UL, 0x9bf4f8a69f764490UL, // 1e58 * 2**-65 + 0xfee50b7025c36a08UL, 0x02f236d04753d5b4UL, // 1e59 * 2**-68 + 0x9f4f2726179a2245UL, 0x01d762422c946590UL, // 1e60 * 2**-72 + 0xc722f0ef9d80aad6UL, 0x424d3ad2b7b97ef5UL, // 1e61 * 2**-75 + 0xf8ebad2b84e0d58bUL, 0xd2e0898765a7deb2UL, // 1e62 * 2**-78 + 0x9b934c3b330c8577UL, 0x63cc55f49f88eb2fUL, // 1e63 * 2**-82 + 0xc2781f49ffcfa6d5UL, 0x3cbf6b71c76b25fbUL, // 1e64 * 2**-85 + 0xf316271c7fc3908aUL, 0x8bef464e3945ef7aUL, // 1e65 * 2**-88 + 0x97edd871cfda3a56UL, 0x97758bf0e3cbb5acUL, // 1e66 * 2**-92 + 0xbde94e8e43d0c8ecUL, 0x3d52eeed1cbea317UL, // 1e67 * 2**-95 + 0xed63a231d4c4fb27UL, 0x4ca7aaa863ee4bddUL, // 1e68 * 2**-98 + 0x945e455f24fb1cf8UL, 0x8fe8caa93e74ef6aUL, // 1e69 * 2**-102 + 0xb975d6b6ee39e436UL, 0xb3e2fd538e122b44UL, // 1e70 * 2**-105 + 0xe7d34c64a9c85d44UL, 0x60dbbca87196b616UL, // 1e71 * 2**-108 + 0x90e40fbeea1d3a4aUL, 0xbc8955e946fe31cdUL, // 1e72 * 2**-112 + 0xb51d13aea4a488ddUL, 0x6babab6398bdbe41UL, // 1e73 * 2**-115 + 0xe264589a4dcdab14UL, 0xc696963c7eed2dd1UL, // 1e74 * 2**-118 + 0x8d7eb76070a08aecUL, 0xfc1e1de5cf543ca2UL, // 1e75 * 2**-122 + 0xb0de65388cc8ada8UL, 0x3b25a55f43294bcbUL, // 1e76 * 2**-125 + 0xdd15fe86affad912UL, 0x49ef0eb713f39ebeUL, // 1e77 * 2**-128 + 0x8a2dbf142dfcc7abUL, 0x6e3569326c784337UL, // 1e78 * 2**-132 + 0xacb92ed9397bf996UL, 0x49c2c37f07965404UL, // 1e79 * 2**-135 + 0xd7e77a8f87daf7fbUL, 0xdc33745ec97be906UL, // 1e80 * 2**-138 + 0x86f0ac99b4e8dafdUL, 0x69a028bb3ded71a3UL, // 1e81 * 2**-142 + 0xa8acd7c0222311bcUL, 0xc40832ea0d68ce0cUL, // 1e82 * 2**-145 + 0xd2d80db02aabd62bUL, 0xf50a3fa490c30190UL, // 1e83 * 2**-148 + 0x83c7088e1aab65dbUL, 0x792667c6da79e0faUL, // 1e84 * 2**-152 + 0xa4b8cab1a1563f52UL, 0x577001b891185938UL, // 1e85 * 2**-155 + 0xcde6fd5e09abcf26UL, 0xed4c0226b55e6f86UL, // 1e86 * 2**-158 + 0x80b05e5ac60b6178UL, 0x544f8158315b05b4UL, // 1e87 * 2**-162 + 0xa0dc75f1778e39d6UL, 0x696361ae3db1c721UL, // 1e88 * 2**-165 + 0xc913936dd571c84cUL, 0x03bc3a19cd1e38e9UL, // 1e89 * 2**-168 + 0xfb5878494ace3a5fUL, 0x04ab48a04065c723UL, // 1e90 * 2**-171 + 0x9d174b2dcec0e47bUL, 0x62eb0d64283f9c76UL, // 1e91 * 2**-175 + 0xc45d1df942711d9aUL, 0x3ba5d0bd324f8394UL, // 1e92 * 2**-178 + 0xf5746577930d6500UL, 0xca8f44ec7ee36479UL, // 1e93 * 2**-181 + 0x9968bf6abbe85f20UL, 0x7e998b13cf4e1ecbUL, // 1e94 * 2**-185 + 0xbfc2ef456ae276e8UL, 0x9e3fedd8c321a67eUL, // 1e95 * 2**-188 + 0xefb3ab16c59b14a2UL, 0xc5cfe94ef3ea101eUL, // 1e96 * 2**-191 + 0x95d04aee3b80ece5UL, 0xbba1f1d158724a12UL, // 1e97 * 2**-195 + 0xbb445da9ca61281fUL, 0x2a8a6e45ae8edc97UL, // 1e98 * 2**-198 + 0xea1575143cf97226UL, 0xf52d09d71a3293bdUL, // 1e99 * 2**-201 + 0x924d692ca61be758UL, 0x593c2626705f9c56UL, // 1e100 * 2**-205 + 0xb6e0c377cfa2e12eUL, 0x6f8b2fb00c77836cUL, // 1e101 * 2**-208 + 0xe498f455c38b997aUL, 0x0b6dfb9c0f956447UL, // 1e102 * 2**-211 + 0x8edf98b59a373fecUL, 0x4724bd4189bd5eacUL, // 1e103 * 2**-215 + 0xb2977ee300c50fe7UL, 0x58edec91ec2cb657UL, // 1e104 * 2**-218 + 0xdf3d5e9bc0f653e1UL, 0x2f2967b66737e3edUL, // 1e105 * 2**-221 + 0x8b865b215899f46cUL, 0xbd79e0d20082ee74UL, // 1e106 * 2**-225 + 0xae67f1e9aec07187UL, 0xecd8590680a3aa11UL, // 1e107 * 2**-228 + 0xda01ee641a708de9UL, 0xe80e6f4820cc9495UL, // 1e108 * 2**-231 + 0x884134fe908658b2UL, 0x3109058d147fdcddUL, // 1e109 * 2**-235 + 0xaa51823e34a7eedeUL, 0xbd4b46f0599fd415UL, // 1e110 * 2**-238 + 0xd4e5e2cdc1d1ea96UL, 0x6c9e18ac7007c91aUL, // 1e111 * 2**-241 + 0x850fadc09923329eUL, 0x03e2cf6bc604ddb0UL, // 1e112 * 2**-245 + 0xa6539930bf6bff45UL, 0x84db8346b786151cUL, // 1e113 * 2**-248 + 0xcfe87f7cef46ff16UL, 0xe612641865679a63UL, // 1e114 * 2**-251 + 0x81f14fae158c5f6eUL, 0x4fcb7e8f3f60c07eUL, // 1e115 * 2**-255 + 0xa26da3999aef7749UL, 0xe3be5e330f38f09dUL, // 1e116 * 2**-258 + 0xcb090c8001ab551cUL, 0x5cadf5bfd3072cc5UL, // 1e117 * 2**-261 + 0xfdcb4fa002162a63UL, 0x73d9732fc7c8f7f6UL, // 1e118 * 2**-264 + 0x9e9f11c4014dda7eUL, 0x2867e7fddcdd9afaUL, // 1e119 * 2**-268 + 0xc646d63501a1511dUL, 0xb281e1fd541501b8UL, // 1e120 * 2**-271 + 0xf7d88bc24209a565UL, 0x1f225a7ca91a4226UL, // 1e121 * 2**-274 + 0x9ae757596946075fUL, 0x3375788de9b06958UL, // 1e122 * 2**-278 + 0xc1a12d2fc3978937UL, 0x0052d6b1641c83aeUL, // 1e123 * 2**-281 + 0xf209787bb47d6b84UL, 0xc0678c5dbd23a49aUL, // 1e124 * 2**-284 + 0x9745eb4d50ce6332UL, 0xf840b7ba963646e0UL, // 1e125 * 2**-288 + 0xbd176620a501fbffUL, 0xb650e5a93bc3d898UL, // 1e126 * 2**-291 + 0xec5d3fa8ce427affUL, 0xa3e51f138ab4cebeUL, // 1e127 * 2**-294 + 0x93ba47c980e98cdfUL, 0xc66f336c36b10137UL, // 1e128 * 2**-298 + 0xb8a8d9bbe123f017UL, 0xb80b0047445d4184UL, // 1e129 * 2**-301 + 0xe6d3102ad96cec1dUL, 0xa60dc059157491e5UL, // 1e130 * 2**-304 + 0x9043ea1ac7e41392UL, 0x87c89837ad68db2fUL, // 1e131 * 2**-308 + 0xb454e4a179dd1877UL, 0x29babe4598c311fbUL, // 1e132 * 2**-311 + 0xe16a1dc9d8545e94UL, 0xf4296dd6fef3d67aUL, // 1e133 * 2**-314 + 0x8ce2529e2734bb1dUL, 0x1899e4a65f58660cUL, // 1e134 * 2**-318 + 0xb01ae745b101e9e4UL, 0x5ec05dcff72e7f8fUL, // 1e135 * 2**-321 + 0xdc21a1171d42645dUL, 0x76707543f4fa1f73UL, // 1e136 * 2**-324 + 0x899504ae72497ebaUL, 0x6a06494a791c53a8UL, // 1e137 * 2**-328 + 0xabfa45da0edbde69UL, 0x0487db9d17636892UL, // 1e138 * 2**-331 + 0xd6f8d7509292d603UL, 0x45a9d2845d3c42b6UL, // 1e139 * 2**-334 + 0x865b86925b9bc5c2UL, 0x0b8a2392ba45a9b2UL, // 1e140 * 2**-338 + 0xa7f26836f282b732UL, 0x8e6cac7768d7141eUL, // 1e141 * 2**-341 + 0xd1ef0244af2364ffUL, 0x3207d795430cd926UL, // 1e142 * 2**-344 + 0x8335616aed761f1fUL, 0x7f44e6bd49e807b8UL, // 1e143 * 2**-348 + 0xa402b9c5a8d3a6e7UL, 0x5f16206c9c6209a6UL, // 1e144 * 2**-351 + 0xcd036837130890a1UL, 0x36dba887c37a8c0fUL, // 1e145 * 2**-354 + 0x802221226be55a64UL, 0xc2494954da2c9789UL, // 1e146 * 2**-358 + 0xa02aa96b06deb0fdUL, 0xf2db9baa10b7bd6cUL, // 1e147 * 2**-361 + 0xc83553c5c8965d3dUL, 0x6f92829494e5acc7UL, // 1e148 * 2**-364 + 0xfa42a8b73abbf48cUL, 0xcb772339ba1f17f9UL, // 1e149 * 2**-367 + 0x9c69a97284b578d7UL, 0xff2a760414536efbUL, // 1e150 * 2**-371 + 0xc38413cf25e2d70dUL, 0xfef5138519684abaUL, // 1e151 * 2**-374 + 0xf46518c2ef5b8cd1UL, 0x7eb258665fc25d69UL, // 1e152 * 2**-377 + 0x98bf2f79d5993802UL, 0xef2f773ffbd97a61UL, // 1e153 * 2**-381 + 0xbeeefb584aff8603UL, 0xaafb550ffacfd8faUL, // 1e154 * 2**-384 + 0xeeaaba2e5dbf6784UL, 0x95ba2a53f983cf38UL, // 1e155 * 2**-387 + 0x952ab45cfa97a0b2UL, 0xdd945a747bf26183UL, // 1e156 * 2**-391 + 0xba756174393d88dfUL, 0x94f971119aeef9e4UL, // 1e157 * 2**-394 + 0xe912b9d1478ceb17UL, 0x7a37cd5601aab85dUL, // 1e158 * 2**-397 + 0x91abb422ccb812eeUL, 0xac62e055c10ab33aUL, // 1e159 * 2**-401 + 0xb616a12b7fe617aaUL, 0x577b986b314d6009UL, // 1e160 * 2**-404 + 0xe39c49765fdf9d94UL, 0xed5a7e85fda0b80bUL, // 1e161 * 2**-407 + 0x8e41ade9fbebc27dUL, 0x14588f13be847307UL, // 1e162 * 2**-411 + 0xb1d219647ae6b31cUL, 0x596eb2d8ae258fc8UL, // 1e163 * 2**-414 + 0xde469fbd99a05fe3UL, 0x6fca5f8ed9aef3bbUL, // 1e164 * 2**-417 + 0x8aec23d680043beeUL, 0x25de7bb9480d5854UL, // 1e165 * 2**-421 + 0xada72ccc20054ae9UL, 0xaf561aa79a10ae6aUL, // 1e166 * 2**-424 + 0xd910f7ff28069da4UL, 0x1b2ba1518094da04UL, // 1e167 * 2**-427 + 0x87aa9aff79042286UL, 0x90fb44d2f05d0842UL, // 1e168 * 2**-431 + 0xa99541bf57452b28UL, 0x353a1607ac744a53UL, // 1e169 * 2**-434 + 0xd3fa922f2d1675f2UL, 0x42889b8997915ce8UL, // 1e170 * 2**-437 + 0x847c9b5d7c2e09b7UL, 0x69956135febada11UL, // 1e171 * 2**-441 + 0xa59bc234db398c25UL, 0x43fab9837e699095UL, // 1e172 * 2**-444 + 0xcf02b2c21207ef2eUL, 0x94f967e45e03f4bbUL, // 1e173 * 2**-447 + 0x8161afb94b44f57dUL, 0x1d1be0eebac278f5UL, // 1e174 * 2**-451 + 0xa1ba1ba79e1632dcUL, 0x6462d92a69731732UL, // 1e175 * 2**-454 + 0xca28a291859bbf93UL, 0x7d7b8f7503cfdcfeUL, // 1e176 * 2**-457 + 0xfcb2cb35e702af78UL, 0x5cda735244c3d43eUL, // 1e177 * 2**-460 + 0x9defbf01b061adabUL, 0x3a0888136afa64a7UL, // 1e178 * 2**-464 + 0xc56baec21c7a1916UL, 0x088aaa1845b8fdd0UL, // 1e179 * 2**-467 + 0xf6c69a72a3989f5bUL, 0x8aad549e57273d45UL, // 1e180 * 2**-470 + 0x9a3c2087a63f6399UL, 0x36ac54e2f678864bUL, // 1e181 * 2**-474 + 0xc0cb28a98fcf3c7fUL, 0x84576a1bb416a7ddUL, // 1e182 * 2**-477 + 0xf0fdf2d3f3c30b9fUL, 0x656d44a2a11c51d5UL, // 1e183 * 2**-480 + 0x969eb7c47859e743UL, 0x9f644ae5a4b1b325UL, // 1e184 * 2**-484 + 0xbc4665b596706114UL, 0x873d5d9f0dde1feeUL, // 1e185 * 2**-487 + 0xeb57ff22fc0c7959UL, 0xa90cb506d155a7eaUL, // 1e186 * 2**-490 + 0x9316ff75dd87cbd8UL, 0x09a7f12442d588f2UL, // 1e187 * 2**-494 + 0xb7dcbf5354e9beceUL, 0x0c11ed6d538aeb2fUL, // 1e188 * 2**-497 + 0xe5d3ef282a242e81UL, 0x8f1668c8a86da5faUL, // 1e189 * 2**-500 + 0x8fa475791a569d10UL, 0xf96e017d694487bcUL, // 1e190 * 2**-504 + 0xb38d92d760ec4455UL, 0x37c981dcc395a9acUL, // 1e191 * 2**-507 + 0xe070f78d3927556aUL, 0x85bbe253f47b1417UL, // 1e192 * 2**-510 + 0x8c469ab843b89562UL, 0x93956d7478ccec8eUL, // 1e193 * 2**-514 + 0xaf58416654a6babbUL, 0x387ac8d1970027b2UL, // 1e194 * 2**-517 + 0xdb2e51bfe9d0696aUL, 0x06997b05fcc0319eUL, // 1e195 * 2**-520 + 0x88fcf317f22241e2UL, 0x441fece3bdf81f03UL, // 1e196 * 2**-524 + 0xab3c2fddeeaad25aUL, 0xd527e81cad7626c3UL, // 1e197 * 2**-527 + 0xd60b3bd56a5586f1UL, 0x8a71e223d8d3b074UL, // 1e198 * 2**-530 + 0x85c7056562757456UL, 0xf6872d5667844e49UL, // 1e199 * 2**-534 + 0xa738c6bebb12d16cUL, 0xb428f8ac016561dbUL, // 1e200 * 2**-537 + 0xd106f86e69d785c7UL, 0xe13336d701beba52UL, // 1e201 * 2**-540 + 0x82a45b450226b39cUL, 0xecc0024661173473UL, // 1e202 * 2**-544 + 0xa34d721642b06084UL, 0x27f002d7f95d0190UL, // 1e203 * 2**-547 + 0xcc20ce9bd35c78a5UL, 0x31ec038df7b441f4UL, // 1e204 * 2**-550 + 0xff290242c83396ceUL, 0x7e67047175a15271UL, // 1e205 * 2**-553 + 0x9f79a169bd203e41UL, 0x0f0062c6e984d386UL, // 1e206 * 2**-557 + 0xc75809c42c684dd1UL, 0x52c07b78a3e60868UL, // 1e207 * 2**-560 + 0xf92e0c3537826145UL, 0xa7709a56ccdf8a82UL, // 1e208 * 2**-563 + 0x9bbcc7a142b17ccbUL, 0x88a66076400bb691UL, // 1e209 * 2**-567 + 0xc2abf989935ddbfeUL, 0x6acff893d00ea435UL, // 1e210 * 2**-570 + 0xf356f7ebf83552feUL, 0x0583f6b8c4124d43UL, // 1e211 * 2**-573 + 0x98165af37b2153deUL, 0xc3727a337a8b704aUL, // 1e212 * 2**-577 + 0xbe1bf1b059e9a8d6UL, 0x744f18c0592e4c5cUL, // 1e213 * 2**-580 + 0xeda2ee1c7064130cUL, 0x1162def06f79df73UL, // 1e214 * 2**-583 + 0x9485d4d1c63e8be7UL, 0x8addcb5645ac2ba8UL, // 1e215 * 2**-587 + 0xb9a74a0637ce2ee1UL, 0x6d953e2bd7173692UL, // 1e216 * 2**-590 + 0xe8111c87c5c1ba99UL, 0xc8fa8db6ccdd0437UL, // 1e217 * 2**-593 + 0x910ab1d4db9914a0UL, 0x1d9c9892400a22a2UL, // 1e218 * 2**-597 + 0xb54d5e4a127f59c8UL, 0x2503beb6d00cab4bUL, // 1e219 * 2**-600 + 0xe2a0b5dc971f303aUL, 0x2e44ae64840fd61dUL, // 1e220 * 2**-603 + 0x8da471a9de737e24UL, 0x5ceaecfed289e5d2UL, // 1e221 * 2**-607 + 0xb10d8e1456105dadUL, 0x7425a83e872c5f47UL, // 1e222 * 2**-610 + 0xdd50f1996b947518UL, 0xd12f124e28f77719UL, // 1e223 * 2**-613 + 0x8a5296ffe33cc92fUL, 0x82bd6b70d99aaa6fUL, // 1e224 * 2**-617 + 0xace73cbfdc0bfb7bUL, 0x636cc64d1001550bUL, // 1e225 * 2**-620 + 0xd8210befd30efa5aUL, 0x3c47f7e05401aa4eUL, // 1e226 * 2**-623 + 0x8714a775e3e95c78UL, 0x65acfaec34810a71UL, // 1e227 * 2**-627 + 0xa8d9d1535ce3b396UL, 0x7f1839a741a14d0dUL, // 1e228 * 2**-630 + 0xd31045a8341ca07cUL, 0x1ede48111209a050UL, // 1e229 * 2**-633 + 0x83ea2b892091e44dUL, 0x934aed0aab460432UL, // 1e230 * 2**-637 + 0xa4e4b66b68b65d60UL, 0xf81da84d5617853fUL, // 1e231 * 2**-640 + 0xce1de40642e3f4b9UL, 0x36251260ab9d668eUL, // 1e232 * 2**-643 + 0x80d2ae83e9ce78f3UL, 0xc1d72b7c6b426019UL, // 1e233 * 2**-647 + 0xa1075a24e4421730UL, 0xb24cf65b8612f81fUL, // 1e234 * 2**-650 + 0xc94930ae1d529cfcUL, 0xdee033f26797b627UL, // 1e235 * 2**-653 + 0xfb9b7cd9a4a7443cUL, 0x169840ef017da3b1UL, // 1e236 * 2**-656 + 0x9d412e0806e88aa5UL, 0x8e1f289560ee864eUL, // 1e237 * 2**-660 + 0xc491798a08a2ad4eUL, 0xf1a6f2bab92a27e2UL, // 1e238 * 2**-663 + 0xf5b5d7ec8acb58a2UL, 0xae10af696774b1dbUL, // 1e239 * 2**-666 + 0x9991a6f3d6bf1765UL, 0xacca6da1e0a8ef29UL, // 1e240 * 2**-670 + 0xbff610b0cc6edd3fUL, 0x17fd090a58d32af3UL, // 1e241 * 2**-673 + 0xeff394dcff8a948eUL, 0xddfc4b4cef07f5b0UL, // 1e242 * 2**-676 + 0x95f83d0a1fb69cd9UL, 0x4abdaf101564f98eUL, // 1e243 * 2**-680 + 0xbb764c4ca7a4440fUL, 0x9d6d1ad41abe37f1UL, // 1e244 * 2**-683 + 0xea53df5fd18d5513UL, 0x84c86189216dc5edUL, // 1e245 * 2**-686 + 0x92746b9be2f8552cUL, 0x32fd3cf5b4e49bb4UL, // 1e246 * 2**-690 + 0xb7118682dbb66a77UL, 0x3fbc8c33221dc2a1UL, // 1e247 * 2**-693 + 0xe4d5e82392a40515UL, 0x0fabaf3feaa5334aUL, // 1e248 * 2**-696 + 0x8f05b1163ba6832dUL, 0x29cb4d87f2a7400eUL, // 1e249 * 2**-700 + 0xb2c71d5bca9023f8UL, 0x743e20e9ef511012UL, // 1e250 * 2**-703 + 0xdf78e4b2bd342cf6UL, 0x914da9246b255416UL, // 1e251 * 2**-706 + 0x8bab8eefb6409c1aUL, 0x1ad089b6c2f7548eUL, // 1e252 * 2**-710 + 0xae9672aba3d0c320UL, 0xa184ac2473b529b1UL, // 1e253 * 2**-713 + 0xda3c0f568cc4f3e8UL, 0xc9e5d72d90a2741eUL, // 1e254 * 2**-716 + 0x8865899617fb1871UL, 0x7e2fa67c7a658892UL, // 1e255 * 2**-720 + 0xaa7eebfb9df9de8dUL, 0xddbb901b98feeab7UL, // 1e256 * 2**-723 + 0xd51ea6fa85785631UL, 0x552a74227f3ea565UL, // 1e257 * 2**-726 + 0x8533285c936b35deUL, 0xd53a88958f87275fUL, // 1e258 * 2**-730 + 0xa67ff273b8460356UL, 0x8a892abaf368f137UL, // 1e259 * 2**-733 + 0xd01fef10a657842cUL, 0x2d2b7569b0432d85UL, // 1e260 * 2**-736 + 0x8213f56a67f6b29bUL, 0x9c3b29620e29fc73UL, // 1e261 * 2**-740 + 0xa298f2c501f45f42UL, 0x8349f3ba91b47b8fUL, // 1e262 * 2**-743 + 0xcb3f2f7642717713UL, 0x241c70a936219a73UL, // 1e263 * 2**-746 + 0xfe0efb53d30dd4d7UL, 0xed238cd383aa0110UL, // 1e264 * 2**-749 + 0x9ec95d1463e8a506UL, 0xf4363804324a40aaUL, // 1e265 * 2**-753 + 0xc67bb4597ce2ce48UL, 0xb143c6053edcd0d5UL, // 1e266 * 2**-756 + 0xf81aa16fdc1b81daUL, 0xdd94b7868e94050aUL, // 1e267 * 2**-759 + 0x9b10a4e5e9913128UL, 0xca7cf2b4191c8326UL, // 1e268 * 2**-763 + 0xc1d4ce1f63f57d72UL, 0xfd1c2f611f63a3f0UL, // 1e269 * 2**-766 + 0xf24a01a73cf2dccfUL, 0xbc633b39673c8cecUL, // 1e270 * 2**-769 + 0x976e41088617ca01UL, 0xd5be0503e085d813UL, // 1e271 * 2**-773 + 0xbd49d14aa79dbc82UL, 0x4b2d8644d8a74e18UL, // 1e272 * 2**-776 + 0xec9c459d51852ba2UL, 0xddf8e7d60ed1219eUL, // 1e273 * 2**-779 + 0x93e1ab8252f33b45UL, 0xcabb90e5c942b503UL, // 1e274 * 2**-783 + 0xb8da1662e7b00a17UL, 0x3d6a751f3b936243UL, // 1e275 * 2**-786 + 0xe7109bfba19c0c9dUL, 0x0cc512670a783ad4UL, // 1e276 * 2**-789 + 0x906a617d450187e2UL, 0x27fb2b80668b24c5UL, // 1e277 * 2**-793 + 0xb484f9dc9641e9daUL, 0xb1f9f660802dedf6UL, // 1e278 * 2**-796 + 0xe1a63853bbd26451UL, 0x5e7873f8a0396973UL, // 1e279 * 2**-799 + 0x8d07e33455637eb2UL, 0xdb0b487b6423e1e8UL, // 1e280 * 2**-803 + 0xb049dc016abc5e5fUL, 0x91ce1a9a3d2cda62UL, // 1e281 * 2**-806 + 0xdc5c5301c56b75f7UL, 0x7641a140cc7810fbUL, // 1e282 * 2**-809 + 0x89b9b3e11b6329baUL, 0xa9e904c87fcb0a9dUL, // 1e283 * 2**-813 + 0xac2820d9623bf429UL, 0x546345fa9fbdcd44UL, // 1e284 * 2**-816 + 0xd732290fbacaf133UL, 0xa97c177947ad4095UL, // 1e285 * 2**-819 + 0x867f59a9d4bed6c0UL, 0x49ed8eabcccc485dUL, // 1e286 * 2**-823 + 0xa81f301449ee8c70UL, 0x5c68f256bfff5a74UL, // 1e287 * 2**-826 + 0xd226fc195c6a2f8cUL, 0x73832eec6fff3111UL, // 1e288 * 2**-829 + 0x83585d8fd9c25db7UL, 0xc831fd53c5ff7eabUL, // 1e289 * 2**-833 + 0xa42e74f3d032f525UL, 0xba3e7ca8b77f5e55UL, // 1e290 * 2**-836 + 0xcd3a1230c43fb26fUL, 0x28ce1bd2e55f35ebUL, // 1e291 * 2**-839 + 0x80444b5e7aa7cf85UL, 0x7980d163cf5b81b3UL, // 1e292 * 2**-843 + 0xa0555e361951c366UL, 0xd7e105bcc332621fUL, // 1e293 * 2**-846 + 0xc86ab5c39fa63440UL, 0x8dd9472bf3fefaa7UL, // 1e294 * 2**-849 + 0xfa856334878fc150UL, 0xb14f98f6f0feb951UL, // 1e295 * 2**-852 + 0x9c935e00d4b9d8d2UL, 0x6ed1bf9a569f33d3UL, // 1e296 * 2**-856 + 0xc3b8358109e84f07UL, 0x0a862f80ec4700c8UL, // 1e297 * 2**-859 + 0xf4a642e14c6262c8UL, 0xcd27bb612758c0faUL, // 1e298 * 2**-862 + 0x98e7e9cccfbd7dbdUL, 0x8038d51cb897789cUL, // 1e299 * 2**-866 + 0xbf21e44003acdd2cUL, 0xe0470a63e6bd56c3UL, // 1e300 * 2**-869 + 0xeeea5d5004981478UL, 0x1858ccfce06cac74UL, // 1e301 * 2**-872 + 0x95527a5202df0ccbUL, 0x0f37801e0c43ebc8UL, // 1e302 * 2**-876 + 0xbaa718e68396cffdUL, 0xd30560258f54e6baUL, // 1e303 * 2**-879 + 0xe950df20247c83fdUL, 0x47c6b82ef32a2069UL, // 1e304 * 2**-882 + 0x91d28b7416cdd27eUL, 0x4cdc331d57fa5441UL, // 1e305 * 2**-886 + 0xb6472e511c81471dUL, 0xe0133fe4adf8e952UL, // 1e306 * 2**-889 + 0xe3d8f9e563a198e5UL, 0x58180fddd97723a6UL, // 1e307 * 2**-892 + 0x8e679c2f5e44ff8fUL, 0x570f09eaa7ea7648UL, // 1e308 * 2**-896 + 0xb201833b35d63f73UL, 0x2cd2cc6551e513daUL, // 1e309 * 2**-899 + 0xde81e40a034bcf4fUL, 0xf8077f7ea65e58d1UL, // 1e310 * 2**-902 + 0x8b112e86420f6191UL, 0xfb04afaf27faf782UL, // 1e311 * 2**-906 + 0xadd57a27d29339f6UL, 0x79c5db9af1f9b563UL, // 1e312 * 2**-909 + 0xd94ad8b1c7380874UL, 0x18375281ae7822bcUL, // 1e313 * 2**-912 + 0x87cec76f1c830548UL, 0x8f2293910d0b15b5UL, // 1e314 * 2**-916 + 0xa9c2794ae3a3c69aUL, 0xb2eb3875504ddb22UL, // 1e315 * 2**-919 + 0xd433179d9c8cb841UL, 0x5fa60692a46151ebUL, // 1e316 * 2**-922 + 0x849feec281d7f328UL, 0xdbc7c41ba6bcd333UL, // 1e317 * 2**-926 + 0xa5c7ea73224deff3UL, 0x12b9b522906c0800UL, // 1e318 * 2**-929 + 0xcf39e50feae16befUL, 0xd768226b34870a00UL, // 1e319 * 2**-932 + 0x81842f29f2cce375UL, 0xe6a1158300d46640UL, // 1e320 * 2**-936 + 0xa1e53af46f801c53UL, 0x60495ae3c1097fd0UL, // 1e321 * 2**-939 + 0xca5e89b18b602368UL, 0x385bb19cb14bdfc4UL, // 1e322 * 2**-942 + 0xfcf62c1dee382c42UL, 0x46729e03dd9ed7b5UL, // 1e323 * 2**-945 + 0x9e19db92b4e31ba9UL, 0x6c07a2c26a8346d1UL, // 1e324 * 2**-949 + 0xc5a05277621be293UL, 0xc7098b7305241885UL, // 1e325 * 2**-952 + 0xf70867153aa2db38UL, 0xb8cbee4fc66d1ea7UL, // 1e326 * 2**-955 + 0x9a65406d44a5c903UL, 0x737f74f1dc043328UL, // 1e327 * 2**-959 + 0xc0fe908895cf3b44UL, 0x505f522e53053ff2UL, // 1e328 * 2**-962 + 0xf13e34aabb430a15UL, 0x647726b9e7c68fefUL, // 1e329 * 2**-965 + 0x96c6e0eab509e64dUL, 0x5eca783430dc19f5UL, // 1e330 * 2**-969 + 0xbc789925624c5fe0UL, 0xb67d16413d132072UL, // 1e331 * 2**-972 + 0xeb96bf6ebadf77d8UL, 0xe41c5bd18c57e88fUL, // 1e332 * 2**-975 + 0x933e37a534cbaae7UL, 0x8e91b962f7b6f159UL, // 1e333 * 2**-979 + 0xb80dc58e81fe95a1UL, 0x723627bbb5a4adb0UL, // 1e334 * 2**-982 + 0xe61136f2227e3b09UL, 0xcec3b1aaa30dd91cUL, // 1e335 * 2**-985 + 0x8fcac257558ee4e6UL, 0x213a4f0aa5e8a7b1UL, // 1e336 * 2**-989 + 0xb3bd72ed2af29e1fUL, 0xa988e2cd4f62d19dUL, // 1e337 * 2**-992 + 0xe0accfa875af45a7UL, 0x93eb1b80a33b8605UL, // 1e338 * 2**-995 + 0x8c6c01c9498d8b88UL, 0xbc72f130660533c3UL, // 1e339 * 2**-999 + 0xaf87023b9bf0ee6aUL, 0xeb8fad7c7f8680b4UL, // 1e340 * 2**-1002 + 0xdb68c2ca82ed2a05UL, 0xa67398db9f6820e1UL, // 1e341 * 2**-1005 + 0x892179be91d43a43UL, 0x88083f8943a1148cUL, // 1e342 * 2**-1009 + 0xab69d82e364948d4UL, 0x6a0a4f6b948959b0UL, // 1e343 * 2**-1012 + 0xd6444e39c3db9b09UL, 0x848ce34679abb01cUL, // 1e344 * 2**-1015 + 0x85eab0e41a6940e5UL, 0xf2d80e0c0c0b4e11UL, // 1e345 * 2**-1019 + 0xa7655d1d2103911fUL, 0x6f8e118f0f0e2195UL, // 1e346 * 2**-1022 + 0xd13eb46469447567UL, 0x4b7195f2d2d1a9fbUL, // 1e347 * 2**-1025 +] diff --git a/internal/strconv/strconv_eisel_lemire_wbtest.mbt b/internal/strconv/strconv_eisel_lemire_wbtest.mbt new file mode 100644 index 000000000..746749641 --- /dev/null +++ b/internal/strconv/strconv_eisel_lemire_wbtest.mbt @@ -0,0 +1,71 @@ +// Copyright 2026 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +///| +test "Eisel-Lemire agrees with exact Decimal conversion" { + let cases : FixedArray[(String, UInt64, Int64, Bool)] = [ + ("-65.613616999999977", 65613616999999977UL, -15L, true), + ("43.420273000000009", 43420273000000009UL, -15L, false), + ("-65.619720000000029", 65619720000000029UL, -15L, true), + ("43.418052999999986", 43418052999999986UL, -15L, false), + ("9.999999999999999999", 9999999999999999999UL, -18L, false), + ("1.234567890123456789e100", 1234567890123456789UL, 82L, false), + ("1e-307", 1UL, -307L, false), + ("1e308", 1UL, 308L, false), + ] + for case in cases { + let (input, mantissa, exponent, negative) = case + let fast = try_eisel_lemire64(mantissa, exponent, negative) + if fast.is_nan() { + fail("Eisel-Lemire unexpectedly rejected \{input}") + } + let exact = parse_decimal_priv(input).to_double_priv() + @test.assert_eq(fast.reinterpret_as_uint64(), exact.reinterpret_as_uint64()) + } +} + +///| +test "Eisel-Lemire preserves negative zero" { + inspect( + try_eisel_lemire64(0UL, 0L, true).reinterpret_as_uint64(), + content="9223372036854775808", + ) +} + +///| +test "Eisel-Lemire rejects values reserved for the exact fallback" { + inspect(try_eisel_lemire64(1UL, -348L, false).is_nan(), content="true") + inspect(try_eisel_lemire64(1UL, 348L, false).is_nan(), content="true") +} + +///| +test "Eisel-Lemire differential exponent coverage" { + let mantissas : FixedArray[UInt64] = [ + 1UL, 10UL, 9007199254740993UL, 65613616999999977UL, 1234567890123456789UL, 9223372036854775807UL, + 9999999999999999999UL, + ] + for mantissa in mantissas { + for exponent in -340..<=340 { + let fast = try_eisel_lemire64(mantissa, exponent.to_int64(), false) + if !fast.is_nan() { + let input = "\{mantissa}e\{exponent}" + let exact = parse_decimal_priv(input).to_double_priv() + @test.assert_eq( + fast.reinterpret_as_uint64(), + exact.reinterpret_as_uint64(), + ) + } + } + } +} diff --git a/json/lex_number.mbt b/json/lex_number.mbt index aa03bc365..1e3b18ec3 100644 --- a/json/lex_number.mbt +++ b/json/lex_number.mbt @@ -383,8 +383,9 @@ fn ParseContext::lex_number_end( ) -> LexedNumber { // Fast path for JSON numbers: the lexer has already validated the grammar, // so scan raw UTF-16 digits once and bypass the general strconv parser for - // safe integers and Clinger-style fast-path doubles. Fall back to strconv for - // large or precision-sensitive numbers so existing rounding behavior is kept. + // safe integers, Clinger-style exact doubles, and Eisel-Lemire conversions. + // Fall back to strconv for truncated or ambiguous numbers so the exact + // Decimal converter preserves existing rounding behavior. let scan = ctx.scan_json_number(start, end) if scan.is_integer { // `is_integer` is set by `scan_json_number` only when no `.` and no `e/E` @@ -416,6 +417,16 @@ fn ParseContext::lex_number_end( if !fast.is_nan() { return { value: fast, repr: None } } + if !scan.many_digits { + let fast = @internal/strconv.try_eisel_lemire64( + scan.mantissa, + scan.exponent, + scan.negative, + ) + if !fast.is_nan() { + return { value: fast, repr: None } + } + } let s = ctx.input.view(start_offset=start, end_offset=end) try { let d = @internal/strconv.parse_double(s) diff --git a/json/lex_number_test.mbt b/json/lex_number_test.mbt index 8d14be2a7..ffcf1a877 100644 --- a/json/lex_number_test.mbt +++ b/json/lex_number_test.mbt @@ -74,6 +74,24 @@ test "parse negative huge exponent" { ) } +///| +test "parse_number 17-19 digit mantissas" { + let cases : FixedArray[(String, UInt64)] = [ + ("-65.613616999999977", 13857689601620889920UL), + ("43.420273000000009", 4631307677475222056UL), + ("-65.619720000000029", 13857690031081335640UL), + ("43.418052999999986", 4631307365037997904UL), + ("9.999999999999999999", 4621819117588971520UL), + ] + for case in cases { + let (input, expected_bits) = case + guard @json.parse(input) is Number(value, ..) else { + fail("expected JSON number") + } + assert_eq(value.reinterpret_as_uint64(), expected_bits) + } +} + ///| test "parse and stringify large integers" { // Test integers at Int boundaries diff --git a/json/number_bench_test.mbt b/json/number_bench_test.mbt index a7590e5b7..faee4dbd2 100644 --- a/json/number_bench_test.mbt +++ b/json/number_bench_test.mbt @@ -40,6 +40,26 @@ fn make_float_array_json(count : Int) -> String { buf.to_string() } +///| +let long_mantissa_json_numbers : FixedArray[String] = [ + "-65.613616999999977", "43.420273000000009", "-65.619720000000029", "43.418052999999986", + "-65.625000000000000", "43.412101000000000", "-65.630279999999994", "43.406101000000010", +] + +///| +fn make_long_mantissa_array_json(count : Int) -> String { + let buf = StringBuilder(size_hint=count * 22) + buf.write_char('[') + for i in 0.. 0 { + buf.write_char(',') + } + buf.write_string(long_mantissa_json_numbers[i % 8]) + } + buf.write_char(']') + buf.to_string() +} + ///| test "bench json parse int array n=10000" (it : @bench.T) { let input = make_int_array_json(10000) @@ -51,3 +71,9 @@ test "bench json parse float array n=10000" (it : @bench.T) { let input = make_float_array_json(10000) it.bench(fn() { it.keep(try! @json.parse(input)) }) } + +///| +test "bench json parse long mantissa array n=10000" (it : @bench.T) { + let input = make_long_mantissa_array_json(10000) + it.bench(fn() { it.keep(try! @json.parse(input)) }) +} diff --git a/json/number_quickcheck_test.mbt b/json/number_quickcheck_test.mbt new file mode 100644 index 000000000..1ea8ad04b --- /dev/null +++ b/json/number_quickcheck_test.mbt @@ -0,0 +1,70 @@ +// Copyright 2026 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Property tests for JSON number parsing. +// +// `lex_number_end` routes a literal to one of several conversions — +// safe-integer, Clinger, Eisel-Lemire, or the exact strconv fallback — +// based purely on the literal's shape. Different spellings of the same +// value therefore take different routes, which yields the property that +// pins them all together: every spelling must parse to the same double, +// bit for bit. Padding the fraction with zeros pushes the significant-digit +// count past the 19 the fast routes tolerate, forcing the exact fallback +// and turning it into the oracle for the fast ones. + +///| +fn number_value_bits(text : String) -> UInt64? { + let json = @json.parse(text) catch { _ => return None } + guard json is Number(value, ..) else { return None } + Some(value.reinterpret_as_uint64()) +} + +///| +test "quickcheck: json number value is independent of its spelling" { + @quickcheck.check( + (input : (UInt64, Int, Int, Bool)) => { + let (raw, shift_code, exp_code, negative) = input + // The shift spreads mantissas across every magnitude; exponents + // overshoot the double range on both sides so the overflow and + // underflow fallbacks are exercised too. + let mantissa = raw >> wrap_index(shift_code, 64) + let exponent = wrap_index(exp_code, 723) - 361 + let sign = if negative { "-" } else { "" } + let digits = mantissa.to_string() + let plain = "\{sign}\{digits}e\{exponent}" + // Fraction zeros leave the value unchanged but push the significant + // digit count past 19, forcing the exact fallback. + let padded = "\{sign}\{digits}.\{String::make(21, '0')}e\{exponent}" + // The decimal point moved behind the first digit, with the exponent + // compensating — the same value split differently between mantissa + // and exponent by the scanner. + let len = digits.length() + let pointed = if len == 1 { + "\{sign}\{digits}.0e\{exponent}" + } else { + "\{sign}\{digits[0:1]}.\{digits[1:len]}e\{exponent + len - 1}" + } + match + ( + number_value_bits(plain), + number_value_bits(padded), + number_value_bits(pointed), + ) { + (Some(a), Some(b), Some(c)) => a == b && b == c + _ => false + } + }, + count=10000, + ) +}