mirror of git://sourceware.org/git/glibc.git
118 lines
3.5 KiB
C
118 lines
3.5 KiB
C
/* Round to integer type (C23 version). Common helper functions.
|
|
Copyright (C) 2016-2025 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
|
|
<https://www.gnu.org/licenses/>. */
|
|
|
|
#include <errno.h>
|
|
#include <fenv.h>
|
|
#include <float.h>
|
|
#include <math.h>
|
|
#include <math-barriers.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), FLOAT to the floating
|
|
type for the function being defined, PREFIX to the prefix of
|
|
<float.h> macros for that type and SUFFIX to the suffix of <math.h>
|
|
functions for that type. */
|
|
|
|
#define M_CONCATX(X, Y) X ## Y
|
|
#define M_CONCAT(X, Y) M_CONCATX (X, Y)
|
|
#define M_SUF(F) M_CONCAT (F, SUFFIX)
|
|
#define M_MAX_EXP M_CONCAT (PREFIX, MAX_EXP)
|
|
|
|
/* Adjust WIDTH into a range sufficient to cover all possible finite
|
|
results from calls to this function. */
|
|
|
|
static unsigned int
|
|
fromfp_adjust_width (unsigned int width)
|
|
{
|
|
if (width > (UNSIGNED ? M_MAX_EXP : M_MAX_EXP + 1))
|
|
return UNSIGNED ? M_MAX_EXP : M_MAX_EXP + 1;
|
|
return width;
|
|
}
|
|
|
|
/* Return the maximum unbiased exponent for a rounded result (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
|
|
returned by fromfp_adjust_width). The result may still be out of
|
|
range in the case of negative arguments. */
|
|
|
|
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 argument X in the rounding
|
|
direction ROUND. */
|
|
|
|
static FLOAT
|
|
fromfp_round (FLOAT x, int rm)
|
|
{
|
|
switch (rm)
|
|
{
|
|
case FP_INT_UPWARD:
|
|
return M_SUF (ceil) (x);
|
|
|
|
case FP_INT_DOWNWARD:
|
|
return M_SUF (floor) (x);
|
|
|
|
case FP_INT_TOWARDZERO:
|
|
default:
|
|
/* Unknown rounding directions are defined to mean unspecified
|
|
rounding; treat this as truncation. */
|
|
return M_SUF (trunc) (x);
|
|
|
|
case FP_INT_TONEARESTFROMZERO:
|
|
return M_SUF (round) (x);
|
|
|
|
case FP_INT_TONEAREST:
|
|
return M_SUF (roundeven) (x);
|
|
}
|
|
}
|
|
|
|
/* Handle a domain error for a call to a fromfp function. */
|
|
|
|
static FLOAT
|
|
fromfp_domain_error (void)
|
|
{
|
|
__set_errno (EDOM);
|
|
return (FLOAT) 0 / (FLOAT) 0;
|
|
}
|
|
|
|
/* X has rounded to RX, which is within range. Return RX, with
|
|
"inexact" raised if appropriate. */
|
|
|
|
static FLOAT
|
|
fromfp_return (FLOAT x, FLOAT rx)
|
|
{
|
|
if (INEXACT && rx != x)
|
|
{
|
|
/* There is no need for this to use the specific floating-point
|
|
type for which this header is included (and indeed 1 +
|
|
LDBL_MIN may not raise "inexact" for IBM long double). */
|
|
float force_inexact = 1.0f + FLT_MIN;
|
|
math_force_eval (force_inexact);
|
|
}
|
|
return rx;
|
|
}
|