File: generate_cache.cpp

package info (click to toggle)
dragonbox 1.1.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,148 kB
  • sloc: cpp: 8,752; ansic: 1,522; makefile: 18
file content (126 lines) | stat: -rw-r--r-- 4,732 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright 2020-2022 Junekey Jeon
//
// The contents of this file may be used under the terms of
// the Apache License v2.0 with LLVM Exceptions.
//
//    (See accompanying file LICENSE-Apache or copy at
//     https://llvm.org/foundation/relicensing/LICENSE.txt)
//
// Alternatively, the contents of this file may be used under the terms of
// the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE-Boost or copy at
//     https://www.boost.org/LICENSE_1_0.txt)
//
// Unless required by applicable law or agreed to in writing, this software
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.

#include "big_uint.h"
#include "continued_fractions.h"
#include "dragonbox/dragonbox.h"
#include <algorithm>
#include <utility>
#include <stdexcept>
#include <vector>

template <class FloatTraits>
auto generate_cache() {
    using impl = jkj::dragonbox::detail::impl<typename FloatTraits::type, FloatTraits>;

    std::vector<jkj::big_uint> results;
    jkj::unsigned_rational<jkj::big_uint> target_number;
    for (int k = impl::min_k; k <= impl::max_k; ++k) {
        // (2f_c +- 1) * 2^beta * (2^(k - e_k - Q) * 5^k)
        // e_k = floor(k log2(10)) - Q + 1, so
        // k - e_k - Q = k - floor(k log2(10)) - 1.
        int exp_2 = k - jkj::dragonbox::detail::log::floor_log2_pow10(k) - 1;

        target_number.numerator = 1;
        target_number.denominator = 1;
        if (k >= 0) {
            target_number.numerator = jkj::big_uint::pow(5, k);
        }
        else {
            target_number.denominator = jkj::big_uint::pow(5, -k);
        }
        if (exp_2 >= 0) {
            target_number.numerator *= jkj::big_uint::power_of_2(exp_2);
        }
        else {
            target_number.denominator *= jkj::big_uint::power_of_2(-exp_2);
        }

        auto div_res = div(jkj::big_uint::power_of_2(impl::cache_bits) * target_number.numerator,
                           target_number.denominator);
        auto m = std::move(div_res.quot);
        if (!div_res.rem.is_zero()) {
            m += 1;
        }

        // Recheck that m is in the correct range.
        if (m < jkj::big_uint::power_of_2(impl::cache_bits - 1) ||
            m >= jkj::big_uint::power_of_2(impl::cache_bits)) {
            throw std::logic_error{"Generated cache entry is not in the correct range"};
        }

        results.push_back(std::move(m));
    }

    return results;
}

#include <fstream>
#include <iomanip>
#include <iostream>

int main() {
    std::cout << "[Generating cache...]\n";

    using jkj::dragonbox::detail::impl;

    auto write_file = [](std::ofstream& out, auto type_tag, auto const& cache_array,
                         auto&& ieee_754_type_name_string, auto&& element_printer) {
        using float_type = typename decltype(type_tag)::type;

        out << "static constexpr int min_k = " << std::dec << impl<float_type>::min_k << ";\n";
        out << "static constexpr int max_k = " << std::dec << impl<float_type>::max_k << ";\n";
        out << "static constexpr cache_entry_type cache[] = {";
        for (int k = impl<float_type>::min_k; k < impl<float_type>::max_k; ++k) {
            auto idx = std::size_t(k - impl<float_type>::min_k);
            out << "\n\t";
            element_printer(out, cache_array[idx]);
            out << ",";
        }
        out << "\n\t";
        element_printer(out, cache_array.back());
        out << "\n};";
    };

    std::ofstream out;

    try {
        out.open("results/binary32_generated_cache.txt");
        auto binary32_cache = generate_cache<jkj::dragonbox::default_float_traits<float>>();
        write_file(out, jkj::dragonbox::default_float_traits<float>{}, binary32_cache, "binary32",
                   [](std::ofstream& out, jkj::big_uint const& value) {
                       out << "0x" << std::hex << std::setw(16) << std::setfill('0') << value[0];
                   });
        out.close();

        out.open("results/binary64_generated_cache.txt");
        auto binary64_cache = generate_cache<jkj::dragonbox::default_float_traits<double>>();
        write_file(out, jkj::dragonbox::default_float_traits<double>{}, binary64_cache, "binary64",
                   [](std::ofstream& out, jkj::big_uint const& value) {
                       out << "{ 0x" << std::hex << std::setw(16) << std::setfill('0') << value[1]
                           << ", 0x" << std::hex << std::setw(16) << std::setfill('0') << value[0]
                           << " }";
                   });
        out.close();
    }
    catch (std::logic_error const& ex) {
        std::cout << ex.what() << "\n";
        return -1;
    }

    std::cout << "Done.\n\n\n";
}