From d8dbb64c772788fe4585277c106b3fdbc8c9195b Mon Sep 17 00:00:00 2001 From: mrabine Date: Thu, 29 Oct 2026 23:39:23 +0100 Subject: [PATCH 1/3] Schubfach algorithm --- README.md | 5 +- dconv/CMakeLists.txt | 3 + dconv/include/dconv/digits.hpp | 96 +++++++ dconv/include/dconv/dtoa.hpp | 3 +- dconv/include/dconv/eisellemire.hpp | 32 +-- dconv/include/dconv/eisellemirepow.hpp | 9 +- dconv/include/dconv/format.hpp | 57 ++++ dconv/include/dconv/power.hpp | 75 ++++++ dconv/include/dconv/schubfach.hpp | 191 ++++++++++++++ dconv/include/dconv/schubfachpow.hpp | 349 +++++++++++++++++++++++++ dconv/tests/CMakeLists.txt | 4 + dconv/tests/digits_test.cpp | 65 +++++ dconv/tests/format_test.cpp | 51 ++++ dconv/tests/schubfach_test.cpp | 196 ++++++++++++++ tools/CMakeLists.txt | 1 + tools/schubfachpowgen/CMakeLists.txt | 35 +++ tools/schubfachpowgen/README.md | 61 +++++ tools/schubfachpowgen/src/main.cpp | 171 ++++++++++++ tools/schubfachpowgen/version.hpp.in | 32 +++ 19 files changed, 1396 insertions(+), 40 deletions(-) create mode 100644 dconv/include/dconv/power.hpp create mode 100644 dconv/include/dconv/schubfach.hpp create mode 100644 dconv/include/dconv/schubfachpow.hpp create mode 100644 dconv/tests/schubfach_test.cpp create mode 100644 tools/schubfachpowgen/CMakeLists.txt create mode 100644 tools/schubfachpowgen/README.md create mode 100644 tools/schubfachpowgen/src/main.cpp create mode 100644 tools/schubfachpowgen/version.hpp.in diff --git a/README.md b/README.md index 2d87426..51018e7 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ **dconv** is a header-only C++20 library for printing and parsing floating point numbers. -Double to string conversion uses the **Grisu2** algorithm by default, described by **Florian Loitsch** in its publication [Printing Floating-Point Numbers Quickly and Accurately with Integers](https://florian.loitsch.com/publications). +Double to string conversion uses the **Schubfach** algorithm by default, described by **Raffaello Giulietti** in its publication *The Schubfach way to render doubles*. It always prints the shortest representation that reads back to the same double, and the closest one when several are possible. -The **Grisu** and **Grisu3** algorithms from the same publication are also available. Grisu prints up to 18 digits without looking for the shortest output, Grisu2 prints the shortest output for about 99.9% of the doubles, and Grisu3 detects the remaining cases and falls back to `std::to_chars`. +The **Grisu**, **Grisu2** and **Grisu3** algorithms, described by **Florian Loitsch** in [Printing Floating-Point Numbers Quickly and Accurately with Integers](https://florian.loitsch.com/publications), are also available. Grisu prints up to 18 digits without looking for the shortest output, Grisu2 prints the shortest output for about 99.9% of the doubles, and Grisu3 detects the remaining cases and falls back to `std::to_chars`. String to double conversion uses the **Eisel-Lemire** algorithm on the first 19 significant digits. Longer mantissas are bracketed between two Eisel-Lemire results; only when they disagree is the number rebuilt from the digits already read and passed to strtod. A stream is read once and never rewound; a buffer is only read again for mantissas longer than 19 digits. @@ -85,6 +85,7 @@ char* end = dconv::grisu3::dtoa (value, -2.22507e-308); | Header | Function | | :--- | :--- | +| `dconv/schubfach.hpp` | `dconv::schubfach::dtoa` | | `dconv/grisu3.hpp` | `dconv::grisu3::dtoa` | | `dconv/grisu2.hpp` | `dconv::grisu2::dtoa` | | `dconv/grisu.hpp` | `dconv::grisu::dtoa` | diff --git a/dconv/CMakeLists.txt b/dconv/CMakeLists.txt index 702fc57..2a87fae 100644 --- a/dconv/CMakeLists.txt +++ b/dconv/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.22.1) set(PUBLIC_HEADERS include/dconv/error.hpp include/dconv/probe.hpp + include/dconv/power.hpp include/dconv/eisellemirepow.hpp include/dconv/eisellemire.hpp include/dconv/atod.hpp @@ -13,6 +14,8 @@ set(PUBLIC_HEADERS include/dconv/grisu.hpp include/dconv/grisu2.hpp include/dconv/grisu3.hpp + include/dconv/schubfachpow.hpp + include/dconv/schubfach.hpp include/dconv/dtoa.hpp ) diff --git a/dconv/include/dconv/digits.hpp b/dconv/include/dconv/digits.hpp index 1009c8e..9828e8c 100644 --- a/dconv/include/dconv/digits.hpp +++ b/dconv/include/dconv/digits.hpp @@ -40,6 +40,22 @@ namespace dconv "0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152" "5354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899"; + /// trailing zeros of the two digits decimal representations of 0 to 99. + alignas (64) constexpr uint8_t pairZeros[] = { + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + /** + * @brief count the trailing zeros of a four digits group. + * @param group four digits group. + * @return number of trailing zeros. + */ + inline int countTrailingZeros (uint32_t group) noexcept + { + return pairZeros[group % 100] + ((group % 100 == 0) ? pairZeros[group / 100] : 0); + } + /** * @brief count the digits of a decimal significand. * @param digits decimal significand. @@ -82,6 +98,86 @@ namespace dconv return (digits >= 1000000000) ? 10 : 9; } + /** + * @brief write the digits of a decimal significand. + * @param buffer buffer to write the digits to. + * @param digits decimal significand. + * @param length number of digits. + * @return number of trailing zeros written. + */ + inline int writeDigits (char* buffer, uint64_t digits, int length) noexcept + { + uint32_t high = static_cast (digits); + uint32_t low = 0; + if (digits >= 100000000) + { + high = static_cast (digits / 100000000); + low = static_cast (digits % 100000000); + } + + char* const end = buffer + length; + char* cur = end; + int zeros = 0; + if (digits >= 100000000) + { + cur -= 8; + if (low == 0) + { + __builtin_memcpy (cur, "00000000", 8); + zeros = 8; + } + else + { + const uint32_t upper = low / 10000; + const uint32_t lower = low % 10000; + __builtin_memcpy (cur, &digitPairs[(upper / 100) * 2], 2); + __builtin_memcpy (cur + 2, &digitPairs[(upper % 100) * 2], 2); + __builtin_memcpy (cur + 4, &digitPairs[(lower / 100) * 2], 2); + __builtin_memcpy (cur + 6, &digitPairs[(lower % 100) * 2], 2); + zeros = (lower != 0) ? countTrailingZeros (lower) : 4 + countTrailingZeros (upper); + } + } + + if (high >= 10000) + { + const uint32_t lower = high % 10000; + high /= 10000; + cur -= 4; + __builtin_memcpy (cur, &digitPairs[(lower / 100) * 2], 2); + __builtin_memcpy (cur + 2, &digitPairs[(lower % 100) * 2], 2); + if (zeros == end - cur - 4) + { + zeros += countTrailingZeros (lower); + } + } + + while (high >= 100) + { + cur -= 2; + __builtin_memcpy (cur, &digitPairs[(high % 100) * 2], 2); + if (zeros == end - cur - 2) + { + zeros += pairZeros[high % 100]; + } + high /= 100; + } + + if (high >= 10) + { + cur -= 2; + __builtin_memcpy (cur, &digitPairs[high * 2], 2); + if (zeros == end - cur - 2) + { + zeros += pairZeros[high]; + } + } + else + { + *--cur = static_cast ('0' + high); + } + + return zeros; + } } } diff --git a/dconv/include/dconv/dtoa.hpp b/dconv/include/dconv/dtoa.hpp index 58e3e14..bbf01e5 100644 --- a/dconv/include/dconv/dtoa.hpp +++ b/dconv/include/dconv/dtoa.hpp @@ -26,6 +26,7 @@ #define __DCONV_DTOA_HPP__ // dconv. +#include #include namespace dconv @@ -38,7 +39,7 @@ namespace dconv */ inline char* dtoa (char* buffer, double value) noexcept { - return grisu2::dtoa (buffer, value); + return schubfach::dtoa (buffer, value); } } diff --git a/dconv/include/dconv/eisellemire.hpp b/dconv/include/dconv/eisellemire.hpp index cbe9e17..0ba1f3e 100644 --- a/dconv/include/dconv/eisellemire.hpp +++ b/dconv/include/dconv/eisellemire.hpp @@ -40,34 +40,6 @@ namespace dconv { namespace eisellemire { - /** - * @brief multiply two 64 bits unsigned integers. - * @param a multiplicand. - * @param b multiplier. - * @param high high 64 bits of the 128-bit result. - * @param low low 64 bits of the 128-bit result. - */ - inline void umul128 (uint64_t a, uint64_t b, uint64_t& high, uint64_t& low) noexcept - { -#if defined(__SIZEOF_INT128__) - __uint128_t p = static_cast<__uint128_t> (a) * b; - - high = static_cast (p >> 64); - low = static_cast (p); -#else - uint64_t b_lo = static_cast (b); - uint64_t b_hi = b >> 32; - uint64_t p0 = (a & 0xFFFFFFFF) * b_lo; - uint64_t p1 = (a >> 32) * b_lo; - uint64_t p2 = (a & 0xFFFFFFFF) * b_hi; - uint64_t p3 = (a >> 32) * b_hi; - uint64_t carry = (p0 >> 32) + (p1 & 0xFFFFFFFF) + (p2 & 0xFFFFFFFF); - - low = (carry << 32) | (p0 & 0xFFFFFFFF); - high = (carry >> 32) + (p1 >> 32) + (p2 >> 32) + p3; -#endif - } - /** * @brief convert double using fast path. * @param significand significand digits (at most 19). @@ -110,11 +82,11 @@ namespace dconv const details::Power& power = details::eisellemirepow[exponent + 342]; uint64_t high, low; - umul128 (power.hi, significand, high, low); + details::umul128 (power.hi, significand, high, low); if ((high & 0x1FF) == 0x1FF) { uint64_t secondHigh, secondLow; - umul128 (power.lo, significand, secondHigh, secondLow); + details::umul128 (power.lo, significand, secondHigh, secondLow); low += secondHigh; high += (secondHigh > low); } diff --git a/dconv/include/dconv/eisellemirepow.hpp b/dconv/include/dconv/eisellemirepow.hpp index e5a20aa..af6d701 100644 --- a/dconv/include/dconv/eisellemirepow.hpp +++ b/dconv/include/dconv/eisellemirepow.hpp @@ -25,18 +25,13 @@ #ifndef __DCONV_EISELLEMIREPOW_HPP__ #define __DCONV_EISELLEMIREPOW_HPP__ -#include +// dconv. +#include namespace dconv { namespace details { - struct Power - { - uint64_t hi; - uint64_t lo; - }; - constexpr Power eisellemirepow[] = { {0xeef453d6923bd65a, 0x113faa2906a13b3f}, {0x9558b4661b6565f8, 0x4ac7ca59a424c507}, {0xbaaee17fa23ebf76, 0x5d79bcf00d2df649}, {0xe95a99df8ace6f53, 0xf4d82c2c107973dc}, diff --git a/dconv/include/dconv/format.hpp b/dconv/include/dconv/format.hpp index cd59943..6c872e9 100644 --- a/dconv/include/dconv/format.hpp +++ b/dconv/include/dconv/format.hpp @@ -131,6 +131,63 @@ namespace dconv return writeExponent (&buffer[length + 2], kk - 1); } } + + /** + * @brief write a decimal significand with the same layout as prettify. + * @param buffer buffer to write the string representation to. + * @param digits decimal significand. + * @param length number of digits. + * @param k decimal exponent. + * @return end position. + */ + inline char* format (char* buffer, uint64_t digits, int length, int k) noexcept + { + const int kk = length + k; + + if ((kk > 21) || (kk <= -6)) + { + length -= writeDigits (buffer + 1, digits, length); + buffer[0] = buffer[1]; + buffer[1] = '.'; + const int position = (length > 1) ? length + 1 : 1; + buffer[position] = 'e'; + return writeExponent (&buffer[position + 1], kk - 1); + } + + if ((length <= kk) && (kk <= 21)) + { + writeDigits (buffer, digits, length); + for (int i = length; i < kk; ++i) + { + buffer[i] = '0'; + } + buffer[kk] = '.'; + buffer[kk + 1] = '0'; + return &buffer[kk + 2]; + } + else if ((0 < kk) && (kk <= 21)) + { + length -= writeDigits (buffer + 1, digits, length); + for (int i = 0; i < kk; ++i) + { + buffer[i] = buffer[i + 1]; + } + buffer[kk] = '.'; + return &buffer[length + 1]; + } + else + { + const int offset = 2 - kk; + buffer[0] = '0'; + buffer[1] = '.'; + for (int i = 2; i < offset; ++i) + { + buffer[i] = '0'; + } + length -= writeDigits (buffer + offset, digits, length); + return &buffer[length + offset]; + } + } } } diff --git a/dconv/include/dconv/power.hpp b/dconv/include/dconv/power.hpp new file mode 100644 index 0000000..62e5414 --- /dev/null +++ b/dconv/include/dconv/power.hpp @@ -0,0 +1,75 @@ +/** + * MIT License + * + * Copyright (c) 2026 Mathieu Rabine + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __DCONV_POWER_HPP__ +#define __DCONV_POWER_HPP__ + +// C. +#include + +namespace dconv +{ + namespace details + { + /// 128 bits power. + struct Power + { + /// high 64 bits. + uint64_t hi; + + /// low 64 bits. + uint64_t lo; + }; + + /** + * @brief multiply two 64 bits unsigned integers. + * @param a multiplicand. + * @param b multiplier. + * @param high high 64 bits of the 128-bit result. + * @param low low 64 bits of the 128-bit result. + */ + inline void umul128 (uint64_t a, uint64_t b, uint64_t& high, uint64_t& low) noexcept + { +#if defined(__SIZEOF_INT128__) + __uint128_t p = static_cast<__uint128_t> (a) * b; + + high = static_cast (p >> 64); + low = static_cast (p); +#else + uint64_t b_lo = static_cast (b); + uint64_t b_hi = b >> 32; + uint64_t p0 = (a & 0xFFFFFFFF) * b_lo; + uint64_t p1 = (a >> 32) * b_lo; + uint64_t p2 = (a & 0xFFFFFFFF) * b_hi; + uint64_t p3 = (a >> 32) * b_hi; + uint64_t carry = (p0 >> 32) + (p1 & 0xFFFFFFFF) + (p2 & 0xFFFFFFFF); + + low = (carry << 32) | (p0 & 0xFFFFFFFF); + high = (carry >> 32) + (p1 >> 32) + (p2 >> 32) + p3; +#endif + } + } +} + +#endif diff --git a/dconv/include/dconv/schubfach.hpp b/dconv/include/dconv/schubfach.hpp new file mode 100644 index 0000000..1076618 --- /dev/null +++ b/dconv/include/dconv/schubfach.hpp @@ -0,0 +1,191 @@ +/** + * MIT License + * + * Copyright (c) 2026 Mathieu Rabine + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __DCONV_SCHUBFACH_HPP__ +#define __DCONV_SCHUBFACH_HPP__ + +// dconv. +#include +#include + +// C. +#include +#include + +namespace dconv +{ + namespace schubfach + { + /** + * @brief compute floor (log10 (2^q)) or floor (log10 (3/4 * 2^q)). + * @param q binary exponent. + * @param asymmetric compute floor (log10 (3/4 * 2^q)) if true. + * @return decimal exponent. + */ + constexpr int floorLog10Pow2 (int q, bool asymmetric) noexcept + { + return (q * 315653 - (asymmetric ? 131008 : 0)) >> 20; + } + + /** + * @brief compute floor (log2 (10^k)). + * @param k decimal exponent. + * @return binary exponent. + */ + constexpr int floorLog2Pow10 (int k) noexcept + { + return (k * 3483294) >> 20; + } + + /** + * @brief multiply by a power of ten and round to odd. + * @param g power of ten. + * @param cp value to multiply. + * @return product rounded to odd. + */ + inline uint64_t roundToOdd (const details::Power& g, uint64_t cp) noexcept + { + uint64_t middle, unused; + details::umul128 (g.lo, cp, middle, unused); + + uint64_t high, low; + details::umul128 (g.hi, cp, high, low); + + const uint64_t z = low + middle; + high += (z < low); + return high | (z != 0); + } + + /** + * @brief compute the shortest decimal significand. + * @param value positive value to convert. + * @param k decimal exponent. + * @return decimal significand, possibly with trailing zeros. + */ + inline uint64_t shortest (double value, int& k) noexcept + { + uint64_t bits; + memcpy (&bits, &value, sizeof (double)); + + const uint64_t fraction = bits & 0x000FFFFFFFFFFFFF; + const int biased = static_cast (bits >> 52); + const uint64_t c = (biased != 0) ? (fraction | 0x0010000000000000) : fraction; + const int q = (biased != 0) ? biased - 1075 : -1074; + + if ((static_cast (-q) <= 52) && ((c & ((static_cast (1) << -q) - 1)) == 0)) + { + k = 0; + return c >> -q; + } + + const bool asymmetric = (fraction == 0) && (biased > 1); + const uint64_t out = c & 1; + + const uint64_t cb = c << 2; + const uint64_t cbl = asymmetric ? cb - 1 : cb - 2; + const uint64_t cbr = cb + 2; + + k = floorLog10Pow2 (q, asymmetric); + const int h = q + floorLog2Pow10 (-k) + 3; + const details::Power& g = details::schubfachpow[292 - k]; + + const uint64_t vb = roundToOdd (g, cb << h); + const uint64_t vbl = roundToOdd (g, cbl << h); + const uint64_t vbr = roundToOdd (g, cbr << h); + + const uint64_t s = vb >> 2; + const uint64_t sp10 = (s / 10) * 10; + const uint64_t tp10 = sp10 + 10; + const bool upin = vbl + out <= (sp10 << 2); + const bool wpin = (tp10 << 2) + out <= vbr; + if (upin != wpin) + { + uint64_t digits = upin ? s / 10 : s / 10 + 1; + ++k; + if (digits < 1000000000000000) + { + digits *= 10; + --k; + } + return digits; + } + + const uint64_t t = s + 1; + const bool uin = vbl + out <= (s << 2); + const bool win = (t << 2) + out <= vbr; + if (uin != win) + { + return uin ? s : t; + } + + const int64_t cmp = static_cast (vb - ((s + t) << 1)); + return ((cmp < 0) || ((cmp == 0) && ((s & 1) == 0))) ? s : t; + } + + /** + * @brief write the shortest decimal digits. + * @param buffer buffer to write the digits to. + * @param length number of digits written. + * @param k decimal exponent. + * @param value positive value to convert. + */ + inline void generate (char* buffer, int& length, int& k, double value) noexcept + { + const uint64_t digits = shortest (value, k); + length = details::countDigits (digits); + const int zeros = details::writeDigits (buffer, digits, length); + length -= zeros; + k += zeros; + } + + /** + * @brief double to string conversion using Schubfach. + * @param buffer buffer to write the string representation to (must point to at least 25 writable bytes). + * @param value value to convert. + * @return end position. + */ + inline char* dtoa (char* buffer, double value) noexcept + { + uint64_t bits; + memcpy (&bits, &value, sizeof (double)); + bool is_negative = (bits >> 63) != 0; + + *buffer = '-'; + buffer += is_negative; + value = is_negative ? -value : value; + + if (value == 0.0) + { + memcpy (buffer, "0.0", 3); + return buffer + 3; + } + + int k = 0; + const uint64_t digits = shortest (value, k); + return details::format (buffer, digits, details::countDigits (digits), k); + } + } +} + +#endif diff --git a/dconv/include/dconv/schubfachpow.hpp b/dconv/include/dconv/schubfachpow.hpp new file mode 100644 index 0000000..2af0bae --- /dev/null +++ b/dconv/include/dconv/schubfachpow.hpp @@ -0,0 +1,349 @@ +/** + * MIT License + * + * Copyright (c) 2026 Mathieu Rabine + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __DCONV_SCHUBFACHPOW_HPP__ +#define __DCONV_SCHUBFACHPOW_HPP__ + +// dconv. +#include + +namespace dconv +{ + namespace details + { + alignas (64) constexpr Power schubfachpow[] = { + {0x3fddec7f2faf3713, 0xc97a3a2704eec3df}, {0x27eab3cf7dcd826c, 0x5dec645863153a6c}, + {0x31e560c35d40e307, 0x75677d6e7bda8906}, {0x3e5eb8f434911bc9, 0x52c15cca1ad12b48}, + {0x26fb3398a0dab15d, 0xd3b8d9fe50c2bb0d}, {0x30ba007ec9115db5, 0x48a7107de4f369d0}, + {0x3ce8809e7b55b522, 0x9ad0d49d5e304444}, {0x261150630d159135, 0xa0c284e25ade2aab}, + {0x2f95a47bd05af583, 0x08f3261af195b555}, {0x3b7b0d9ac471b2e3, 0xcb2fefa1adfb22ab}, + {0x252ce880bac70fce, 0x5efdf5c50cbcf5ab}, {0x2e7822a0e978d3c1, 0xf6bd73364fec3315}, + {0x3a162b4923d708b2, 0x746cd003e3e73fdb}, {0x244ddb0db666656f, 0x88c402026e7087e9}, + {0x2d6151d123fffecb, 0x6af502830a0ca9e3}, {0x38b9a6456cfffe7e, 0x45b24323cc8fd45c}, + {0x237407eb641fff0e, 0xeb8f69f65fd9e4b9}, {0x2c5109e63d27fed2, 0xa6734473f7d05de8}, + {0x37654c5fcc71fe87, 0x50101590f5c47561}, {0x229f4fbbdfc73f14, 0x920a0d7a999ac95d}, + {0x2b4723aad7b90ed9, 0xb68c90d940017bb4}, {0x3618ec958da75290, 0x242fb50f9001daa1}, + {0x21cf93dd7888939a, 0x169dd129ba0128a5}, {0x2a4378d4d6aab880, 0x9c454574288172ce}, + {0x34d4570a0c5566a0, 0xc35696d132a1cf81}, {0x2104b66647b56024, 0x7a161e42bfa521b1}, + {0x2945e3ffd9a2b82d, 0x989ba5d36f8e6a1d}, {0x33975cffd00b6638, 0xfec28f484b7204a4}, + {0x203e9a1fe2071fe3, 0x9f39998d2f2742e7}, {0x284e40a7da88e7dc, 0x8707fff07af113a1}, + {0x3261d0d1d12b21d3, 0xa8c9ffec99ad5889}, {0x3efa45064575ea48, 0x92fc7fe7c018aeab}, + {0x275c6b23eb69b26d, 0x5bddcff0d80f6d2b}, {0x313385ece6441f08, 0xb2d543ed0e134875}, + {0x3d8067681fd526ca, 0xdf8a94e851981a93}, {0x267040a113e5383e, 0xcbb69d1132ff109c}, + {0x300c50c958de864e, 0x7ea444557fbed4c3}, {0x3c0f64fbaf1627e2, 0x1e4d556adfae89f3}, + {0x25899f1d4d6dd8ed, 0x52f05562cbcd1638}, {0x2eec06e4a0c94f28, 0xa7ac6abb7ec05bc6}, + {0x3aa7089dc8fba2f2, 0xd197856a5e7072b8}, {0x24a865629d9d45d7, 0xc2feb3627b0647b3}, + {0x2dd27ebb4504974d, 0xb3be603b19c7d99f}, {0x39471e6a1645bd21, 0x20adf849e039d007}, + {0x23cc73024deb9634, 0xb46cbb2e2c242205}, {0x2cbf8fc2e1667bc1, 0xe187e9f9b72d2a86}, + {0x37ef73b399c01ab2, 0x59e9e47824f87527}, {0x22f5a850401810af, 0x78322ecb171b4939}, + {0x2bb31264501e14db, 0x563eba7ddce21b87}, {0x369fd6fd64259a12, 0x2bce691d541aa268}, + {0x2223e65e5e97804b, 0x5b6101b25490a581}, {0x2aacdff5f63d605e, 0x3239421ee9b4cee1}, + {0x355817f373ccb875, 0xbec792a6a422029a}, {0x21570ef8285ff349, 0x973cbba8269541a0}, + {0x29acd2b63277f01b, 0xfd0bea92303a9208}, {0x34180763bf15ec22, 0xfc4ee536bc49368a}, + {0x208f049e576db395, 0xddb14f4235adc217}, {0x28b2c5c5ed49207b, 0x551da312c319329c}, + {0x32df7737689b689a, 0x2a650bd773df7f43}, {0x3f97550542c242c0, 0xb4fe4ecd50d75f14}, + {0x27be952349b969b8, 0x711ef14052869b6c}, {0x31ae3a6c1c27c426, 0x8d66ad9067284247}, + {0x3e19c9072331b530, 0x30c058f480f252d9}, {0x26d01da475ff113e, 0x1e783798d09773c8}, + {0x3084250d937ed58d, 0xa616457f04bd50ba}, {0x3ca52e50f85e8af1, 0x0f9bd6dec5eca4e8}, + {0x25e73cf29b3b16d6, 0xa9c1664b3bb3e711}, {0x2f610c2f4209dc8c, 0x5431bfde0aa0e0d5}, + {0x3b394f3b128c53af, 0x693e2fd58d49190b}, {0x2503d184eb97b44d, 0xa1c6dde5784dafa7}, + {0x2e44c5e6267da161, 0x0a38955ed6611b90}, {0x39d5f75fb01d09b9, 0x4cc6bab68bf96274}, + {0x2425ba9bce122613, 0xcffc34b2177bdd89}, {0x2d2f2942c196af98, 0xc3fb41de9d5ad4eb}, + {0x387af39371fc5b7e, 0xf4fa125644b18a26}, {0x234cd83c273db92f, 0x591c4b75eaeef658}, + {0x2c200e4b310d277b, 0x2f635e5365aab3ed}, {0x372811ddfd507159, 0xfb3c35e83f1560e9}, + {0x22790b2abe5246d8, 0x3d05a1b1276d5c92}, {0x2b174df56de6d88e, 0x4c470a1d7148b3b6}, + {0x35dd2172c9608eb1, 0xdf58cca4cd9ae0a3}, {0x21aa34e7bddc592f, 0x2b977fe70080cc66}, + {0x2a14c221ad536f7a, 0xf67d5fe0c0a0ff80}, {0x3499f2aa18a84b59, 0xb41cb7d8f0c93f5f}, + {0x20e037aa4f692f18, 0x1091f2e7967dc79c}, {0x29184594e3437ade, 0x14b66fa17c1d3983}, + {0x335e56fa1c145995, 0x99e40b89db2487e3}, {0x201af65c518cb7fd, 0x802e873628f6d4ee}, + {0x2821b3f365efe5fc, 0xe03a2903b3348a2a}, {0x322a20f03f6bdf7c, 0x1848b344a001acb4}, + {0x3eb4a92c4f46d75b, 0x1e5ae015c80217e1}, {0x2730e9bbb18c4698, 0xf2f8cc0d9d014eed}, + {0x30fd242a9def583f, 0x2fb6ff110441a2a8}, {0x3d3c6d35456b2e4e, 0xfba4bed545520b52}, + {0x2645c4414b62fcf1, 0x5d46f7454b534713}, {0x2fd735519e3bbc2d, 0xb498b5169e2818d8}, + {0x3bcd02a605caab39, 0x21bee25c45b21f0e}, {0x256021a7c39eab03, 0xb5174d79ab8f5369}, + {0x2eb82a11b48655c4, 0xa25d20d816732843}, {0x3a66349621a7eb35, 0xcaf4690e1c0ff253}, + {0x247fe0ddd508f301, 0x9ed8c1a8d189f774}, {0x2d9fd9154a4b2fc2, 0x068ef21305ec7551}, + {0x3907cf5a9cddfbb2, 0x8832ae97c76792a5}, {0x23a4e198a20abd4f, 0x951fad1edca0bba8}, + {0x2c8e19feca8d6ca3, 0x7a67986693c8ea91}, {0x37b1a07e7d30c7cc, 0x59017e8038bb2536}, + {0x22cf044f0e3e7cdf, 0xb7a0ef102374f742}, {0x2b82c562d1ce1c17, 0xa5892ad42c523512}, + {0x366376bb8641a31d, 0x8eeb75893766c256}, {0x21fe2a3533e905f2, 0x79532975c2a03976}, + {0x2a7db4c280e3476f, 0x17a7f3d3334847d4}, {0x351d21f3211c194a, 0xdd91f0c8001a59c8}, + {0x21323537f4b18fce, 0xca7b367d0010781d}, {0x297ec285f1ddf3c2, 0x7d1a041c40149625}, + {0x33de73276e5570b3, 0x1c6085235019bbae}, {0x206b07f8a4f5666f, 0xf1bc53361210154d}, + {0x2885c9f6ce32c00b, 0xee2b680396941aa0}, {0x32a73c7481bf700e, 0xe9b642047c392148}, + {0x3f510b91a22f4c12, 0xa423d2859b476999}, {0x2792a73b055d8f8b, 0xa6966393810ca200}, + {0x31775109c6b4f36e, 0x903bfc78614fca80}, {0x3dd5254c3862304a, 0x344afb9679a3bd20}, + {0x26a5374fa33d5e2e, 0x60aedd3e0c065634}, {0x304e85238c0cb5b9, 0xf8da948d8f07ebc1}, + {0x3c62266c6f0fe328, 0x771139b0f2c9e6b1}, {0x25bd5803c569edf9, 0x4a6ac40e97be302f}, + {0x2f2cae04b6c46977, 0x9d0575123dadbc3a}, {0x3af7d985e47583d5, 0x8446d256cd192b49}, + {0x24dae7f3aec97265, 0x72ac4376402fbb0e}, {0x2e11a1f09a7bcefe, 0xcf575453d03ba9d1}, + {0x39960a6cc11ac2be, 0x832d2968c44a9445}, {0x23fdc683f8b0b9b7, 0x11fc39e17aae9cab}, + {0x2cfd3824f6dce824, 0xd67b4859d95a43d6}, {0x383c862e3494222e, 0x0c1a1a704fb0d4cc}, + {0x2325d3dce0dc955c, 0xc790508631ce84ff}, {0x2bef48d41913bab3, 0xf97464a7be42263f}, + {0x36eb1b091f58a960, 0xf7d17dd1add2afcf}, {0x2252f0e5b39769dc, 0x9ae2eea30ca3ade1}, + {0x2ae7ad1f207d4453, 0xc19baa4bcfcc995a}, {0x35a19866e89c9568, 0xb20294dec3bfbfb0}, + {0x2184ff405161dd61, 0x6f419d0b3a57d7ce}, {0x29e63f1065ba54b9, 0xcb12044e08edcdc2}, + {0x345fced47f28e9e8, 0x3dd685618b294132}, {0x20bbe144cf799231, 0x26a6135cf6f9c8bf}, + {0x28ead9960357f6bd, 0x704f983434b83aef}, {0x33258ffb842df46c, 0xcc637e4141e649ab}, + {0x3feef3fa65397187, 0xff7c5dd1925fdc15}, {0x27f5587c7f43e6f4, 0xffadbaa2fb7be98d}, + {0x31f2ae9b9f14e0b2, 0x3f99294bba5ae3f1}, {0x3e6f5a4286da18de, 0xcf7f739ea8f19ced}, + {0x2705986994484f8b, 0x41afa84329970214}, {0x30c6fe83f95a636e, 0x121b9253f3fcc299}, + {0x3cf8be24f7b0fc49, 0x96a276e8f0fbf33f}, {0x261b76d71ace9dad, 0xfe258a51969d7808}, + {0x2fa2548ce1824519, 0x7daeece5fc44d609}, {0x3b8ae9b019e2d65f, 0xdd1aa81f7b560b8c}, + {0x2536d20e102dc5fb, 0xea30a913ad15c738}, {0x2e8486919439377a, 0xe4bcd358985b3905}, + {0x3a25a835f9478559, 0x9dec082ebe720746}, {0x24578921bbccb358, 0x02b3851d3707448c}, + {0x2d6d6b6a2abfe02e, 0x0360666484c915af}, {0x38c8c644b56fd839, 0x84387ffda5fb5b1b}, + {0x237d7beaf165e723, 0xf2a34ffe87bd18f1}, {0x2c5cdae5adbf60ec, 0xef4c23fe29ac5f2d}, + {0x3774119f192f3928, 0x2b1f2cfdb41776f8}, {0x22a88b036fbd83b9, 0x1af37c1e908eaa5b}, + {0x2b52adc44bace4a7, 0x61b05b2634b254f2}, {0x362759355e981dd1, 0x3a1c71efc1deea2e}, + {0x21d897c15b1f12a2, 0xc451c735d92b525d}, {0x2a4ebdb1b1e6d74b, 0x756639034f7626f4}, + {0x34e26d1e1e608d1e, 0x52bfc7442353b0b1}, {0x210d8432d2fc5832, 0xf3b7dc8a96144e6f}, + {0x2950e53f87bb6e3f, 0xb0a5d3ad3b99620b}, {0x33a51e8f69aa49cf, 0x9ccf48988a7fba8d}, + {0x20473319a20a6e21, 0xc2018d5f568fd498}, {0x2858ffe00a8d09aa, 0x3281f0b72c33c9be}, + {0x326f3fd80d304c14, 0xbf226ce4f740bc2e}, {0x3f0b0fce107c5f19, 0xeeeb081e3510eb39}, + {0x2766e9e0ca4dbb70, 0x3552e512e12a9304}, {0x3140a458fce12a4c, 0x42a79e57997537c5}, + {0x3d90cd6f3c1974df, 0x535185ed7fd285b6}, {0x267a8065858fe90b, 0x9412f3b46fe39392}, + {0x3019207ee6f3e34e, 0x7917b0a18bdc7876}, {0x3c1f689ea0b0dc22, 0x175d9cc9eed39694}, + {0x2593a163246e8995, 0x4e9a81fe35443e1c}, {0x2ef889bbed8a2bfa, 0xa241227dc2954da3}, + {0x3ab6ac2ae8ecb6f9, 0x4ad16b1d333aa10c}, {0x24b22b9ad193f25b, 0xcec2e2f24004a4a8}, + {0x2ddeb68185f8eef2, 0xc2739baed005cdd2}, {0x39566421e7772aaf, 0x7310829a84074146}, + {0x23d5fe9530aa7aad, 0xa7ea51a0928488cc}, {0x2ccb7e3a7cd51959, 0x11e4e608b725aaff}, + {0x37fe5dc91c0a5faf, 0x565e1f8ae4ef15be}, {0x22fefa9db1867bcd, 0x95fad3b6cf156d97}, + {0x2bbeb9451de81ac0, 0xfb7988a482dac8fd}, {0x36ae679665622171, 0x3a57eacda3917b3c}, + {0x222d00bdff5d54e6, 0xc476f2c0863aed06}, {0x2ab840ed7f34aa20, 0x7594af70a7c9a847}, + {0x35665128df01d4a8, 0x92f9db4cd1bc1258}, {0x215ff2b98b6124e9, 0x5bdc291003158b77}, + {0x29b7ef67ee396e23, 0xb2d3335403daee55}, {0x3425eb41e9c7c9ac, 0x9f88002904d1a9ea}, + {0x2097b309321cde0b, 0xe3b50019a3030a33}, {0x28bd9fcb7ea4158e, 0xdca240200bc3ccbf}, + {0x32ed07be5e4d1af2, 0x93cad0280eb4bfef}, {0x3fa849adf5e061af, 0x38bd84321261efeb}, + {0x27c92e0cb9ac3d0d, 0x8376729f4b7d35f3}, {0x31bb798fe8174c50, 0xe4540f471e5c836f}, + {0x3e2a57f3e21d1f65, 0x1d691318e5f3a44b}, {0x26da76f86d52339f, 0x3261abef8fb846af}, + {0x309114b688a6c086, 0xfefa16eb73a6585b}, {0x3cb559e42ad070a8, 0xbeb89ca6508fee71}, + {0x25f1582e9ac24669, 0x773361e7f259f507}, {0x2f6dae3a4172d803, 0xd5003a61eef07249}, + {0x3b4919c8d1cf8e04, 0xca4048fa6aac8edb}, {0x250db01d8321b8c2, 0xfe682d9c82abd949}, + {0x2e511c24e3ea26f3, 0xbe023903a356cf9b}, {0x39e5632e1ce4b0b0, 0xad82c7448c2c8382}, + {0x242f5dfcd20eee6e, 0x6c71bc8ad79bd231}, {0x2d3b357c0692aa0a, 0x078e2bad8d82c6bd}, + {0x388a02db0837548c, 0x8971b698f0e3786d}, {0x235641c8e52294d7, 0xd5e7121f968e2b44}, + {0x2c2bd23b1e6b3a0d, 0xcb60d6a77c31b615}, {0x3736c6c9e6060891, 0x3e390c515b3e239a}, + {0x22823c3e2fc3c55a, 0xc6e3a7b2d906d640}, {0x2b22cb4dbbb4b6b1, 0x789c919f8f488bd0}, + {0x35eb7e212aa1e45d, 0xd6c3b607731aaec4}, {0x21b32ed4baa52eba, 0xa63a51c4a7f0ad3b}, + {0x2a1ffa89e94e7a69, 0x4fc8e635d1ecd88a}, {0x34a7f92c63a21903, 0xa3bb1fc346680eac}, + {0x20e8fbbbbe454fa2, 0x4654f3da0c01092c}, {0x29233aaaadd6a38a, 0xd7ea30d08f014b76}, + {0x336c0955594c4c6d, 0x8de4bd04b2c19e54}, {0x202385d557cfafc4, 0x78aef622efb902f5}, + {0x282c674aadc39bb5, 0x96dab3ababa743b2}, {0x3237811d593482a2, 0xfc9160969691149e}, + {0x3ec56164af81a34b, 0xbbb5b8bc3c3559c5}, {0x273b5cdeedb1060f, 0x55519375a5a1581b}, + {0x310a3416a91d4793, 0x2aa5f8530f09ae22}, {0x3d4cc11c53649977, 0xf54f7667d2cc19ab}, + {0x264ff8b1b41edfea, 0xf951aa00e3bf900b}, {0x2fe3f6de212697e5, 0xb7a614811caf740d}, + {0x3bdcf495a9703ddf, 0x258f99a163db5111}, {0x256a18dd89e626ab, 0x7779c004de6912ab}, + {0x2ec49f14ec5fb056, 0x5558300616035755}, {0x3a75c6da27779c6b, 0xeaae3c079b842d2a}, + {0x24899c4858aac1c3, 0x72ace584c1329c3b}, {0x2dac035a6ed57234, 0x4f581ee5f17f4349}, + {0x391704310a8acec1, 0x632e269f6ddf141b}, {0x23ae629ea696c138, 0xddfcd823a4ab6c91}, + {0x2c99fb46503c7187, 0x157c0e2c8dd647b5}, {0x37c07a17e44b8de8, 0xdadb11b7b14bd9a3}, + {0x22d84c4eeeaf38b1, 0x88c8eb12cecf6806}, {0x2b8e5f62aa5b06dd, 0xeafb25d782834207}, + {0x3671f73b54f1c895, 0x65b9ef4d63241289}, {0x22073a8515171d5d, 0x5f9435905df68b96}, + {0x2a8909265a5ce4b4, 0xb77942f475742e7b}, {0x352b4b6ff0f41de1, 0xe55793b192d13a1a}, + {0x213b0f25f69892ad, 0x2f56bc4efbc2c450}, {0x2989d2ef743eb758, 0x7b2c6b62bab37564}, + {0x33ec47ab514e652e, 0x99f7863b696052bd}, {0x2073accb12d0ff3d, 0x203ab3e521dc33b6}, + {0x289097fdd7853f0c, 0x684960de6a5340a4}, {0x32b4bdfd4d668ecf, 0x825bb91604e810cd}, + {0x3f61ed7ca0c03283, 0x62f2a75b86221500}, {0x279d346de4781f92, 0x1dd7a89933d54d20}, + {0x318481895d962776, 0xa54d92bf80caa068}, {0x3de5a1ebb4fbb154, 0x4ea0f76f60fd4882}, + {0x26af8533511d4ed4, 0xb1249aa59c9e4d51}, {0x305b66802564a289, 0xdd6dc14f03c5e0a5}, + {0x3c7240202ebdcb2c, 0x54c931a2c4b758cf}, {0x25c768141d369efb, 0xb4fdbf05baf29781}, + {0x2f394219248446ba, 0xa23d2ec729af3d62}, {0x3b07929f6da55869, 0x4acc7a78f41b0cba}, + {0x24e4bba3a4875741, 0xcebfcc8b9890e7f4}, {0x2e1dea8c8da92d12, 0x426fbfae7eb521f1}, + {0x39a5652fb1137856, 0xd30baf9a1e626a6d}, {0x24075f3dceac2b36, 0x43e74dc052fd8285}, + {0x2d09370d42573603, 0xd4e1213067bce326}, {0x384b84d092ed0384, 0xca19697c81ac1bef}, + {0x232f33025bd42232, 0xfe4fe1edd10b9175}, {0x2bfaffc2f2c92abf, 0xbde3da69454e75d3}, + {0x36f9bfb3af7b756f, 0xad5cd10396a21347}, {0x225c17d04dad2965, 0xcc5a02a23e254c0d}, + {0x2af31dc4611873bf, 0x3f70834acdae9f10}, {0x35afe535795e90af, 0x0f4ca41d811a46d4}, + {0x218def416bdb1a6d, 0x698fe69270b06c44}, {0x29f16b11c6d1e108, 0xc3f3e0370cdc8755}, + {0x346dc5d63886594a, 0xf4f0d844d013a92b}, {0x20c49ba5e353f7ce, 0xd916872b020c49bb}, + {0x28f5c28f5c28f5c2, 0x8f5c28f5c28f5c29}, {0x3333333333333333, 0x3333333333333334}, + {0x2000000000000000, 0x0000000000000001}, {0x2800000000000000, 0x0000000000000001}, + {0x3200000000000000, 0x0000000000000001}, {0x3e80000000000000, 0x0000000000000001}, + {0x2710000000000000, 0x0000000000000001}, {0x30d4000000000000, 0x0000000000000001}, + {0x3d09000000000000, 0x0000000000000001}, {0x2625a00000000000, 0x0000000000000001}, + {0x2faf080000000000, 0x0000000000000001}, {0x3b9aca0000000000, 0x0000000000000001}, + {0x2540be4000000000, 0x0000000000000001}, {0x2e90edd000000000, 0x0000000000000001}, + {0x3a35294400000000, 0x0000000000000001}, {0x246139ca80000000, 0x0000000000000001}, + {0x2d79883d20000000, 0x0000000000000001}, {0x38d7ea4c68000000, 0x0000000000000001}, + {0x2386f26fc1000000, 0x0000000000000001}, {0x2c68af0bb1400000, 0x0000000000000001}, + {0x3782dace9d900000, 0x0000000000000001}, {0x22b1c8c1227a0000, 0x0000000000000001}, + {0x2b5e3af16b188000, 0x0000000000000001}, {0x3635c9adc5dea000, 0x0000000000000001}, + {0x21e19e0c9bab2400, 0x0000000000000001}, {0x2a5a058fc295ed00, 0x0000000000000001}, + {0x34f086f3b33b6840, 0x0000000000000001}, {0x2116545850052128, 0x0000000000000001}, + {0x295be96e64066972, 0x0000000000000001}, {0x33b2e3c9fd0803ce, 0x8000000000000001}, + {0x204fce5e3e250261, 0x1000000000000001}, {0x2863c1f5cdae42f9, 0x5400000000000001}, + {0x327cb2734119d3b7, 0xa900000000000001}, {0x3f1bdf10116048a5, 0x9340000000000001}, + {0x27716b6a0adc2d67, 0x7c08000000000001}, {0x314dc6448d9338c1, 0x5b0a000000000001}, + {0x3da137d5b0f806f1, 0xb1cc800000000001}, {0x2684c2e58e9b0457, 0x0f1fd00000000001}, + {0x3025f39ef241c56c, 0xd2e7c40000000001}, {0x3c2f7086aed236c8, 0x07a1b50000000001}, + {0x259da6542d43623d, 0x04c5112000000001}, {0x2f050fe938943acc, 0x45f6556800000001}, + {0x3ac653e386b9497f, 0x5773eac200000001}, {0x24bbf46e3433cdef, 0x96a872b940000001}, + {0x2deaf189c140c16b, 0x7c528f6790000001}, {0x3965adec3190f1c6, 0x5b67334174000001}, + {0x23df8cb39efa971b, 0xf9208008e8800001}, {0x2cd76fe086b93ce2, 0xf768a00b22a00001}, + {0x380d4bd8a8678c1b, 0xb542c80deb480001}, {0x23084f676940b791, 0x5149bd08b30d0001}, + {0x2bca63414390e575, 0xa59c2c4adfd04001}, {0x36bcfc1194751ed3, 0x0f03375d97c45001}, + {0x22361d8afcc93343, 0xe962029a7edab201}, {0x2ac3a4edbbfb8014, 0xe3ba83411e915e81}, + {0x35748e292afa601a, 0x1ca924116635b621}, {0x2168d8d9badc7c10, 0x51e9b68adfe191d5}, + {0x29c30f1029939b14, 0x6664242d97d9f64a}, {0x3433d2d433f881d9, 0x7ffd2d38fdd073dc}, + {0x20a063c4a07b5127, 0xeffe3c439ea2486a}, {0x28c87cb5c89a2571, 0xebfdcb54864ada84}, + {0x32fa9be33ac0aece, 0x66fd3e29a7dd9125}, {0x3fb942dc0970da82, 0x00bc8db411d4f56e}, + {0x27d3c9c985e68891, 0x4075d8908b251965}, {0x31c8bc3be7602ab5, 0x90934eb4adee5fbe}, + {0x3e3aeb4ae1383562, 0xf4b82261d969f7ad}, {0x26e4d30eccc3215d, 0xd8f3157d27e23acc}, + {0x309e07d27ff3e9b5, 0x4f2fdadc71dac97f}, {0x3cc589c71ff0e422, 0xa2fbd1938e517bdf}, + {0x25fb761c73f68e95, 0xa5dd62fc38f2ed6c}, {0x2f7a53a390f4323b, 0x0f54bbbb472fa8c6}, + {0x3b58e88c75313ec9, 0xd329eaaa18fb92f8}, {0x25179157c93ec73e, 0x23fa32aa4f9d3bdb}, + {0x2e5d75adbb8e790d, 0xacf8bf54e3848ad2}, {0x39f4d3192a721751, 0x1836ef2a1c65ad86}, + {0x243903efba874e92, 0xaf22557a51bf8c74}, {0x2d4744eba9292237, 0x5aeaead8e62f6f91}, + {0x3899162693736ac5, 0x31a5a58f1fbb4b75}, {0x235fadd81c2822bb, 0x3f07877973d50f29}, + {0x2c37994e23322b6a, 0x0ec96957d0ca52f3}, {0x37457fa1abfeb644, 0x927bc3adc4fce7b0}, + {0x228b6fc50b7f31ea, 0xdb8d5a4c9b1e10ce}, {0x2b2e4bb64e5efe65, 0x9270b0dfc1e59502}, + {0x35f9dea3e1f6bdfe, 0xf70cdd17b25efa42}, {0x21bc2b266d3a36bf, 0x5a680a2ecf7b5c69}, + {0x2a2b35f00888c46f, 0x31020cba835a3384}, {0x34b6036c0aaaf58a, 0xfd428fe92430c065}, + {0x20f1c22386aad976, 0xde4999f1b69e783f}, {0x292e32ac68558fd4, 0x95dc006e2446164f}, + {0x3379bf57826af3c9, 0xbb530089ad579be2}, {0x202c1796b182d85e, 0x1513e0560c56c16e}, + {0x28371d7c5de38e75, 0x9a58d86b8f6c71c9}, {0x3244e4db755c7213, 0x00ef0e8673478e3b}, + {0x3ed61e1252b38e97, 0xc12ad228101971c9}, {0x2745d2cb73b0391e, 0xd8bac3590a0fe71e}, + {0x3117477e509c4766, 0x8ee9742f4c93e0e6}, {0x3d5d195de4c35940, 0x32a3d13b1fb8d91f}, + {0x265a2fdaaefa17c8, 0x1fa662c4f3d387b3}, {0x2ff0bbd15ab89dba, 0x278ffb7630c869a0}, + {0x3beceac5b166c528, 0xb173fa53bcfa8408}, {0x257412bb8ee03b39, 0x6ee87c74561c9285}, + {0x2ed1176a72984a07, 0xcaa29b916ba3b726}, {0x3a855d450f3e5c89, 0xbd4b4275c68ca4f0}, + {0x24935a4b2986f9d6, 0x164f09899c17e716}, {0x2db830ddf3e8b84b, 0x9be2cbec031de0dc}, + {0x39263d1570e2e65e, 0x82db7ee703e55912}, {0x23b7e62d668dcffb, 0x11c92f50626f57ac}, + {0x2ca5dfb8c03143f9, 0xd63b7b247b0b2d96}, {0x37cf57a6f03d94f8, 0x4bca59ed99cdf8fc}, + {0x22e196c856267d1b, 0x2f5e78348020bb9e}, {0x2b99fc7a6bb01c61, 0xfb361641a028ea85}, + {0x36807b99069c237a, 0x7a039bd208332526}, {0x22104d3fa421962c, 0x8c424163451ff738}, + {0x2a94608f8d29fbb7, 0xaf52d1bc1667f506}, {0x353978b370747aa5, 0x9b27862b1c01f247}, + {0x2143eb702648cca7, 0x80f8b3daf181376d}, {0x2994e64c2fdaffd1, 0x6136e0d1ade18548}, + {0x33fa1fdf3bd1bfc5, 0xb98499061959e699}, {0x207c53eb856317db, 0x93f2dfa3cfd83020}, + {0x289b68e666bbddd2, 0x78ef978cc3ce3c28}, {0x32c24320006ad547, 0x172b7d6ff4c1cb32}, + {0x3f72d3e800858a98, 0xdcf65ccbf1f23dfe}, {0x27a7c4710053769f, 0x8a19f9ff773766bf}, + {0x3191b58d40685447, 0x6ca0787f5505406f}, {0x3df622f090826959, 0x47c8969f2a46908a}, + {0x26b9d5d65a5181d7, 0xccdd5e237a6c1a57}, {0x30684b4bf0e5e24d, 0xc014b5ac590720ec}, + {0x3c825e1eed1f5ae1, 0x3019e3176f48e927}, {0x25d17ad3543398cc, 0xbe102deea58d91b9}, + {0x2f45d98829407eff, 0xed94396a4ef0f627}, {0x3b174fea33909ebf, 0xe8f947c4e2ad33b0}, + {0x24ee91f2603a6337, 0xf19bccdb0dac404e}, {0x2e2a366ef848fc05, 0xee02c011d1175062}, + {0x39b4c40ab65b3b07, 0x69837016455d247a}, {0x2410fa86b1f904e4, 0xa1f2260deb5a36cc}, + {0x2d1539285e77461d, 0xca6eaf916630c47f}, {0x385a8772761517a5, 0x3d0a5b75bfbcf59f}, + {0x233894a789cd2ec7, 0x4626792997d61984}, {0x2c06b9d16c407a79, 0x17b01773fdcb9fe4}, + {0x37086845c7509917, 0x5d9c1d50fd3e87dd}, {0x2265412b9c925fae, 0x9a8192529e4714eb}, + {0x2afe917683b6f79a, 0x4121f6e745d8da25}, {0x35be35d424a4b580, 0xd16a74a1174f10ae}, + {0x2196e1a496e6f170, 0x82e288e4ae916a6d}, {0x29fc9a0dbca0adcc, 0xa39b2b1dda35c508}, + {0x347bc0912bc8d93f, 0xcc81f5e550c3364a}, {0x20cd585abb5d87c7, 0xdfd139af527a01ef}, + {0x2900ae716a34e9b9, 0xd7c5881b2718826a}, {0x3340da0dc4c22428, 0x4db6ea21f0dea304}, + {0x200888489af95699, 0x30925255368b25e3}, {0x280aaa5ac1b7ac3f, 0x7cb6e6ea842def5c}, + {0x320d54f17225974f, 0x5be4a0a525396b32}, {0x3e90aa2dceaefd23, 0x32ddc8ce6e87c5ff}, + {0x271a6a5ca12d5e35, 0xffca9d810514dbbf}, {0x30e104f3c978b5c3, 0x7fbd44e1465a12af}, + {0x3d194630bbd6e334, 0x5fac961997f0975b}, {0x262fcbde75664e00, 0xbbcbddcffef65e99}, + {0x2fbbbed612bfe180, 0xeabed543feb3f63f}, {0x3baaae8b976fd9e1, 0x256e8a94fe60f3cf}, + {0x254aad173ea5e82c, 0xb765169d1efc9861}, {0x2e9d585d0e4f6237, 0xe53e5c4466bbbe7a}, + {0x3a44ae7451e33ac5, 0xde8df355806aae18}, {0x246aed08b32e04bb, 0xab18b8157042accf}, + {0x2d85a84adff985ea, 0x95dee61acc535803}, {0x38e7125d97f7e765, 0x3b569fa17f682e03}, + {0x23906b7a7efaf09f, 0x451623c4efa11cc2}, {0x2c7486591eb9acc7, 0x165bacb62b8963f3}, + {0x3791a7ef666817f8, 0xdbf297e3b66bbcef}, {0x22bb08f5a0010efb, 0x89779eee52035616}, + {0x2b69cb33080152ba, 0x6bd586a9e6842b9b}, {0x36443dffca01a769, 0x06cae85460253682}, + {0x21eaa6bfde4108a1, 0xa43ed134bc174211}, {0x2a65506fd5d14aca, 0x0d4e8581eb1d1295}, + {0x34fea48bcb459d7c, 0x90a226e265e4573b}, {0x211f26d75f0b826d, 0xda65584d7faeb685}, + {0x2966f08d36ce6309, 0x50feae60df9a6426}, {0x33c0acb08481fbcb, 0xa53e59f91780fd2f}, + {0x20586bee52d13d5f, 0x4746f83baeb09e3e}, {0x286e86e9e7858cb7, 0x1918b64a9a5cc5cd}, + {0x328a28a46166efe4, 0xdf5ee3dd40f3f740}, {0x3f2cb2cd79c0abde, 0x17369cd49130f510}, + {0x277befc06c186b6a, 0xce822204dabe992a}, {0x315aebb0871e8645, 0x8222aa86116e3f75}, + {0x3db1a69ca8e627d6, 0xe2ab552795c9cf52}, {0x268f0821e98fd8e6, 0x4dab1538bd9e2193}, + {0x3032ca2a63f3cf1f, 0xe115da86ed05a9f8}, {0x3c3f7cb4fcf0c2e7, 0xd95b5128a8471476}, + {0x25a7adf11e1679d0, 0xe7d912b9692c6cca}, {0x2f11996d659c1845, 0x21cf5767c37787fc}, + {0x3ad5ffc8bf031e56, 0x6a432d41b45569fb}, {0x24c5bfdd7761f2f6, 0x0269fc4910b5623d}, + {0x2df72fd4d53a6fb3, 0x83047b5b54e2bacc}, {0x3974fbca0a890ba0, 0x63c59a322a1b697f}, + {0x23e91d5e4695a744, 0x3e5b805f5a5121f0}, {0x2ce364b5d83b1115, 0x4df2607730e56a6c}, + {0x381c3de34e49d55a, 0xa16ef894fd1ec506}, {0x2311a6ae10ee2558, 0xa4e55b5d1e333b24}, + {0x2bd610599529aeae, 0xce1eb23465c009ed}, {0x36cb946ffa741a5a, 0x81a65ec17f300c68}, + {0x223f3cc5fc889078, 0x9107fb38ef7e07c1}, {0x2acf0bf77baab496, 0xb549fa072b5d89b1}, + {0x3582cef55a9561bc, 0x629c7888f634ec1e}, {0x2171c159589d5d15, 0xbda1cb5599e11393}, + {0x29ce31afaec4b45b, 0x2d0a3e2b00595877}, {0x3441be1b9a75e171, 0xf84ccdb5c06fae95}, + {0x20a916d14089ace7, 0x3b3000919845cd1d}, {0x28d35c8590ac1821, 0x09fc00b5fe574065}, + {0x330833a6f4d71e29, 0x4c7b00e37ded107e}, {0x3fca4090b20ce5b3, 0x9f99c11c5d68549d}, + {0x27de685a6f480f90, 0x43c018b1ba6134e2}, {0x31d602710b1a1374, 0x54b01ede28f9821b}, + {0x3e4b830d4de09851, 0x69dc2695b337e2a1}, {0x26ef31e850ac5f32, 0xe229981d9002eda5}, + {0x30aafe6264d776ff, 0x9ab3fe24f403a90e}, {0x3cd5bdfafe0d54bf, 0x8160fdae31049351}, + {0x260596bcdec854f7, 0xb0dc9e8cdea2dc13}, {0x2f86fc6c167a6a35, 0x9d13c630164b9318}, + {0x3b68bb871c1904c3, 0x0458b7bc1bde77dd}, {0x25217534718fa2f9, 0xe2b772d5916b0aeb}, + {0x2e69d2818df38bb8, 0x5b654f8af5c5cda5}, {0x3a044721f1706ea6, 0x723ea36db337410e}, + {0x2442ac7536e64528, 0x07672624900288a9}, {0x2d535792849fd672, 0x0940efadb4032ad3}, + {0x38a82d7725c7cc0e, 0x8b912b992103f588}, {0x23691c6a779cdf89, 0x173abb3fb4a27975}, + {0x2c4363851584176b, 0x5d096a0fa1cb17d2}, {0x37543c665ae51d46, 0x344bc4938a3dddc7}, + {0x2294a5bff8cf324b, 0xe0af5adc3666aa9c}, {0x2b39cf2ff702fede, 0xd8db319344005543}, + {0x360842fbf4c3be96, 0x8f11fdf815006a94}, {0x21c529dd78fa571e, 0x196b3ebb0d20429d}, + {0x2a367454d738ece5, 0x9fc60e69d0685344}, {0x34c4116a0d07281f, 0x07b7920444826815}, + {0x20fa8ae248247913, 0x64d2bb42aad1810d}, {0x29392d9ada2d9758, 0x3e076a135585e150}, + {0x3387790190b8fd2e, 0x4d8944982ae759a4}, {0x2034aba0fa739e3c, 0xf075cadf1ad09807}, + {0x2841d689391085cc, 0x2c933d96e184be08}, {0x32524c2b8754a73f, 0x37b80cfc99e5ed8a}, + {0x3ee6df366929d10f, 0x05a6103bc05f68ed}, {0x27504b8201ba22a9, 0x6387ca25583ba194}, + {0x31245e628228ab53, 0xbc69bcaeae4a89f9}, {0x3d6d75fb22b2d628, 0xab842bda59dd2c77}, + {0x266469bcf5afc5d9, 0x6b329b68782a3bcb}, {0x2ffd842c331bb74f, 0xc5ff42429634cabd}, + {0x3bfce5373fe2a523, 0xb77f12d33bc1fd6d}, {0x257e0f4287eda736, 0x52af6bc405593e64}, + {0x2edd931329e91103, 0xe75b46b506af8dfd}, {0x3a94f7d7f4635544, 0xe1321862485b717c}, + {0x249d1ae6f8be154b, 0x0cbf4f3d6d3926ee}, {0x2dc461a0b6ed9a9d, 0xcfef230cc88770a9}, + {0x39357a08e4a90145, 0x43eaebcffaa94cd3}, {0x23c16c458ee9a0cb, 0x4a72d361fca9d004}, + {0x2cb1c756f2a408fe, 0x1d0f883a7bd44405}, {0x37de392caf4d0b3d, 0xa4536a491ac95506}, + {0x22eae3bbed902706, 0x86b4226db0bdd524}, {0x2ba59caae8f430c8, 0x28612b091ced4a6d}, + {0x368f03d5a3313cfa, 0x327975cb64289d08}, {0x2219626585fec61c, 0x5f8be99f1e996225}, + {0x2a9fbafee77e77a3, 0x776ee406e63fbaae}, {0x3547a9bea15e158c, 0x554a9d089fcfa95a}, + {0x214cca1724dacd77, 0xb54ea22563e1c9d8}, {0x299ffc9cee1180d5, 0xa2a24aaebcda3c4e}, + {0x3407fbc42995e10b, 0x0b4add5a6c10cb62}, {0x2084fd5a99fdaca6, 0xe70eca58838a7f1d}, + {0x28a63cb1407d17d0, 0xa0d27ceea46d1ee4}, {0x32cfcbdd909c5dc4, 0xc9071c2a4d88669d}, + {0x3f83bed4f4c37535, 0xfb48e334e0ea8045}, {0x27b2574518fa2941, 0xbd0d8e010c92902b}, + {0x319eed165f38b392, 0x2c50f1814fb73436}, {0x3e06a85bf706e076, 0xb7652de1a3a50143}, + {0x26c429397a644c4a, 0x329f3cad064720ca}, {0x30753387d8fd5f5c, 0xbf470bd847d8e8fd}, + {0x3c928069cf3cb733, 0xef18cece59cf233c}, {0x25db90422185f280, 0x756f8140f8217605}, + {0x2f527452a9e76f20, 0x92cb61913629d387}, {0x3b27116754614ae8, 0xb77e39f583b44868}, + {0x24f86ae094bcced1, 0x72aee4397250ad41}, {0x2e368598b9ec0285, 0xcf5a9d47cee4d891}, + {0x39c426fee8670327, 0x43314499c29e0eb6}, {0x241a985f514061f8, 0x89fecae019a2c932}, + {0x2d213e7725907a76, 0xac7e7d98200b7b7e}, {0x38698e14eef49914, 0x579e1cfe280e5a5d}, + {0x2341f8cd1558dfac, 0xb6c2d21ed908f87b}, {0x2c1277005aaf1797, 0xe47386a68f4b3699}, + {0x371714c0715add7d, 0xdd906850331e043f}, {0x226e6cf846d8ca6e, 0xaa7a41321ff2c2a8}, + {0x2b0a0836588efd0a, 0x5518d17ea7ef7352}, {0x35cc8a43eeb2bc4c, 0xea5f05de51eb5026}, + {0x219fd66a752fb5b0, 0x127b63aaf3331218}, {0x2a07cc05127ba31c, 0x171a3c95afffd69e}, + {0x3489bf06571a8be3, 0x1ce0cbbb1bffcc45}, {0x20d61763f670976d, 0xf20c7f54f17fdfab}, + {0x290b9d3cf40cbd49, 0x6e8f9f2a2ddfd796}, {0x334e848c310fec9b, 0xca3386f4b957cd7b}, + {0x201112d79ea9f3e1, 0x5e603458f3d6e06d}, {0x2815578d865470d9, 0xb5f8416f30cc9888}, + {0x321aad70e7e98d10, 0x237651cafcffbeaa}, {0x3ea158cd21e3f054, 0x2c53e63dbc3fae55}, + {0x2724d780352e7634, 0x9bb46fe695a7ccf5}, {0x30ee0d60427a13c1, 0xc2a18be03b11c033}, + {0x3d2990b8531898b2, 0x3349eed849d6303f}, {0x2639fa7333ef5f6f, 0x600e35472e25de28}, + {0x2fc8791000eb374b, 0x3811c298f9af55b1}, {0x3bba97540126051e, 0x0616333f381b2b1e}, + {0x25549e9480b7c332, 0xc3cde0078310faf3}, {0x2ea9c639a0e5b3ff, 0x74c1580963d539af}, + {0x3a5437c8091f20ff, 0x51f1ae0bbcca881b}, {0x2474a2dd05b3749f, 0x93370cc755fe9511}, + {0x2d91cb94472051c7, 0x7804cff92b7e3a55}, {0x38f63e7958e86639, 0x560603f7765dc8ea}, + {0x2399e70bd7913fe3, 0xd5c3c27aa9fa9d93}, {0x2c8060cecd758fdc, 0xcb34b319547944f7}, + {0x37a0790280d2f3d3, 0xfe01dfdfa9979635}, {0x22c44ba19083d864, 0x7ec12bebc9febde1}, + {0x2b755e89f4a4ce7d, 0x9e7176e6bc7e6d59}, {0x3652b62c71ce021d, 0x060dd4a06b9e08b0}, + {0x21f3b1dbc720c152, 0x23c8a4e44342c56e}, {0x2a709e52b8e8f1a6, 0xacbace1d541376c9}, + {0x350cc5e767232e10, 0x57e981a4a918547b}, {0x2127fbb0a075fcca, 0x36f1f106e9af34cd}, + {0x2971fa9cc8937bfc, 0xc4ae6d48a41b0201}, {0x33ce7943fab85afb, 0xf5da089acd21c281}, + {0x20610bca7cb338dd, 0x79a84560c0351991}, {0x28794ebd1be00714, 0xd81256b8f0425ff5}, + {0x3297a26c62d808da, 0x0e16ec672c52f7f2}, {0x3f3d8b077b8e0b10, 0x919ca780f767b5ee}, + {0x278676e4ad38c6ea, 0x5b01e8b09aa0d1b5}, + }; + } +} + +#endif diff --git a/dconv/tests/CMakeLists.txt b/dconv/tests/CMakeLists.txt index 906b4ad..7c76b9f 100644 --- a/dconv/tests/CMakeLists.txt +++ b/dconv/tests/CMakeLists.txt @@ -38,6 +38,10 @@ add_executable(grisu3.gtest grisu3_test.cpp) target_link_libraries(grisu3.gtest ${PROJECT_NAME} GTest::gtest_main pthread) gtest_discover_tests(grisu3.gtest) +add_executable(schubfach.gtest schubfach_test.cpp) +target_link_libraries(schubfach.gtest ${PROJECT_NAME} GTest::gtest_main pthread) +gtest_discover_tests(schubfach.gtest) + add_executable(dtoa.gtest dtoa_test.cpp) target_link_libraries(dtoa.gtest ${PROJECT_NAME} GTest::gtest_main pthread) gtest_discover_tests(dtoa.gtest) diff --git a/dconv/tests/digits_test.cpp b/dconv/tests/digits_test.cpp index 50178e2..3b33192 100644 --- a/dconv/tests/digits_test.cpp +++ b/dconv/tests/digits_test.cpp @@ -28,6 +28,9 @@ // libraries. #include +// C++. +#include + /** * @brief countDigits test. */ @@ -44,6 +47,68 @@ TEST (digits, countDigits) EXPECT_EQ (dconv::details::countDigits (UINT32_MAX), 10); } +/** + * @brief countTrailingZeros test. + */ +TEST (digits, countTrailingZeros) +{ + EXPECT_EQ (dconv::details::countTrailingZeros (0), 4); + EXPECT_EQ (dconv::details::countTrailingZeros (1), 0); + EXPECT_EQ (dconv::details::countTrailingZeros (10), 1); + EXPECT_EQ (dconv::details::countTrailingZeros (100), 2); + EXPECT_EQ (dconv::details::countTrailingZeros (1000), 3); + EXPECT_EQ (dconv::details::countTrailingZeros (1200), 2); + EXPECT_EQ (dconv::details::countTrailingZeros (1234), 0); + EXPECT_EQ (dconv::details::countTrailingZeros (9990), 1); +} + +/** + * @brief writeDigits test. + */ +TEST (digits, writeDigits) +{ + char buffer[32] = {}; + + EXPECT_EQ (dconv::details::writeDigits (buffer, 1u, 1), 0); + EXPECT_EQ (std::string (buffer, 1), "1"); + + EXPECT_EQ (dconv::details::writeDigits (buffer, 10u, 2), 1); + EXPECT_EQ (std::string (buffer, 2), "10"); + + EXPECT_EQ (dconv::details::writeDigits (buffer, 123u, 3), 0); + EXPECT_EQ (std::string (buffer, 3), "123"); + + EXPECT_EQ (dconv::details::writeDigits (buffer, 1000u, 4), 3); + EXPECT_EQ (std::string (buffer, 4), "1000"); + + EXPECT_EQ (dconv::details::writeDigits (buffer, 12340000u, 8), 4); + EXPECT_EQ (std::string (buffer, 8), "12340000"); + + EXPECT_EQ (dconv::details::writeDigits (buffer, 12345678u, 8), 0); + EXPECT_EQ (std::string (buffer, 8), "12345678"); + + EXPECT_EQ (dconv::details::writeDigits (buffer, 100000000u, 9), 8); + EXPECT_EQ (std::string (buffer, 9), "100000000"); + + EXPECT_EQ (dconv::details::writeDigits (buffer, 123456789u, 9), 0); + EXPECT_EQ (std::string (buffer, 9), "123456789"); + + EXPECT_EQ (dconv::details::writeDigits (buffer, 120000000000u, 12), 10); + EXPECT_EQ (std::string (buffer, 12), "120000000000"); + + EXPECT_EQ (dconv::details::writeDigits (buffer, 1234567800000000u, 16), 8); + EXPECT_EQ (std::string (buffer, 16), "1234567800000000"); + + EXPECT_EQ (dconv::details::writeDigits (buffer, 1234567890123400u, 16), 2); + EXPECT_EQ (std::string (buffer, 16), "1234567890123400"); + + EXPECT_EQ (dconv::details::writeDigits (buffer, 12345678901234567u, 17), 0); + EXPECT_EQ (std::string (buffer, 17), "12345678901234567"); + + EXPECT_EQ (dconv::details::writeDigits (buffer, 10000000000000000u, 17), 16); + EXPECT_EQ (std::string (buffer, 17), "10000000000000000"); +} + /** * @brief main function. */ diff --git a/dconv/tests/format_test.cpp b/dconv/tests/format_test.cpp index 0ae0656..d53c27f 100644 --- a/dconv/tests/format_test.cpp +++ b/dconv/tests/format_test.cpp @@ -115,6 +115,57 @@ TEST (format, prettify) EXPECT_EQ (std::string (buffer, end), "12345678901234567.8"); } +/** + * @brief format test. + */ +TEST (format, format) +{ + char buffer[32] = {}; + char* end = nullptr; + + end = dconv::details::format (buffer, 12345u, dconv::details::countDigits (12345u), 0); + EXPECT_EQ (std::string (buffer, end), "12345.0"); + + end = dconv::details::format (buffer, 12345u, dconv::details::countDigits (12345u), 2); + EXPECT_EQ (std::string (buffer, end), "1234500.0"); + + end = dconv::details::format (buffer, 12345u, dconv::details::countDigits (12345u), -2); + EXPECT_EQ (std::string (buffer, end), "123.45"); + + end = dconv::details::format (buffer, 12345u, dconv::details::countDigits (12345u), -5); + EXPECT_EQ (std::string (buffer, end), "0.12345"); + + end = dconv::details::format (buffer, 12345u, dconv::details::countDigits (12345u), -7); + EXPECT_EQ (std::string (buffer, end), "0.0012345"); + + end = dconv::details::format (buffer, 12345u, dconv::details::countDigits (12345u), -11); + EXPECT_EQ (std::string (buffer, end), "1.2345e-7"); + + end = dconv::details::format (buffer, 12345u, dconv::details::countDigits (12345u), 17); + EXPECT_EQ (std::string (buffer, end), "1.2345e21"); + + end = dconv::details::format (buffer, 1u, dconv::details::countDigits (1u), -7); + EXPECT_EQ (std::string (buffer, end), "1e-7"); + + end = dconv::details::format (buffer, 1u, dconv::details::countDigits (1u), 30); + EXPECT_EQ (std::string (buffer, end), "1e30"); + + end = dconv::details::format (buffer, 1000u, dconv::details::countDigits (1000u), 0); + EXPECT_EQ (std::string (buffer, end), "1000.0"); + + end = dconv::details::format (buffer, 1230000000000000u, dconv::details::countDigits (1230000000000000u), -21); + EXPECT_EQ (std::string (buffer, end), "0.00000123"); + + end = dconv::details::format (buffer, 1230000000000000u, dconv::details::countDigits (1230000000000000u), -30); + EXPECT_EQ (std::string (buffer, end), "1.23e-15"); + + end = dconv::details::format (buffer, 1000000000000000u, dconv::details::countDigits (1000000000000000u), 10); + EXPECT_EQ (std::string (buffer, end), "1e25"); + + end = dconv::details::format (buffer, 1234567890123450u, dconv::details::countDigits (1234567890123450u), -10); + EXPECT_EQ (std::string (buffer, end), "123456.789012345"); +} + /** * @brief main function. */ diff --git a/dconv/tests/schubfach_test.cpp b/dconv/tests/schubfach_test.cpp new file mode 100644 index 0000000..30df60b --- /dev/null +++ b/dconv/tests/schubfach_test.cpp @@ -0,0 +1,196 @@ +/** + * MIT License + * + * Copyright (c) 2026 Mathieu Rabine + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// dconv. +#include + +// libraries. +#include + +// C++. +#include + +/** + * @brief floorLog10Pow2 test. + */ +TEST (schubfach, floorLog10Pow2) +{ + EXPECT_EQ (dconv::schubfach::floorLog10Pow2 (0, false), 0); + EXPECT_EQ (dconv::schubfach::floorLog10Pow2 (3, false), 0); + EXPECT_EQ (dconv::schubfach::floorLog10Pow2 (4, false), 1); + EXPECT_EQ (dconv::schubfach::floorLog10Pow2 (10, false), 3); + EXPECT_EQ (dconv::schubfach::floorLog10Pow2 (-1, false), -1); + EXPECT_EQ (dconv::schubfach::floorLog10Pow2 (-1074, false), -324); + EXPECT_EQ (dconv::schubfach::floorLog10Pow2 (971, false), 292); + EXPECT_EQ (dconv::schubfach::floorLog10Pow2 (0, true), -1); + EXPECT_EQ (dconv::schubfach::floorLog10Pow2 (4, true), 1); + EXPECT_EQ (dconv::schubfach::floorLog10Pow2 (-1074, true), -324); + EXPECT_EQ (dconv::schubfach::floorLog10Pow2 (971, true), 292); +} + +/** + * @brief floorLog2Pow10 test. + */ +TEST (schubfach, floorLog2Pow10) +{ + EXPECT_EQ (dconv::schubfach::floorLog2Pow10 (0), 0); + EXPECT_EQ (dconv::schubfach::floorLog2Pow10 (1), 3); + EXPECT_EQ (dconv::schubfach::floorLog2Pow10 (2), 6); + EXPECT_EQ (dconv::schubfach::floorLog2Pow10 (-1), -4); + EXPECT_EQ (dconv::schubfach::floorLog2Pow10 (308), 1023); + EXPECT_EQ (dconv::schubfach::floorLog2Pow10 (-292), -971); + EXPECT_EQ (dconv::schubfach::floorLog2Pow10 (324), 1076); +} + +/** + * @brief roundToOdd test. + */ +TEST (schubfach, roundToOdd) +{ + const dconv::details::Power quarter = {static_cast (1) << 62, 0}; + EXPECT_EQ (dconv::schubfach::roundToOdd (quarter, 8), 2u); + EXPECT_EQ (dconv::schubfach::roundToOdd (quarter, 9), 3u); + EXPECT_EQ (dconv::schubfach::roundToOdd (quarter, 12), 3u); + + const dconv::details::Power carry = {static_cast (1) << 62, UINT64_MAX}; + EXPECT_EQ (dconv::schubfach::roundToOdd (carry, 4), 1u); +} + +/** + * @brief shortest test. + */ +TEST (schubfach, shortest) +{ + int k = 0; + EXPECT_EQ (dconv::schubfach::shortest (1234.0, k), 1234u); + EXPECT_EQ (k, 0); + + EXPECT_EQ (dconv::schubfach::shortest (0.3, k), 3000000000000000u); + EXPECT_EQ (k, -16); + + EXPECT_EQ (dconv::schubfach::shortest (0.30000000000000004, k), 30000000000000004u); + EXPECT_EQ (k, -17); + + EXPECT_EQ (dconv::schubfach::shortest (5e-324, k), 5u); + EXPECT_EQ (k, -324); + + EXPECT_EQ (dconv::schubfach::shortest (2.2250738585072014e-308, k), 22250738585072014u); + EXPECT_EQ (k, -324); + + EXPECT_EQ (dconv::schubfach::shortest (1.7976931348623157e308, k), 17976931348623157u); + EXPECT_EQ (k, 292); +} + +/** + * @brief generate test. + */ +TEST (schubfach, generate) +{ + char buffer[32] = {}; + int length = 0, k = 0; + + dconv::schubfach::generate (buffer, length, k, 0.3); + EXPECT_EQ (std::string (buffer, length), "3"); + EXPECT_EQ (k, -1); + + dconv::schubfach::generate (buffer, length, k, 1000.0); + EXPECT_EQ (std::string (buffer, length), "1"); + EXPECT_EQ (k, 3); + + dconv::schubfach::generate (buffer, length, k, 1e23); + EXPECT_EQ (std::string (buffer, length), "1"); + EXPECT_EQ (k, 23); +} + +/** + * @brief dtoa test. + */ +TEST (schubfach, dtoa) +{ + char beg[32] = {}; + char* end = nullptr; + + end = dconv::schubfach::dtoa (beg, 0.0); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "0.0"); + + end = dconv::schubfach::dtoa (beg, -0.0); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "-0.0"); + + end = dconv::schubfach::dtoa (beg, 0.1); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "0.1"); + + end = dconv::schubfach::dtoa (beg, -1.5); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "-1.5"); + + end = dconv::schubfach::dtoa (beg, 100.0); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "100.0"); + + end = dconv::schubfach::dtoa (beg, 1e21); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "1e21"); + + end = dconv::schubfach::dtoa (beg, 1e22); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "1e22"); + + end = dconv::schubfach::dtoa (beg, 1e23); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "1e23"); + + end = dconv::schubfach::dtoa (beg, 123e18); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "123000000000000000000.0"); + + end = dconv::schubfach::dtoa (beg, 0.000123); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "0.000123"); + + end = dconv::schubfach::dtoa (beg, 0.00001); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "0.00001"); + + end = dconv::schubfach::dtoa (beg, 1e-7); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "1e-7"); + + end = dconv::schubfach::dtoa (beg, 7e-10); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "7e-10"); + + end = dconv::schubfach::dtoa (beg, 5e-324); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "5e-324"); + + end = dconv::schubfach::dtoa (beg, 4.9406564584124654e-320); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "4.9407e-320"); + + end = dconv::schubfach::dtoa (beg, 2.225073858507201e-308); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "2.225073858507201e-308"); + + end = dconv::schubfach::dtoa (beg, 1.7976931348623157e308); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "1.7976931348623157e308"); + + end = dconv::schubfach::dtoa (beg, 9007199254740992.0); + EXPECT_STREQ (std::string (beg, end - beg).c_str (), "9007199254740992.0"); +} + +/** + * @brief main function. + */ +int main (int argc, char** argv) +{ + testing::InitGoogleTest (&argc, argv); + return RUN_ALL_TESTS (); +} diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 1deb54a..44ad054 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -2,3 +2,4 @@ cmake_minimum_required(VERSION 3.22.1) add_subdirectory(eisellemirepowgen) add_subdirectory(grisupowgen) +add_subdirectory(schubfachpowgen) diff --git a/tools/schubfachpowgen/CMakeLists.txt b/tools/schubfachpowgen/CMakeLists.txt new file mode 100644 index 0000000..cbc4ab4 --- /dev/null +++ b/tools/schubfachpowgen/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.22.1) + +set(SCHUBFACHPOWGEN_VERSION ${DCONV_VERSION}) + +set(SCHUBFACHPOWGEN_VERSION_MAJOR ${DCONV_VERSION_MAJOR}) +set(SCHUBFACHPOWGEN_VERSION_MINOR ${DCONV_VERSION_MINOR}) +set(SCHUBFACHPOWGEN_VERSION_PATCH ${DCONV_VERSION_PATCH}) + +message(STATUS "schubfachpowgen version: ${SCHUBFACHPOWGEN_VERSION}") +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/version.hpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/include/version.hpp") + +set(PRIVATE_HEADER_DIRS + src +) + +set(PUBLIC_HEADER_DIRS + include + ../eisellemirepowgen/include +) + +set(PUBLIC_HEADERS + include/version.hpp +) + +set(SOURCES + src/main.cpp +) + +add_executable(schubfachpowgen ${SOURCES}) +set_target_properties(schubfachpowgen PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADERS}") + +target_include_directories(schubfachpowgen PUBLIC ${PUBLIC_HEADER_DIRS}) +target_include_directories(schubfachpowgen PRIVATE ${PRIVATE_HEADER_DIRS}) + +install(TARGETS schubfachpowgen DESTINATION /bin) diff --git a/tools/schubfachpowgen/README.md b/tools/schubfachpowgen/README.md new file mode 100644 index 0000000..71e8c43 --- /dev/null +++ b/tools/schubfachpowgen/README.md @@ -0,0 +1,61 @@ +# schubfachpowgen + +**schubfachpowgen** is a command-line tool that generates the **lookup +table** of powers of 10 used by the Schubfach algorithm. + +Each power of 10 is stored on 126 bits, rounded up, as a high and a +low 64-bit word. + +The tool outputs a fully self-contained C++ header containing: + +- `MIN_EXPONENT`, `MAX_EXPONENT` +- a `Power { uint64_t hi; uint64_t lo; }` structure +- a `constexpr Power powers[]` lookup table + +## Usage + +| Option | Description | +|-----------------|---------------------------------------| +| `-h` | Show help message | +| `-l ` | Set lower exponent (default: `-292`) | +| `-u ` | Set upper exponent (default: `324`) | +| `-v` | Show program version | + +## Example + +Generate powers for exponents −200 through +200 and write them to +`power.hpp`: + +``` bash +schubfachpowgen -l -200 -u 200 > power.hpp +``` + +The generated header will contain definitions like: + +``` cpp +#ifndef __POWER_HPP__ +#define __POWER_HPP__ + +#include + +#define MIN_EXPONENT -200 +#define MAX_EXPONENT 200 + +struct Power { + uint64_t hi; + uint64_t lo; +}; + +constexpr Power powers[] = { + {0x1234567890abcdef, 0xfedcba0987654321}, + ... + ... + ... +}; + +#endif +``` + +## License + +[MIT](https://choosealicense.com/licenses/mit/) diff --git a/tools/schubfachpowgen/src/main.cpp b/tools/schubfachpowgen/src/main.cpp new file mode 100644 index 0000000..eca9259 --- /dev/null +++ b/tools/schubfachpowgen/src/main.cpp @@ -0,0 +1,171 @@ +/** + * MIT License + * + * Copyright (c) 2026 Mathieu Rabine + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "version.hpp" +#include "bigint.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include + +// ========================================================================= +// CLASS : +// METHOD : version +// ========================================================================= +void version () +{ + std::cout << "schubfachpowgen version " << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_PATCH + << std::endl; +} + +// ========================================================================= +// CLASS : +// METHOD : usage +// ========================================================================= +void usage () +{ + std::cout << "Usage" << std::endl; + std::cout << " schubfachpowgen [options]" << std::endl; + std::cout << std::endl; + std::cout << "Options" << std::endl; + std::cout << " -h show available options" << std::endl; + std::cout << " -l lower lower exponent (default: -292)" << std::endl; + std::cout << " -u upper upper exponent (default: 324)" << std::endl; + std::cout << " -v print version" << std::endl; +} + +// ========================================================================= +// CLASS : +// METHOD : compute +// ========================================================================= +Power compute (int exponent) +{ + Power power = {1ULL << 63, 0}; + + if (exponent > 0) + { + BigInt val (1); + for (int i = 0; i < exponent; ++i) + { + val.multiply (10); + } + power = val.getTop128 (); + } + else if (exponent < 0) + { + int absExp = -exponent; + int bitsNeeded = static_cast (absExp * std::log2 (10.0)) + 128 + 64; + BigInt val = BigInt::powerOfTwo (bitsNeeded); + for (int i = 0; i < absExp; ++i) + { + val.divide (10); + } + power = val.getTop128 (); + } + + power.lo = ((power.lo >> 2) | (power.hi << 62)) + 1; + power.hi = (power.hi >> 2) + (power.lo == 0); + return power; +} + +// ========================================================================= +// CLASS : +// METHOD : main +// ========================================================================= +int main (int argc, char* argv[]) +{ + int minExp = -292, maxExp = 324; + + int opt; + while ((opt = getopt (argc, argv, "hl:u:v")) != -1) + { + switch (opt) + { + case 'h': + usage (); + _exit (EXIT_SUCCESS); + case 'l': + minExp = std::stoi (optarg); + break; + case 'u': + maxExp = std::stoi (optarg); + break; + case 'v': + version (); + _exit (EXIT_SUCCESS); + default: + usage (); + _exit (EXIT_FAILURE); + } + } + + if (minExp > maxExp) + { + std::cerr << "min exponent must be less than max exponent" << std::endl; + _exit (EXIT_FAILURE); + } + + std::vector powers; + for (int exp = minExp; exp <= maxExp; ++exp) + { + powers.push_back (compute (exp)); + } + + std::cout << "#ifndef __POWER_HPP__" << std::endl; + std::cout << "#define __POWER_HPP__" << std::endl; + std::cout << std::endl; + + std::cout << "#include " << std::endl; + std::cout << std::endl; + + std::cout << "#define MIN_EXPONENT " << minExp << std::endl; + std::cout << "#define MAX_EXPONENT " << maxExp << std::endl; + std::cout << std::endl; + + std::cout << "struct Power {" << std::endl; + std::cout << " uint64_t hi;" << std::endl; + std::cout << " uint64_t lo;" << std::endl; + std::cout << "};" << std::endl; + std::cout << std::endl; + + std::cout << "constexpr Power powers[] = {" << std::endl; + for (size_t i = 0; i < powers.size (); ++i) + { + std::cout << std::hex << " {0x" << std::setw (16) << std::setfill ('0') << powers[i].hi << ", " + << "0x" << std::setw (16) << std::setfill ('0') << powers[i].lo << "}," << std::dec << std::endl; + } + std::cout << "};" << std::endl; + std::cout << std::endl; + + std::cout << "#endif" << std::endl; + std::cout << std::endl; + + _exit (EXIT_SUCCESS); +} diff --git a/tools/schubfachpowgen/version.hpp.in b/tools/schubfachpowgen/version.hpp.in new file mode 100644 index 0000000..0cd6e9e --- /dev/null +++ b/tools/schubfachpowgen/version.hpp.in @@ -0,0 +1,32 @@ +/** + * MIT License + * + * Copyright (c) 2026 Mathieu Rabine + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __SCHUBFACHPOWGEN_VERSION_H__ +#define __SCHUBFACHPOWGEN_VERSION_H__ + +#define VERSION_MAJOR "@SCHUBFACHPOWGEN_VERSION_MAJOR@" +#define VERSION_MINOR "@SCHUBFACHPOWGEN_VERSION_MINOR@" +#define VERSION_PATCH "@SCHUBFACHPOWGEN_VERSION_PATCH@" + +#endif From f3fddff25c2571155c362f44dabc0fd2c61b45f2 Mon Sep 17 00:00:00 2001 From: mrabine Date: Thu, 29 Oct 2026 23:45:34 +0100 Subject: [PATCH 2/3] codacy warning --- dconv/include/dconv/format.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dconv/include/dconv/format.hpp b/dconv/include/dconv/format.hpp index 6c872e9..c0fc938 100644 --- a/dconv/include/dconv/format.hpp +++ b/dconv/include/dconv/format.hpp @@ -154,7 +154,7 @@ namespace dconv return writeExponent (&buffer[position + 1], kk - 1); } - if ((length <= kk) && (kk <= 21)) + if (length <= kk) { writeDigits (buffer, digits, length); for (int i = length; i < kk; ++i) @@ -165,7 +165,7 @@ namespace dconv buffer[kk + 1] = '0'; return &buffer[kk + 2]; } - else if ((0 < kk) && (kk <= 21)) + else if (0 < kk) { length -= writeDigits (buffer + 1, digits, length); for (int i = 0; i < kk; ++i) From 8a8d845268fb13d6c8f2cc84f95505d1732bde6e Mon Sep 17 00:00:00 2001 From: mrabine Date: Thu, 29 Oct 2026 23:48:28 +0100 Subject: [PATCH 3/3] Bump version to 1.1.0 --- VERSION | 2 +- doxyfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 90a27f9..9084fa2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.5 +1.1.0 diff --git a/doxyfile b/doxyfile index 339c718..403e9d3 100644 --- a/doxyfile +++ b/doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "dconv" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.0 +PROJECT_NUMBER = 1.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a