Guest User

APFloat Constant Generator

a guest
Sep 30th, 2026
36
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.77 KB | None | 0 0
  1. #include <mpfr.h>
  2.  
  3. #include <bit>
  4. #include <cinttypes>
  5. #include <cstdint>
  6. #include <cstdio>
  7. #include <cstdlib>
  8. #include <cstring>
  9. #include <cmath>
  10. #include <string>
  11. #include <chrono>
  12.  
  13. using std::string;
  14.  
  15. string string_val(const char *str, mpfr_prec_t Precision, mpfr_rnd_t RND) {
  16.   mpfr_t value;
  17.   mpfr_init2(value, Precision);
  18.   mpfr_strtofr(value, str, nullptr, 10, RND);
  19.  
  20.   // Scale to [1, 2) (exact), remembering the binary exponent
  21.   long exp = mpfr_get_exp(value) - 1;
  22.   if (mpfr_mul_2si(value, value, -exp, MPFR_RNDN) != 0)
  23.     printf("Rounding occured for [%s]\n", str);
  24.  
  25.   // 1 leading hex digit + enough fraction digits for the remaining (Precision - 1) bits
  26.   size_t ndigits = 1 + (Precision - 1 + 3) / 4;
  27.   mpfr_exp_t hex_exp;
  28.   char *digits = mpfr_get_str(nullptr, &hex_exp, 16, ndigits, value, MPFR_RNDN);
  29.   char buf[999];
  30.   snprintf(buf, sizeof(buf), "0x%c.%sp%+ld", digits[0], digits + 1, exp);
  31.  
  32.   mpfr_free_str(digits);
  33.   mpfr_clear(value);
  34.   return buf;
  35. }
  36.  
  37. // Rounds the decimal in `str` to the nearest double-double under RND.
  38. //
  39. // hi is always RN(x): a canonical double-double requires RN(hi + lo) == hi, so
  40. // hi is fixed by x and only lo is free. The value increases with lo, so a
  41. // directed mode on the value is the same directed mode on the residual, except
  42. // for the two sign-relative modes, which have to be resolved against the sign
  43. // of x first.
  44. //
  45. // The pair spans more than the 106 bits of a fixed-width significand, because
  46. // lo carries its own exponent; that is why rounding through a flat 106-bit
  47. // format loses the last bit of lo.
  48. void double_double_val(const char *str, mpfr_rnd_t RND, double &hi,
  49.                        double &lo) {
  50.   mpfr_prec_t Precision = 2112;
  51.   mpfr_t value, hi_exact, residual;
  52.   mpfr_init2(value, Precision);
  53.   mpfr_init2(hi_exact, Precision);
  54.   mpfr_init2(residual, Precision);
  55.  
  56.   mpfr_strtofr(value, str, nullptr, 10, MPFR_RNDN);
  57.  
  58.   hi = mpfr_get_d(value, MPFR_RNDN);
  59.  
  60.   // residual = value - hi, exact at this precision
  61.   mpfr_set_d(hi_exact, hi, MPFR_RNDN);
  62.   if (mpfr_sub(residual, value, hi_exact, MPFR_RNDN) != 0)
  63.     printf("Rounding occured computing the residual for [%s]\n", str);
  64.  
  65.   // Toward/away from zero refer to the value, not the residual, and the
  66.   // residual takes either sign.
  67.   mpfr_rnd_t ResidualRND = RND;
  68.   if (RND == MPFR_RNDZ)
  69.     ResidualRND = mpfr_sgn(value) < 0 ? MPFR_RNDU : MPFR_RNDD;
  70.   else if (RND == MPFR_RNDA)
  71.     ResidualRND = mpfr_sgn(value) < 0 ? MPFR_RNDD : MPFR_RNDU;
  72.  
  73.   lo = mpfr_get_d(residual, ResidualRND);
  74.  
  75.   // APFloat wants a canonical double-double: adding lo back must not change hi.
  76.   if (hi + lo != hi)
  77.     printf("Not a canonical double-double for [%s]\n", str);
  78.  
  79.   mpfr_clear(residual);
  80.   mpfr_clear(hi_exact);
  81.   mpfr_clear(value);
  82. }
  83.  
  84. uint64_t f64_to_u64(double x) {
  85.   return std::bit_cast<uint64_t>(x);
  86. }
  87.  
  88. // These literals are not sufficient for ieee_binary256
  89. static const struct { const char *label; const char *str; } constants[] = {
  90.   { "e",          "2.7182818284590452353602874713526624977572470936999595749669676277..." },
  91.   { "log2e",      "1.4426950408889634073599246810018921374266459541529859341354494069..." },
  92.   { "log10e",     "0.4342944819032518276511289189166050822943970058036665661144537831..." },
  93.   { "pi",         "3.1415926535897932384626433832795028841971693993751058209749445923..." },
  94.   { "inv_pi",     "0.3183098861837906715377675267450287240689192914809128974953346881..." },
  95.   { "inv_sqrtpi", "0.5641895835477562869480794515607725858440506293289988568440857217..." },
  96.   { "ln2",        "0.6931471805599453094172321214581765680755001343602552541206800094..." },
  97.   { "ln10",       "2.3025850929940456840179914546843642076011014886287729760333279009..." },
  98.   { "sqrt2",      "1.4142135623730950488016887242096980785696718753769480731766797379..." },
  99.   { "sqrt3",      "1.7320508075688772935274463415058723669428052538103806280558069794..." },
  100.   { "inv_sqrt3",  "0.5773502691896257645091487805019574556476017512701268760186023264..." },
  101.   { "egamma",     "0.5772156649015328606065120900824024310421593359399235988057672348..." },
  102.   { "phi",        "1.6180339887498948482045868343656381177203091798057628621354486227..." },
  103. };
  104.  
  105. // struct { const char *name; mpfr_rnd_t rnd; } modes[] = {
  106. //   { "rmNearestTiesToEven", MPFR_RNDN },
  107. //   { "rmTowardPositive",    MPFR_RNDU },
  108. //   { "rmTowardNegative",    MPFR_RNDD },
  109. //   { "rmTowardZero",        MPFR_RNDZ },
  110. // };
  111.  
  112. void print_literals(mpfr_prec_t Precision) {
  113.   for (auto &c : constants) {
  114.     string Down = string_val(c.str, Precision, MPFR_RNDD);
  115.     string Near = string_val(c.str, Precision, MPFR_RNDN);
  116.     string Up = string_val(c.str, Precision, MPFR_RNDU);
  117.     printf("    {APFloat::MathConstant::%s, \"%s\",\n", c.label, c.label);
  118.     printf("     \"%s\",\n", Down.c_str());
  119.     printf("     \"%s\",\n", Near.c_str());
  120.     printf("     \"%s\"},\n", Up.c_str());
  121.   }
  122.   printf("\n");
  123. }
  124.  
  125. void print_PPCDoubleDouble_literals() {
  126.   for (auto &c : constants) {
  127.     double Down_hi, Down_lo;
  128.     double Near_hi, Near_lo;
  129.     double Up_hi, Up_lo;
  130.     double_double_val(c.str, MPFR_RNDD, Down_hi, Down_lo);
  131.     double_double_val(c.str, MPFR_RNDN, Near_hi, Near_lo);
  132.     double_double_val(c.str, MPFR_RNDU, Up_hi, Up_lo);
  133.     printf("    {APFloat::MathConstant::%s, \"%s\",\n", c.label, c.label);
  134.     printf("     \"0x%" PRIx64 "u, 0x%" PRIx64 "u,\n", f64_to_u64(Down_hi), f64_to_u64(Down_lo));
  135.     printf("     \"0x%" PRIx64 "u, 0x%" PRIx64 "u,\n", f64_to_u64(Near_hi), f64_to_u64(Near_lo));
  136.     printf("     \"0x%" PRIx64 "u, 0x%" PRIx64 "u},\n", f64_to_u64(Up_hi), f64_to_u64(Up_lo));
  137.   }
  138.   printf("\n");
  139. }
  140.  
  141. int main(void) {
  142.  
  143. #if 1
  144.   mpfr_prec_t Precision = 53;
  145.   print_literals(Precision);
  146. #else
  147.   print_PPCDoubleDouble_literals();
  148. #endif
  149.  
  150.   return 0;
  151. }
  152.  
Advertisement
Add Comment
Please, Sign In to add comment