(root)/
gcc-13.2.0/
libgcc/
config/
libbid/
bid64_string.c
       1  /* Copyright (C) 2007-2023 Free Software Foundation, Inc.
       2  
       3  This file is part of GCC.
       4  
       5  GCC is free software; you can redistribute it and/or modify it under
       6  the terms of the GNU General Public License as published by the Free
       7  Software Foundation; either version 3, or (at your option) any later
       8  version.
       9  
      10  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11  WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13  for more details.
      14  
      15  Under Section 7 of GPL version 3, you are granted additional
      16  permissions described in the GCC Runtime Library Exception, version
      17  3.1, as published by the Free Software Foundation.
      18  
      19  You should have received a copy of the GNU General Public License and
      20  a copy of the GCC Runtime Library Exception along with this program;
      21  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      22  <http://www.gnu.org/licenses/>.  */
      23  
      24  #include <ctype.h>
      25  #include "bid_internal.h"
      26  #include "bid128_2_str.h"
      27  #include "bid128_2_str_macros.h"
      28  
      29  #define MAX_FORMAT_DIGITS     16
      30  #define DECIMAL_EXPONENT_BIAS 398
      31  #define MAX_DECIMAL_EXPONENT  767
      32  
      33  #if DECIMAL_CALL_BY_REFERENCE
      34  
      35  void
      36  bid64_to_string (char *ps, UINT64 * px
      37  		 _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
      38    UINT64 x;
      39  #else
      40  
      41  void
      42  bid64_to_string (char *ps, UINT64 x
      43  		 _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
      44  #endif
      45  // the destination string (pointed to by ps) must be pre-allocated
      46    UINT64 sign_x, coefficient_x, D, ER10;
      47    int istart, exponent_x, j, digits_x, bin_expon_cx;
      48    int_float tempx;
      49    UINT32 MiDi[12], *ptr;
      50    UINT64 HI_18Dig, LO_18Dig, Tmp;
      51    char *c_ptr_start, *c_ptr;
      52    int midi_ind, k_lcv, len;
      53    unsigned int save_fpsf;
      54  
      55  #if DECIMAL_CALL_BY_REFERENCE
      56    x = *px;
      57  #endif
      58  
      59    save_fpsf = *pfpsf; // place holder only
      60    // unpack arguments, check for NaN or Infinity
      61    if (!unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x)) {
      62      // x is Inf. or NaN or 0
      63  
      64      // Inf or NaN?
      65      if ((x & 0x7800000000000000ull) == 0x7800000000000000ull) {
      66        if ((x & 0x7c00000000000000ull) == 0x7c00000000000000ull) {
      67      ps[0] = (sign_x) ? '-' : '+';
      68      ps[1] = ((x & MASK_SNAN) == MASK_SNAN)? 'S':'Q';
      69  	ps[2] = 'N';
      70  	ps[3] = 'a';
      71  	ps[4] = 'N';
      72  	ps[5] = 0;
      73  	return;
      74        }
      75        // x is Inf
      76        ps[0] = (sign_x) ? '-' : '+';
      77        ps[1] = 'I';
      78        ps[2] = 'n';
      79        ps[3] = 'f';
      80        ps[4] = 0;
      81        return;
      82      }
      83      // 0
      84      istart = 0;
      85      if (sign_x) {
      86        ps[istart++] = '-';
      87      }
      88  
      89      ps[istart++] = '0';
      90      ps[istart++] = 'E';
      91  
      92      exponent_x -= 398;
      93      if (exponent_x < 0) {
      94        ps[istart++] = '-';
      95        exponent_x = -exponent_x;
      96      } else
      97        ps[istart++] = '+';
      98  
      99      if (exponent_x) {
     100        // get decimal digits in coefficient_x
     101        tempx.d = (float) exponent_x;
     102        bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f;
     103        digits_x = estimate_decimal_digits[bin_expon_cx];
     104        if ((UINT64)exponent_x >= power10_table_128[digits_x].w[0])
     105  	digits_x++;
     106  
     107        j = istart + digits_x - 1;
     108        istart = j + 1;
     109  
     110        // 2^32/10
     111        ER10 = 0x1999999a;
     112  
     113        while (exponent_x > 9) {
     114  	D = (UINT64) exponent_x *ER10;
     115  	D >>= 32;
     116  	exponent_x = exponent_x - (D << 1) - (D << 3);
     117  
     118  	ps[j--] = '0' + (char) exponent_x;
     119  	exponent_x = D;
     120        }
     121        ps[j] = '0' + (char) exponent_x;
     122      } else {
     123        ps[istart++] = '0';
     124      }
     125  
     126      ps[istart] = 0;
     127  
     128      return;
     129    }
     130    // convert expon, coeff to ASCII
     131    exponent_x -= DECIMAL_EXPONENT_BIAS;
     132  
     133    ER10 = 0x1999999a;
     134  
     135    istart = 0;
     136    if (sign_x) {
     137      ps[0] = '-';
     138      istart = 1;
     139    }
     140    // if zero or non-canonical, set coefficient to '0'
     141    if ((coefficient_x > 9999999999999999ull) ||	// non-canonical
     142        ((coefficient_x == 0))	// significand is zero
     143      ) {
     144      ps[istart++] = '0';
     145    } else {
     146      /* ****************************************************
     147         This takes a bid coefficient in C1.w[1],C1.w[0] 
     148         and put the converted character sequence at location 
     149         starting at &(str[k]). The function returns the number
     150         of MiDi returned. Note that the character sequence 
     151         does not have leading zeros EXCEPT when the input is of
     152         zero value. It will then output 1 character '0'
     153         The algorithm essentailly tries first to get a sequence of
     154         Millenial Digits "MiDi" and then uses table lookup to get the
     155         character strings of these MiDis.
     156         **************************************************** */
     157      /* Algorithm first decompose possibly 34 digits in hi and lo
     158         18 digits. (The high can have at most 16 digits). It then
     159         uses macro that handle 18 digit portions.
     160         The first step is to get hi and lo such that
     161         2^(64) C1.w[1] + C1.w[0] = hi * 10^18  + lo,   0 <= lo < 10^18.
     162         We use a table lookup method to obtain the hi and lo 18 digits.
     163         [C1.w[1],C1.w[0]] = c_8 2^(107) + c_7 2^(101) + ... + c_0 2^(59) + d
     164         where 0 <= d < 2^59 and each c_j has 6 bits. Because d fits in
     165         18 digits,  we set hi = 0, and lo = d to begin with.
     166         We then retrieve from a table, for j = 0, 1, ..., 8
     167         that gives us A and B where c_j 2^(59+6j) = A * 10^18 + B.
     168         hi += A ; lo += B; After each accumulation into lo, we normalize 
     169         immediately. So at the end, we have the decomposition as we need. */
     170  
     171      Tmp = coefficient_x >> 59;
     172      LO_18Dig = (coefficient_x << 5) >> 5;
     173      HI_18Dig = 0;
     174      k_lcv = 0;
     175  
     176      while (Tmp) {
     177        midi_ind = (int) (Tmp & 0x000000000000003FLL);
     178        midi_ind <<= 1;
     179        Tmp >>= 6;
     180        HI_18Dig += mod10_18_tbl[k_lcv][midi_ind++];
     181        LO_18Dig += mod10_18_tbl[k_lcv++][midi_ind];
     182        __L0_Normalize_10to18 (HI_18Dig, LO_18Dig);
     183      }
     184  
     185      ptr = MiDi;
     186      __L1_Split_MiDi_6_Lead (LO_18Dig, ptr);
     187      len = ptr - MiDi;
     188      c_ptr_start = &(ps[istart]);
     189      c_ptr = c_ptr_start;
     190  
     191      /* now convert the MiDi into character strings */
     192      __L0_MiDi2Str_Lead (MiDi[0], c_ptr);
     193      for (k_lcv = 1; k_lcv < len; k_lcv++) {
     194        __L0_MiDi2Str (MiDi[k_lcv], c_ptr);
     195      }
     196      istart = istart + (c_ptr - c_ptr_start);
     197    }
     198  
     199    ps[istart++] = 'E';
     200  
     201    if (exponent_x < 0) {
     202      ps[istart++] = '-';
     203      exponent_x = -exponent_x;
     204    } else
     205      ps[istart++] = '+';
     206  
     207    if (exponent_x) {
     208      // get decimal digits in coefficient_x
     209      tempx.d = (float) exponent_x;
     210      bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f;
     211      digits_x = estimate_decimal_digits[bin_expon_cx];
     212      if ((UINT64)exponent_x >= power10_table_128[digits_x].w[0])
     213        digits_x++;
     214  
     215      j = istart + digits_x - 1;
     216      istart = j + 1;
     217  
     218      // 2^32/10
     219      ER10 = 0x1999999a;
     220  
     221      while (exponent_x > 9) {
     222        D = (UINT64) exponent_x *ER10;
     223        D >>= 32;
     224        exponent_x = exponent_x - (D << 1) - (D << 3);
     225  
     226        ps[j--] = '0' + (char) exponent_x;
     227        exponent_x = D;
     228      }
     229      ps[j] = '0' + (char) exponent_x;
     230    } else {
     231      ps[istart++] = '0';
     232    }
     233  
     234    ps[istart] = 0;
     235  
     236    return;
     237  
     238  }
     239  
     240  
     241  #if DECIMAL_CALL_BY_REFERENCE
     242  void
     243  bid64_from_string (UINT64 * pres, char *ps
     244  		   _RND_MODE_PARAM _EXC_FLAGS_PARAM 
     245                     _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
     246  #else
     247  UINT64
     248  bid64_from_string (char *ps
     249  		   _RND_MODE_PARAM _EXC_FLAGS_PARAM 
     250                     _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
     251  #endif
     252    UINT64 sign_x, coefficient_x = 0, rounded = 0, res;
     253    int expon_x = 0, sgn_expon, ndigits, add_expon = 0, midpoint =
     254      0, rounded_up = 0;
     255    int dec_expon_scale = 0, right_radix_leading_zeros = 0, rdx_pt_enc =
     256      0;
     257    unsigned fpsc;
     258    char c;
     259    unsigned int save_fpsf;
     260  
     261  #if DECIMAL_CALL_BY_REFERENCE
     262  #if !DECIMAL_GLOBAL_ROUNDING
     263    _IDEC_round rnd_mode = *prnd_mode;
     264  #endif
     265  #endif
     266  
     267    save_fpsf = *pfpsf; // place holder only
     268    // eliminate leading whitespace
     269    while (((*ps == ' ') || (*ps == '\t')) && (*ps))
     270      ps++;
     271  
     272    // get first non-whitespace character
     273    c = *ps;
     274  
     275    // detect special cases (INF or NaN)
     276    if (!c || (c != '.' && c != '-' && c != '+' && (c < '0' || c > '9'))) {
     277      // Infinity?
     278      if ((tolower_macro (ps[0]) == 'i' && tolower_macro (ps[1]) == 'n' && 
     279          tolower_macro (ps[2]) == 'f') && (!ps[3] || 
     280          (tolower_macro (ps[3]) == 'i' && 
     281          tolower_macro (ps[4]) == 'n' && tolower_macro (ps[5]) == 'i' && 
     282          tolower_macro (ps[6]) == 't' && tolower_macro (ps[7]) == 'y' && 
     283          !ps[8]))) {
     284        res = 0x7800000000000000ull;
     285        BID_RETURN (res);
     286      }
     287      // return sNaN
     288      if (tolower_macro (ps[0]) == 's' && tolower_macro (ps[1]) == 'n' && 
     289          tolower_macro (ps[2]) == 'a' && tolower_macro (ps[3]) == 'n') { 
     290          // case insensitive check for snan
     291        res = 0x7e00000000000000ull;
     292        BID_RETURN (res);
     293      } else {
     294        // return qNaN
     295        res = 0x7c00000000000000ull;
     296        BID_RETURN (res);
     297      }
     298    }
     299    // detect +INF or -INF
     300    if ((tolower_macro (ps[1]) == 'i' && tolower_macro (ps[2]) == 'n' && 
     301        tolower_macro (ps[3]) == 'f') && (!ps[4] || 
     302        (tolower_macro (ps[4]) == 'i' && tolower_macro (ps[5]) == 'n' && 
     303        tolower_macro (ps[6]) == 'i' && tolower_macro (ps[7]) == 't' && 
     304        tolower_macro (ps[8]) == 'y' && !ps[9]))) {
     305      if (c == '+')
     306        res = 0x7800000000000000ull;
     307      else if (c == '-')
     308        res = 0xf800000000000000ull;
     309      else
     310        res = 0x7c00000000000000ull;
     311      BID_RETURN (res);
     312    }
     313    // if +sNaN, +SNaN, -sNaN, or -SNaN
     314    if (tolower_macro (ps[1]) == 's' && tolower_macro (ps[2]) == 'n'
     315        && tolower_macro (ps[3]) == 'a' && tolower_macro (ps[4]) == 'n') {
     316      if (c == '-')
     317        res = 0xfe00000000000000ull;
     318      else
     319        res = 0x7e00000000000000ull;
     320      BID_RETURN (res);
     321    }
     322    // determine sign
     323    if (c == '-')
     324      sign_x = 0x8000000000000000ull;
     325    else
     326      sign_x = 0;
     327  
     328    // get next character if leading +/- sign
     329    if (c == '-' || c == '+') {
     330      ps++;
     331      c = *ps;
     332    }
     333    // if c isn't a decimal point or a decimal digit, return NaN
     334    if (c != '.' && (c < '0' || c > '9')) {
     335      // return NaN
     336      res = 0x7c00000000000000ull | sign_x;
     337      BID_RETURN (res);
     338    }
     339  
     340    rdx_pt_enc = 0;
     341  
     342    // detect zero (and eliminate/ignore leading zeros)
     343    if (*(ps) == '0' || *(ps) == '.') {
     344  
     345      if (*(ps) == '.') {
     346        rdx_pt_enc = 1;
     347        ps++;
     348      }
     349      // if all numbers are zeros (with possibly 1 radix point, the number is zero
     350      // should catch cases such as: 000.0
     351      while (*ps == '0') {
     352        ps++;
     353        // for numbers such as 0.0000000000000000000000000000000000001001, 
     354        // we want to count the leading zeros
     355        if (rdx_pt_enc) {
     356  	right_radix_leading_zeros++;
     357        }
     358        // if this character is a radix point, make sure we haven't already 
     359        // encountered one
     360        if (*(ps) == '.') {
     361  	if (rdx_pt_enc == 0) {
     362  	  rdx_pt_enc = 1;
     363  	  // if this is the first radix point, and the next character is NULL, 
     364            // we have a zero
     365  	  if (!*(ps + 1)) {
     366  	    res =
     367  	      ((UINT64) (398 - right_radix_leading_zeros) << 53) |
     368  	      sign_x;
     369  	    BID_RETURN (res);
     370  	  }
     371  	  ps = ps + 1;
     372  	} else {
     373  	  // if 2 radix points, return NaN
     374  	  res = 0x7c00000000000000ull | sign_x;
     375  	  BID_RETURN (res);
     376  	}
     377        } else if (!*(ps)) {
     378  	//pres->w[1] = 0x3040000000000000ull | sign_x;
     379  	res =
     380  	  ((UINT64) (398 - right_radix_leading_zeros) << 53) | sign_x;
     381  	BID_RETURN (res);
     382        }
     383      }
     384    }
     385  
     386    c = *ps;
     387  
     388    ndigits = 0;
     389    while ((c >= '0' && c <= '9') || c == '.') {
     390      if (c == '.') {
     391        if (rdx_pt_enc) {
     392  	// return NaN
     393  	res = 0x7c00000000000000ull | sign_x;
     394  	BID_RETURN (res);
     395        }
     396        rdx_pt_enc = 1;
     397        ps++;
     398        c = *ps;
     399        continue;
     400      }
     401      dec_expon_scale += rdx_pt_enc;
     402  
     403      ndigits++;
     404      if (ndigits <= 16) {
     405        coefficient_x = (coefficient_x << 1) + (coefficient_x << 3);
     406        coefficient_x += (UINT64) (c - '0');
     407      } else if (ndigits == 17) {
     408        // coefficient rounding
     409  		switch(rnd_mode){
     410  	case ROUNDING_TO_NEAREST:
     411        midpoint = (c == '5' && !(coefficient_x & 1)) ? 1 : 0; 
     412            // if coefficient is even and c is 5, prepare to round up if 
     413            // subsequent digit is nonzero
     414        // if str[MAXDIG+1] > 5, we MUST round up
     415        // if str[MAXDIG+1] == 5 and coefficient is ODD, ROUND UP!
     416        if (c > '5' || (c == '5' && (coefficient_x & 1))) {
     417  	coefficient_x++;
     418  	rounded_up = 1;
     419  	break;
     420  
     421  	case ROUNDING_DOWN:
     422  		if(sign_x) { coefficient_x++; rounded_up=1; }
     423  		break;
     424  	case ROUNDING_UP:
     425  		if(!sign_x) { coefficient_x++; rounded_up=1; }
     426  		break;
     427  	case ROUNDING_TIES_AWAY:
     428  		if(c>='5') { coefficient_x++; rounded_up=1; }
     429  		break;
     430  	  }
     431  	if (coefficient_x == 10000000000000000ull) {
     432  	  coefficient_x = 1000000000000000ull;
     433  	  add_expon = 1;
     434  	}
     435        }
     436        if (c > '0')
     437  	rounded = 1;
     438        add_expon += 1;
     439      } else { // ndigits > 17
     440        add_expon++;
     441        if (midpoint && c > '0') {
     442  	coefficient_x++;
     443  	midpoint = 0;
     444  	rounded_up = 1;
     445        }
     446        if (c > '0')
     447  	rounded = 1;
     448      }
     449      ps++;
     450      c = *ps;
     451    }
     452  
     453    add_expon -= (dec_expon_scale + right_radix_leading_zeros);
     454  
     455    if (!c) {
     456      res =
     457        fast_get_BID64_check_OF (sign_x,
     458  			       add_expon + DECIMAL_EXPONENT_BIAS,
     459  			       coefficient_x, 0, &fpsc);
     460      BID_RETURN (res);
     461    }
     462  
     463    if (c != 'E' && c != 'e') {
     464      // return NaN
     465      res = 0x7c00000000000000ull | sign_x;
     466      BID_RETURN (res);
     467    }
     468    ps++;
     469    c = *ps;
     470    sgn_expon = (c == '-') ? 1 : 0;
     471    if (c == '-' || c == '+') {
     472      ps++;
     473      c = *ps;
     474    }
     475    if (!c || c < '0' || c > '9') {
     476      // return NaN
     477      res = 0x7c00000000000000ull | sign_x;
     478      BID_RETURN (res);
     479    }
     480  
     481    while (c >= '0' && c <= '9') {
     482      expon_x = (expon_x << 1) + (expon_x << 3);
     483      expon_x += (int) (c - '0');
     484  
     485      ps++;
     486      c = *ps;
     487    }
     488  
     489    if (c) {
     490      // return NaN
     491      res = 0x7c00000000000000ull | sign_x;
     492      BID_RETURN (res);
     493    }
     494  
     495    if (sgn_expon)
     496      expon_x = -expon_x;
     497  
     498    expon_x += add_expon + DECIMAL_EXPONENT_BIAS;
     499  
     500    if (expon_x < 0) {
     501      if (rounded_up)
     502        coefficient_x--;
     503      rnd_mode = 0;
     504      res =
     505        get_BID64_UF (sign_x, expon_x, coefficient_x, rounded, rnd_mode,
     506  		    &fpsc);
     507      BID_RETURN (res);
     508    }
     509    res = get_BID64 (sign_x, expon_x, coefficient_x, rnd_mode, &fpsc);
     510    BID_RETURN (res);
     511  }