github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/native/fastfloat.c (about)

     1  /* Copyright 2020 Alexander Bolz
     2   * 
     3   * Boost Software License - Version 1.0 - August 17th, 2003
     4   * 
     5   * Permission is hereby granted, free of charge, to any person or organization
     6   * obtaining a copy of the software and accompanying documentation covered by
     7   * this license (the "Software") to use, reproduce, display, distribute,
     8   * execute, and transmit the Software, and to prepare derivative works of the
     9   * Software, and to permit third-parties to whom the Software is furnished to
    10   * do so, all subject to the following:
    11   * 
    12   * The copyright notices in the Software and this entire statement, including
    13   * the above license grant, this restriction and the following disclaimer,
    14   * must be included in all copies of the Software, in whole or in part, and
    15   * all derivative works of the Software, unless such copies or derivative
    16   * works are solely in the form of machine-executable object code generated by
    17   * a source language processor.
    18   *
    19   * Unless required by applicable law or agreed to in writing, this software
    20   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    21   * KIND, either express or implied.
    22   * 
    23   * This file may have been modified by ByteDance authors. All ByteDance
    24   * Modifications are Copyright 2022 ByteDance Authors.
    25   */
    26  
    27  #include "native.h"
    28  #include "tab.h"
    29  #include "test/xassert.h"
    30  
    31  #define F64_BITS         64
    32  #define F64_EXP_BITS     11
    33  #define F64_SIG_BITS     52
    34  #define F64_EXP_MASK     0x7FF0000000000000ull // middle 11 bits
    35  #define F64_SIG_MASK     0x000FFFFFFFFFFFFFull // lower 52 bits
    36  #define F64_EXP_BIAS     1023
    37  #define F64_INF_NAN_EXP  0x7FF
    38  #define F64_HIDDEN_BIT   0x0010000000000000ull
    39  
    40  struct f64_dec {
    41      uint64_t sig;
    42      int64_t exp;
    43  };
    44  typedef struct f64_dec f64_dec;
    45  
    46  typedef __uint128_t uint128_t;
    47  
    48  static inline unsigned ctz10(const uint64_t v) {
    49      xassert(0 <= v && v < 100000000000000000ull);
    50      if (v >= 10000000000ull) {
    51          if (v <      100000000000ull) return 11;
    52          if (v <     1000000000000ull) return 12;
    53          if (v <    10000000000000ull) return 13;
    54          if (v <   100000000000000ull) return 14;
    55          if (v <  1000000000000000ull) return 15;
    56          if (v < 10000000000000000ull) return 16;
    57          else                          return 17;
    58      }
    59          if (v <                10ull) return 1;
    60          if (v <               100ull) return 2;
    61          if (v <              1000ull) return 3;
    62          if (v <             10000ull) return 4;
    63          if (v <            100000ull) return 5;
    64          if (v <           1000000ull) return 6;
    65          if (v <          10000000ull) return 7;
    66          if (v <         100000000ull) return 8;
    67          if (v <        1000000000ull) return 9;
    68          else                          return 10;
    69  
    70  }
    71  
    72  static inline char* format_significand(uint64_t sig, char *out, int cnt) {
    73      char *p = out + cnt;
    74      int ctz = 0;
    75  
    76      if ((sig >> 32) != 0) {
    77          uint64_t q = sig / 100000000;
    78          uint32_t r = ((uint32_t)sig) - 100000000 * ((uint32_t) q);
    79          sig = q;
    80          if (r != 0) {
    81              uint32_t c  = r % 10000;
    82              r /= 10000;
    83              uint32_t d  = r % 10000;
    84              uint32_t c0 = (c % 100) << 1;
    85              uint32_t c1 = (c / 100) << 1;
    86              uint32_t d0 = (d % 100) << 1;
    87              uint32_t d1 = (d / 100) << 1;
    88              copy_two_digs(p - 2, Digits + c0);
    89              copy_two_digs(p - 4, Digits + c1);
    90              copy_two_digs(p - 6, Digits + d0);
    91              copy_two_digs(p - 8, Digits + d1);
    92          } else {
    93              ctz += 8;
    94          }
    95          p -= 8;
    96      }
    97  
    98      uint32_t sig2 = (uint32_t)sig;
    99      while (sig2 >= 10000) {
   100          uint32_t c = sig2 - 10000 * (sig2 / 10000);
   101          sig2 /= 10000;
   102          uint32_t c0 = (c % 100) << 1;
   103          uint32_t c1 = (c / 100) << 1;
   104          copy_two_digs(p - 2, Digits + c0);
   105          copy_two_digs(p - 4, Digits + c1);
   106          p -= 4;
   107      }
   108      if (sig2 >= 100) {
   109          uint32_t c = (sig2 % 100) << 1;
   110          sig2 /= 100;
   111          copy_two_digs(p - 2, Digits + c);
   112          p -= 2;
   113      }
   114      if (sig2 >= 10) {
   115          uint32_t c = sig2 << 1;
   116          copy_two_digs(p - 2, Digits + c);
   117      } else {
   118          *out = (char) ('0' + sig2);
   119      }
   120      return out + cnt - ctz;
   121  }
   122  
   123  static inline char* format_integer(uint64_t sig, char *out, unsigned cnt) {
   124      char *p = out + cnt;
   125      if ((sig >> 32) != 0) {
   126          uint64_t q = sig / 100000000;
   127          uint32_t r = ((uint32_t)sig) - 100000000 * ((uint32_t) q);
   128          sig = q;
   129          uint32_t c  = r % 10000;
   130          r /= 10000;
   131          uint32_t d  = r % 10000;
   132          uint32_t c0 = (c % 100) << 1;
   133          uint32_t c1 = (c / 100) << 1;
   134          uint32_t d0 = (d % 100) << 1;
   135          uint32_t d1 = (d / 100) << 1;
   136          copy_two_digs(p - 2, Digits + c0);
   137          copy_two_digs(p - 4, Digits + c1);
   138          copy_two_digs(p - 6, Digits + d0);
   139          copy_two_digs(p - 8, Digits + d1);
   140          p -= 8;
   141      }
   142  
   143      uint32_t sig2 = (uint32_t)sig;
   144      while (sig2 >= 10000) {
   145          uint32_t c = sig2 - 10000 * (sig2 / 10000);
   146          sig2 /= 10000;
   147          uint32_t c0 = (c % 100) << 1;
   148          uint32_t c1 = (c / 100) << 1;
   149          copy_two_digs(p - 2, Digits + c0);
   150          copy_two_digs(p - 4, Digits + c1);
   151          p -= 4;
   152      }
   153      if (sig2 >= 100) {
   154          uint32_t c = (sig2 % 100) << 1;
   155          sig2 /= 100;
   156          copy_two_digs(p - 2, Digits + c);
   157          p -= 2;
   158      }
   159      if (sig2 >= 10) {
   160          uint32_t c = sig2 << 1;
   161          copy_two_digs(p - 2, Digits + c);
   162      } else {
   163          *out = (char) ('0' + sig2);
   164      }
   165      return out + cnt;
   166  }
   167  
   168  static inline char* format_exponent(f64_dec v, char *out, unsigned cnt) {
   169      char* p = out + 1;
   170      char* end = format_significand(v.sig, p, cnt);
   171      while (*(end - 1) == '0') end--;
   172  
   173      /* print decimal point if needed */
   174      *out = *p;
   175      if (end - p > 1) {
   176          *p = '.';
   177      } else {
   178          end--;
   179      }
   180  
   181      /* print the exponent */
   182      *end++ = 'e';
   183      int32_t exp = v.exp + (int32_t) cnt - 1;
   184      if (exp < 0) {
   185          *end++ = '-';
   186          exp = -exp;
   187      } else {
   188          *end++ = '+';
   189      }
   190  
   191      if (exp >= 100) {
   192          int32_t c = exp % 10;
   193          copy_two_digs(end, Digits + 2 * (exp / 10));
   194          end[2] = (char) ('0' + c);
   195          end += 3;
   196      } else if (exp >= 10) {
   197          copy_two_digs(end, Digits + 2 * exp);
   198          end += 2;
   199      } else {
   200          *end++ = (char) ('0' + exp);
   201      }
   202      return end;
   203  }
   204  
   205  static inline char* format_decimal(f64_dec v, char* out, unsigned cnt) {
   206      char* p = out;
   207      char* end;
   208      int point = cnt + v.exp;
   209  
   210      /* print leading zeros if fp < 1 */
   211      if (point <= 0) {
   212          *p++ = '0', *p++ = '.';
   213          for (int i = 0; i < -point; i++) {
   214              *p++ = '0';
   215          }
   216      }
   217  
   218      /* add the remaining digits */
   219      end = format_significand(v.sig, p, cnt);
   220      while (*(end - 1) == '0') end--;
   221      if (point <= 0) {
   222          return end;
   223      }
   224  
   225      /* insert point or add trailing zeros */
   226      int digs = end - p;
   227      if (digs > point) {
   228          for (int i = 0; i < digs - point; i++) {
   229              *(end - i) = *(end - i - 1);
   230          }
   231          p[point] = '.';
   232          end++;
   233      } else {
   234          for (int i = 0; i < point - digs; i++) {
   235              *end++ = '0';
   236          }
   237      }
   238      return end;
   239  }
   240  
   241  static inline char* write_dec(f64_dec dec, char* p) {
   242      int cnt = ctz10(dec.sig);
   243      int dot = cnt + dec.exp;
   244      int sci_exp = dot - 1;
   245      bool exp_fmt = sci_exp < -6 || sci_exp > 20;
   246      bool has_dot = dot < cnt;
   247  
   248      if (exp_fmt) {
   249          return format_exponent(dec, p, cnt);
   250      }
   251      if (has_dot) {
   252          return format_decimal(dec, p, cnt);
   253      }
   254  
   255      char* end = p + dot;
   256      p = format_integer(dec.sig, p, cnt);
   257      while (p < end) *p++ = '0';
   258      return end;
   259  }
   260  
   261  static inline uint64_t f64toraw(double fp) {
   262      union {
   263          uint64_t u64;
   264          double   f64;
   265      } uval;
   266      uval.f64 = fp;
   267      return uval.u64;
   268  }
   269  
   270  static inline uint64_t round_odd(uint64x2 g, uint64_t cp) {
   271      const uint128_t x = ((uint128_t)cp) * g.lo;
   272      const uint128_t y = ((uint128_t)cp) * g.hi + ((uint64_t)(x >> 64));
   273  
   274      const uint64_t y0 = ((uint64_t)y);
   275      const uint64_t y1 = ((uint64_t)(y >> 64));
   276      return y1 | (y0 > 1);
   277  }
   278  
   279  /**
   280   Rendering float point number into decimal.
   281   The function used Schubfach algorithm, reference:
   282   The Schubfach way to render doubles, Raffaello Giulietti, 2022-03-20.
   283   https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb
   284   https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-November/083536.html
   285   https://github.com/openjdk/jdk/pull/3402 (Java implementation)
   286   https://github.com/abolz/Drachennest (C++ implementation)
   287   */
   288  static inline f64_dec f64todec(uint64_t rsig, int32_t rexp, uint64_t c, int32_t q) {
   289      uint64_t cbl, cb, cbr, vbl, vb, vbr, lower, upper, s;
   290      int32_t k, h;
   291      bool even, irregular, w_inside, u_inside;
   292      f64_dec dec;
   293  
   294      even = !(c & 1);
   295      irregular = rsig == 0 && rexp > 1;
   296  
   297      cbl = 4 * c - 2 + irregular;
   298      cb = 4 * c;
   299      cbr = 4 * c + 2;
   300  
   301      /*  q is in [-1500, 1500]
   302          k = irregular ? floor(log_10(3/4 * 2^q)) : floor(log10(pow(2^q)))
   303          floor(log10(3/4 * 2^q))  = (q * 1262611 - 524031) >> 22
   304          floor(log10(pow(2^q))) = (q * 1262611) >> 22 */
   305      k = (q * 1262611 - (irregular ? 524031 : 0)) >> 22;
   306  
   307      /*  k is in [-1233, 1233]
   308          s = floor(V) = floor(c * 2^q * 10^-k)
   309          vb = 4V = 4 * c * 2^q * 10^-k */
   310      h = q + ((-k) * 1741647 >> 19) + 1;
   311      uint64x2 pow10 = pow10_ceil_sig(-k);
   312      vbl = round_odd(pow10, cbl << h);
   313      vb = round_odd(pow10, cb << h);
   314      vbr = round_odd(pow10, cbr << h);
   315  
   316      lower = vbl + !even;
   317      upper = vbr - !even;
   318  
   319      s = vb / 4;
   320      if (s >= 10) {
   321          /* R_k+1 interval contains at most one: up or wp */
   322          uint64_t sp = s / 10;
   323          bool up_inside = lower <= (40 * sp);
   324          bool wp_inside = (40 * sp + 40) <= upper;
   325          if (up_inside != wp_inside) {
   326              dec.sig = sp + wp_inside;
   327              dec.exp = k + 1;
   328              return dec;
   329          }
   330      }
   331  
   332      /* R_k interval contains at least one: u or w */
   333      u_inside = lower <= (4 * s);
   334      w_inside = (4 * s + 4) <= upper;
   335      if (u_inside != w_inside) {
   336          dec.sig = s + w_inside;
   337          dec.exp = k;
   338          return dec;
   339      }
   340  
   341      /* R_k interval contains both u or w */
   342      uint64_t mid = 4 * s + 2;
   343      bool round_up = vb > mid || (vb == mid && (s & 1) != 0);
   344      dec.sig = s + round_up;
   345      dec.exp = k;
   346      return dec;
   347  }
   348  
   349  int f64toa(char *out, double fp) {
   350      char* p = out;
   351      uint64_t raw = f64toraw(fp);
   352      bool neg;
   353      uint64_t rsig, c;
   354      int32_t rexp, q;
   355  
   356      neg = ((raw >> (F64_BITS - 1)) != 0);
   357      rsig = raw & F64_SIG_MASK;
   358      rexp = (int32_t)((raw & F64_EXP_MASK) >> F64_SIG_BITS);
   359  
   360      /* check infinity and nan */
   361      if (unlikely(rexp == F64_INF_NAN_EXP)) {
   362          return 0;
   363      }
   364  
   365      /* check negative numbers */
   366      *p = '-';
   367      p += neg;
   368  
   369      /* simple case of 0.0 */
   370      if ((raw << 1) ==  0) {
   371          *p++ = '0';
   372          return p - out;
   373      }
   374  
   375      /* fp = c * 2^q */
   376      if (likely(rexp != 0)) {
   377          /* double is normal */
   378          c = rsig | F64_HIDDEN_BIT;
   379          q = rexp - F64_EXP_BIAS - F64_SIG_BITS;
   380  
   381          /* fast path for integer */
   382          if (q <= 0 && q >= -F64_SIG_BITS && is_div_pow2(c, -q)) {
   383              uint64_t u = c >> -q;
   384              p = format_integer(u, p, ctz10(u));
   385              return p - out;
   386          }
   387  
   388      } else {
   389          c = rsig;
   390          q = 1 - F64_EXP_BIAS - F64_SIG_BITS;
   391      }
   392  
   393      f64_dec dec = f64todec(rsig, rexp, c, q);
   394      p = write_dec(dec, p);
   395      return p - out;
   396  }
   397  
   398  #undef F64_BITS       
   399  #undef F64_EXP_BITS   
   400  #undef F64_SIG_BITS   
   401  #undef F64_EXP_MASK   
   402  #undef F64_SIG_MASK   
   403  #undef F64_EXP_BIAS   
   404  #undef F64_INF_NAN_EXP
   405  #undef F64_HIDDEN_BIT