(root)/
gcc-13.2.0/
libgcc/
config/
libbid/
bid_from_int.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 "bid_internal.h"
      25  
      26  /*****************************************************************************
      27   *  BID64_round_integral_exact
      28   ****************************************************************************/
      29  
      30  #if DECIMAL_CALL_BY_REFERENCE
      31  void
      32  bid64_from_int32 (UINT64 * pres,
      33  		  int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
      34    int x = *px;
      35  #else
      36  UINT64
      37  bid64_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
      38  #endif
      39    UINT64 res;
      40  
      41    // if integer is negative, put the absolute value
      42    // in the lowest 32bits of the result
      43    if ((x & SIGNMASK32) == SIGNMASK32) {
      44      // negative int32
      45      x = ~x + 1;	// 2's complement of x
      46      res = (unsigned int) x | 0xb1c0000000000000ull;
      47      // (exp << 53)) = biased exp. is 0
      48    } else {	// positive int32
      49      res = x | 0x31c0000000000000ull;	// (exp << 53)) = biased exp. is 0
      50    }
      51    BID_RETURN (res);
      52  }
      53  
      54  #if DECIMAL_CALL_BY_REFERENCE
      55  void
      56  bid64_from_uint32 (UINT64 * pres, unsigned int *px
      57  		   _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
      58    unsigned int x = *px;
      59  #else
      60  UINT64
      61  bid64_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
      62  #endif
      63    UINT64 res;
      64  
      65    res = x | 0x31c0000000000000ull;	// (exp << 53)) = biased exp. is 0
      66    BID_RETURN (res);
      67  }
      68  
      69  #if DECIMAL_CALL_BY_REFERENCE
      70  void
      71  bid64_from_int64 (UINT64 * pres, SINT64 * px
      72  		  _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
      73  		  _EXC_INFO_PARAM) {
      74    SINT64 x = *px;
      75  #if !DECIMAL_GLOBAL_ROUNDING
      76    unsigned int rnd_mode = *prnd_mode;
      77  #endif
      78  #else
      79  UINT64
      80  bid64_from_int64 (SINT64 x
      81  		  _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
      82  		  _EXC_INFO_PARAM) {
      83  #endif
      84  
      85    UINT64 res;
      86    UINT64 x_sign, C;
      87    unsigned int q, ind;
      88    int incr_exp = 0;
      89    int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0;
      90    int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
      91  
      92    x_sign = x & 0x8000000000000000ull;
      93    // if the integer is negative, use the absolute value
      94    if (x_sign)
      95      C = ~((UINT64) x) + 1;
      96    else
      97      C = x;
      98    if (C <= BID64_SIG_MAX) {	// |C| <= 10^16-1 and the result is exact
      99      if (C < 0x0020000000000000ull) {	// C < 2^53
     100        res = x_sign | 0x31c0000000000000ull | C;
     101      } else {	// C >= 2^53
     102        res =
     103  	x_sign | 0x6c70000000000000ull | (C & 0x0007ffffffffffffull);
     104      }
     105    } else {	// |C| >= 10^16 and the result may be inexact 
     106      // the smallest |C| is 10^16 which has 17 decimal digits
     107      // the largest |C| is 0x8000000000000000 = 9223372036854775808 w/ 19 digits
     108      if (C < 0x16345785d8a0000ull) {	// x < 10^17 
     109        q = 17;
     110        ind = 1;	// number of digits to remove for q = 17
     111      } else if (C < 0xde0b6b3a7640000ull) {	// C < 10^18
     112        q = 18;
     113        ind = 2;	// number of digits to remove for q = 18 
     114      } else {	// C < 10^19
     115        q = 19;
     116        ind = 3;	// number of digits to remove for q = 19
     117      }
     118      // overflow and underflow are not possible
     119      // Note: performace can be improved by inlining this call
     120      round64_2_18 (	// will work for 19 digits too if C fits in 64 bits
     121  		   q, ind, C, &res, &incr_exp,
     122  		   &is_midpoint_lt_even, &is_midpoint_gt_even,
     123  		   &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
     124      if (incr_exp)
     125        ind++;
     126      // set the inexact flag
     127      if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
     128  	is_midpoint_lt_even || is_midpoint_gt_even)
     129        *pfpsf |= INEXACT_EXCEPTION;
     130      // general correction from RN to RA, RM, RP, RZ; result uses ind for exp
     131      if (rnd_mode != ROUNDING_TO_NEAREST) {
     132        if ((!x_sign
     133  	   && ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint)
     134  	       ||
     135  	       ((rnd_mode == ROUNDING_TIES_AWAY
     136  		 || rnd_mode == ROUNDING_UP) && is_midpoint_gt_even)))
     137  	  || (x_sign
     138  	      && ((rnd_mode == ROUNDING_DOWN && is_inexact_lt_midpoint)
     139  		  ||
     140  		  ((rnd_mode == ROUNDING_TIES_AWAY
     141  		    || rnd_mode == ROUNDING_DOWN)
     142  		   && is_midpoint_gt_even)))) {
     143  	res = res + 1;
     144  	if (res == 0x002386f26fc10000ull) {	// res = 10^16 => rounding overflow
     145  	  res = 0x00038d7ea4c68000ull;	// 10^15
     146  	  ind = ind + 1;
     147  	}
     148        } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) &&
     149  		 ((x_sign && (rnd_mode == ROUNDING_UP ||
     150  			      rnd_mode == ROUNDING_TO_ZERO)) ||
     151  		  (!x_sign && (rnd_mode == ROUNDING_DOWN ||
     152  			       rnd_mode == ROUNDING_TO_ZERO)))) {
     153  	res = res - 1;
     154  	// check if we crossed into the lower decade
     155  	if (res == 0x00038d7ea4c67fffull) {	// 10^15 - 1
     156  	  res = 0x002386f26fc0ffffull;	// 10^16 - 1
     157  	  ind = ind - 1;
     158  	}
     159        } else {
     160  	;	// exact, the result is already correct
     161        }
     162      }
     163      if (res < 0x0020000000000000ull) {	// res < 2^53
     164        res = x_sign | (((UINT64) ind + 398) << 53) | res;
     165      } else {	// res >= 2^53 
     166        res =
     167  	x_sign | 0x6000000000000000ull | (((UINT64) ind + 398) << 51) |
     168  	(res & 0x0007ffffffffffffull);
     169      }
     170    }
     171    BID_RETURN (res);
     172  }
     173  
     174  #if DECIMAL_CALL_BY_REFERENCE
     175  void
     176  bid64_from_uint64 (UINT64 * pres, UINT64 * px
     177  		   _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
     178  		   _EXC_INFO_PARAM) {
     179    UINT64 x = *px;
     180  #if !DECIMAL_GLOBAL_ROUNDING
     181    unsigned int rnd_mode = *prnd_mode;
     182  #endif
     183  #else
     184  UINT64
     185  bid64_from_uint64 (UINT64 x
     186  		   _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
     187  		   _EXC_INFO_PARAM) {
     188  #endif
     189  
     190    UINT64 res;
     191    UINT128 x128, res128;
     192    unsigned int q, ind;
     193    int incr_exp = 0;
     194    int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0;
     195    int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
     196  
     197    if (x <= BID64_SIG_MAX) {	// x <= 10^16-1 and the result is exact
     198      if (x < 0x0020000000000000ull) {	// x < 2^53
     199        res = 0x31c0000000000000ull | x;
     200      } else {	// x >= 2^53
     201        res = 0x6c70000000000000ull | (x & 0x0007ffffffffffffull);
     202      }
     203    } else {	// x >= 10^16 and the result may be inexact 
     204      // the smallest x is 10^16 which has 17 decimal digits
     205      // the largest x is 0xffffffffffffffff = 18446744073709551615 w/ 20 digits
     206      if (x < 0x16345785d8a0000ull) {	// x < 10^17 
     207        q = 17;
     208        ind = 1;	// number of digits to remove for q = 17
     209      } else if (x < 0xde0b6b3a7640000ull) {	// x < 10^18
     210        q = 18;
     211        ind = 2;	// number of digits to remove for q = 18 
     212      } else if (x < 0x8ac7230489e80000ull) {	// x < 10^19
     213        q = 19;
     214        ind = 3;	// number of digits to remove for q = 19
     215      } else {	// x < 10^20
     216        q = 20;
     217        ind = 4;	// number of digits to remove for q = 20
     218      }
     219      // overflow and underflow are not possible
     220      // Note: performace can be improved by inlining this call
     221      if (q <= 19) {
     222        round64_2_18 (	// will work for 20 digits too if x fits in 64 bits
     223  		     q, ind, x, &res, &incr_exp,
     224  		     &is_midpoint_lt_even, &is_midpoint_gt_even,
     225  		     &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
     226      } else {	// q = 20
     227        x128.w[1] = 0x0;
     228        x128.w[0] = x;
     229        round128_19_38 (q, ind, x128, &res128, &incr_exp,
     230  		      &is_midpoint_lt_even, &is_midpoint_gt_even,
     231  		      &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
     232        res = res128.w[0];	// res.w[1] is 0
     233      }
     234      if (incr_exp)
     235        ind++;
     236      // set the inexact flag
     237      if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
     238  	is_midpoint_lt_even || is_midpoint_gt_even)
     239        *pfpsf |= INEXACT_EXCEPTION;
     240      // general correction from RN to RA, RM, RP, RZ; result uses ind for exp
     241      if (rnd_mode != ROUNDING_TO_NEAREST) {
     242        if ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint) ||
     243  	  ((rnd_mode == ROUNDING_TIES_AWAY || rnd_mode == ROUNDING_UP)
     244  	   && is_midpoint_gt_even)) {
     245  	res = res + 1;
     246  	if (res == 0x002386f26fc10000ull) {	// res = 10^16 => rounding overflow
     247  	  res = 0x00038d7ea4c68000ull;	// 10^15
     248  	  ind = ind + 1;
     249  	}
     250        } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) &&
     251  		 (rnd_mode == ROUNDING_DOWN ||
     252  		  rnd_mode == ROUNDING_TO_ZERO)) {
     253  	res = res - 1;
     254  	// check if we crossed into the lower decade
     255  	if (res == 0x00038d7ea4c67fffull) {	// 10^15 - 1
     256  	  res = 0x002386f26fc0ffffull;	// 10^16 - 1
     257  	  ind = ind - 1;
     258  	}
     259        } else {
     260  	;	// exact, the result is already correct
     261        }
     262      }
     263      if (res < 0x0020000000000000ull) {	// res < 2^53
     264        res = (((UINT64) ind + 398) << 53) | res;
     265      } else {	// res >= 2^53 
     266        res = 0x6000000000000000ull | (((UINT64) ind + 398) << 51) |
     267  	(res & 0x0007ffffffffffffull);
     268      }
     269    }
     270    BID_RETURN (res);
     271  }
     272  
     273  #if DECIMAL_CALL_BY_REFERENCE
     274  void
     275  bid128_from_int32 (UINT128 * pres,
     276  		   int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
     277    int x = *px;
     278  #else
     279  UINT128
     280  bid128_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
     281  #endif
     282    UINT128 res;
     283  
     284    // if integer is negative, use the absolute value
     285    if ((x & SIGNMASK32) == SIGNMASK32) {
     286      res.w[HIGH_128W] = 0xb040000000000000ull;
     287      res.w[LOW_128W] = ~((unsigned int) x) + 1;	// 2's complement of x
     288    } else {
     289      res.w[HIGH_128W] = 0x3040000000000000ull;
     290      res.w[LOW_128W] = (unsigned int) x;
     291    }
     292    BID_RETURN (res);
     293  }
     294  
     295  #if DECIMAL_CALL_BY_REFERENCE
     296  void
     297  bid128_from_uint32 (UINT128 * pres, unsigned int *px
     298  		    _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
     299    unsigned int x = *px;
     300  #else
     301  UINT128
     302  bid128_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
     303  #endif
     304    UINT128 res;
     305  
     306    res.w[HIGH_128W] = 0x3040000000000000ull;
     307    res.w[LOW_128W] = x;
     308    BID_RETURN (res);
     309  }
     310  
     311  #if DECIMAL_CALL_BY_REFERENCE
     312  void
     313  bid128_from_int64 (UINT128 * pres, SINT64 * px
     314  		   _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
     315    SINT64 x = *px;
     316  #else
     317  UINT128
     318  bid128_from_int64 (SINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
     319  #endif
     320  
     321    UINT128 res;
     322  
     323    // if integer is negative, use the absolute value
     324    if ((x & SIGNMASK64) == SIGNMASK64) {
     325      res.w[HIGH_128W] = 0xb040000000000000ull;
     326      res.w[LOW_128W] = ~x + 1;	// 2's complement of x
     327    } else {
     328      res.w[HIGH_128W] = 0x3040000000000000ull;
     329      res.w[LOW_128W] = x;
     330    }
     331    BID_RETURN (res);
     332  }
     333  
     334  #if DECIMAL_CALL_BY_REFERENCE
     335  void
     336  bid128_from_uint64 (UINT128 * pres, UINT64 * px
     337  		    _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
     338    UINT64 x = *px;
     339  #else
     340  UINT128
     341  bid128_from_uint64 (UINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
     342  #endif
     343  
     344    UINT128 res;
     345  
     346    res.w[HIGH_128W] = 0x3040000000000000ull;
     347    res.w[LOW_128W] = x;
     348    BID_RETURN (res);
     349  }