(root)/
gawk-5.2.2/
floatcomp.c
       1  /*
       2   * floatcomp.c - Isolate floating point details.
       3   */
       4  
       5  /*
       6   * Copyright (C) 1986, 1988, 1989, 1991-2011, 2016, 2021,
       7   * the Free Software Foundation, Inc.
       8   *
       9   * This file is part of GAWK, the GNU implementation of the
      10   * AWK Programming Language.
      11   *
      12   * GAWK is free software; you can redistribute it and/or modify
      13   * it under the terms of the GNU General Public License as published by
      14   * the Free Software Foundation; either version 3 of the License, or
      15   * (at your option) any later version.
      16   *
      17   * GAWK is distributed in the hope that it will be useful,
      18   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      19   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20   * GNU General Public License for more details.
      21   *
      22   * You should have received a copy of the GNU General Public License
      23   * along with this program; if not, write to the Free Software
      24   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
      25   */
      26  
      27  #include "awk.h"
      28  
      29  #ifdef HAVE_UINTMAX_T
      30  
      31  /* Assume IEEE-754 arithmetic on pre-C89 hosts.  */
      32  #ifndef FLT_RADIX
      33  #define FLT_RADIX 2
      34  #endif
      35  #ifndef FLT_MANT_DIG
      36  #define FLT_MANT_DIG 24
      37  #endif
      38  #ifndef DBL_MANT_DIG
      39  #define DBL_MANT_DIG 53
      40  #endif
      41  
      42  /*
      43   * The number of base-FLT_RADIX digits in an AWKNUM fraction, assuming
      44   * that AWKNUM is not long double.
      45   */
      46  #define AWKSMALL_MANT_DIG \
      47    (sizeof (AWKNUM) == sizeof (double) ? DBL_MANT_DIG : FLT_MANT_DIG)
      48  
      49  /*
      50   * The number of base-FLT_DIGIT digits in an AWKNUM fraction, even if
      51   * AWKNUM is long double.  Don't mention 'long double' unless
      52   * LDBL_MANT_DIG is defined, for the sake of ancient compilers that
      53   * lack 'long double'.
      54   */
      55  #ifdef LDBL_MANT_DIG
      56  #define AWKNUM_MANT_DIG \
      57    (sizeof (AWKNUM) == sizeof (long double) ? LDBL_MANT_DIG : AWKSMALL_MANT_DIG)
      58  #else
      59  #define AWKNUM_MANT_DIG AWKSMALL_MANT_DIG
      60  #endif
      61  
      62  /*
      63   * The number of bits in an AWKNUM fraction, assuming FLT_RADIX is
      64   * either 2 or 16.  IEEE and VAX formats use radix 2, and IBM
      65   * mainframe format uses radix 16; we know of no other radices in
      66   * practical use.
      67   */
      68  #if FLT_RADIX != 2 && FLT_RADIX != 16
      69  Please port the following code to your weird host;
      70  #endif
      71  #define AWKNUM_FRACTION_BITS (AWKNUM_MANT_DIG * (FLT_RADIX == 2 ? 1 : 4))
      72  #define DBL_FRACTION_BITS (DBL_MANT_DIG * (FLT_RADIX == 2 ? 1 : 4))
      73  
      74  /* Return the number of trailing zeros in N.  N must be nonzero.  */
      75  static int
      76  count_trailing_zeros(uintmax_t n)
      77  {
      78  #if 3 < (__GNUC__ + (4 <= __GNUC_MINOR__)) && UINTMAX_MAX <= ULLONG_MAX
      79  	return __builtin_ctzll(n);
      80  #else
      81  	int i = 0;
      82  	for (; (n & 3) == 0; n >>= 2)
      83  		i += 2;
      84  	return i + (1 & ~n);
      85  #endif
      86  }
      87  
      88  /* adjust_uint --- fiddle with values, ask Paul Eggert to explain */
      89  
      90  uintmax_t
      91  adjust_uint(uintmax_t n)
      92  {
      93  	/*
      94  	 * If uintmax_t is so wide that AWKNUM cannot represent all its
      95  	 * values, strip leading nonzero bits of integers that are so large
      96  	 * that they cannot be represented exactly as AWKNUMs, so that their
      97  	 * low order bits are represented exactly, without rounding errors.
      98  	 * This is more desirable in practice, since it means the user sees
      99  	 * integers that are the same width as the AWKNUM fractions.
     100  	 */
     101  	int wordbits = CHAR_BIT * sizeof n;
     102  	if (AWKNUM_FRACTION_BITS < wordbits) {
     103  		uintmax_t one = 1;
     104  		uintmax_t sentinel = one << (wordbits - AWKNUM_FRACTION_BITS);
     105  		int shift = count_trailing_zeros(n | sentinel);
     106  		uintmax_t mask = (one << AWKNUM_FRACTION_BITS) - 1;
     107  
     108  		n &= mask << shift;
     109  	}
     110  
     111  	return n;
     112  }
     113  #endif /* HAVE_UINTMAX_T */