diff options
Diffstat (limited to 'REORG.TODO/math/fromfp.h')
-rw-r--r-- | REORG.TODO/math/fromfp.h | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/REORG.TODO/math/fromfp.h b/REORG.TODO/math/fromfp.h new file mode 100644 index 0000000000..db60a00491 --- /dev/null +++ b/REORG.TODO/math/fromfp.h @@ -0,0 +1,174 @@ +/* Round to integer type. Common helper functions. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fenv.h> +#include <float.h> +#include <math.h> +#include <math_private.h> +#include <stdbool.h> +#include <stdint.h> + +/* The including file should have defined UNSIGNED to 0 (signed return + type) or 1 (unsigned return type), INEXACT to 0 (no inexact + exceptions) or 1 (raise inexact exceptions) and RET_TYPE to the + return type (intmax_t or uintmax_t). */ + +/* Return the maximum unbiased exponent for an argument (negative if + NEGATIVE is set) that might be in range for a call to a fromfp + function with width WIDTH (greater than 0, and not exceeding that + of intmax_t). The truncated argument may still be out of range in + the case of negative arguments, and if not out of range it may + become out of range as a result of rounding. */ + +static int +fromfp_max_exponent (bool negative, int width) +{ + if (UNSIGNED) + return negative ? -1 : width - 1; + else + return negative ? width - 1 : width - 2; +} + +/* Return the result of rounding an integer value X (passed as the + absolute value; NEGATIVE is true if the value is negative), where + HALF_BIT is true if the bit with value 0.5 is set and MORE_BITS is + true if any lower bits are set, in the rounding direction + ROUND. */ + +static uintmax_t +fromfp_round (bool negative, uintmax_t x, bool half_bit, bool more_bits, + int round) +{ + switch (round) + { + case FP_INT_UPWARD: + return x + (!negative && (half_bit || more_bits)); + + case FP_INT_DOWNWARD: + return x + (negative && (half_bit || more_bits)); + + case FP_INT_TOWARDZERO: + default: + /* Unknown rounding directions are defined to mean unspecified + rounding; treat this as truncation. */ + return x; + + case FP_INT_TONEARESTFROMZERO: + return x + half_bit; + + case FP_INT_TONEAREST: + return x + (half_bit && ((x & 1) || more_bits)); + } +} + +/* Integer rounding, of a value whose exponent EXPONENT did not exceed + the maximum exponent MAX_EXPONENT and so did not necessarily + overflow, has produced X (possibly wrapping to 0); the sign is + negative if NEGATIVE is true. Return whether this overflowed the + allowed width. */ + +static bool +fromfp_overflowed (bool negative, uintmax_t x, int exponent, int max_exponent) +{ + if (UNSIGNED) + { + if (negative) + return x != 0; + else if (max_exponent == INTMAX_WIDTH - 1) + return exponent == INTMAX_WIDTH - 1 && x == 0; + else + return x == (1ULL << (max_exponent + 1)); + } + else + { + if (negative) + return exponent == max_exponent && x != (1ULL << max_exponent); + else + return x == (1ULL << (max_exponent + 1)); + } +} + +/* Handle a domain error for a call to a fromfp function with an + argument which is negative if NEGATIVE is set, and specified width + (not exceeding that of intmax_t) WIDTH. The return value is + unspecified (with it being unclear if the result needs to fit + within WIDTH bits in this case); we choose to saturate to the given + number of bits (treating NaNs like any other value). */ + +static RET_TYPE +fromfp_domain_error (bool negative, unsigned int width) +{ + feraiseexcept (FE_INVALID); + __set_errno (EDOM); + /* The return value is unspecified; we choose to saturate to the + given number of bits (treating NaNs like any other value). */ + if (UNSIGNED) + { + if (negative) + return 0; + else if (width == INTMAX_WIDTH) + return -1; + else + return (1ULL << width) - 1; + } + else + { + if (width == 0) + return 0; + else if (negative) + return -(1ULL << (width - 1)); + else + return (1ULL << (width - 1)) - 1; + } +} + +/* Given X, the absolute value of a floating-point number (negative if + NEGATIVE is set) truncated towards zero, where HALF_BIT is true if + the bit with value 0.5 is set and MORE_BITS is true if any lower + bits are set, round it in the rounding direction ROUND, handle + errors and exceptions and return the appropriate return value for a + fromfp function. X originally had floating-point exponent + EXPONENT, which does not exceed MAX_EXPONENT, the return value from + fromfp_max_exponent with width WIDTH. */ + +static RET_TYPE +fromfp_round_and_return (bool negative, uintmax_t x, bool half_bit, + bool more_bits, int round, int exponent, + int max_exponent, unsigned int width) +{ + uintmax_t uret = fromfp_round (negative, x, half_bit, more_bits, round); + if (fromfp_overflowed (negative, uret, exponent, max_exponent)) + return fromfp_domain_error (negative, width); + + if (INEXACT && (half_bit || more_bits)) + { + /* There is no need for this to use the specific floating-point + type for which this header is included, and there is no need + for this header to know that type at all, so just use float + here. */ + float force_inexact = 1.0f + FLT_MIN; + math_force_eval (force_inexact); + } + if (UNSIGNED) + /* A negative argument not rounding to zero will already have + produced a domain error. */ + return uret; + else + return negative ? -uret : uret; +} |