/* Return X^Y for integer Y. Copyright (C) 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 . */ #include #include #include #include #include #include #include #include FLOAT M_DECL_FUNC (__pown) (FLOAT x, long long int y) { FLOAT ret; #if M_MANT_DIG >= LLONG_WIDTH - 1 ret = M_SUF (__ieee754_pow) (x, y); #else if ((y <= 1LL << M_MANT_DIG && y >= -(1LL << M_MANT_DIG)) || y == LLONG_MIN) ret = M_SUF (__ieee754_pow) (x, y); else { { /* To avoid problems with overflow and underflow from intermediate computations occurring in the wrong directed rounding mode (when X is negative and Y is odd), do these computations in round-to-nearest mode and correct overflowing and underflowing results afterwards. */ M_SET_RESTORE_ROUND (FE_TONEAREST); ret = M_LIT (1.0); while (y != 0) { long long int absy = llabs (y); int bits = LLONG_WIDTH - __builtin_clzll (absy); if (bits <= M_MANT_DIG) { ret *= M_SUF (__ieee754_pow) (x, y); y = 0; } else { long long int absy_high = absy & (((1ULL << M_MANT_DIG) - 1) << (bits - M_MANT_DIG)); long long int absy_low = absy - absy_high; long long int y_high = y < 0 ? -absy_high : absy_high; ret *= M_SUF (__ieee754_pow) (x, y_high); y = y < 0 ? -absy_low : absy_low; } } ret = math_narrow_eval (ret); math_force_eval (ret); } if (isfinite (x) && x != M_LIT (0.0)) { if (isinf (ret)) ret = math_narrow_eval (M_COPYSIGN (M_MAX, ret) * M_MAX); else if (ret == M_LIT (0.0)) ret = math_narrow_eval (M_COPYSIGN (M_MIN, ret) * M_MIN); } } #endif if (!isfinite (ret)) { if (isfinite (x)) __set_errno (ERANGE); } else if (ret == 0 && isfinite (x) && x != 0) __set_errno (ERANGE); return ret; } declare_mgen_alias (__pown, pown);