├── gtest ├── .clang-format ├── CMakeLists.txt └── gtest │ └── gtest-spi.h ├── example.cc ├── .clang-format ├── zmij.h ├── CMakeLists.txt ├── gen-pow10.py ├── LICENSE ├── zmij-test.cc ├── README.md ├── zmij.c └── zmij.cc /gtest/.clang-format: -------------------------------------------------------------------------------- 1 | # Disable clang-format here. 2 | DisableFormat: true 3 | SortIncludes: Never 4 | -------------------------------------------------------------------------------- /example.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "zmij.h" 4 | 5 | int main() { 6 | char buf[zmij::buffer_size]; 7 | zmij::dtoa(6.62607015e-34, buf); 8 | puts(buf); 9 | } 10 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # Run manually to reformat a file: 2 | # clang-format -i --style=file 3 | Language: Cpp 4 | BasedOnStyle: Google 5 | IndentPPDirectives: AfterHash 6 | IndentCaseLabels: false 7 | AlwaysBreakTemplateDeclarations: false 8 | DerivePointerAlignment: false 9 | AllowShortCaseLabelsOnASingleLine: true 10 | QualifierAlignment: Left 11 | AlignConsecutiveShortCaseStatements: 12 | Enabled: true 13 | AcrossEmptyLines: true 14 | AcrossComments: true 15 | AlignCaseColons: false -------------------------------------------------------------------------------- /zmij.h: -------------------------------------------------------------------------------- 1 | // A double-to-string conversion algorithm based on Schubfach. 2 | // Copyright (c) 2025 - present, Victor Zverovich 3 | // Distributed under the MIT license (see LICENSE) or alternatively 4 | // the Boost Software License, Version 1.0. 5 | 6 | namespace zmij { 7 | 8 | constexpr int buffer_size = 25; 9 | 10 | /// Writes the shortest correctly rounded decimal representation of `value` to 11 | /// `buffer`. `buffer` should point to a buffer of size `buffer_size` or larger. 12 | void dtoa(double value, char* buffer) noexcept; 13 | 14 | } // namespace zmij 15 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(zmij CXX) 3 | 4 | add_library(zmij zmij.cc zmij.h) 5 | target_compile_features(zmij PRIVATE cxx_std_20) 6 | 7 | add_executable(example example.cc) 8 | target_link_libraries(example zmij) 9 | 10 | set(CMAKE_CTEST_ARGUMENTS "--output-on-failure") 11 | enable_testing() 12 | add_subdirectory(gtest) 13 | 14 | add_executable(zmij-test zmij-test.cc) 15 | target_link_libraries(zmij-test gtest) 16 | add_test(NAME zmij-test COMMAND zmij-test) 17 | 18 | add_executable(zmij-no-int128-test zmij-test.cc) 19 | target_compile_definitions(zmij-no-int128-test PRIVATE ZMIJ_USE_INT128=0) 20 | target_link_libraries(zmij-no-int128-test gtest) 21 | add_test(NAME zmij-no-int128-test COMMAND zmij-no-int128-test) 22 | -------------------------------------------------------------------------------- /gen-pow10.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Power of 10 significand generator for Żmij. 3 | # Copyright (c) 2025 - present, Victor Zverovich 4 | 5 | import math 6 | 7 | # Range of decimal exponents [K_min, K_max] from the paper. 8 | dec_exp_min = -324 9 | dec_exp_max = 292 10 | 11 | num_bits = 128 12 | 13 | # Negate dec_pow_min and dec_pow_max because we need negative powers 10^-k. 14 | for dec_exp in range(-dec_exp_max, -dec_exp_min + 1, 1): 15 | # dec_exp is -k in the paper. 16 | bin_exp = math.floor(dec_exp * math.log2(10)) - (num_bits - 1) 17 | bin_pow = 2**abs(bin_exp) 18 | dec_pow = 10**abs(dec_exp) 19 | if dec_exp < 0: 20 | result = bin_pow // dec_pow 21 | elif bin_exp < 0: 22 | result = dec_pow * bin_pow 23 | else: 24 | result = dec_pow // bin_pow 25 | hi, lo = result >> 64, (result & (2**64 - 1)) 26 | print(f"{{{hi:#x}, {lo:#018x}}}, // {dec_exp:4}") 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Victor Zverovich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /gtest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------ 2 | # Build the google test library 3 | 4 | # Compile Google Test ourselves instead of using pre-compiled libraries. 5 | # See the Google Test FAQ "Why is it not recommended to install a 6 | # pre-compiled copy of Google Test (for example, into /usr/local)?" 7 | # at http://code.google.com/p/googletest/wiki/FAQ for more details. 8 | add_library(gtest STATIC 9 | gmock-gtest-all.cc gmock/gmock.h gtest/gtest.h gtest/gtest-spi.h) 10 | target_compile_definitions(gtest PUBLIC GTEST_HAS_STD_WSTRING=1) 11 | target_include_directories(gtest SYSTEM PUBLIC .) 12 | target_compile_features(gtest PUBLIC cxx_std_11) 13 | 14 | find_package(Threads) 15 | if (Threads_FOUND) 16 | target_link_libraries(gtest ${CMAKE_THREAD_LIBS_INIT}) 17 | else () 18 | target_compile_definitions(gtest PUBLIC GTEST_HAS_PTHREAD=0) 19 | endif () 20 | 21 | if (MSVC) 22 | # Disable MSVC warnings about _CRT_INSECURE_DEPRECATE functions. 23 | target_compile_definitions(gtest PRIVATE _CRT_SECURE_NO_WARNINGS) 24 | if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") 25 | # Disable MSVC warnings about POSIX functions. 26 | target_compile_options(gtest PUBLIC -Wno-deprecated-declarations) 27 | endif () 28 | endif () 29 | -------------------------------------------------------------------------------- /zmij-test.cc: -------------------------------------------------------------------------------- 1 | #include "zmij.cc" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | auto dtoa(double value) -> std::string { 11 | char buffer[zmij::buffer_size]; 12 | zmij::dtoa(value, buffer); 13 | return buffer; 14 | } 15 | 16 | TEST(zmij_test, utilities) { 17 | EXPECT_EQ(count_lzero(1), 63); 18 | EXPECT_EQ(count_lzero(~0ull), 0); 19 | 20 | EXPECT_EQ(count_trailing_nonzeros(0x30303030'30303030ull), 0); 21 | EXPECT_EQ(count_trailing_nonzeros(0x30303030'30303031ull), 1); 22 | EXPECT_EQ(count_trailing_nonzeros(0x30303030'30303039ull), 1); 23 | EXPECT_EQ(count_trailing_nonzeros(0x30393030'39303030ull), 7); 24 | EXPECT_EQ(count_trailing_nonzeros(0x31303030'30303030ull), 8); 25 | EXPECT_EQ(count_trailing_nonzeros(0x39303030'30303030ull), 8); 26 | } 27 | 28 | TEST(zmij_test, umul192_upper64_inexact_to_odd) { 29 | auto pow10 = pow10_significands[0]; 30 | EXPECT_EQ(umul192_upper64_inexact_to_odd(pow10.hi, pow10.lo, 31 | 0x1234567890abcdef << 1), 32 | 0x24554a3ce60a45f5); 33 | EXPECT_EQ(umul192_upper64_inexact_to_odd(pow10.hi, pow10.lo, 34 | 0x1234567890abce16 << 1), 35 | 0x24554a3ce60a4643); 36 | } 37 | 38 | TEST(zmij_test, normal) { EXPECT_EQ(dtoa(6.62607015e-34), "6.62607015e-34"); } 39 | 40 | TEST(zmij_test, small_int) { EXPECT_EQ(dtoa(1), "1e+00"); } 41 | 42 | TEST(zmij_test, zero) { 43 | EXPECT_EQ(dtoa(0), "0"); 44 | EXPECT_EQ(dtoa(-0.0), "-0"); 45 | } 46 | 47 | TEST(zmij_test, inf) { 48 | EXPECT_EQ(dtoa(std::numeric_limits::infinity()), "inf"); 49 | EXPECT_EQ(dtoa(-std::numeric_limits::infinity()), "-inf"); 50 | } 51 | 52 | TEST(zmij_test, nan) { 53 | EXPECT_EQ(dtoa(std::numeric_limits::quiet_NaN()), "nan"); 54 | EXPECT_EQ(dtoa(-std::numeric_limits::quiet_NaN()), "-nan"); 55 | } 56 | 57 | TEST(zmij_test, shorter) { 58 | // A possibly shorter underestimate is picked (u' in Schubfach). 59 | EXPECT_EQ(dtoa(-4.932096661796888e-226), "-4.932096661796888e-226"); 60 | 61 | // A possibly shorter overestimate is picked (w' in Schubfach). 62 | EXPECT_EQ(dtoa(3.439070283483335e+35), "3.439070283483335e+35"); 63 | } 64 | 65 | TEST(zmij_test, single_candidate) { 66 | // Only an underestimate is in the rounding region (u in Schubfach). 67 | EXPECT_EQ(dtoa(6.606854224493745e-17), "6.606854224493745e-17"); 68 | 69 | // Only an overestimate is in the rounding region (w in Schubfach). 70 | EXPECT_EQ(dtoa(6.079537928711555e+61), "6.079537928711555e+61"); 71 | } 72 | 73 | TEST(zmij_test, all_exponents) { 74 | using limits = std::numeric_limits; 75 | for (int exp = limits::min_exponent; exp < limits::max_exponent; ++exp) { 76 | double expected = ldexp(1, exp); 77 | double actual = 0; 78 | sscanf(dtoa(expected).c_str(), "%lg", &actual); 79 | EXPECT_EQ(actual, expected); 80 | } 81 | } 82 | 83 | auto main(int argc, char** argv) -> int { 84 | testing::InitGoogleTest(&argc, argv); 85 | return RUN_ALL_TESTS(); 86 | } 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Żmij 2 | 3 | A double-to-string conversion algorithm based on [Schubfach](https://fmt.dev/papers/Schubfach4.pdf) 4 | and [yy](https://github.com/ibireme/c_numconv_benchmark/blob/master/vendor/yy_double/yy_double.c) 5 | with implementations in C and C++ 6 | 7 | ## Features 8 | 9 | * Round trip guarantee 10 | * Shortest decimal representation 11 | * Correct rounding 12 | * High [performance](#performance) 13 | * Fast [compile time](#compile-time) 14 | * Negative zero dependencies 15 | * Small, clean codebase consisting of one [source file]( 16 | https://github.com/vitaut/zmij/blob/main/zmij.cc) and one [header](https://github.com/vitaut/zmij/blob/main/zmij.h) 17 | * Permissive [license](https://github.com/vitaut/zmij/blob/main/LICENSE) 18 | 19 | ## Usage 20 | 21 | ```c++ 22 | #include "zmij.h" 23 | #include 24 | 25 | int main() { 26 | char buf[zmij::buffer_size]; 27 | zmij::dtoa(6.62607015e-34, buf); 28 | puts(buf); 29 | } 30 | ``` 31 | 32 | ## Performance 33 | 34 | More than 3x faster than [Ryu](https://github.com/ulfjack/ryu) used by multiple 35 | C++ standard library implementations and ~2x faster than 36 | [Schubfach](https://github.com/vitaut/schubfach) 37 | on [dtoa-benchmark](https://github.com/fmtlib/dtoa-benchmark) run on Apple M1. 38 | 39 | | Function | Time (ns) | Speedup | 40 | |---------------------|----------:|--------:| 41 | | ostringstream | 871.982 | 1.00x | 42 | | sprintf | 737.510 | 1.18x | 43 | | double-conversion | 84.304 | 10.34x | 44 | | to_chars | 42.786 | 20.38x | 45 | | ryu | 37.081 | 23.52x | 46 | | schubfach | 24.885 | 35.04x | 47 | | fmt | 22.274 | 39.15x | 48 | | dragonbox | 20.701 | 42.12x | 49 | | yy | 13.974 | 62.40x | 50 | | zmij | 12.271 | 71.06x | 51 | | null | 0.930 | 937.62x | 52 | 53 | image 54 | 55 | image 56 | 57 | ## Compile time 58 | 59 | Compile time is ~60ms by default and ~68ms with optimizations enabled as measured by 60 | 61 | ``` 62 | % time c++ -c -std=c++20 zmij.cc [-O2] 63 | ``` 64 | 65 | taking the best of 3 runs. 66 | 67 | ## Other languages 68 | 69 | * Rust: https://docs.rs/zmij/latest/zmij/index.html 70 | 71 | ## Differences from Schubfach 72 | 73 | * 1 instead of 3 multiplications by powers of 10 in the common case 74 | * Faster logarithm approximations 75 | * Faster division and modulo 76 | * Fewer conditional branches 77 | * More efficient significand and exponent output 78 | * Improved storage of powers of 10 79 | 80 | ## Name 81 | 82 | Żmij (pronounced roughly zhmeey or more precisely /ʐmij/) is a Polish word that refers 83 | to a mythical dragon- or serpent-like creature. This continues the dragon theme [started 84 | by Steele and White](https://fmt.dev/papers/p372-steele.pdf). Nice feature of this name 85 | is that it has a floating point in the first letter. 86 | -------------------------------------------------------------------------------- /gtest/gtest/gtest-spi.h: -------------------------------------------------------------------------------- 1 | // Copyright 2007, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // 31 | // Utilities for testing Google Test itself and code that uses Google Test 32 | // (e.g. frameworks built on top of Google Test). 33 | 34 | // GOOGLETEST_CM0004 DO NOT DELETE 35 | 36 | #ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_ 37 | #define GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_ 38 | 39 | #include "gtest/gtest.h" 40 | 41 | GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ 42 | /* class A needs to have dll-interface to be used by clients of class B */) 43 | 44 | namespace testing { 45 | 46 | // This helper class can be used to mock out Google Test failure reporting 47 | // so that we can test Google Test or code that builds on Google Test. 48 | // 49 | // An object of this class appends a TestPartResult object to the 50 | // TestPartResultArray object given in the constructor whenever a Google Test 51 | // failure is reported. It can either intercept only failures that are 52 | // generated in the same thread that created this object or it can intercept 53 | // all generated failures. The scope of this mock object can be controlled with 54 | // the second argument to the two arguments constructor. 55 | class GTEST_API_ ScopedFakeTestPartResultReporter 56 | : public TestPartResultReporterInterface { 57 | public: 58 | // The two possible mocking modes of this object. 59 | enum InterceptMode { 60 | INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. 61 | INTERCEPT_ALL_THREADS // Intercepts all failures. 62 | }; 63 | 64 | // The c'tor sets this object as the test part result reporter used 65 | // by Google Test. The 'result' parameter specifies where to report the 66 | // results. This reporter will only catch failures generated in the current 67 | // thread. DEPRECATED 68 | explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); 69 | 70 | // Same as above, but you can choose the interception scope of this object. 71 | ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, 72 | TestPartResultArray* result); 73 | 74 | // The d'tor restores the previous test part result reporter. 75 | ~ScopedFakeTestPartResultReporter() override; 76 | 77 | // Appends the TestPartResult object to the TestPartResultArray 78 | // received in the constructor. 79 | // 80 | // This method is from the TestPartResultReporterInterface 81 | // interface. 82 | void ReportTestPartResult(const TestPartResult& result) override; 83 | 84 | private: 85 | void Init(); 86 | 87 | const InterceptMode intercept_mode_; 88 | TestPartResultReporterInterface* old_reporter_; 89 | TestPartResultArray* const result_; 90 | 91 | GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); 92 | }; 93 | 94 | namespace internal { 95 | 96 | // A helper class for implementing EXPECT_FATAL_FAILURE() and 97 | // EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given 98 | // TestPartResultArray contains exactly one failure that has the given 99 | // type and contains the given substring. If that's not the case, a 100 | // non-fatal failure will be generated. 101 | class GTEST_API_ SingleFailureChecker { 102 | public: 103 | // The constructor remembers the arguments. 104 | SingleFailureChecker(const TestPartResultArray* results, 105 | TestPartResult::Type type, const std::string& substr); 106 | ~SingleFailureChecker(); 107 | private: 108 | const TestPartResultArray* const results_; 109 | const TestPartResult::Type type_; 110 | const std::string substr_; 111 | 112 | GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); 113 | }; 114 | 115 | } // namespace internal 116 | 117 | } // namespace testing 118 | 119 | GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 120 | 121 | // A set of macros for testing Google Test assertions or code that's expected 122 | // to generate Google Test fatal failures. It verifies that the given 123 | // statement will cause exactly one fatal Google Test failure with 'substr' 124 | // being part of the failure message. 125 | // 126 | // There are two different versions of this macro. EXPECT_FATAL_FAILURE only 127 | // affects and considers failures generated in the current thread and 128 | // EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. 129 | // 130 | // The verification of the assertion is done correctly even when the statement 131 | // throws an exception or aborts the current function. 132 | // 133 | // Known restrictions: 134 | // - 'statement' cannot reference local non-static variables or 135 | // non-static members of the current object. 136 | // - 'statement' cannot return a value. 137 | // - You cannot stream a failure message to this macro. 138 | // 139 | // Note that even though the implementations of the following two 140 | // macros are much alike, we cannot refactor them to use a common 141 | // helper macro, due to some peculiarity in how the preprocessor 142 | // works. The AcceptsMacroThatExpandsToUnprotectedComma test in 143 | // gtest_unittest.cc will fail to compile if we do that. 144 | #define EXPECT_FATAL_FAILURE(statement, substr) \ 145 | do { \ 146 | class GTestExpectFatalFailureHelper {\ 147 | public:\ 148 | static void Execute() { statement; }\ 149 | };\ 150 | ::testing::TestPartResultArray gtest_failures;\ 151 | ::testing::internal::SingleFailureChecker gtest_checker(\ 152 | >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ 153 | {\ 154 | ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ 155 | ::testing::ScopedFakeTestPartResultReporter:: \ 156 | INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ 157 | GTestExpectFatalFailureHelper::Execute();\ 158 | }\ 159 | } while (::testing::internal::AlwaysFalse()) 160 | 161 | #define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ 162 | do { \ 163 | class GTestExpectFatalFailureHelper {\ 164 | public:\ 165 | static void Execute() { statement; }\ 166 | };\ 167 | ::testing::TestPartResultArray gtest_failures;\ 168 | ::testing::internal::SingleFailureChecker gtest_checker(\ 169 | >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ 170 | {\ 171 | ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ 172 | ::testing::ScopedFakeTestPartResultReporter:: \ 173 | INTERCEPT_ALL_THREADS, >est_failures);\ 174 | GTestExpectFatalFailureHelper::Execute();\ 175 | }\ 176 | } while (::testing::internal::AlwaysFalse()) 177 | 178 | // A macro for testing Google Test assertions or code that's expected to 179 | // generate Google Test non-fatal failures. It asserts that the given 180 | // statement will cause exactly one non-fatal Google Test failure with 'substr' 181 | // being part of the failure message. 182 | // 183 | // There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only 184 | // affects and considers failures generated in the current thread and 185 | // EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. 186 | // 187 | // 'statement' is allowed to reference local variables and members of 188 | // the current object. 189 | // 190 | // The verification of the assertion is done correctly even when the statement 191 | // throws an exception or aborts the current function. 192 | // 193 | // Known restrictions: 194 | // - You cannot stream a failure message to this macro. 195 | // 196 | // Note that even though the implementations of the following two 197 | // macros are much alike, we cannot refactor them to use a common 198 | // helper macro, due to some peculiarity in how the preprocessor 199 | // works. If we do that, the code won't compile when the user gives 200 | // EXPECT_NONFATAL_FAILURE() a statement that contains a macro that 201 | // expands to code containing an unprotected comma. The 202 | // AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc 203 | // catches that. 204 | // 205 | // For the same reason, we have to write 206 | // if (::testing::internal::AlwaysTrue()) { statement; } 207 | // instead of 208 | // GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) 209 | // to avoid an MSVC warning on unreachable code. 210 | #define EXPECT_NONFATAL_FAILURE(statement, substr) \ 211 | do {\ 212 | ::testing::TestPartResultArray gtest_failures;\ 213 | ::testing::internal::SingleFailureChecker gtest_checker(\ 214 | >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ 215 | (substr));\ 216 | {\ 217 | ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ 218 | ::testing::ScopedFakeTestPartResultReporter:: \ 219 | INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ 220 | if (::testing::internal::AlwaysTrue()) { statement; }\ 221 | }\ 222 | } while (::testing::internal::AlwaysFalse()) 223 | 224 | #define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ 225 | do {\ 226 | ::testing::TestPartResultArray gtest_failures;\ 227 | ::testing::internal::SingleFailureChecker gtest_checker(\ 228 | >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ 229 | (substr));\ 230 | {\ 231 | ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ 232 | ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ 233 | >est_failures);\ 234 | if (::testing::internal::AlwaysTrue()) { statement; }\ 235 | }\ 236 | } while (::testing::internal::AlwaysFalse()) 237 | 238 | #endif // GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_ 239 | -------------------------------------------------------------------------------- /zmij.c: -------------------------------------------------------------------------------- 1 | // A double-to-string conversion algorithm based on Schubfach. 2 | // Copyright (c) 2025 - present, Victor Zverovich 3 | // Distributed under the MIT license (see LICENSE). 4 | // https://github.com/vitaut/zmij/ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef _MSC_VER 13 | #include // lzcnt/adc/umul128/umulh 14 | #endif 15 | 16 | typedef struct { 17 | uint64_t hi; 18 | uint64_t lo; 19 | } uint128; 20 | 21 | #if defined(__SIZEOF_INT128__) 22 | typedef unsigned __int128 uint128_t; 23 | #else 24 | typedef uint128 uint128_t; 25 | #endif 26 | 27 | static inline uint128 uint128_add(uint128 a, uint128 b) { 28 | #if defined(_MSC_VER) && defined(_M_AMD64) 29 | uint128 r; 30 | _addcarry_u64(_addcarry_u64(0, a.lo, b.lo, &r.lo), a.hi, b.hi, &r.hi); 31 | return r; 32 | #else 33 | uint64_t lo = a.lo + b.lo; 34 | uint128 r; 35 | r.hi = a.hi + b.hi + (lo < a.lo); 36 | r.lo = lo; 37 | return r; 38 | #endif 39 | } 40 | 41 | static inline uint128 uint128_shr(uint128 x, int shift) { 42 | assert(shift >= 64 && shift < 128); 43 | uint128 r = {0, x.hi >> (shift - 64)}; 44 | return r; 45 | } 46 | 47 | // 128-bit significands of strict overestimates of powers of 10. 48 | // Generated with gen-pow10.py. 49 | static const uint128 pow10_significands[] = { 50 | {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, // -292 51 | {0x9faacf3df73609b1, 0x77b191618c54e9ad}, // -291 52 | {0xc795830d75038c1d, 0xd59df5b9ef6a2418}, // -290 53 | {0xf97ae3d0d2446f25, 0x4b0573286b44ad1e}, // -289 54 | {0x9becce62836ac577, 0x4ee367f9430aec33}, // -288 55 | {0xc2e801fb244576d5, 0x229c41f793cda740}, // -287 56 | {0xf3a20279ed56d48a, 0x6b43527578c11110}, // -286 57 | {0x9845418c345644d6, 0x830a13896b78aaaa}, // -285 58 | {0xbe5691ef416bd60c, 0x23cc986bc656d554}, // -284 59 | {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9}, // -283 60 | {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa}, // -282 61 | {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54}, // -281 62 | {0xe858ad248f5c22c9, 0xd1b3400f8f9cff69}, // -280 63 | {0x91376c36d99995be, 0x23100809b9c21fa2}, // -279 64 | {0xb58547448ffffb2d, 0xabd40a0c2832a78b}, // -278 65 | {0xe2e69915b3fff9f9, 0x16c90c8f323f516d}, // -277 66 | {0x8dd01fad907ffc3b, 0xae3da7d97f6792e4}, // -276 67 | {0xb1442798f49ffb4a, 0x99cd11cfdf41779d}, // -275 68 | {0xdd95317f31c7fa1d, 0x40405643d711d584}, // -274 69 | {0x8a7d3eef7f1cfc52, 0x482835ea666b2573}, // -273 70 | {0xad1c8eab5ee43b66, 0xda3243650005eed0}, // -272 71 | {0xd863b256369d4a40, 0x90bed43e40076a83}, // -271 72 | {0x873e4f75e2224e68, 0x5a7744a6e804a292}, // -270 73 | {0xa90de3535aaae202, 0x711515d0a205cb37}, // -269 74 | {0xd3515c2831559a83, 0x0d5a5b44ca873e04}, // -268 75 | {0x8412d9991ed58091, 0xe858790afe9486c3}, // -267 76 | {0xa5178fff668ae0b6, 0x626e974dbe39a873}, // -266 77 | {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, // -265 78 | {0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a}, // -264 79 | {0xa139029f6a239f72, 0x1c1fffc1ebc44e81}, // -263 80 | {0xc987434744ac874e, 0xa327ffb266b56221}, // -262 81 | {0xfbe9141915d7a922, 0x4bf1ff9f0062baa9}, // -261 82 | {0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa}, // -260 83 | {0xc4ce17b399107c22, 0xcb550fb4384d21d4}, // -259 84 | {0xf6019da07f549b2b, 0x7e2a53a146606a49}, // -258 85 | {0x99c102844f94e0fb, 0x2eda7444cbfc426e}, // -257 86 | {0xc0314325637a1939, 0xfa911155fefb5309}, // -256 87 | {0xf03d93eebc589f88, 0x793555ab7eba27cb}, // -255 88 | {0x96267c7535b763b5, 0x4bc1558b2f3458df}, // -254 89 | {0xbbb01b9283253ca2, 0x9eb1aaedfb016f17}, // -253 90 | {0xea9c227723ee8bcb, 0x465e15a979c1cadd}, // -252 91 | {0x92a1958a7675175f, 0x0bfacd89ec191eca}, // -251 92 | {0xb749faed14125d36, 0xcef980ec671f667c}, // -250 93 | {0xe51c79a85916f484, 0x82b7e12780e7401b}, // -249 94 | {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811}, // -248 95 | {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16}, // -247 96 | {0xdfbdcece67006ac9, 0x67a791e093e1d49b}, // -246 97 | {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1}, // -245 98 | {0xaecc49914078536d, 0x58fae9f773886e19}, // -244 99 | {0xda7f5bf590966848, 0xaf39a475506a899f}, // -243 100 | {0x888f99797a5e012d, 0x6d8406c952429604}, // -242 101 | {0xaab37fd7d8f58178, 0xc8e5087ba6d33b84}, // -241 102 | {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65}, // -240 103 | {0x855c3be0a17fcd26, 0x5cf2eea09a550680}, // -239 104 | {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, // -238 105 | {0xd0601d8efc57b08b, 0xf13b94daf124da27}, // -237 106 | {0x823c12795db6ce57, 0x76c53d08d6b70859}, // -236 107 | {0xa2cb1717b52481ed, 0x54768c4b0c64ca6f}, // -235 108 | {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a}, // -234 109 | {0xfe5d54150b090b02, 0xd3f93b35435d7c4d}, // -233 110 | {0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0}, // -232 111 | {0xc6b8e9b0709f109a, 0x359ab6419ca1091c}, // -231 112 | {0xf867241c8cc6d4c0, 0xc30163d203c94b63}, // -230 113 | {0x9b407691d7fc44f8, 0x79e0de63425dcf1e}, // -229 114 | {0xc21094364dfb5636, 0x985915fc12f542e5}, // -228 115 | {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e}, // -227 116 | {0x979cf3ca6cec5b5a, 0xa705992ceecf9c43}, // -226 117 | {0xbd8430bd08277231, 0x50c6ff782a838354}, // -225 118 | {0xece53cec4a314ebd, 0xa4f8bf5635246429}, // -224 119 | {0x940f4613ae5ed136, 0x871b7795e136be9a}, // -223 120 | {0xb913179899f68584, 0x28e2557b59846e40}, // -222 121 | {0xe757dd7ec07426e5, 0x331aeada2fe589d0}, // -221 122 | {0x9096ea6f3848984f, 0x3ff0d2c85def7622}, // -220 123 | {0xb4bca50b065abe63, 0x0fed077a756b53aa}, // -219 124 | {0xe1ebce4dc7f16dfb, 0xd3e8495912c62895}, // -218 125 | {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d}, // -217 126 | {0xb080392cc4349dec, 0xbd8d794d96aacfb4}, // -216 127 | {0xdca04777f541c567, 0xecf0d7a0fc5583a1}, // -215 128 | {0x89e42caaf9491b60, 0xf41686c49db57245}, // -214 129 | {0xac5d37d5b79b6239, 0x311c2875c522ced6}, // -213 130 | {0xd77485cb25823ac7, 0x7d633293366b828c}, // -212 131 | {0x86a8d39ef77164bc, 0xae5dff9c02033198}, // -211 132 | {0xa8530886b54dbdeb, 0xd9f57f830283fdfd}, // -210 133 | {0xd267caa862a12d66, 0xd072df63c324fd7c}, // -209 134 | {0x8380dea93da4bc60, 0x4247cb9e59f71e6e}, // -208 135 | {0xa46116538d0deb78, 0x52d9be85f074e609}, // -207 136 | {0xcd795be870516656, 0x67902e276c921f8c}, // -206 137 | {0x806bd9714632dff6, 0x00ba1cd8a3db53b7}, // -205 138 | {0xa086cfcd97bf97f3, 0x80e8a40eccd228a5}, // -204 139 | {0xc8a883c0fdaf7df0, 0x6122cd128006b2ce}, // -203 140 | {0xfad2a4b13d1b5d6c, 0x796b805720085f82}, // -202 141 | {0x9cc3a6eec6311a63, 0xcbe3303674053bb1}, // -201 142 | {0xc3f490aa77bd60fc, 0xbedbfc4411068a9d}, // -200 143 | {0xf4f1b4d515acb93b, 0xee92fb5515482d45}, // -199 144 | {0x991711052d8bf3c5, 0x751bdd152d4d1c4b}, // -198 145 | {0xbf5cd54678eef0b6, 0xd262d45a78a0635e}, // -197 146 | {0xef340a98172aace4, 0x86fb897116c87c35}, // -196 147 | {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1}, // -195 148 | {0xbae0a846d2195712, 0x8974836059cca10a}, // -194 149 | {0xe998d258869facd7, 0x2bd1a438703fc94c}, // -193 150 | {0x91ff83775423cc06, 0x7b6306a34627ddd0}, // -192 151 | {0xb67f6455292cbf08, 0x1a3bc84c17b1d543}, // -191 152 | {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94}, // -190 153 | {0x8e938662882af53e, 0x547eb47b7282ee9d}, // -189 154 | {0xb23867fb2a35b28d, 0xe99e619a4f23aa44}, // -188 155 | {0xdec681f9f4c31f31, 0x6405fa00e2ec94d5}, // -187 156 | {0x8b3c113c38f9f37e, 0xde83bc408dd3dd05}, // -186 157 | {0xae0b158b4738705e, 0x9624ab50b148d446}, // -185 158 | {0xd98ddaee19068c76, 0x3badd624dd9b0958}, // -184 159 | {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7}, // -183 160 | {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d}, // -182 161 | {0xd47487cc8470652b, 0x7647c32000696720}, // -181 162 | {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074}, // -180 163 | {0xa5fb0a17c777cf09, 0xf468107100525891}, // -179 164 | {0xcf79cc9db955c2cc, 0x7182148d4066eeb5}, // -178 165 | {0x81ac1fe293d599bf, 0xc6f14cd848405531}, // -177 166 | {0xa21727db38cb002f, 0xb8ada00e5a506a7d}, // -176 167 | {0xca9cf1d206fdc03b, 0xa6d90811f0e4851d}, // -175 168 | {0xfd442e4688bd304a, 0x908f4a166d1da664}, // -174 169 | {0x9e4a9cec15763e2e, 0x9a598e4e043287ff}, // -173 170 | {0xc5dd44271ad3cdba, 0x40eff1e1853f29fe}, // -172 171 | {0xf7549530e188c128, 0xd12bee59e68ef47d}, // -171 172 | {0x9a94dd3e8cf578b9, 0x82bb74f8301958cf}, // -170 173 | {0xc13a148e3032d6e7, 0xe36a52363c1faf02}, // -169 174 | {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2}, // -168 175 | {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba}, // -167 176 | {0xbcb2b812db11a5de, 0x7415d448f6b6f0e8}, // -166 177 | {0xebdf661791d60f56, 0x111b495b3464ad22}, // -165 178 | {0x936b9fcebb25c995, 0xcab10dd900beec35}, // -164 179 | {0xb84687c269ef3bfb, 0x3d5d514f40eea743}, // -163 180 | {0xe65829b3046b0afa, 0x0cb4a5a3112a5113}, // -162 181 | {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac}, // -161 182 | {0xb3f4e093db73a093, 0x59ed216765690f57}, // -160 183 | {0xe0f218b8d25088b8, 0x306869c13ec3532d}, // -159 184 | {0x8c974f7383725573, 0x1e414218c73a13fc}, // -158 185 | {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, // -157 186 | {0xdbac6c247d62a583, 0xdf45f746b74abf3a}, // -156 187 | {0x894bc396ce5da772, 0x6b8bba8c328eb784}, // -155 188 | {0xab9eb47c81f5114f, 0x066ea92f3f326565}, // -154 189 | {0xd686619ba27255a2, 0xc80a537b0efefebe}, // -153 190 | {0x8613fd0145877585, 0xbd06742ce95f5f37}, // -152 191 | {0xa798fc4196e952e7, 0x2c48113823b73705}, // -151 192 | {0xd17f3b51fca3a7a0, 0xf75a15862ca504c6}, // -150 193 | {0x82ef85133de648c4, 0x9a984d73dbe722fc}, // -149 194 | {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb}, // -148 195 | {0xcc963fee10b7d1b3, 0x318df905079926a9}, // -147 196 | {0xffbbcfe994e5c61f, 0xfdf17746497f7053}, // -146 197 | {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634}, // -145 198 | {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1}, // -144 199 | {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1}, // -143 200 | {0x9c1661a651213e2d, 0x06bea10ca65c084f}, // -142 201 | {0xc31bfa0fe5698db8, 0x486e494fcff30a63}, // -141 202 | {0xf3e2f893dec3f126, 0x5a89dba3c3efccfb}, // -140 203 | {0x986ddb5c6b3a76b7, 0xf89629465a75e01d}, // -139 204 | {0xbe89523386091465, 0xf6bbb397f1135824}, // -138 205 | {0xee2ba6c0678b597f, 0x746aa07ded582e2d}, // -137 206 | {0x94db483840b717ef, 0xa8c2a44eb4571cdd}, // -136 207 | {0xba121a4650e4ddeb, 0x92f34d62616ce414}, // -135 208 | {0xe896a0d7e51e1566, 0x77b020baf9c81d18}, // -134 209 | {0x915e2486ef32cd60, 0x0ace1474dc1d122f}, // -133 210 | {0xb5b5ada8aaff80b8, 0x0d819992132456bb}, // -132 211 | {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a}, // -131 212 | {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, // -130 213 | {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3}, // -129 214 | {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf}, // -128 215 | {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c}, // -127 216 | {0xad4ab7112eb3929d, 0x86c16c98d2c953c7}, // -126 217 | {0xd89d64d57a607744, 0xe871c7bf077ba8b8}, // -125 218 | {0x87625f056c7c4a8b, 0x11471cd764ad4973}, // -124 219 | {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0}, // -123 220 | {0xd389b47879823479, 0x4aff1d108d4ec2c4}, // -122 221 | {0x843610cb4bf160cb, 0xcedf722a585139bb}, // -121 222 | {0xa54394fe1eedb8fe, 0xc2974eb4ee658829}, // -120 223 | {0xce947a3da6a9273e, 0x733d226229feea33}, // -119 224 | {0x811ccc668829b887, 0x0806357d5a3f5260}, // -118 225 | {0xa163ff802a3426a8, 0xca07c2dcb0cf26f8}, // -117 226 | {0xc9bcff6034c13052, 0xfc89b393dd02f0b6}, // -116 227 | {0xfc2c3f3841f17c67, 0xbbac2078d443ace3}, // -115 228 | {0x9d9ba7832936edc0, 0xd54b944b84aa4c0e}, // -114 229 | {0xc5029163f384a931, 0x0a9e795e65d4df12}, // -113 230 | {0xf64335bcf065d37d, 0x4d4617b5ff4a16d6}, // -112 231 | {0x99ea0196163fa42e, 0x504bced1bf8e4e46}, // -111 232 | {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7}, // -110 233 | {0xf07da27a82c37088, 0x5d767327bb4e5a4d}, // -109 234 | {0x964e858c91ba2655, 0x3a6a07f8d510f870}, // -108 235 | {0xbbe226efb628afea, 0x890489f70a55368c}, // -107 236 | {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f}, // -106 237 | {0x92c8ae6b464fc96f, 0x3b0b8bc90012929e}, // -105 238 | {0xb77ada0617e3bbcb, 0x09ce6ebb40173745}, // -104 239 | {0xe55990879ddcaabd, 0xcc420a6a101d0516}, // -103 240 | {0x8f57fa54c2a9eab6, 0x9fa946824a12232e}, // -102 241 | {0xb32df8e9f3546564, 0x47939822dc96abfa}, // -101 242 | {0xdff9772470297ebd, 0x59787e2b93bc56f8}, // -100 243 | {0x8bfbea76c619ef36, 0x57eb4edb3c55b65b}, // -99 244 | {0xaefae51477a06b03, 0xede622920b6b23f2}, // -98 245 | {0xdab99e59958885c4, 0xe95fab368e45ecee}, // -97 246 | {0x88b402f7fd75539b, 0x11dbcb0218ebb415}, // -96 247 | {0xaae103b5fcd2a881, 0xd652bdc29f26a11a}, // -95 248 | {0xd59944a37c0752a2, 0x4be76d3346f04960}, // -94 249 | {0x857fcae62d8493a5, 0x6f70a4400c562ddc}, // -93 250 | {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953}, // -92 251 | {0xd097ad07a71f26b2, 0x7e2000a41346a7a8}, // -91 252 | {0x825ecc24c873782f, 0x8ed400668c0c28c9}, // -90 253 | {0xa2f67f2dfa90563b, 0x728900802f0f32fb}, // -89 254 | {0xcbb41ef979346bca, 0x4f2b40a03ad2ffba}, // -88 255 | {0xfea126b7d78186bc, 0xe2f610c84987bfa9}, // -87 256 | {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca}, // -86 257 | {0xc6ede63fa05d3143, 0x91503d1c79720dbc}, // -85 258 | {0xf8a95fcf88747d94, 0x75a44c6397ce912b}, // -84 259 | {0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb}, // -83 260 | {0xc24452da229b021b, 0xfbe85badce996169}, // -82 261 | {0xf2d56790ab41c2a2, 0xfae27299423fb9c4}, // -81 262 | {0x97c560ba6b0919a5, 0xdccd879fc967d41b}, // -80 263 | {0xbdb6b8e905cb600f, 0x5400e987bbc1c921}, // -79 264 | {0xed246723473e3813, 0x290123e9aab23b69}, // -78 265 | {0x9436c0760c86e30b, 0xf9a0b6720aaf6522}, // -77 266 | {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, // -76 267 | {0xe7958cb87392c2c2, 0xb60b1d1230b20e05}, // -75 268 | {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3}, // -74 269 | {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4}, // -73 270 | {0xe2280b6c20dd5232, 0x25c6da63c38de1b1}, // -72 271 | {0x8d590723948a535f, 0x579c487e5a38ad0f}, // -71 272 | {0xb0af48ec79ace837, 0x2d835a9df0c6d852}, // -70 273 | {0xdcdb1b2798182244, 0xf8e431456cf88e66}, // -69 274 | {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900}, // -68 275 | {0xac8b2d36eed2dac5, 0xe272467e3d222f40}, // -67 276 | {0xd7adf884aa879177, 0x5b0ed81dcc6abb10}, // -66 277 | {0x86ccbb52ea94baea, 0x98e947129fc2b4ea}, // -65 278 | {0xa87fea27a539e9a5, 0x3f2398d747b36225}, // -64 279 | {0xd29fe4b18e88640e, 0x8eec7f0d19a03aae}, // -63 280 | {0x83a3eeeef9153e89, 0x1953cf68300424ad}, // -62 281 | {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8}, // -61 282 | {0xcdb02555653131b6, 0x3792f412cb06794e}, // -60 283 | {0x808e17555f3ebf11, 0xe2bbd88bbee40bd1}, // -59 284 | {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5}, // -58 285 | {0xc8de047564d20a8b, 0xf245825a5a445276}, // -57 286 | {0xfb158592be068d2e, 0xeed6e2f0f0d56713}, // -56 287 | {0x9ced737bb6c4183d, 0x55464dd69685606c}, // -55 288 | {0xc428d05aa4751e4c, 0xaa97e14c3c26b887}, // -54 289 | {0xf53304714d9265df, 0xd53dd99f4b3066a9}, // -53 290 | {0x993fe2c6d07b7fab, 0xe546a8038efe402a}, // -52 291 | {0xbf8fdb78849a5f96, 0xde98520472bdd034}, // -51 292 | {0xef73d256a5c0f77c, 0x963e66858f6d4441}, // -50 293 | {0x95a8637627989aad, 0xdde7001379a44aa9}, // -49 294 | {0xbb127c53b17ec159, 0x5560c018580d5d53}, // -48 295 | {0xe9d71b689dde71af, 0xaab8f01e6e10b4a7}, // -47 296 | {0x9226712162ab070d, 0xcab3961304ca70e9}, // -46 297 | {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23}, // -45 298 | {0xe45c10c42a2b3b05, 0x8cb89a7db77c506b}, // -44 299 | {0x8eb98a7a9a5b04e3, 0x77f3608e92adb243}, // -43 300 | {0xb267ed1940f1c61c, 0x55f038b237591ed4}, // -42 301 | {0xdf01e85f912e37a3, 0x6b6c46dec52f6689}, // -41 302 | {0x8b61313bbabce2c6, 0x2323ac4b3b3da016}, // -40 303 | {0xae397d8aa96c1b77, 0xabec975e0a0d081b}, // -39 304 | {0xd9c7dced53c72255, 0x96e7bd358c904a22}, // -38 305 | {0x881cea14545c7575, 0x7e50d64177da2e55}, // -37 306 | {0xaa242499697392d2, 0xdde50bd1d5d0b9ea}, // -36 307 | {0xd4ad2dbfc3d07787, 0x955e4ec64b44e865}, // -35 308 | {0x84ec3c97da624ab4, 0xbd5af13bef0b113f}, // -34 309 | {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f}, // -33 310 | {0xcfb11ead453994ba, 0x67de18eda5814af3}, // -32 311 | {0x81ceb32c4b43fcf4, 0x80eacf948770ced8}, // -31 312 | {0xa2425ff75e14fc31, 0xa1258379a94d028e}, // -30 313 | {0xcad2f7f5359a3b3e, 0x096ee45813a04331}, // -29 314 | {0xfd87b5f28300ca0d, 0x8bca9d6e188853fd}, // -28 315 | {0x9e74d1b791e07e48, 0x775ea264cf55347e}, // -27 316 | {0xc612062576589dda, 0x95364afe032a819e}, // -26 317 | {0xf79687aed3eec551, 0x3a83ddbd83f52205}, // -25 318 | {0x9abe14cd44753b52, 0xc4926a9672793543}, // -24 319 | {0xc16d9a0095928a27, 0x75b7053c0f178294}, // -23 320 | {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, // -22 321 | {0x971da05074da7bee, 0xd3f6fc16ebca5e04}, // -21 322 | {0xbce5086492111aea, 0x88f4bb1ca6bcf585}, // -20 323 | {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6}, // -19 324 | {0x9392ee8e921d5d07, 0x3aff322e62439fd0}, // -18 325 | {0xb877aa3236a4b449, 0x09befeb9fad487c3}, // -17 326 | {0xe69594bec44de15b, 0x4c2ebe687989a9b4}, // -16 327 | {0x901d7cf73ab0acd9, 0x0f9d37014bf60a11}, // -15 328 | {0xb424dc35095cd80f, 0x538484c19ef38c95}, // -14 329 | {0xe12e13424bb40e13, 0x2865a5f206b06fba}, // -13 330 | {0x8cbccc096f5088cb, 0xf93f87b7442e45d4}, // -12 331 | {0xafebff0bcb24aafe, 0xf78f69a51539d749}, // -11 332 | {0xdbe6fecebdedd5be, 0xb573440e5a884d1c}, // -10 333 | {0x89705f4136b4a597, 0x31680a88f8953031}, // -9 334 | {0xabcc77118461cefc, 0xfdc20d2b36ba7c3e}, // -8 335 | {0xd6bf94d5e57a42bc, 0x3d32907604691b4d}, // -7 336 | {0x8637bd05af6c69b5, 0xa63f9a49c2c1b110}, // -6 337 | {0xa7c5ac471b478423, 0x0fcf80dc33721d54}, // -5 338 | {0xd1b71758e219652b, 0xd3c36113404ea4a9}, // -4 339 | {0x83126e978d4fdf3b, 0x645a1cac083126ea}, // -3 340 | {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4}, // -2 341 | {0xcccccccccccccccc, 0xcccccccccccccccd}, // -1 342 | {0x8000000000000000, 0x0000000000000001}, // 0 343 | {0xa000000000000000, 0x0000000000000001}, // 1 344 | {0xc800000000000000, 0x0000000000000001}, // 2 345 | {0xfa00000000000000, 0x0000000000000001}, // 3 346 | {0x9c40000000000000, 0x0000000000000001}, // 4 347 | {0xc350000000000000, 0x0000000000000001}, // 5 348 | {0xf424000000000000, 0x0000000000000001}, // 6 349 | {0x9896800000000000, 0x0000000000000001}, // 7 350 | {0xbebc200000000000, 0x0000000000000001}, // 8 351 | {0xee6b280000000000, 0x0000000000000001}, // 9 352 | {0x9502f90000000000, 0x0000000000000001}, // 10 353 | {0xba43b74000000000, 0x0000000000000001}, // 11 354 | {0xe8d4a51000000000, 0x0000000000000001}, // 12 355 | {0x9184e72a00000000, 0x0000000000000001}, // 13 356 | {0xb5e620f480000000, 0x0000000000000001}, // 14 357 | {0xe35fa931a0000000, 0x0000000000000001}, // 15 358 | {0x8e1bc9bf04000000, 0x0000000000000001}, // 16 359 | {0xb1a2bc2ec5000000, 0x0000000000000001}, // 17 360 | {0xde0b6b3a76400000, 0x0000000000000001}, // 18 361 | {0x8ac7230489e80000, 0x0000000000000001}, // 19 362 | {0xad78ebc5ac620000, 0x0000000000000001}, // 20 363 | {0xd8d726b7177a8000, 0x0000000000000001}, // 21 364 | {0x878678326eac9000, 0x0000000000000001}, // 22 365 | {0xa968163f0a57b400, 0x0000000000000001}, // 23 366 | {0xd3c21bcecceda100, 0x0000000000000001}, // 24 367 | {0x84595161401484a0, 0x0000000000000001}, // 25 368 | {0xa56fa5b99019a5c8, 0x0000000000000001}, // 26 369 | {0xcecb8f27f4200f3a, 0x0000000000000001}, // 27 370 | {0x813f3978f8940984, 0x4000000000000001}, // 28 371 | {0xa18f07d736b90be5, 0x5000000000000001}, // 29 372 | {0xc9f2c9cd04674ede, 0xa400000000000001}, // 30 373 | {0xfc6f7c4045812296, 0x4d00000000000001}, // 31 374 | {0x9dc5ada82b70b59d, 0xf020000000000001}, // 32 375 | {0xc5371912364ce305, 0x6c28000000000001}, // 33 376 | {0xf684df56c3e01bc6, 0xc732000000000001}, // 34 377 | {0x9a130b963a6c115c, 0x3c7f400000000001}, // 35 378 | {0xc097ce7bc90715b3, 0x4b9f100000000001}, // 36 379 | {0xf0bdc21abb48db20, 0x1e86d40000000001}, // 37 380 | {0x96769950b50d88f4, 0x1314448000000001}, // 38 381 | {0xbc143fa4e250eb31, 0x17d955a000000001}, // 39 382 | {0xeb194f8e1ae525fd, 0x5dcfab0800000001}, // 40 383 | {0x92efd1b8d0cf37be, 0x5aa1cae500000001}, // 41 384 | {0xb7abc627050305ad, 0xf14a3d9e40000001}, // 42 385 | {0xe596b7b0c643c719, 0x6d9ccd05d0000001}, // 43 386 | {0x8f7e32ce7bea5c6f, 0xe4820023a2000001}, // 44 387 | {0xb35dbf821ae4f38b, 0xdda2802c8a800001}, // 45 388 | {0xe0352f62a19e306e, 0xd50b2037ad200001}, // 46 389 | {0x8c213d9da502de45, 0x4526f422cc340001}, // 47 390 | {0xaf298d050e4395d6, 0x9670b12b7f410001}, // 48 391 | {0xdaf3f04651d47b4c, 0x3c0cdd765f114001}, // 49 392 | {0x88d8762bf324cd0f, 0xa5880a69fb6ac801}, // 50 393 | {0xab0e93b6efee0053, 0x8eea0d047a457a01}, // 51 394 | {0xd5d238a4abe98068, 0x72a4904598d6d881}, // 52 395 | {0x85a36366eb71f041, 0x47a6da2b7f864751}, // 53 396 | {0xa70c3c40a64e6c51, 0x999090b65f67d925}, // 54 397 | {0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6e}, // 55 398 | {0x82818f1281ed449f, 0xbff8f10e7a8921a5}, // 56 399 | {0xa321f2d7226895c7, 0xaff72d52192b6a0e}, // 57 400 | {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764491}, // 58 401 | {0xfee50b7025c36a08, 0x02f236d04753d5b5}, // 59 402 | {0x9f4f2726179a2245, 0x01d762422c946591}, // 60 403 | {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef6}, // 61 404 | {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb3}, // 62 405 | {0x9b934c3b330c8577, 0x63cc55f49f88eb30}, // 63 406 | {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fc}, // 64 407 | {0xf316271c7fc3908a, 0x8bef464e3945ef7b}, // 65 408 | {0x97edd871cfda3a56, 0x97758bf0e3cbb5ad}, // 66 409 | {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea318}, // 67 410 | {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bde}, // 68 411 | {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6b}, // 69 412 | {0xb975d6b6ee39e436, 0xb3e2fd538e122b45}, // 70 413 | {0xe7d34c64a9c85d44, 0x60dbbca87196b617}, // 71 414 | {0x90e40fbeea1d3a4a, 0xbc8955e946fe31ce}, // 72 415 | {0xb51d13aea4a488dd, 0x6babab6398bdbe42}, // 73 416 | {0xe264589a4dcdab14, 0xc696963c7eed2dd2}, // 74 417 | {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca3}, // 75 418 | {0xb0de65388cc8ada8, 0x3b25a55f43294bcc}, // 76 419 | {0xdd15fe86affad912, 0x49ef0eb713f39ebf}, // 77 420 | {0x8a2dbf142dfcc7ab, 0x6e3569326c784338}, // 78 421 | {0xacb92ed9397bf996, 0x49c2c37f07965405}, // 79 422 | {0xd7e77a8f87daf7fb, 0xdc33745ec97be907}, // 80 423 | {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a4}, // 81 424 | {0xa8acd7c0222311bc, 0xc40832ea0d68ce0d}, // 82 425 | {0xd2d80db02aabd62b, 0xf50a3fa490c30191}, // 83 426 | {0x83c7088e1aab65db, 0x792667c6da79e0fb}, // 84 427 | {0xa4b8cab1a1563f52, 0x577001b891185939}, // 85 428 | {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, // 86 429 | {0x80b05e5ac60b6178, 0x544f8158315b05b5}, // 87 430 | {0xa0dc75f1778e39d6, 0x696361ae3db1c722}, // 88 431 | {0xc913936dd571c84c, 0x03bc3a19cd1e38ea}, // 89 432 | {0xfb5878494ace3a5f, 0x04ab48a04065c724}, // 90 433 | {0x9d174b2dcec0e47b, 0x62eb0d64283f9c77}, // 91 434 | {0xc45d1df942711d9a, 0x3ba5d0bd324f8395}, // 92 435 | {0xf5746577930d6500, 0xca8f44ec7ee3647a}, // 93 436 | {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecc}, // 94 437 | {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67f}, // 95 438 | {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101f}, // 96 439 | {0x95d04aee3b80ece5, 0xbba1f1d158724a13}, // 97 440 | {0xbb445da9ca61281f, 0x2a8a6e45ae8edc98}, // 98 441 | {0xea1575143cf97226, 0xf52d09d71a3293be}, // 99 442 | {0x924d692ca61be758, 0x593c2626705f9c57}, // 100 443 | {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836d}, // 101 444 | {0xe498f455c38b997a, 0x0b6dfb9c0f956448}, // 102 445 | {0x8edf98b59a373fec, 0x4724bd4189bd5ead}, // 103 446 | {0xb2977ee300c50fe7, 0x58edec91ec2cb658}, // 104 447 | {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ee}, // 105 448 | {0x8b865b215899f46c, 0xbd79e0d20082ee75}, // 106 449 | {0xae67f1e9aec07187, 0xecd8590680a3aa12}, // 107 450 | {0xda01ee641a708de9, 0xe80e6f4820cc9496}, // 108 451 | {0x884134fe908658b2, 0x3109058d147fdcde}, // 109 452 | {0xaa51823e34a7eede, 0xbd4b46f0599fd416}, // 110 453 | {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91b}, // 111 454 | {0x850fadc09923329e, 0x03e2cf6bc604ddb1}, // 112 455 | {0xa6539930bf6bff45, 0x84db8346b786151d}, // 113 456 | {0xcfe87f7cef46ff16, 0xe612641865679a64}, // 114 457 | {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07f}, // 115 458 | {0xa26da3999aef7749, 0xe3be5e330f38f09e}, // 116 459 | {0xcb090c8001ab551c, 0x5cadf5bfd3072cc6}, // 117 460 | {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f7}, // 118 461 | {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afb}, // 119 462 | {0xc646d63501a1511d, 0xb281e1fd541501b9}, // 120 463 | {0xf7d88bc24209a565, 0x1f225a7ca91a4227}, // 121 464 | {0x9ae757596946075f, 0x3375788de9b06959}, // 122 465 | {0xc1a12d2fc3978937, 0x0052d6b1641c83af}, // 123 466 | {0xf209787bb47d6b84, 0xc0678c5dbd23a49b}, // 124 467 | {0x9745eb4d50ce6332, 0xf840b7ba963646e1}, // 125 468 | {0xbd176620a501fbff, 0xb650e5a93bc3d899}, // 126 469 | {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebf}, // 127 470 | {0x93ba47c980e98cdf, 0xc66f336c36b10138}, // 128 471 | {0xb8a8d9bbe123f017, 0xb80b0047445d4185}, // 129 472 | {0xe6d3102ad96cec1d, 0xa60dc059157491e6}, // 130 473 | {0x9043ea1ac7e41392, 0x87c89837ad68db30}, // 131 474 | {0xb454e4a179dd1877, 0x29babe4598c311fc}, // 132 475 | {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67b}, // 133 476 | {0x8ce2529e2734bb1d, 0x1899e4a65f58660d}, // 134 477 | {0xb01ae745b101e9e4, 0x5ec05dcff72e7f90}, // 135 478 | {0xdc21a1171d42645d, 0x76707543f4fa1f74}, // 136 479 | {0x899504ae72497eba, 0x6a06494a791c53a9}, // 137 480 | {0xabfa45da0edbde69, 0x0487db9d17636893}, // 138 481 | {0xd6f8d7509292d603, 0x45a9d2845d3c42b7}, // 139 482 | {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, // 140 483 | {0xa7f26836f282b732, 0x8e6cac7768d7141f}, // 141 484 | {0xd1ef0244af2364ff, 0x3207d795430cd927}, // 142 485 | {0x8335616aed761f1f, 0x7f44e6bd49e807b9}, // 143 486 | {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a7}, // 144 487 | {0xcd036837130890a1, 0x36dba887c37a8c10}, // 145 488 | {0x802221226be55a64, 0xc2494954da2c978a}, // 146 489 | {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6d}, // 147 490 | {0xc83553c5c8965d3d, 0x6f92829494e5acc8}, // 148 491 | {0xfa42a8b73abbf48c, 0xcb772339ba1f17fa}, // 149 492 | {0x9c69a97284b578d7, 0xff2a760414536efc}, // 150 493 | {0xc38413cf25e2d70d, 0xfef5138519684abb}, // 151 494 | {0xf46518c2ef5b8cd1, 0x7eb258665fc25d6a}, // 152 495 | {0x98bf2f79d5993802, 0xef2f773ffbd97a62}, // 153 496 | {0xbeeefb584aff8603, 0xaafb550ffacfd8fb}, // 154 497 | {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf39}, // 155 498 | {0x952ab45cfa97a0b2, 0xdd945a747bf26184}, // 156 499 | {0xba756174393d88df, 0x94f971119aeef9e5}, // 157 500 | {0xe912b9d1478ceb17, 0x7a37cd5601aab85e}, // 158 501 | {0x91abb422ccb812ee, 0xac62e055c10ab33b}, // 159 502 | {0xb616a12b7fe617aa, 0x577b986b314d600a}, // 160 503 | {0xe39c49765fdf9d94, 0xed5a7e85fda0b80c}, // 161 504 | {0x8e41ade9fbebc27d, 0x14588f13be847308}, // 162 505 | {0xb1d219647ae6b31c, 0x596eb2d8ae258fc9}, // 163 506 | {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bc}, // 164 507 | {0x8aec23d680043bee, 0x25de7bb9480d5855}, // 165 508 | {0xada72ccc20054ae9, 0xaf561aa79a10ae6b}, // 166 509 | {0xd910f7ff28069da4, 0x1b2ba1518094da05}, // 167 510 | {0x87aa9aff79042286, 0x90fb44d2f05d0843}, // 168 511 | {0xa99541bf57452b28, 0x353a1607ac744a54}, // 169 512 | {0xd3fa922f2d1675f2, 0x42889b8997915ce9}, // 170 513 | {0x847c9b5d7c2e09b7, 0x69956135febada12}, // 171 514 | {0xa59bc234db398c25, 0x43fab9837e699096}, // 172 515 | {0xcf02b2c21207ef2e, 0x94f967e45e03f4bc}, // 173 516 | {0x8161afb94b44f57d, 0x1d1be0eebac278f6}, // 174 517 | {0xa1ba1ba79e1632dc, 0x6462d92a69731733}, // 175 518 | {0xca28a291859bbf93, 0x7d7b8f7503cfdcff}, // 176 519 | {0xfcb2cb35e702af78, 0x5cda735244c3d43f}, // 177 520 | {0x9defbf01b061adab, 0x3a0888136afa64a8}, // 178 521 | {0xc56baec21c7a1916, 0x088aaa1845b8fdd1}, // 179 522 | {0xf6c69a72a3989f5b, 0x8aad549e57273d46}, // 180 523 | {0x9a3c2087a63f6399, 0x36ac54e2f678864c}, // 181 524 | {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7de}, // 182 525 | {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d6}, // 183 526 | {0x969eb7c47859e743, 0x9f644ae5a4b1b326}, // 184 527 | {0xbc4665b596706114, 0x873d5d9f0dde1fef}, // 185 528 | {0xeb57ff22fc0c7959, 0xa90cb506d155a7eb}, // 186 529 | {0x9316ff75dd87cbd8, 0x09a7f12442d588f3}, // 187 530 | {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb30}, // 188 531 | {0xe5d3ef282a242e81, 0x8f1668c8a86da5fb}, // 189 532 | {0x8fa475791a569d10, 0xf96e017d694487bd}, // 190 533 | {0xb38d92d760ec4455, 0x37c981dcc395a9ad}, // 191 534 | {0xe070f78d3927556a, 0x85bbe253f47b1418}, // 192 535 | {0x8c469ab843b89562, 0x93956d7478ccec8f}, // 193 536 | {0xaf58416654a6babb, 0x387ac8d1970027b3}, // 194 537 | {0xdb2e51bfe9d0696a, 0x06997b05fcc0319f}, // 195 538 | {0x88fcf317f22241e2, 0x441fece3bdf81f04}, // 196 539 | {0xab3c2fddeeaad25a, 0xd527e81cad7626c4}, // 197 540 | {0xd60b3bd56a5586f1, 0x8a71e223d8d3b075}, // 198 541 | {0x85c7056562757456, 0xf6872d5667844e4a}, // 199 542 | {0xa738c6bebb12d16c, 0xb428f8ac016561dc}, // 200 543 | {0xd106f86e69d785c7, 0xe13336d701beba53}, // 201 544 | {0x82a45b450226b39c, 0xecc0024661173474}, // 202 545 | {0xa34d721642b06084, 0x27f002d7f95d0191}, // 203 546 | {0xcc20ce9bd35c78a5, 0x31ec038df7b441f5}, // 204 547 | {0xff290242c83396ce, 0x7e67047175a15272}, // 205 548 | {0x9f79a169bd203e41, 0x0f0062c6e984d387}, // 206 549 | {0xc75809c42c684dd1, 0x52c07b78a3e60869}, // 207 550 | {0xf92e0c3537826145, 0xa7709a56ccdf8a83}, // 208 551 | {0x9bbcc7a142b17ccb, 0x88a66076400bb692}, // 209 552 | {0xc2abf989935ddbfe, 0x6acff893d00ea436}, // 210 553 | {0xf356f7ebf83552fe, 0x0583f6b8c4124d44}, // 211 554 | {0x98165af37b2153de, 0xc3727a337a8b704b}, // 212 555 | {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5d}, // 213 556 | {0xeda2ee1c7064130c, 0x1162def06f79df74}, // 214 557 | {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba9}, // 215 558 | {0xb9a74a0637ce2ee1, 0x6d953e2bd7173693}, // 216 559 | {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0438}, // 217 560 | {0x910ab1d4db9914a0, 0x1d9c9892400a22a3}, // 218 561 | {0xb54d5e4a127f59c8, 0x2503beb6d00cab4c}, // 219 562 | {0xe2a0b5dc971f303a, 0x2e44ae64840fd61e}, // 220 563 | {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, // 221 564 | {0xb10d8e1456105dad, 0x7425a83e872c5f48}, // 222 565 | {0xdd50f1996b947518, 0xd12f124e28f7771a}, // 223 566 | {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa70}, // 224 567 | {0xace73cbfdc0bfb7b, 0x636cc64d1001550c}, // 225 568 | {0xd8210befd30efa5a, 0x3c47f7e05401aa4f}, // 226 569 | {0x8714a775e3e95c78, 0x65acfaec34810a72}, // 227 570 | {0xa8d9d1535ce3b396, 0x7f1839a741a14d0e}, // 228 571 | {0xd31045a8341ca07c, 0x1ede48111209a051}, // 229 572 | {0x83ea2b892091e44d, 0x934aed0aab460433}, // 230 573 | {0xa4e4b66b68b65d60, 0xf81da84d56178540}, // 231 574 | {0xce1de40642e3f4b9, 0x36251260ab9d668f}, // 232 575 | {0x80d2ae83e9ce78f3, 0xc1d72b7c6b42601a}, // 233 576 | {0xa1075a24e4421730, 0xb24cf65b8612f820}, // 234 577 | {0xc94930ae1d529cfc, 0xdee033f26797b628}, // 235 578 | {0xfb9b7cd9a4a7443c, 0x169840ef017da3b2}, // 236 579 | {0x9d412e0806e88aa5, 0x8e1f289560ee864f}, // 237 580 | {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e3}, // 238 581 | {0xf5b5d7ec8acb58a2, 0xae10af696774b1dc}, // 239 582 | {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef2a}, // 240 583 | {0xbff610b0cc6edd3f, 0x17fd090a58d32af4}, // 241 584 | {0xeff394dcff8a948e, 0xddfc4b4cef07f5b1}, // 242 585 | {0x95f83d0a1fb69cd9, 0x4abdaf101564f98f}, // 243 586 | {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f2}, // 244 587 | {0xea53df5fd18d5513, 0x84c86189216dc5ee}, // 245 588 | {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb5}, // 246 589 | {0xb7118682dbb66a77, 0x3fbc8c33221dc2a2}, // 247 590 | {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, // 248 591 | {0x8f05b1163ba6832d, 0x29cb4d87f2a7400f}, // 249 592 | {0xb2c71d5bca9023f8, 0x743e20e9ef511013}, // 250 593 | {0xdf78e4b2bd342cf6, 0x914da9246b255417}, // 251 594 | {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548f}, // 252 595 | {0xae9672aba3d0c320, 0xa184ac2473b529b2}, // 253 596 | {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741f}, // 254 597 | {0x8865899617fb1871, 0x7e2fa67c7a658893}, // 255 598 | {0xaa7eebfb9df9de8d, 0xddbb901b98feeab8}, // 256 599 | {0xd51ea6fa85785631, 0x552a74227f3ea566}, // 257 600 | {0x8533285c936b35de, 0xd53a88958f872760}, // 258 601 | {0xa67ff273b8460356, 0x8a892abaf368f138}, // 259 602 | {0xd01fef10a657842c, 0x2d2b7569b0432d86}, // 260 603 | {0x8213f56a67f6b29b, 0x9c3b29620e29fc74}, // 261 604 | {0xa298f2c501f45f42, 0x8349f3ba91b47b90}, // 262 605 | {0xcb3f2f7642717713, 0x241c70a936219a74}, // 263 606 | {0xfe0efb53d30dd4d7, 0xed238cd383aa0111}, // 264 607 | {0x9ec95d1463e8a506, 0xf4363804324a40ab}, // 265 608 | {0xc67bb4597ce2ce48, 0xb143c6053edcd0d6}, // 266 609 | {0xf81aa16fdc1b81da, 0xdd94b7868e94050b}, // 267 610 | {0x9b10a4e5e9913128, 0xca7cf2b4191c8327}, // 268 611 | {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f1}, // 269 612 | {0xf24a01a73cf2dccf, 0xbc633b39673c8ced}, // 270 613 | {0x976e41088617ca01, 0xd5be0503e085d814}, // 271 614 | {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e19}, // 272 615 | {0xec9c459d51852ba2, 0xddf8e7d60ed1219f}, // 273 616 | {0x93e1ab8252f33b45, 0xcabb90e5c942b504}, // 274 617 | {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, // 275 618 | {0xe7109bfba19c0c9d, 0x0cc512670a783ad5}, // 276 619 | {0x906a617d450187e2, 0x27fb2b80668b24c6}, // 277 620 | {0xb484f9dc9641e9da, 0xb1f9f660802dedf7}, // 278 621 | {0xe1a63853bbd26451, 0x5e7873f8a0396974}, // 279 622 | {0x8d07e33455637eb2, 0xdb0b487b6423e1e9}, // 280 623 | {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda63}, // 281 624 | {0xdc5c5301c56b75f7, 0x7641a140cc7810fc}, // 282 625 | {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9e}, // 283 626 | {0xac2820d9623bf429, 0x546345fa9fbdcd45}, // 284 627 | {0xd732290fbacaf133, 0xa97c177947ad4096}, // 285 628 | {0x867f59a9d4bed6c0, 0x49ed8eabcccc485e}, // 286 629 | {0xa81f301449ee8c70, 0x5c68f256bfff5a75}, // 287 630 | {0xd226fc195c6a2f8c, 0x73832eec6fff3112}, // 288 631 | {0x83585d8fd9c25db7, 0xc831fd53c5ff7eac}, // 289 632 | {0xa42e74f3d032f525, 0xba3e7ca8b77f5e56}, // 290 633 | {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35ec}, // 291 634 | {0x80444b5e7aa7cf85, 0x7980d163cf5b81b4}, // 292 635 | {0xa0555e361951c366, 0xd7e105bcc3326220}, // 293 636 | {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa8}, // 294 637 | {0xfa856334878fc150, 0xb14f98f6f0feb952}, // 295 638 | {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d4}, // 296 639 | {0xc3b8358109e84f07, 0x0a862f80ec4700c9}, // 297 640 | {0xf4a642e14c6262c8, 0xcd27bb612758c0fb}, // 298 641 | {0x98e7e9cccfbd7dbd, 0x8038d51cb897789d}, // 299 642 | {0xbf21e44003acdd2c, 0xe0470a63e6bd56c4}, // 300 643 | {0xeeea5d5004981478, 0x1858ccfce06cac75}, // 301 644 | {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, // 302 645 | {0xbaa718e68396cffd, 0xd30560258f54e6bb}, // 303 646 | {0xe950df20247c83fd, 0x47c6b82ef32a206a}, // 304 647 | {0x91d28b7416cdd27e, 0x4cdc331d57fa5442}, // 305 648 | {0xb6472e511c81471d, 0xe0133fe4adf8e953}, // 306 649 | {0xe3d8f9e563a198e5, 0x58180fddd97723a7}, // 307 650 | {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7649}, // 308 651 | {0xb201833b35d63f73, 0x2cd2cc6551e513db}, // 309 652 | {0xde81e40a034bcf4f, 0xf8077f7ea65e58d2}, // 310 653 | {0x8b112e86420f6191, 0xfb04afaf27faf783}, // 311 654 | {0xadd57a27d29339f6, 0x79c5db9af1f9b564}, // 312 655 | {0xd94ad8b1c7380874, 0x18375281ae7822bd}, // 313 656 | {0x87cec76f1c830548, 0x8f2293910d0b15b6}, // 314 657 | {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb23}, // 315 658 | {0xd433179d9c8cb841, 0x5fa60692a46151ec}, // 316 659 | {0x849feec281d7f328, 0xdbc7c41ba6bcd334}, // 317 660 | {0xa5c7ea73224deff3, 0x12b9b522906c0801}, // 318 661 | {0xcf39e50feae16bef, 0xd768226b34870a01}, // 319 662 | {0x81842f29f2cce375, 0xe6a1158300d46641}, // 320 663 | {0xa1e53af46f801c53, 0x60495ae3c1097fd1}, // 321 664 | {0xca5e89b18b602368, 0x385bb19cb14bdfc5}, // 322 665 | {0xfcf62c1dee382c42, 0x46729e03dd9ed7b6}, // 323 666 | {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2}, // 324 667 | }; 668 | 669 | static inline uint128_t umul128(uint64_t x, uint64_t y) { 670 | #if defined(__SIZEOF_INT128__) 671 | return (uint128_t)x * y; 672 | #elif defined(_MSC_VER) && defined(_M_AMD64) 673 | uint128 r; 674 | r.lo = _umul128(x, y, &r.hi); 675 | return r; 676 | #elif defined(_MSC_VER) && defined(_M_ARM64) 677 | uint128 r; 678 | r.hi = __umulh(x, y); 679 | r.lo = x * y; 680 | return r; 681 | #else 682 | uint64_t a = x >> 32; 683 | uint64_t b = (uint32_t)x; 684 | uint64_t c = y >> 32; 685 | uint64_t d = (uint32_t)y; 686 | 687 | uint64_t ac = a * c; 688 | uint64_t bc = b * c; 689 | uint64_t ad = a * d; 690 | uint64_t bd = b * d; 691 | 692 | uint64_t cs = (bd >> 32) + (uint32_t)ad + (uint32_t)bc; 693 | 694 | uint128 r; 695 | r.hi = ac + (ad >> 32) + (bc >> 32) + (cs >> 32); 696 | r.lo = (cs << 32) + (uint32_t)bd; 697 | return r; 698 | #endif 699 | } 700 | 701 | static inline uint128 umul192_upper128(uint64_t x_hi, uint64_t x_lo, 702 | uint64_t y) { 703 | #if defined(__SIZEOF_INT128__) 704 | uint128_t p = umul128(x_hi, y); 705 | uint64_t lo = (uint64_t)p + (uint64_t)(umul128(x_lo, y) >> 64); 706 | uint128 r = {(uint64_t)(p >> 64) + (lo < (uint64_t)p), lo}; 707 | return r; 708 | #else 709 | uint128 p = umul128(x_hi, y); 710 | uint128 q = umul128(x_lo, y); 711 | uint64_t lo = p.lo + q.hi; 712 | uint128 r; 713 | r.hi = p.hi + (lo < p.lo); 714 | r.lo = lo; 715 | return r; 716 | #endif 717 | } 718 | 719 | // Computes upper 64 bits of multiplication of x and y, discards the least 720 | // significant bit and rounds to odd, where x = uint128_t(x_hi << 64) | x_lo. 721 | static inline uint64_t umul192_upper64_inexact_to_odd(uint64_t x_hi, 722 | uint64_t x_lo, 723 | uint64_t y) { 724 | uint128 r = umul192_upper128(x_hi, x_lo, y); 725 | return r.hi | ((r.lo >> 1) != 0); 726 | } 727 | 728 | typedef struct { 729 | uint32_t div; 730 | uint32_t mod; 731 | } divmod_result; 732 | 733 | // Returns {value / 100, value % 100} correct for values of up to 4 digits. 734 | static inline divmod_result divmod100(uint32_t value) { 735 | assert(value < 10000); 736 | const int exp = 19; 737 | const uint32_t sig = ((uint32_t)1 << exp) / 100 + 1; 738 | uint32_t div = (value * sig) >> exp; 739 | divmod_result r = {div, value - div * 100}; 740 | return r; 741 | } 742 | 743 | static inline bool is_big_endian(void) { 744 | uint32_t x = 1; 745 | return ((uint8_t*)&x)[0] == 0; 746 | } 747 | 748 | static inline int count_lzero(uint64_t x) { 749 | #if defined(_MSC_VER) && defined(__AVX2__) 750 | return __lzcnt64(x); 751 | #elif defined(_MSC_VER) 752 | unsigned long idx; 753 | _BitScanReverse64(&idx, x); 754 | return 63 - idx; 755 | #else 756 | int n = 64; 757 | while (x) { 758 | --n; 759 | x >>= 1; 760 | } 761 | return n; 762 | #endif 763 | } 764 | 765 | static inline int count_trailing_nonzeros(uint64_t x) { 766 | assert(!is_big_endian()); 767 | const uint64_t mask = ((uint64_t)0x3030303030303030ULL << 1) | 1; 768 | return (70 - count_lzero((x << 1) ^ mask)) / 8; 769 | } 770 | 771 | // Converts value in the range [0, 100) to a string. GCC generates a bit better 772 | // code when value is pointer-size (https://www.godbolt.org/z/5fEPMT1cc). 773 | static inline const char* digits2(size_t value) { 774 | static const char data[] = 775 | "0001020304050607080910111213141516171819" 776 | "2021222324252627282930313233343536373839" 777 | "4041424344454647484950515253545556575859" 778 | "6061626364656667686970717273747576777879" 779 | "8081828384858687888990919293949596979899"; 780 | return &data[value * 2]; 781 | } 782 | 783 | static inline uint64_t digits2_u64(uint32_t value) { 784 | uint16_t d; 785 | memcpy(&d, digits2(value), 2); 786 | return d; 787 | } 788 | 789 | // Converts the value `aa * 10**6 + bb * 10**4 + cc * 10**2 + dd` to a string 790 | // returned as a 64-bit integer. 791 | static inline uint64_t digits8_u64(uint32_t aa, uint32_t bb, uint32_t cc, 792 | uint32_t dd) { 793 | return (digits2_u64(dd) << 48) | (digits2_u64(cc) << 32) | 794 | (digits2_u64(bb) << 16) | digits2_u64(aa); 795 | } 796 | 797 | // Writes a significand consisting of 16 or 17 decimal digits and removes 798 | // trailing zeros. 799 | static char* write_significand(char* buffer, uint64_t value) { 800 | uint32_t abbccddee = (uint32_t)(value / 100000000ULL); 801 | uint32_t ffgghhii = (uint32_t)(value % 100000000ULL); 802 | 803 | uint32_t abbcc = abbccddee / 10000; 804 | uint32_t ddee = abbccddee % 10000; 805 | uint32_t abb = abbcc / 100; 806 | uint32_t cc = abbcc % 100; 807 | 808 | divmod_result r1 = divmod100(abb); 809 | divmod_result r2 = divmod100(ddee); 810 | 811 | *buffer = (char)('0' + r1.div); 812 | buffer += (r1.div != 0); 813 | 814 | uint64_t digits = digits8_u64(r1.mod, cc, r2.div, r2.mod); 815 | memcpy(buffer, &digits, 8); 816 | 817 | if (ffgghhii == 0) return buffer + count_trailing_nonzeros(digits); 818 | 819 | buffer += 8; 820 | 821 | uint32_t ffgg = ffgghhii / 10000; 822 | uint32_t hhii = ffgghhii % 10000; 823 | 824 | divmod_result r3 = divmod100(ffgg); 825 | divmod_result r4 = divmod100(hhii); 826 | 827 | digits = digits8_u64(r3.div, r3.mod, r4.div, r4.mod); 828 | memcpy(buffer, &digits, 8); 829 | 830 | return buffer + count_trailing_nonzeros(digits); 831 | } 832 | 833 | // Writes the decimal FP number dec_sig * 10**dec_exp to buffer. 834 | static void write(char* buffer, uint64_t dec_sig, int dec_exp) { 835 | dec_exp += 15 + (dec_sig >= 10000000000000000ULL); 836 | 837 | char* start = buffer; 838 | buffer = write_significand(buffer + 1, dec_sig); 839 | start[0] = start[1]; 840 | start[1] = '.'; 841 | 842 | *buffer++ = 'e'; 843 | 844 | char sign = '+'; 845 | if (dec_exp < 0) { 846 | sign = '-'; 847 | dec_exp = -dec_exp; 848 | } 849 | *buffer++ = sign; 850 | 851 | divmod_result r = divmod100((uint32_t)dec_exp); 852 | *buffer = (char)('0' + r.div); 853 | buffer += (dec_exp >= 100); 854 | 855 | memcpy(buffer, digits2(r.mod), 2); 856 | buffer[2] = '\0'; 857 | } 858 | 859 | void zmij_dtoa(double value, char* buffer) { 860 | static_assert(sizeof(double) == 8, "IEEE-754 double required"); 861 | 862 | uint64_t bits; 863 | memcpy(&bits, &value, sizeof(bits)); 864 | 865 | *buffer = '-'; 866 | buffer += bits >> 63; 867 | 868 | const int num_sig_bits = 52; 869 | const uint64_t implicit_bit = (uint64_t)1 << num_sig_bits; 870 | 871 | uint64_t bin_sig = bits & (implicit_bit - 1); // binary_significand 872 | bool regular = (bin_sig != 0); 873 | 874 | const int num_exp_bits = 11; 875 | const int exp_mask = (1 << num_exp_bits) - 1; 876 | const int exp_bias = (1 << (num_exp_bits - 1)) - 1; 877 | 878 | int bin_exp = (int)((bits >> num_sig_bits) & exp_mask); // binary exponent 879 | 880 | if (((bin_exp + 1) & exp_mask) <= 1) { 881 | if (bin_exp != 0) { 882 | memcpy(buffer, bin_sig == 0 ? "inf" : "nan", 4); 883 | return; 884 | } 885 | if (bin_sig == 0) { 886 | memcpy(buffer, "0", 2); 887 | return; 888 | } 889 | // Handle subnormals. 890 | bin_sig |= implicit_bit; 891 | bin_exp = 1; 892 | regular = true; 893 | } 894 | 895 | bin_sig ^= implicit_bit; 896 | bin_exp -= num_sig_bits + exp_bias; 897 | 898 | // Compute the decimal exponent as floor(log10(2**bin_exp)) if regular or 899 | // floor(log10(3/4 * 2**bin_exp)) otherwise, without branching. 900 | // log10_3_over_4_sig = round(log10(3/4) * 2**log10_2_exp) 901 | const int log10_3_over_4_sig = -131008; 902 | // log10_2_sig = round(log10(2) * 2**log10_2_exp) 903 | const int log10_2_sig = 315653; 904 | const int log10_2_exp = 20; 905 | int dec_exp = 906 | (bin_exp * log10_2_sig + (!regular) * log10_3_over_4_sig) >> log10_2_exp; 907 | 908 | const int dec_exp_min = -292; 909 | uint128 pow10 = pow10_significands[-dec_exp - dec_exp_min]; 910 | 911 | // log2_pow10_sig = round(log2(10) * 2**log2_pow10_exp) + 1 912 | const int log2_pow10_sig = 217707; 913 | const int log2_pow10_exp = 16; 914 | // pow10_bin_exp = floor(log2(10**-dec_exp)) 915 | int pow10_bin_exp = (-dec_exp * log2_pow10_sig) >> log2_pow10_exp; 916 | // pow10 = ((pow10_hi << 64) | pow10_lo) * 2**(pow10_bin_exp - 127) 917 | 918 | // Shift to ensure the intermediate result of multiplying by a power of 10 919 | // has a fixed 128-bit fractional part. For example, 3 * 2**59 and 3 * 2**60 920 | // both have dec_exp = 2 and dividing them by 10**dec_exp would have the 921 | // decimal point in different (bit) positions without the shift: 922 | // 3 * 2**59 / 100 = 1.72...e+16 (shift = 1 + 1) 923 | // 3 * 2**60 / 100 = 3.45...e+16 (shift = 2 + 1) 924 | int shift = bin_exp + pow10_bin_exp + 1; 925 | 926 | if (regular) { 927 | uint128 r = umul192_upper128(pow10.hi, pow10.lo - 1, bin_sig << shift); 928 | uint64_t digit = r.hi % 10; 929 | 930 | const int num_fractional_bits = 60; 931 | const uint64_t ten = (uint64_t)10 << num_fractional_bits; 932 | // Fixed-point remainder of the scaled significand modulo 10. 933 | uint64_t rem10 = (digit << num_fractional_bits) | (r.lo >> 4); 934 | uint64_t half_ulp = pow10.hi >> (5 - shift); 935 | uint64_t upper = rem10 + half_ulp; 936 | 937 | // An optimization from yy_double by Yaoyuan Guo: 938 | if (r.lo != ((uint64_t)1 << 63) && rem10 != half_ulp && ten - upper > 1) { 939 | bool round = (upper >> num_fractional_bits) >= 10; 940 | uint64_t shorter = r.hi - digit + round * 10; 941 | uint64_t longer = r.hi + (r.lo >= ((uint64_t)1 << 63)); 942 | 943 | write(buffer, ((half_ulp >= rem10) + round) ? shorter : longer, dec_exp); 944 | return; 945 | } 946 | } 947 | 948 | // Shift the significand so that boundaries are integer. 949 | uint64_t bin_sig_shifted = bin_sig << 2; 950 | 951 | // Compute the estimates of lower and upper bounds of the rounding interval 952 | // by multiplying them by the power of 10 and applying modified rounding. 953 | uint64_t lsb = bin_sig & 1; 954 | uint64_t lower = 955 | umul192_upper64_inexact_to_odd( 956 | pow10.hi, pow10.lo, (bin_sig_shifted - (regular + 1)) << shift) + 957 | lsb; 958 | uint64_t upper = umul192_upper64_inexact_to_odd( 959 | pow10.hi, pow10.lo, (bin_sig_shifted + 2) << shift) - 960 | lsb; 961 | 962 | // The idea of using a single shorter candidate is by Cassio Neri. 963 | // It is less or equal to the upper bound by construction. 964 | uint64_t shorter = 10 * ((upper >> 2) / 10); 965 | if ((shorter << 2) >= lower) { 966 | write(buffer, shorter, dec_exp); 967 | return; 968 | } 969 | 970 | uint64_t scaled_sig = umul192_upper64_inexact_to_odd( 971 | pow10.hi, pow10.lo, bin_sig_shifted << shift); 972 | uint64_t under = scaled_sig >> 2; 973 | uint64_t over = under + 1; 974 | 975 | // Pick the closest of dec_sig_under and dec_sig_over and check if it's in 976 | // the rounding interval. 977 | int64_t cmp = (int64_t)(scaled_sig - ((under + over) << 1)); 978 | bool under_closer = cmp < 0 || (cmp == 0 && !(under & 1)); 979 | bool under_in = (under << 2) >= lower; 980 | write(buffer, (under_closer && under_in) ? under : over, dec_exp); 981 | } 982 | -------------------------------------------------------------------------------- /zmij.cc: -------------------------------------------------------------------------------- 1 | // A double-to-string conversion algorithm based on Schubfach. 2 | // Copyright (c) 2025 - present, Victor Zverovich 3 | // Distributed under the MIT license (see LICENSE). 4 | // https://github.com/vitaut/zmij/ 5 | 6 | #if __has_include("zmij.h") 7 | # include "zmij.h" 8 | #endif 9 | 10 | #include // assert 11 | #include // CHAR_BIT 12 | #include // uint64_t 13 | #include // memcpy 14 | 15 | #include // std::numeric_limits 16 | 17 | #ifdef _MSC_VER 18 | # include // lzcnt/adc/umul128/umulh 19 | #endif 20 | 21 | namespace { 22 | 23 | struct uint128 { 24 | uint64_t hi; 25 | uint64_t lo; 26 | 27 | [[maybe_unused]] explicit operator uint64_t() const noexcept { return lo; } 28 | 29 | [[maybe_unused]] auto operator>>(int shift) const noexcept -> uint128 { 30 | assert(shift >= 64 && shift < 128); 31 | return {0, hi >> (shift - 64)}; 32 | } 33 | }; 34 | 35 | [[maybe_unused]] auto operator+(uint128 lhs, uint128 rhs) noexcept -> uint128 { 36 | #if defined(_MSC_VER) && defined(_M_AMD64) 37 | uint64_t lo, hi; 38 | _addcarry_u64(_addcarry_u64(0, lhs.lo, rhs.lo, &lo), lhs.hi, rhs.hi, &hi); 39 | return {hi, lo}; 40 | #else 41 | uint64_t lo = lhs.lo + rhs.lo; 42 | return {lhs.hi + rhs.hi + (lo < lhs.lo), lo}; 43 | #endif 44 | } 45 | 46 | #ifdef ZMIJ_USE_INT128 47 | // Use the provided definition. 48 | #elif defined(__SIZEOF_INT128__) 49 | # define ZMIJ_USE_INT128 1 50 | #else 51 | # define ZMIJ_USE_INT128 0 52 | #endif 53 | 54 | #if ZMIJ_USE_INT128 55 | using uint128_t = unsigned __int128; 56 | #else 57 | using uint128_t = uint128; 58 | #endif // ZMIJ_USE_INT128 59 | 60 | // 128-bit significands of powers of 10 rounded down. 61 | // Generated with gen-pow10.py. 62 | const uint128 pow10_significands[] = { 63 | {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7a}, // -292 64 | {0x9faacf3df73609b1, 0x77b191618c54e9ac}, // -291 65 | {0xc795830d75038c1d, 0xd59df5b9ef6a2417}, // -290 66 | {0xf97ae3d0d2446f25, 0x4b0573286b44ad1d}, // -289 67 | {0x9becce62836ac577, 0x4ee367f9430aec32}, // -288 68 | {0xc2e801fb244576d5, 0x229c41f793cda73f}, // -287 69 | {0xf3a20279ed56d48a, 0x6b43527578c1110f}, // -286 70 | {0x9845418c345644d6, 0x830a13896b78aaa9}, // -285 71 | {0xbe5691ef416bd60c, 0x23cc986bc656d553}, // -284 72 | {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa8}, // -283 73 | {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6a9}, // -282 74 | {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc53}, // -281 75 | {0xe858ad248f5c22c9, 0xd1b3400f8f9cff68}, // -280 76 | {0x91376c36d99995be, 0x23100809b9c21fa1}, // -279 77 | {0xb58547448ffffb2d, 0xabd40a0c2832a78a}, // -278 78 | {0xe2e69915b3fff9f9, 0x16c90c8f323f516c}, // -277 79 | {0x8dd01fad907ffc3b, 0xae3da7d97f6792e3}, // -276 80 | {0xb1442798f49ffb4a, 0x99cd11cfdf41779c}, // -275 81 | {0xdd95317f31c7fa1d, 0x40405643d711d583}, // -274 82 | {0x8a7d3eef7f1cfc52, 0x482835ea666b2572}, // -273 83 | {0xad1c8eab5ee43b66, 0xda3243650005eecf}, // -272 84 | {0xd863b256369d4a40, 0x90bed43e40076a82}, // -271 85 | {0x873e4f75e2224e68, 0x5a7744a6e804a291}, // -270 86 | {0xa90de3535aaae202, 0x711515d0a205cb36}, // -269 87 | {0xd3515c2831559a83, 0x0d5a5b44ca873e03}, // -268 88 | {0x8412d9991ed58091, 0xe858790afe9486c2}, // -267 89 | {0xa5178fff668ae0b6, 0x626e974dbe39a872}, // -266 90 | {0xce5d73ff402d98e3, 0xfb0a3d212dc8128f}, // -265 91 | {0x80fa687f881c7f8e, 0x7ce66634bc9d0b99}, // -264 92 | {0xa139029f6a239f72, 0x1c1fffc1ebc44e80}, // -263 93 | {0xc987434744ac874e, 0xa327ffb266b56220}, // -262 94 | {0xfbe9141915d7a922, 0x4bf1ff9f0062baa8}, // -261 95 | {0x9d71ac8fada6c9b5, 0x6f773fc3603db4a9}, // -260 96 | {0xc4ce17b399107c22, 0xcb550fb4384d21d3}, // -259 97 | {0xf6019da07f549b2b, 0x7e2a53a146606a48}, // -258 98 | {0x99c102844f94e0fb, 0x2eda7444cbfc426d}, // -257 99 | {0xc0314325637a1939, 0xfa911155fefb5308}, // -256 100 | {0xf03d93eebc589f88, 0x793555ab7eba27ca}, // -255 101 | {0x96267c7535b763b5, 0x4bc1558b2f3458de}, // -254 102 | {0xbbb01b9283253ca2, 0x9eb1aaedfb016f16}, // -253 103 | {0xea9c227723ee8bcb, 0x465e15a979c1cadc}, // -252 104 | {0x92a1958a7675175f, 0x0bfacd89ec191ec9}, // -251 105 | {0xb749faed14125d36, 0xcef980ec671f667b}, // -250 106 | {0xe51c79a85916f484, 0x82b7e12780e7401a}, // -249 107 | {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908810}, // -248 108 | {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa15}, // -247 109 | {0xdfbdcece67006ac9, 0x67a791e093e1d49a}, // -246 110 | {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e0}, // -245 111 | {0xaecc49914078536d, 0x58fae9f773886e18}, // -244 112 | {0xda7f5bf590966848, 0xaf39a475506a899e}, // -243 113 | {0x888f99797a5e012d, 0x6d8406c952429603}, // -242 114 | {0xaab37fd7d8f58178, 0xc8e5087ba6d33b83}, // -241 115 | {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a64}, // -240 116 | {0x855c3be0a17fcd26, 0x5cf2eea09a55067f}, // -239 117 | {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481e}, // -238 118 | {0xd0601d8efc57b08b, 0xf13b94daf124da26}, // -237 119 | {0x823c12795db6ce57, 0x76c53d08d6b70858}, // -236 120 | {0xa2cb1717b52481ed, 0x54768c4b0c64ca6e}, // -235 121 | {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd09}, // -234 122 | {0xfe5d54150b090b02, 0xd3f93b35435d7c4c}, // -233 123 | {0x9efa548d26e5a6e1, 0xc47bc5014a1a6daf}, // -232 124 | {0xc6b8e9b0709f109a, 0x359ab6419ca1091b}, // -231 125 | {0xf867241c8cc6d4c0, 0xc30163d203c94b62}, // -230 126 | {0x9b407691d7fc44f8, 0x79e0de63425dcf1d}, // -229 127 | {0xc21094364dfb5636, 0x985915fc12f542e4}, // -228 128 | {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939d}, // -227 129 | {0x979cf3ca6cec5b5a, 0xa705992ceecf9c42}, // -226 130 | {0xbd8430bd08277231, 0x50c6ff782a838353}, // -225 131 | {0xece53cec4a314ebd, 0xa4f8bf5635246428}, // -224 132 | {0x940f4613ae5ed136, 0x871b7795e136be99}, // -223 133 | {0xb913179899f68584, 0x28e2557b59846e3f}, // -222 134 | {0xe757dd7ec07426e5, 0x331aeada2fe589cf}, // -221 135 | {0x9096ea6f3848984f, 0x3ff0d2c85def7621}, // -220 136 | {0xb4bca50b065abe63, 0x0fed077a756b53a9}, // -219 137 | {0xe1ebce4dc7f16dfb, 0xd3e8495912c62894}, // -218 138 | {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95c}, // -217 139 | {0xb080392cc4349dec, 0xbd8d794d96aacfb3}, // -216 140 | {0xdca04777f541c567, 0xecf0d7a0fc5583a0}, // -215 141 | {0x89e42caaf9491b60, 0xf41686c49db57244}, // -214 142 | {0xac5d37d5b79b6239, 0x311c2875c522ced5}, // -213 143 | {0xd77485cb25823ac7, 0x7d633293366b828b}, // -212 144 | {0x86a8d39ef77164bc, 0xae5dff9c02033197}, // -211 145 | {0xa8530886b54dbdeb, 0xd9f57f830283fdfc}, // -210 146 | {0xd267caa862a12d66, 0xd072df63c324fd7b}, // -209 147 | {0x8380dea93da4bc60, 0x4247cb9e59f71e6d}, // -208 148 | {0xa46116538d0deb78, 0x52d9be85f074e608}, // -207 149 | {0xcd795be870516656, 0x67902e276c921f8b}, // -206 150 | {0x806bd9714632dff6, 0x00ba1cd8a3db53b6}, // -205 151 | {0xa086cfcd97bf97f3, 0x80e8a40eccd228a4}, // -204 152 | {0xc8a883c0fdaf7df0, 0x6122cd128006b2cd}, // -203 153 | {0xfad2a4b13d1b5d6c, 0x796b805720085f81}, // -202 154 | {0x9cc3a6eec6311a63, 0xcbe3303674053bb0}, // -201 155 | {0xc3f490aa77bd60fc, 0xbedbfc4411068a9c}, // -200 156 | {0xf4f1b4d515acb93b, 0xee92fb5515482d44}, // -199 157 | {0x991711052d8bf3c5, 0x751bdd152d4d1c4a}, // -198 158 | {0xbf5cd54678eef0b6, 0xd262d45a78a0635d}, // -197 159 | {0xef340a98172aace4, 0x86fb897116c87c34}, // -196 160 | {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da0}, // -195 161 | {0xbae0a846d2195712, 0x8974836059cca109}, // -194 162 | {0xe998d258869facd7, 0x2bd1a438703fc94b}, // -193 163 | {0x91ff83775423cc06, 0x7b6306a34627ddcf}, // -192 164 | {0xb67f6455292cbf08, 0x1a3bc84c17b1d542}, // -191 165 | {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a93}, // -190 166 | {0x8e938662882af53e, 0x547eb47b7282ee9c}, // -189 167 | {0xb23867fb2a35b28d, 0xe99e619a4f23aa43}, // -188 168 | {0xdec681f9f4c31f31, 0x6405fa00e2ec94d4}, // -187 169 | {0x8b3c113c38f9f37e, 0xde83bc408dd3dd04}, // -186 170 | {0xae0b158b4738705e, 0x9624ab50b148d445}, // -185 171 | {0xd98ddaee19068c76, 0x3badd624dd9b0957}, // -184 172 | {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d6}, // -183 173 | {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4c}, // -182 174 | {0xd47487cc8470652b, 0x7647c3200069671f}, // -181 175 | {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e073}, // -180 176 | {0xa5fb0a17c777cf09, 0xf468107100525890}, // -179 177 | {0xcf79cc9db955c2cc, 0x7182148d4066eeb4}, // -178 178 | {0x81ac1fe293d599bf, 0xc6f14cd848405530}, // -177 179 | {0xa21727db38cb002f, 0xb8ada00e5a506a7c}, // -176 180 | {0xca9cf1d206fdc03b, 0xa6d90811f0e4851c}, // -175 181 | {0xfd442e4688bd304a, 0x908f4a166d1da663}, // -174 182 | {0x9e4a9cec15763e2e, 0x9a598e4e043287fe}, // -173 183 | {0xc5dd44271ad3cdba, 0x40eff1e1853f29fd}, // -172 184 | {0xf7549530e188c128, 0xd12bee59e68ef47c}, // -171 185 | {0x9a94dd3e8cf578b9, 0x82bb74f8301958ce}, // -170 186 | {0xc13a148e3032d6e7, 0xe36a52363c1faf01}, // -169 187 | {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac1}, // -168 188 | {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0b9}, // -167 189 | {0xbcb2b812db11a5de, 0x7415d448f6b6f0e7}, // -166 190 | {0xebdf661791d60f56, 0x111b495b3464ad21}, // -165 191 | {0x936b9fcebb25c995, 0xcab10dd900beec34}, // -164 192 | {0xb84687c269ef3bfb, 0x3d5d514f40eea742}, // -163 193 | {0xe65829b3046b0afa, 0x0cb4a5a3112a5112}, // -162 194 | {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ab}, // -161 195 | {0xb3f4e093db73a093, 0x59ed216765690f56}, // -160 196 | {0xe0f218b8d25088b8, 0x306869c13ec3532c}, // -159 197 | {0x8c974f7383725573, 0x1e414218c73a13fb}, // -158 198 | {0xafbd2350644eeacf, 0xe5d1929ef90898fa}, // -157 199 | {0xdbac6c247d62a583, 0xdf45f746b74abf39}, // -156 200 | {0x894bc396ce5da772, 0x6b8bba8c328eb783}, // -155 201 | {0xab9eb47c81f5114f, 0x066ea92f3f326564}, // -154 202 | {0xd686619ba27255a2, 0xc80a537b0efefebd}, // -153 203 | {0x8613fd0145877585, 0xbd06742ce95f5f36}, // -152 204 | {0xa798fc4196e952e7, 0x2c48113823b73704}, // -151 205 | {0xd17f3b51fca3a7a0, 0xf75a15862ca504c5}, // -150 206 | {0x82ef85133de648c4, 0x9a984d73dbe722fb}, // -149 207 | {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebba}, // -148 208 | {0xcc963fee10b7d1b3, 0x318df905079926a8}, // -147 209 | {0xffbbcfe994e5c61f, 0xfdf17746497f7052}, // -146 210 | {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa633}, // -145 211 | {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc0}, // -144 212 | {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b0}, // -143 213 | {0x9c1661a651213e2d, 0x06bea10ca65c084e}, // -142 214 | {0xc31bfa0fe5698db8, 0x486e494fcff30a62}, // -141 215 | {0xf3e2f893dec3f126, 0x5a89dba3c3efccfa}, // -140 216 | {0x986ddb5c6b3a76b7, 0xf89629465a75e01c}, // -139 217 | {0xbe89523386091465, 0xf6bbb397f1135823}, // -138 218 | {0xee2ba6c0678b597f, 0x746aa07ded582e2c}, // -137 219 | {0x94db483840b717ef, 0xa8c2a44eb4571cdc}, // -136 220 | {0xba121a4650e4ddeb, 0x92f34d62616ce413}, // -135 221 | {0xe896a0d7e51e1566, 0x77b020baf9c81d17}, // -134 222 | {0x915e2486ef32cd60, 0x0ace1474dc1d122e}, // -133 223 | {0xb5b5ada8aaff80b8, 0x0d819992132456ba}, // -132 224 | {0xe3231912d5bf60e6, 0x10e1fff697ed6c69}, // -131 225 | {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c1}, // -130 226 | {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb2}, // -129 227 | {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbde}, // -128 228 | {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96b}, // -127 229 | {0xad4ab7112eb3929d, 0x86c16c98d2c953c6}, // -126 230 | {0xd89d64d57a607744, 0xe871c7bf077ba8b7}, // -125 231 | {0x87625f056c7c4a8b, 0x11471cd764ad4972}, // -124 232 | {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bcf}, // -123 233 | {0xd389b47879823479, 0x4aff1d108d4ec2c3}, // -122 234 | {0x843610cb4bf160cb, 0xcedf722a585139ba}, // -121 235 | {0xa54394fe1eedb8fe, 0xc2974eb4ee658828}, // -120 236 | {0xce947a3da6a9273e, 0x733d226229feea32}, // -119 237 | {0x811ccc668829b887, 0x0806357d5a3f525f}, // -118 238 | {0xa163ff802a3426a8, 0xca07c2dcb0cf26f7}, // -117 239 | {0xc9bcff6034c13052, 0xfc89b393dd02f0b5}, // -116 240 | {0xfc2c3f3841f17c67, 0xbbac2078d443ace2}, // -115 241 | {0x9d9ba7832936edc0, 0xd54b944b84aa4c0d}, // -114 242 | {0xc5029163f384a931, 0x0a9e795e65d4df11}, // -113 243 | {0xf64335bcf065d37d, 0x4d4617b5ff4a16d5}, // -112 244 | {0x99ea0196163fa42e, 0x504bced1bf8e4e45}, // -111 245 | {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d6}, // -110 246 | {0xf07da27a82c37088, 0x5d767327bb4e5a4c}, // -109 247 | {0x964e858c91ba2655, 0x3a6a07f8d510f86f}, // -108 248 | {0xbbe226efb628afea, 0x890489f70a55368b}, // -107 249 | {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842e}, // -106 250 | {0x92c8ae6b464fc96f, 0x3b0b8bc90012929d}, // -105 251 | {0xb77ada0617e3bbcb, 0x09ce6ebb40173744}, // -104 252 | {0xe55990879ddcaabd, 0xcc420a6a101d0515}, // -103 253 | {0x8f57fa54c2a9eab6, 0x9fa946824a12232d}, // -102 254 | {0xb32df8e9f3546564, 0x47939822dc96abf9}, // -101 255 | {0xdff9772470297ebd, 0x59787e2b93bc56f7}, // -100 256 | {0x8bfbea76c619ef36, 0x57eb4edb3c55b65a}, // -99 257 | {0xaefae51477a06b03, 0xede622920b6b23f1}, // -98 258 | {0xdab99e59958885c4, 0xe95fab368e45eced}, // -97 259 | {0x88b402f7fd75539b, 0x11dbcb0218ebb414}, // -96 260 | {0xaae103b5fcd2a881, 0xd652bdc29f26a119}, // -95 261 | {0xd59944a37c0752a2, 0x4be76d3346f0495f}, // -94 262 | {0x857fcae62d8493a5, 0x6f70a4400c562ddb}, // -93 263 | {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb952}, // -92 264 | {0xd097ad07a71f26b2, 0x7e2000a41346a7a7}, // -91 265 | {0x825ecc24c873782f, 0x8ed400668c0c28c8}, // -90 266 | {0xa2f67f2dfa90563b, 0x728900802f0f32fa}, // -89 267 | {0xcbb41ef979346bca, 0x4f2b40a03ad2ffb9}, // -88 268 | {0xfea126b7d78186bc, 0xe2f610c84987bfa8}, // -87 269 | {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7c9}, // -86 270 | {0xc6ede63fa05d3143, 0x91503d1c79720dbb}, // -85 271 | {0xf8a95fcf88747d94, 0x75a44c6397ce912a}, // -84 272 | {0x9b69dbe1b548ce7c, 0xc986afbe3ee11aba}, // -83 273 | {0xc24452da229b021b, 0xfbe85badce996168}, // -82 274 | {0xf2d56790ab41c2a2, 0xfae27299423fb9c3}, // -81 275 | {0x97c560ba6b0919a5, 0xdccd879fc967d41a}, // -80 276 | {0xbdb6b8e905cb600f, 0x5400e987bbc1c920}, // -79 277 | {0xed246723473e3813, 0x290123e9aab23b68}, // -78 278 | {0x9436c0760c86e30b, 0xf9a0b6720aaf6521}, // -77 279 | {0xb94470938fa89bce, 0xf808e40e8d5b3e69}, // -76 280 | {0xe7958cb87392c2c2, 0xb60b1d1230b20e04}, // -75 281 | {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c2}, // -74 282 | {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af3}, // -73 283 | {0xe2280b6c20dd5232, 0x25c6da63c38de1b0}, // -72 284 | {0x8d590723948a535f, 0x579c487e5a38ad0e}, // -71 285 | {0xb0af48ec79ace837, 0x2d835a9df0c6d851}, // -70 286 | {0xdcdb1b2798182244, 0xf8e431456cf88e65}, // -69 287 | {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b58ff}, // -68 288 | {0xac8b2d36eed2dac5, 0xe272467e3d222f3f}, // -67 289 | {0xd7adf884aa879177, 0x5b0ed81dcc6abb0f}, // -66 290 | {0x86ccbb52ea94baea, 0x98e947129fc2b4e9}, // -65 291 | {0xa87fea27a539e9a5, 0x3f2398d747b36224}, // -64 292 | {0xd29fe4b18e88640e, 0x8eec7f0d19a03aad}, // -63 293 | {0x83a3eeeef9153e89, 0x1953cf68300424ac}, // -62 294 | {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd7}, // -61 295 | {0xcdb02555653131b6, 0x3792f412cb06794d}, // -60 296 | {0x808e17555f3ebf11, 0xe2bbd88bbee40bd0}, // -59 297 | {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec4}, // -58 298 | {0xc8de047564d20a8b, 0xf245825a5a445275}, // -57 299 | {0xfb158592be068d2e, 0xeed6e2f0f0d56712}, // -56 300 | {0x9ced737bb6c4183d, 0x55464dd69685606b}, // -55 301 | {0xc428d05aa4751e4c, 0xaa97e14c3c26b886}, // -54 302 | {0xf53304714d9265df, 0xd53dd99f4b3066a8}, // -53 303 | {0x993fe2c6d07b7fab, 0xe546a8038efe4029}, // -52 304 | {0xbf8fdb78849a5f96, 0xde98520472bdd033}, // -51 305 | {0xef73d256a5c0f77c, 0x963e66858f6d4440}, // -50 306 | {0x95a8637627989aad, 0xdde7001379a44aa8}, // -49 307 | {0xbb127c53b17ec159, 0x5560c018580d5d52}, // -48 308 | {0xe9d71b689dde71af, 0xaab8f01e6e10b4a6}, // -47 309 | {0x9226712162ab070d, 0xcab3961304ca70e8}, // -46 310 | {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d22}, // -45 311 | {0xe45c10c42a2b3b05, 0x8cb89a7db77c506a}, // -44 312 | {0x8eb98a7a9a5b04e3, 0x77f3608e92adb242}, // -43 313 | {0xb267ed1940f1c61c, 0x55f038b237591ed3}, // -42 314 | {0xdf01e85f912e37a3, 0x6b6c46dec52f6688}, // -41 315 | {0x8b61313bbabce2c6, 0x2323ac4b3b3da015}, // -40 316 | {0xae397d8aa96c1b77, 0xabec975e0a0d081a}, // -39 317 | {0xd9c7dced53c72255, 0x96e7bd358c904a21}, // -38 318 | {0x881cea14545c7575, 0x7e50d64177da2e54}, // -37 319 | {0xaa242499697392d2, 0xdde50bd1d5d0b9e9}, // -36 320 | {0xd4ad2dbfc3d07787, 0x955e4ec64b44e864}, // -35 321 | {0x84ec3c97da624ab4, 0xbd5af13bef0b113e}, // -34 322 | {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58e}, // -33 323 | {0xcfb11ead453994ba, 0x67de18eda5814af2}, // -32 324 | {0x81ceb32c4b43fcf4, 0x80eacf948770ced7}, // -31 325 | {0xa2425ff75e14fc31, 0xa1258379a94d028d}, // -30 326 | {0xcad2f7f5359a3b3e, 0x096ee45813a04330}, // -29 327 | {0xfd87b5f28300ca0d, 0x8bca9d6e188853fc}, // -28 328 | {0x9e74d1b791e07e48, 0x775ea264cf55347d}, // -27 329 | {0xc612062576589dda, 0x95364afe032a819d}, // -26 330 | {0xf79687aed3eec551, 0x3a83ddbd83f52204}, // -25 331 | {0x9abe14cd44753b52, 0xc4926a9672793542}, // -24 332 | {0xc16d9a0095928a27, 0x75b7053c0f178293}, // -23 333 | {0xf1c90080baf72cb1, 0x5324c68b12dd6338}, // -22 334 | {0x971da05074da7bee, 0xd3f6fc16ebca5e03}, // -21 335 | {0xbce5086492111aea, 0x88f4bb1ca6bcf584}, // -20 336 | {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e5}, // -19 337 | {0x9392ee8e921d5d07, 0x3aff322e62439fcf}, // -18 338 | {0xb877aa3236a4b449, 0x09befeb9fad487c2}, // -17 339 | {0xe69594bec44de15b, 0x4c2ebe687989a9b3}, // -16 340 | {0x901d7cf73ab0acd9, 0x0f9d37014bf60a10}, // -15 341 | {0xb424dc35095cd80f, 0x538484c19ef38c94}, // -14 342 | {0xe12e13424bb40e13, 0x2865a5f206b06fb9}, // -13 343 | {0x8cbccc096f5088cb, 0xf93f87b7442e45d3}, // -12 344 | {0xafebff0bcb24aafe, 0xf78f69a51539d748}, // -11 345 | {0xdbe6fecebdedd5be, 0xb573440e5a884d1b}, // -10 346 | {0x89705f4136b4a597, 0x31680a88f8953030}, // -9 347 | {0xabcc77118461cefc, 0xfdc20d2b36ba7c3d}, // -8 348 | {0xd6bf94d5e57a42bc, 0x3d32907604691b4c}, // -7 349 | {0x8637bd05af6c69b5, 0xa63f9a49c2c1b10f}, // -6 350 | {0xa7c5ac471b478423, 0x0fcf80dc33721d53}, // -5 351 | {0xd1b71758e219652b, 0xd3c36113404ea4a8}, // -4 352 | {0x83126e978d4fdf3b, 0x645a1cac083126e9}, // -3 353 | {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a3}, // -2 354 | {0xcccccccccccccccc, 0xcccccccccccccccc}, // -1 355 | {0x8000000000000000, 0x0000000000000000}, // 0 356 | {0xa000000000000000, 0x0000000000000000}, // 1 357 | {0xc800000000000000, 0x0000000000000000}, // 2 358 | {0xfa00000000000000, 0x0000000000000000}, // 3 359 | {0x9c40000000000000, 0x0000000000000000}, // 4 360 | {0xc350000000000000, 0x0000000000000000}, // 5 361 | {0xf424000000000000, 0x0000000000000000}, // 6 362 | {0x9896800000000000, 0x0000000000000000}, // 7 363 | {0xbebc200000000000, 0x0000000000000000}, // 8 364 | {0xee6b280000000000, 0x0000000000000000}, // 9 365 | {0x9502f90000000000, 0x0000000000000000}, // 10 366 | {0xba43b74000000000, 0x0000000000000000}, // 11 367 | {0xe8d4a51000000000, 0x0000000000000000}, // 12 368 | {0x9184e72a00000000, 0x0000000000000000}, // 13 369 | {0xb5e620f480000000, 0x0000000000000000}, // 14 370 | {0xe35fa931a0000000, 0x0000000000000000}, // 15 371 | {0x8e1bc9bf04000000, 0x0000000000000000}, // 16 372 | {0xb1a2bc2ec5000000, 0x0000000000000000}, // 17 373 | {0xde0b6b3a76400000, 0x0000000000000000}, // 18 374 | {0x8ac7230489e80000, 0x0000000000000000}, // 19 375 | {0xad78ebc5ac620000, 0x0000000000000000}, // 20 376 | {0xd8d726b7177a8000, 0x0000000000000000}, // 21 377 | {0x878678326eac9000, 0x0000000000000000}, // 22 378 | {0xa968163f0a57b400, 0x0000000000000000}, // 23 379 | {0xd3c21bcecceda100, 0x0000000000000000}, // 24 380 | {0x84595161401484a0, 0x0000000000000000}, // 25 381 | {0xa56fa5b99019a5c8, 0x0000000000000000}, // 26 382 | {0xcecb8f27f4200f3a, 0x0000000000000000}, // 27 383 | {0x813f3978f8940984, 0x4000000000000000}, // 28 384 | {0xa18f07d736b90be5, 0x5000000000000000}, // 29 385 | {0xc9f2c9cd04674ede, 0xa400000000000000}, // 30 386 | {0xfc6f7c4045812296, 0x4d00000000000000}, // 31 387 | {0x9dc5ada82b70b59d, 0xf020000000000000}, // 32 388 | {0xc5371912364ce305, 0x6c28000000000000}, // 33 389 | {0xf684df56c3e01bc6, 0xc732000000000000}, // 34 390 | {0x9a130b963a6c115c, 0x3c7f400000000000}, // 35 391 | {0xc097ce7bc90715b3, 0x4b9f100000000000}, // 36 392 | {0xf0bdc21abb48db20, 0x1e86d40000000000}, // 37 393 | {0x96769950b50d88f4, 0x1314448000000000}, // 38 394 | {0xbc143fa4e250eb31, 0x17d955a000000000}, // 39 395 | {0xeb194f8e1ae525fd, 0x5dcfab0800000000}, // 40 396 | {0x92efd1b8d0cf37be, 0x5aa1cae500000000}, // 41 397 | {0xb7abc627050305ad, 0xf14a3d9e40000000}, // 42 398 | {0xe596b7b0c643c719, 0x6d9ccd05d0000000}, // 43 399 | {0x8f7e32ce7bea5c6f, 0xe4820023a2000000}, // 44 400 | {0xb35dbf821ae4f38b, 0xdda2802c8a800000}, // 45 401 | {0xe0352f62a19e306e, 0xd50b2037ad200000}, // 46 402 | {0x8c213d9da502de45, 0x4526f422cc340000}, // 47 403 | {0xaf298d050e4395d6, 0x9670b12b7f410000}, // 48 404 | {0xdaf3f04651d47b4c, 0x3c0cdd765f114000}, // 49 405 | {0x88d8762bf324cd0f, 0xa5880a69fb6ac800}, // 50 406 | {0xab0e93b6efee0053, 0x8eea0d047a457a00}, // 51 407 | {0xd5d238a4abe98068, 0x72a4904598d6d880}, // 52 408 | {0x85a36366eb71f041, 0x47a6da2b7f864750}, // 53 409 | {0xa70c3c40a64e6c51, 0x999090b65f67d924}, // 54 410 | {0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d}, // 55 411 | {0x82818f1281ed449f, 0xbff8f10e7a8921a4}, // 56 412 | {0xa321f2d7226895c7, 0xaff72d52192b6a0d}, // 57 413 | {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490}, // 58 414 | {0xfee50b7025c36a08, 0x02f236d04753d5b4}, // 59 415 | {0x9f4f2726179a2245, 0x01d762422c946590}, // 60 416 | {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5}, // 61 417 | {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2}, // 62 418 | {0x9b934c3b330c8577, 0x63cc55f49f88eb2f}, // 63 419 | {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb}, // 64 420 | {0xf316271c7fc3908a, 0x8bef464e3945ef7a}, // 65 421 | {0x97edd871cfda3a56, 0x97758bf0e3cbb5ac}, // 66 422 | {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317}, // 67 423 | {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd}, // 68 424 | {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a}, // 69 425 | {0xb975d6b6ee39e436, 0xb3e2fd538e122b44}, // 70 426 | {0xe7d34c64a9c85d44, 0x60dbbca87196b616}, // 71 427 | {0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd}, // 72 428 | {0xb51d13aea4a488dd, 0x6babab6398bdbe41}, // 73 429 | {0xe264589a4dcdab14, 0xc696963c7eed2dd1}, // 74 430 | {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2}, // 75 431 | {0xb0de65388cc8ada8, 0x3b25a55f43294bcb}, // 76 432 | {0xdd15fe86affad912, 0x49ef0eb713f39ebe}, // 77 433 | {0x8a2dbf142dfcc7ab, 0x6e3569326c784337}, // 78 434 | {0xacb92ed9397bf996, 0x49c2c37f07965404}, // 79 435 | {0xd7e77a8f87daf7fb, 0xdc33745ec97be906}, // 80 436 | {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3}, // 81 437 | {0xa8acd7c0222311bc, 0xc40832ea0d68ce0c}, // 82 438 | {0xd2d80db02aabd62b, 0xf50a3fa490c30190}, // 83 439 | {0x83c7088e1aab65db, 0x792667c6da79e0fa}, // 84 440 | {0xa4b8cab1a1563f52, 0x577001b891185938}, // 85 441 | {0xcde6fd5e09abcf26, 0xed4c0226b55e6f86}, // 86 442 | {0x80b05e5ac60b6178, 0x544f8158315b05b4}, // 87 443 | {0xa0dc75f1778e39d6, 0x696361ae3db1c721}, // 88 444 | {0xc913936dd571c84c, 0x03bc3a19cd1e38e9}, // 89 445 | {0xfb5878494ace3a5f, 0x04ab48a04065c723}, // 90 446 | {0x9d174b2dcec0e47b, 0x62eb0d64283f9c76}, // 91 447 | {0xc45d1df942711d9a, 0x3ba5d0bd324f8394}, // 92 448 | {0xf5746577930d6500, 0xca8f44ec7ee36479}, // 93 449 | {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb}, // 94 450 | {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e}, // 95 451 | {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e}, // 96 452 | {0x95d04aee3b80ece5, 0xbba1f1d158724a12}, // 97 453 | {0xbb445da9ca61281f, 0x2a8a6e45ae8edc97}, // 98 454 | {0xea1575143cf97226, 0xf52d09d71a3293bd}, // 99 455 | {0x924d692ca61be758, 0x593c2626705f9c56}, // 100 456 | {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c}, // 101 457 | {0xe498f455c38b997a, 0x0b6dfb9c0f956447}, // 102 458 | {0x8edf98b59a373fec, 0x4724bd4189bd5eac}, // 103 459 | {0xb2977ee300c50fe7, 0x58edec91ec2cb657}, // 104 460 | {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed}, // 105 461 | {0x8b865b215899f46c, 0xbd79e0d20082ee74}, // 106 462 | {0xae67f1e9aec07187, 0xecd8590680a3aa11}, // 107 463 | {0xda01ee641a708de9, 0xe80e6f4820cc9495}, // 108 464 | {0x884134fe908658b2, 0x3109058d147fdcdd}, // 109 465 | {0xaa51823e34a7eede, 0xbd4b46f0599fd415}, // 110 466 | {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a}, // 111 467 | {0x850fadc09923329e, 0x03e2cf6bc604ddb0}, // 112 468 | {0xa6539930bf6bff45, 0x84db8346b786151c}, // 113 469 | {0xcfe87f7cef46ff16, 0xe612641865679a63}, // 114 470 | {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e}, // 115 471 | {0xa26da3999aef7749, 0xe3be5e330f38f09d}, // 116 472 | {0xcb090c8001ab551c, 0x5cadf5bfd3072cc5}, // 117 473 | {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6}, // 118 474 | {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa}, // 119 475 | {0xc646d63501a1511d, 0xb281e1fd541501b8}, // 120 476 | {0xf7d88bc24209a565, 0x1f225a7ca91a4226}, // 121 477 | {0x9ae757596946075f, 0x3375788de9b06958}, // 122 478 | {0xc1a12d2fc3978937, 0x0052d6b1641c83ae}, // 123 479 | {0xf209787bb47d6b84, 0xc0678c5dbd23a49a}, // 124 480 | {0x9745eb4d50ce6332, 0xf840b7ba963646e0}, // 125 481 | {0xbd176620a501fbff, 0xb650e5a93bc3d898}, // 126 482 | {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe}, // 127 483 | {0x93ba47c980e98cdf, 0xc66f336c36b10137}, // 128 484 | {0xb8a8d9bbe123f017, 0xb80b0047445d4184}, // 129 485 | {0xe6d3102ad96cec1d, 0xa60dc059157491e5}, // 130 486 | {0x9043ea1ac7e41392, 0x87c89837ad68db2f}, // 131 487 | {0xb454e4a179dd1877, 0x29babe4598c311fb}, // 132 488 | {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a}, // 133 489 | {0x8ce2529e2734bb1d, 0x1899e4a65f58660c}, // 134 490 | {0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f}, // 135 491 | {0xdc21a1171d42645d, 0x76707543f4fa1f73}, // 136 492 | {0x899504ae72497eba, 0x6a06494a791c53a8}, // 137 493 | {0xabfa45da0edbde69, 0x0487db9d17636892}, // 138 494 | {0xd6f8d7509292d603, 0x45a9d2845d3c42b6}, // 139 495 | {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b2}, // 140 496 | {0xa7f26836f282b732, 0x8e6cac7768d7141e}, // 141 497 | {0xd1ef0244af2364ff, 0x3207d795430cd926}, // 142 498 | {0x8335616aed761f1f, 0x7f44e6bd49e807b8}, // 143 499 | {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6}, // 144 500 | {0xcd036837130890a1, 0x36dba887c37a8c0f}, // 145 501 | {0x802221226be55a64, 0xc2494954da2c9789}, // 146 502 | {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c}, // 147 503 | {0xc83553c5c8965d3d, 0x6f92829494e5acc7}, // 148 504 | {0xfa42a8b73abbf48c, 0xcb772339ba1f17f9}, // 149 505 | {0x9c69a97284b578d7, 0xff2a760414536efb}, // 150 506 | {0xc38413cf25e2d70d, 0xfef5138519684aba}, // 151 507 | {0xf46518c2ef5b8cd1, 0x7eb258665fc25d69}, // 152 508 | {0x98bf2f79d5993802, 0xef2f773ffbd97a61}, // 153 509 | {0xbeeefb584aff8603, 0xaafb550ffacfd8fa}, // 154 510 | {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38}, // 155 511 | {0x952ab45cfa97a0b2, 0xdd945a747bf26183}, // 156 512 | {0xba756174393d88df, 0x94f971119aeef9e4}, // 157 513 | {0xe912b9d1478ceb17, 0x7a37cd5601aab85d}, // 158 514 | {0x91abb422ccb812ee, 0xac62e055c10ab33a}, // 159 515 | {0xb616a12b7fe617aa, 0x577b986b314d6009}, // 160 516 | {0xe39c49765fdf9d94, 0xed5a7e85fda0b80b}, // 161 517 | {0x8e41ade9fbebc27d, 0x14588f13be847307}, // 162 518 | {0xb1d219647ae6b31c, 0x596eb2d8ae258fc8}, // 163 519 | {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb}, // 164 520 | {0x8aec23d680043bee, 0x25de7bb9480d5854}, // 165 521 | {0xada72ccc20054ae9, 0xaf561aa79a10ae6a}, // 166 522 | {0xd910f7ff28069da4, 0x1b2ba1518094da04}, // 167 523 | {0x87aa9aff79042286, 0x90fb44d2f05d0842}, // 168 524 | {0xa99541bf57452b28, 0x353a1607ac744a53}, // 169 525 | {0xd3fa922f2d1675f2, 0x42889b8997915ce8}, // 170 526 | {0x847c9b5d7c2e09b7, 0x69956135febada11}, // 171 527 | {0xa59bc234db398c25, 0x43fab9837e699095}, // 172 528 | {0xcf02b2c21207ef2e, 0x94f967e45e03f4bb}, // 173 529 | {0x8161afb94b44f57d, 0x1d1be0eebac278f5}, // 174 530 | {0xa1ba1ba79e1632dc, 0x6462d92a69731732}, // 175 531 | {0xca28a291859bbf93, 0x7d7b8f7503cfdcfe}, // 176 532 | {0xfcb2cb35e702af78, 0x5cda735244c3d43e}, // 177 533 | {0x9defbf01b061adab, 0x3a0888136afa64a7}, // 178 534 | {0xc56baec21c7a1916, 0x088aaa1845b8fdd0}, // 179 535 | {0xf6c69a72a3989f5b, 0x8aad549e57273d45}, // 180 536 | {0x9a3c2087a63f6399, 0x36ac54e2f678864b}, // 181 537 | {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd}, // 182 538 | {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5}, // 183 539 | {0x969eb7c47859e743, 0x9f644ae5a4b1b325}, // 184 540 | {0xbc4665b596706114, 0x873d5d9f0dde1fee}, // 185 541 | {0xeb57ff22fc0c7959, 0xa90cb506d155a7ea}, // 186 542 | {0x9316ff75dd87cbd8, 0x09a7f12442d588f2}, // 187 543 | {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb2f}, // 188 544 | {0xe5d3ef282a242e81, 0x8f1668c8a86da5fa}, // 189 545 | {0x8fa475791a569d10, 0xf96e017d694487bc}, // 190 546 | {0xb38d92d760ec4455, 0x37c981dcc395a9ac}, // 191 547 | {0xe070f78d3927556a, 0x85bbe253f47b1417}, // 192 548 | {0x8c469ab843b89562, 0x93956d7478ccec8e}, // 193 549 | {0xaf58416654a6babb, 0x387ac8d1970027b2}, // 194 550 | {0xdb2e51bfe9d0696a, 0x06997b05fcc0319e}, // 195 551 | {0x88fcf317f22241e2, 0x441fece3bdf81f03}, // 196 552 | {0xab3c2fddeeaad25a, 0xd527e81cad7626c3}, // 197 553 | {0xd60b3bd56a5586f1, 0x8a71e223d8d3b074}, // 198 554 | {0x85c7056562757456, 0xf6872d5667844e49}, // 199 555 | {0xa738c6bebb12d16c, 0xb428f8ac016561db}, // 200 556 | {0xd106f86e69d785c7, 0xe13336d701beba52}, // 201 557 | {0x82a45b450226b39c, 0xecc0024661173473}, // 202 558 | {0xa34d721642b06084, 0x27f002d7f95d0190}, // 203 559 | {0xcc20ce9bd35c78a5, 0x31ec038df7b441f4}, // 204 560 | {0xff290242c83396ce, 0x7e67047175a15271}, // 205 561 | {0x9f79a169bd203e41, 0x0f0062c6e984d386}, // 206 562 | {0xc75809c42c684dd1, 0x52c07b78a3e60868}, // 207 563 | {0xf92e0c3537826145, 0xa7709a56ccdf8a82}, // 208 564 | {0x9bbcc7a142b17ccb, 0x88a66076400bb691}, // 209 565 | {0xc2abf989935ddbfe, 0x6acff893d00ea435}, // 210 566 | {0xf356f7ebf83552fe, 0x0583f6b8c4124d43}, // 211 567 | {0x98165af37b2153de, 0xc3727a337a8b704a}, // 212 568 | {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c}, // 213 569 | {0xeda2ee1c7064130c, 0x1162def06f79df73}, // 214 570 | {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8}, // 215 571 | {0xb9a74a0637ce2ee1, 0x6d953e2bd7173692}, // 216 572 | {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437}, // 217 573 | {0x910ab1d4db9914a0, 0x1d9c9892400a22a2}, // 218 574 | {0xb54d5e4a127f59c8, 0x2503beb6d00cab4b}, // 219 575 | {0xe2a0b5dc971f303a, 0x2e44ae64840fd61d}, // 220 576 | {0x8da471a9de737e24, 0x5ceaecfed289e5d2}, // 221 577 | {0xb10d8e1456105dad, 0x7425a83e872c5f47}, // 222 578 | {0xdd50f1996b947518, 0xd12f124e28f77719}, // 223 579 | {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f}, // 224 580 | {0xace73cbfdc0bfb7b, 0x636cc64d1001550b}, // 225 581 | {0xd8210befd30efa5a, 0x3c47f7e05401aa4e}, // 226 582 | {0x8714a775e3e95c78, 0x65acfaec34810a71}, // 227 583 | {0xa8d9d1535ce3b396, 0x7f1839a741a14d0d}, // 228 584 | {0xd31045a8341ca07c, 0x1ede48111209a050}, // 229 585 | {0x83ea2b892091e44d, 0x934aed0aab460432}, // 230 586 | {0xa4e4b66b68b65d60, 0xf81da84d5617853f}, // 231 587 | {0xce1de40642e3f4b9, 0x36251260ab9d668e}, // 232 588 | {0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019}, // 233 589 | {0xa1075a24e4421730, 0xb24cf65b8612f81f}, // 234 590 | {0xc94930ae1d529cfc, 0xdee033f26797b627}, // 235 591 | {0xfb9b7cd9a4a7443c, 0x169840ef017da3b1}, // 236 592 | {0x9d412e0806e88aa5, 0x8e1f289560ee864e}, // 237 593 | {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2}, // 238 594 | {0xf5b5d7ec8acb58a2, 0xae10af696774b1db}, // 239 595 | {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29}, // 240 596 | {0xbff610b0cc6edd3f, 0x17fd090a58d32af3}, // 241 597 | {0xeff394dcff8a948e, 0xddfc4b4cef07f5b0}, // 242 598 | {0x95f83d0a1fb69cd9, 0x4abdaf101564f98e}, // 243 599 | {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1}, // 244 600 | {0xea53df5fd18d5513, 0x84c86189216dc5ed}, // 245 601 | {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4}, // 246 602 | {0xb7118682dbb66a77, 0x3fbc8c33221dc2a1}, // 247 603 | {0xe4d5e82392a40515, 0x0fabaf3feaa5334a}, // 248 604 | {0x8f05b1163ba6832d, 0x29cb4d87f2a7400e}, // 249 605 | {0xb2c71d5bca9023f8, 0x743e20e9ef511012}, // 250 606 | {0xdf78e4b2bd342cf6, 0x914da9246b255416}, // 251 607 | {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e}, // 252 608 | {0xae9672aba3d0c320, 0xa184ac2473b529b1}, // 253 609 | {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e}, // 254 610 | {0x8865899617fb1871, 0x7e2fa67c7a658892}, // 255 611 | {0xaa7eebfb9df9de8d, 0xddbb901b98feeab7}, // 256 612 | {0xd51ea6fa85785631, 0x552a74227f3ea565}, // 257 613 | {0x8533285c936b35de, 0xd53a88958f87275f}, // 258 614 | {0xa67ff273b8460356, 0x8a892abaf368f137}, // 259 615 | {0xd01fef10a657842c, 0x2d2b7569b0432d85}, // 260 616 | {0x8213f56a67f6b29b, 0x9c3b29620e29fc73}, // 261 617 | {0xa298f2c501f45f42, 0x8349f3ba91b47b8f}, // 262 618 | {0xcb3f2f7642717713, 0x241c70a936219a73}, // 263 619 | {0xfe0efb53d30dd4d7, 0xed238cd383aa0110}, // 264 620 | {0x9ec95d1463e8a506, 0xf4363804324a40aa}, // 265 621 | {0xc67bb4597ce2ce48, 0xb143c6053edcd0d5}, // 266 622 | {0xf81aa16fdc1b81da, 0xdd94b7868e94050a}, // 267 623 | {0x9b10a4e5e9913128, 0xca7cf2b4191c8326}, // 268 624 | {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0}, // 269 625 | {0xf24a01a73cf2dccf, 0xbc633b39673c8cec}, // 270 626 | {0x976e41088617ca01, 0xd5be0503e085d813}, // 271 627 | {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18}, // 272 628 | {0xec9c459d51852ba2, 0xddf8e7d60ed1219e}, // 273 629 | {0x93e1ab8252f33b45, 0xcabb90e5c942b503}, // 274 630 | {0xb8da1662e7b00a17, 0x3d6a751f3b936243}, // 275 631 | {0xe7109bfba19c0c9d, 0x0cc512670a783ad4}, // 276 632 | {0x906a617d450187e2, 0x27fb2b80668b24c5}, // 277 633 | {0xb484f9dc9641e9da, 0xb1f9f660802dedf6}, // 278 634 | {0xe1a63853bbd26451, 0x5e7873f8a0396973}, // 279 635 | {0x8d07e33455637eb2, 0xdb0b487b6423e1e8}, // 280 636 | {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62}, // 281 637 | {0xdc5c5301c56b75f7, 0x7641a140cc7810fb}, // 282 638 | {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d}, // 283 639 | {0xac2820d9623bf429, 0x546345fa9fbdcd44}, // 284 640 | {0xd732290fbacaf133, 0xa97c177947ad4095}, // 285 641 | {0x867f59a9d4bed6c0, 0x49ed8eabcccc485d}, // 286 642 | {0xa81f301449ee8c70, 0x5c68f256bfff5a74}, // 287 643 | {0xd226fc195c6a2f8c, 0x73832eec6fff3111}, // 288 644 | {0x83585d8fd9c25db7, 0xc831fd53c5ff7eab}, // 289 645 | {0xa42e74f3d032f525, 0xba3e7ca8b77f5e55}, // 290 646 | {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb}, // 291 647 | {0x80444b5e7aa7cf85, 0x7980d163cf5b81b3}, // 292 648 | {0xa0555e361951c366, 0xd7e105bcc332621f}, // 293 649 | {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7}, // 294 650 | {0xfa856334878fc150, 0xb14f98f6f0feb951}, // 295 651 | {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3}, // 296 652 | {0xc3b8358109e84f07, 0x0a862f80ec4700c8}, // 297 653 | {0xf4a642e14c6262c8, 0xcd27bb612758c0fa}, // 298 654 | {0x98e7e9cccfbd7dbd, 0x8038d51cb897789c}, // 299 655 | {0xbf21e44003acdd2c, 0xe0470a63e6bd56c3}, // 300 656 | {0xeeea5d5004981478, 0x1858ccfce06cac74}, // 301 657 | {0x95527a5202df0ccb, 0x0f37801e0c43ebc8}, // 302 658 | {0xbaa718e68396cffd, 0xd30560258f54e6ba}, // 303 659 | {0xe950df20247c83fd, 0x47c6b82ef32a2069}, // 304 660 | {0x91d28b7416cdd27e, 0x4cdc331d57fa5441}, // 305 661 | {0xb6472e511c81471d, 0xe0133fe4adf8e952}, // 306 662 | {0xe3d8f9e563a198e5, 0x58180fddd97723a6}, // 307 663 | {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648}, // 308 664 | {0xb201833b35d63f73, 0x2cd2cc6551e513da}, // 309 665 | {0xde81e40a034bcf4f, 0xf8077f7ea65e58d1}, // 310 666 | {0x8b112e86420f6191, 0xfb04afaf27faf782}, // 311 667 | {0xadd57a27d29339f6, 0x79c5db9af1f9b563}, // 312 668 | {0xd94ad8b1c7380874, 0x18375281ae7822bc}, // 313 669 | {0x87cec76f1c830548, 0x8f2293910d0b15b5}, // 314 670 | {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb22}, // 315 671 | {0xd433179d9c8cb841, 0x5fa60692a46151eb}, // 316 672 | {0x849feec281d7f328, 0xdbc7c41ba6bcd333}, // 317 673 | {0xa5c7ea73224deff3, 0x12b9b522906c0800}, // 318 674 | {0xcf39e50feae16bef, 0xd768226b34870a00}, // 319 675 | {0x81842f29f2cce375, 0xe6a1158300d46640}, // 320 676 | {0xa1e53af46f801c53, 0x60495ae3c1097fd0}, // 321 677 | {0xca5e89b18b602368, 0x385bb19cb14bdfc4}, // 322 678 | {0xfcf62c1dee382c42, 0x46729e03dd9ed7b5}, // 323 679 | {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d1}, // 324 680 | }; 681 | 682 | // Computes 128-bit result of multiplication of two 64-bit unsigned integers. 683 | inline auto umul128(uint64_t x, uint64_t y) noexcept -> uint128_t { 684 | #if ZMIJ_USE_INT128 685 | return uint128_t(x) * y; 686 | #elif defined(_MSC_VER) && defined(_M_AMD64) 687 | uint64_t hi; 688 | uint64_t lo = _umul128(x, y, &hi); 689 | return {hi, lo}; 690 | #elif defined(_MSC_VER) && defined(_M_ARM64) 691 | return {__umulh(x, y), x * y}; 692 | #else 693 | uint64_t a = x >> 32; 694 | uint64_t b = uint32_t(x); 695 | uint64_t c = y >> 32; 696 | uint64_t d = uint32_t(y); 697 | 698 | uint64_t ac = a * c; 699 | uint64_t bc = b * c; 700 | uint64_t ad = a * d; 701 | uint64_t bd = b * d; 702 | 703 | uint64_t cs = (bd >> 32) + uint32_t(ad) + uint32_t(bc); // cross sum 704 | return {ac + (ad >> 32) + (bc >> 32) + (cs >> 32), (cs << 32) + uint32_t(bd)}; 705 | #endif // ZMIJ_USE_INT128 706 | } 707 | 708 | inline auto umul192_upper128(uint64_t x_hi, uint64_t x_lo, uint64_t y) noexcept 709 | -> uint128 { 710 | uint128_t p = umul128(x_hi, y); 711 | uint64_t lo = uint64_t(p) + uint64_t(umul128(x_lo, y) >> 64); 712 | return {uint64_t(p >> 64) + (lo < uint64_t(p)), lo}; 713 | } 714 | 715 | // Computes upper 64 bits of multiplication of x and y, discards the least 716 | // significant bit and rounds to odd, where x = uint128_t(x_hi << 64) | x_lo. 717 | auto umul192_upper64_inexact_to_odd(uint64_t x_hi, uint64_t x_lo, 718 | uint64_t y) noexcept -> uint64_t { 719 | auto [hi, lo] = umul192_upper128(x_hi, x_lo, y); 720 | return hi | ((lo >> 1) != 0); 721 | } 722 | 723 | struct divmod_result { 724 | uint32_t quo; 725 | uint32_t rem; 726 | }; 727 | 728 | // Returns {value / 100, value % 100} correct for values of up to 4 digits. 729 | inline auto divmod100(uint32_t value) noexcept -> divmod_result { 730 | assert(value < 10'000); 731 | constexpr int exp = 19; // 19 is faster or equal to 12 even for 3 digits. 732 | constexpr int sig = (1 << exp) / 100 + 1; 733 | uint32_t div = (value * sig) >> exp; // value / 100 734 | return {div, value - div * 100}; 735 | } 736 | 737 | inline auto is_big_endian() noexcept -> bool { 738 | char bytes[sizeof(int)]; 739 | int n = 1; 740 | memcpy(&bytes, &n, sizeof(int)); 741 | return bytes[0] == 0; 742 | } 743 | 744 | inline auto count_lzero(uint64_t x) noexcept -> int { 745 | #if defined(_MSC_VER) && defined(__AVX2__) 746 | // use lzcnt on MSVC only on AVX2 capable CPU's that all have this BMI 747 | // instruction 748 | return __lzcnt64(x); 749 | #elif defined(_MSC_VER) 750 | // otherwise fallback to BSR instruction. Note that 0 is not allowed as input 751 | // here 752 | unsigned long idx; 753 | _BitScanReverse64(&idx, x); 754 | return 63 - idx; 755 | #else 756 | // Unlike MSVC, clang and gcc recognize this implementation and replace 757 | // it with the assembly instructions which are appropriate for the 758 | // target (lzcnt or bsr + zero handling). 759 | int n = 64; 760 | for (; x > 0; x >>= 1) --n; 761 | return n; 762 | #endif 763 | } 764 | 765 | inline auto count_trailing_nonzeros(uint64_t x) noexcept -> int { 766 | // This assumes little-endian, that is the first char of the string 767 | // is in the lowest byte and the last char is in the highest byte. 768 | assert(!is_big_endian()); 769 | // We count the number of characters until there are only '0' == 0x30 770 | // characters left. 771 | // The code is equivalent to 772 | // return 8 - count_lzero(x & ~0x30303030'30303030) / 8 773 | // but if the BSR instruction is emitted, subtracting the constant 774 | // before dividing allows combining it with the subtraction from BSR 775 | // counting in the opposite direction. 776 | // return size_t(71 - count_lzero(x & ~0x30303030'30303030)) / 8; 777 | // Additionally, the bsr instruction requires a zero check. Since the 778 | // high bit is never set we can avoid the zero check by shifting the 779 | // datum left by one and using XOR to both remove the 0x30s and insert 780 | // a sentinel bit at the end. 781 | constexpr uint64_t mask_with_sentinel = (0x30303030'30303030ull << 1) | 1; 782 | return (70u - count_lzero((x << 1) ^ mask_with_sentinel)) / 8; 783 | } 784 | 785 | // Converts value in the range [0, 100) to a string. GCC generates a bit better 786 | // code when value is pointer-size (https://www.godbolt.org/z/5fEPMT1cc). 787 | inline auto digits2(size_t value) noexcept -> const char* { 788 | // Align data since unaligned access may be slower when crossing a 789 | // hardware-specific boundary. 790 | alignas(2) static const char data[] = 791 | "0001020304050607080910111213141516171819" 792 | "2021222324252627282930313233343536373839" 793 | "4041424344454647484950515253545556575859" 794 | "6061626364656667686970717273747576777879" 795 | "8081828384858687888990919293949596979899"; 796 | return &data[value * 2]; 797 | } 798 | 799 | inline auto digits2_u64(uint32_t value) noexcept -> uint64_t { 800 | uint16_t digits; 801 | memcpy(&digits, digits2(value), 2); 802 | return digits; 803 | } 804 | 805 | // Converts the value `aa * 10**6 + bb * 10**4 + cc * 10**2 + dd` to a string 806 | // returned as a 64-bit integer. 807 | auto digits8_u64(uint32_t aa, uint32_t bb, uint32_t cc, uint32_t dd) noexcept 808 | -> uint64_t { 809 | return digits2_u64(dd) << 48 | digits2_u64(cc) << 32 | digits2_u64(bb) << 16 | 810 | digits2_u64(aa); 811 | } 812 | 813 | // Writes a significand consisting of 16 or 17 decimal digits and removes 814 | // trailing zeros. 815 | auto write_significand(char* buffer, uint64_t value) noexcept -> char* { 816 | // Each digits is denoted by a letter so value is abbccddeeffgghhii where 817 | // digit a can be zero. 818 | uint32_t abbccddee = uint32_t(value / 100'000'000); 819 | uint32_t ffgghhii = uint32_t(value % 100'000'000); 820 | uint32_t abbcc = abbccddee / 10'000; 821 | uint32_t ddee = abbccddee % 10'000; 822 | uint32_t abb = abbcc / 100; 823 | uint32_t cc = abbcc % 100; 824 | auto [a, bb] = divmod100(abb); 825 | auto [dd, ee] = divmod100(ddee); 826 | 827 | char* start = buffer; 828 | *buffer = char('0' + a); 829 | buffer += a != 0; 830 | 831 | // Use an intermediate uint64_t to make sure that the compiler constructs 832 | // the value in a register. This way the buffer is written to memory in 833 | // one go and count_trailing_nonzeros doesn't have to load from memory. 834 | uint64_t digits = digits8_u64(bb, cc, dd, ee); 835 | memcpy(buffer, &digits, 8); 836 | if (ffgghhii == 0) { 837 | buffer += count_trailing_nonzeros(digits); 838 | buffer -= (buffer - start == 1) ? 1 : 0; 839 | return buffer; 840 | } 841 | 842 | buffer += 8; 843 | uint32_t ffgg = ffgghhii / 10'000; 844 | uint32_t hhii = ffgghhii % 10'000; 845 | auto [ff, gg] = divmod100(ffgg); 846 | auto [hh, ii] = divmod100(hhii); 847 | digits = digits8_u64(ff, gg, hh, ii); 848 | memcpy(buffer, &digits, 8); 849 | return buffer + count_trailing_nonzeros(digits); 850 | } 851 | 852 | // Writes the decimal FP number dec_sig * 10**dec_exp to buffer. 853 | void write(char* buffer, uint64_t dec_sig, int dec_exp) noexcept { 854 | dec_exp += 15 + (dec_sig >= uint64_t(1e16)); 855 | 856 | char* start = buffer; 857 | buffer = write_significand(buffer + 1, dec_sig); 858 | start[0] = start[1]; 859 | start[1] = '.'; 860 | 861 | *buffer++ = 'e'; 862 | char sign = '+'; 863 | if (dec_exp < 0) { 864 | sign = '-'; 865 | dec_exp = -dec_exp; 866 | } 867 | *buffer++ = sign; 868 | auto [a, bb] = divmod100(uint32_t(dec_exp)); 869 | *buffer = char('0' + a); 870 | buffer += dec_exp >= 100; 871 | memcpy(buffer, digits2(bb), 2); 872 | buffer[2] = '\0'; 873 | } 874 | 875 | } // namespace 876 | 877 | namespace zmij { 878 | 879 | void dtoa(double value, char* buffer) noexcept { 880 | static_assert(std::numeric_limits::is_iec559, "IEEE 754 required"); 881 | constexpr int num_bits = sizeof(value) * CHAR_BIT; 882 | uint64_t bits = 0; 883 | memcpy(&bits, &value, sizeof(value)); 884 | 885 | *buffer = '-'; 886 | buffer += bits >> (num_bits - 1); 887 | 888 | constexpr int num_sig_bits = std::numeric_limits::digits - 1; 889 | constexpr uint64_t implicit_bit = uint64_t(1) << num_sig_bits; 890 | uint64_t bin_sig = bits & (implicit_bit - 1); // binary significand 891 | bool regular = bin_sig != 0; 892 | 893 | constexpr int num_exp_bits = num_bits - num_sig_bits - 1; 894 | constexpr int exp_mask = (1 << num_exp_bits) - 1; 895 | constexpr int exp_bias = (1 << (num_exp_bits - 1)) - 1; 896 | int bin_exp = int(bits >> num_sig_bits) & exp_mask; // binary exponent 897 | if (((bin_exp + 1) & exp_mask) <= 1) [[unlikely]] { 898 | if (bin_exp != 0) { 899 | memcpy(buffer, bin_sig == 0 ? "inf" : "nan", 4); 900 | return; 901 | } 902 | if (bin_sig == 0) { 903 | memcpy(buffer, "0", 2); 904 | return; 905 | } 906 | // Handle subnormals. 907 | bin_sig |= implicit_bit; 908 | bin_exp = 1; 909 | regular = true; 910 | } 911 | bin_sig ^= implicit_bit; 912 | bin_exp -= num_sig_bits + exp_bias; 913 | 914 | // Compute the decimal exponent as floor(log10(2**bin_exp)) if regular or 915 | // floor(log10(3/4 * 2**bin_exp)) otherwise, without branching. 916 | // log10_3_over_4_sig = round(log10(3/4) * 2**log10_2_exp) 917 | constexpr int log10_3_over_4_sig = -131'008; 918 | // log10_2_sig = round(log10(2) * 2**log10_2_exp) 919 | constexpr int log10_2_sig = 315'653; 920 | constexpr int log10_2_exp = 20; 921 | assert(bin_exp >= -1334 && bin_exp <= 2620); 922 | int dec_exp = 923 | (bin_exp * log10_2_sig + !regular * log10_3_over_4_sig) >> log10_2_exp; 924 | 925 | constexpr int dec_exp_min = -292; 926 | auto [pow10_hi, pow10_lo] = pow10_significands[-dec_exp - dec_exp_min]; 927 | 928 | // log2_pow10_sig = round(log2(10) * 2**log2_pow10_exp) + 1 929 | constexpr int log2_pow10_sig = 217'707, log2_pow10_exp = 16; 930 | assert(dec_exp >= -350 && dec_exp <= 350); 931 | // pow10_bin_exp = floor(log2(10**-dec_exp)) 932 | int pow10_bin_exp = -dec_exp * log2_pow10_sig >> log2_pow10_exp; 933 | // pow10 = ((pow10_hi << 64) | pow10_lo) * 2**(pow10_bin_exp - 127) 934 | 935 | // Shift to ensure the intermediate result of multiplying by a power of 10 936 | // has a fixed 128-bit fractional part. For example, 3 * 2**59 and 3 * 2**60 937 | // both have dec_exp = 2 and dividing them by 10**dec_exp would have the 938 | // decimal point in different (bit) positions without the shift: 939 | // 3 * 2**59 / 100 = 1.72...e+16 (exp_shift = 1 + 1) 940 | // 3 * 2**60 / 100 = 3.45...e+16 (exp_shift = 2 + 1) 941 | int exp_shift = bin_exp + pow10_bin_exp + 1; 942 | 943 | if (regular) [[likely]] { 944 | auto [integral, fractional] = 945 | umul192_upper128(pow10_hi, pow10_lo, bin_sig << exp_shift); 946 | uint64_t digit = integral % 10; 947 | 948 | // Switch to a fixed-point representation with the integral part in the 949 | // upper 4 bits and the rest being the fractional part. 950 | constexpr int num_integral_bits = 4; 951 | constexpr int num_fractional_bits = num_bits - num_integral_bits; 952 | constexpr uint64_t ten = uint64_t(10) << num_fractional_bits; 953 | // Fixed-point remainder of the scaled significand modulo 10. 954 | uint64_t rem10 = 955 | (digit << num_fractional_bits) | (fractional >> num_integral_bits); 956 | // dec_exp is chosen so that 10**dec_exp <= 2**bin_exp < 10**(dec_exp + 1). 957 | // Since 1ulp == 2**bin_exp it will be in the range [1, 10) after scaling by 958 | // 10**dec_exp. Add 1 to combine the shift with division by two. 959 | uint64_t half_ulp10 = pow10_hi >> (num_integral_bits - exp_shift + 1); 960 | uint64_t upper = rem10 + half_ulp10; 961 | 962 | // An optimization from yy by Yaoyuan Guo: 963 | if ( 964 | // Exact half-ulp tie when rounding to nearest integer. 965 | fractional != (uint64_t(1) << 63) && 966 | // Exact half-ulp tie when rounding to nearest 10. 967 | rem10 != half_ulp10 && 968 | // Near-boundary case for rounding to nearest 10. 969 | ten - upper > uint64_t(1)) [[likely]] { 970 | bool round = (upper >> num_fractional_bits) >= 10; 971 | uint64_t shorter = integral - digit + round * 10; 972 | uint64_t longer = integral + (fractional >= (uint64_t(1) << 63)); 973 | return write(buffer, 974 | ((rem10 <= half_ulp10) + round != 0) ? shorter : longer, 975 | dec_exp); 976 | } 977 | } 978 | 979 | // Fallback to Schubfach to guarantee correctness and switch to overestimates. 980 | ++pow10_lo; 981 | 982 | // Shift the significand so that boundaries are integer. 983 | uint64_t bin_sig_shifted = bin_sig << 2; 984 | 985 | // Compute the estimates of lower and upper bounds of the rounding interval 986 | // by multiplying them by the power of 10 and applying modified rounding. 987 | uint64_t lsb = bin_sig & 1; 988 | uint64_t lower = (bin_sig_shifted - (regular + 1)) << exp_shift; 989 | lower = umul192_upper64_inexact_to_odd(pow10_hi, pow10_lo, lower) + lsb; 990 | uint64_t upper = (bin_sig_shifted + 2) << exp_shift; 991 | upper = umul192_upper64_inexact_to_odd(pow10_hi, pow10_lo, upper) - lsb; 992 | 993 | // The idea of using a single shorter candidate is by Cassio Neri. 994 | // It is less or equal to the upper bound by construction. 995 | uint64_t shorter = 10 * ((upper >> 2) / 10); 996 | if ((shorter << 2) >= lower) return write(buffer, shorter, dec_exp); 997 | 998 | uint64_t scaled_sig = umul192_upper64_inexact_to_odd( 999 | pow10_hi, pow10_lo, bin_sig_shifted << exp_shift); 1000 | uint64_t dec_sig_under = scaled_sig >> 2; 1001 | uint64_t dec_sig_over = dec_sig_under + 1; 1002 | 1003 | // Pick the closest of dec_sig_under and dec_sig_over and check if it's in 1004 | // the rounding interval. 1005 | int64_t cmp = int64_t(scaled_sig - ((dec_sig_under + dec_sig_over) << 1)); 1006 | bool under_closer = cmp < 0 || (cmp == 0 && (dec_sig_under & 1) == 0); 1007 | bool under_in = (dec_sig_under << 2) >= lower; 1008 | write(buffer, (under_closer & under_in) ? dec_sig_under : dec_sig_over, 1009 | dec_exp); 1010 | } 1011 | 1012 | } // namespace zmij 1013 | --------------------------------------------------------------------------------