1bbbf1280Sopenharmony_ci/* 2bbbf1280Sopenharmony_ci * Double-precision math error handling. 3bbbf1280Sopenharmony_ci * 4bbbf1280Sopenharmony_ci * Copyright (c) 2018, Arm Limited. 5bbbf1280Sopenharmony_ci * SPDX-License-Identifier: MIT 6bbbf1280Sopenharmony_ci */ 7bbbf1280Sopenharmony_ci 8bbbf1280Sopenharmony_ci#include "math_config.h" 9bbbf1280Sopenharmony_ci 10bbbf1280Sopenharmony_ci#if WANT_ERRNO 11bbbf1280Sopenharmony_ci#include <errno.h> 12bbbf1280Sopenharmony_ci/* NOINLINE reduces code size and avoids making math functions non-leaf 13bbbf1280Sopenharmony_ci when the error handling is inlined. */ 14bbbf1280Sopenharmony_ciNOINLINE static double 15bbbf1280Sopenharmony_ciwith_errno (double y, int e) 16bbbf1280Sopenharmony_ci{ 17bbbf1280Sopenharmony_ci errno = e; 18bbbf1280Sopenharmony_ci return y; 19bbbf1280Sopenharmony_ci} 20bbbf1280Sopenharmony_ci#else 21bbbf1280Sopenharmony_ci#define with_errno(x, e) (x) 22bbbf1280Sopenharmony_ci#endif 23bbbf1280Sopenharmony_ci 24bbbf1280Sopenharmony_ci/* NOINLINE reduces code size. */ 25bbbf1280Sopenharmony_ciNOINLINE static double 26bbbf1280Sopenharmony_cixflow (uint32_t sign, double y) 27bbbf1280Sopenharmony_ci{ 28bbbf1280Sopenharmony_ci y = eval_as_double (opt_barrier_double (sign ? -y : y) * y); 29bbbf1280Sopenharmony_ci return with_errno (y, ERANGE); 30bbbf1280Sopenharmony_ci} 31bbbf1280Sopenharmony_ci 32bbbf1280Sopenharmony_ciHIDDEN double 33bbbf1280Sopenharmony_ci__math_uflow (uint32_t sign) 34bbbf1280Sopenharmony_ci{ 35bbbf1280Sopenharmony_ci return xflow (sign, 0x1p-767); 36bbbf1280Sopenharmony_ci} 37bbbf1280Sopenharmony_ci 38bbbf1280Sopenharmony_ci#if WANT_ERRNO_UFLOW 39bbbf1280Sopenharmony_ci/* Underflows to zero in some non-nearest rounding mode, setting errno 40bbbf1280Sopenharmony_ci is valid even if the result is non-zero, but in the subnormal range. */ 41bbbf1280Sopenharmony_ciHIDDEN double 42bbbf1280Sopenharmony_ci__math_may_uflow (uint32_t sign) 43bbbf1280Sopenharmony_ci{ 44bbbf1280Sopenharmony_ci return xflow (sign, 0x1.8p-538); 45bbbf1280Sopenharmony_ci} 46bbbf1280Sopenharmony_ci#endif 47bbbf1280Sopenharmony_ci 48bbbf1280Sopenharmony_ciHIDDEN double 49bbbf1280Sopenharmony_ci__math_oflow (uint32_t sign) 50bbbf1280Sopenharmony_ci{ 51bbbf1280Sopenharmony_ci return xflow (sign, 0x1p769); 52bbbf1280Sopenharmony_ci} 53bbbf1280Sopenharmony_ci 54bbbf1280Sopenharmony_ciHIDDEN double 55bbbf1280Sopenharmony_ci__math_divzero (uint32_t sign) 56bbbf1280Sopenharmony_ci{ 57bbbf1280Sopenharmony_ci double y = opt_barrier_double (sign ? -1.0 : 1.0) / 0.0; 58bbbf1280Sopenharmony_ci return with_errno (y, ERANGE); 59bbbf1280Sopenharmony_ci} 60bbbf1280Sopenharmony_ci 61bbbf1280Sopenharmony_ciHIDDEN double 62bbbf1280Sopenharmony_ci__math_invalid (double x) 63bbbf1280Sopenharmony_ci{ 64bbbf1280Sopenharmony_ci double y = (x - x) / (x - x); 65bbbf1280Sopenharmony_ci return isnan (x) ? y : with_errno (y, EDOM); 66bbbf1280Sopenharmony_ci} 67bbbf1280Sopenharmony_ci 68bbbf1280Sopenharmony_ci/* Check result and set errno if necessary. */ 69bbbf1280Sopenharmony_ci 70bbbf1280Sopenharmony_ciHIDDEN double 71bbbf1280Sopenharmony_ci__math_check_uflow (double y) 72bbbf1280Sopenharmony_ci{ 73bbbf1280Sopenharmony_ci return y == 0.0 ? with_errno (y, ERANGE) : y; 74bbbf1280Sopenharmony_ci} 75bbbf1280Sopenharmony_ci 76bbbf1280Sopenharmony_ciHIDDEN double 77bbbf1280Sopenharmony_ci__math_check_oflow (double y) 78bbbf1280Sopenharmony_ci{ 79bbbf1280Sopenharmony_ci return isinf (y) ? with_errno (y, ERANGE) : y; 80bbbf1280Sopenharmony_ci} 81