/* Implementation of various C99 functions Copyright (C) 2004 Free Software Foundation, Inc. This file is part of the GNU Fortran 95 runtime library (libgfortran). Libgfortran is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. In addition to the permissions in the GNU General Public License, the Free Software Foundation gives you unlimited permission to link the compiled version of this file into combinations with other programs, and to distribute those combinations without any restriction coming from the use of this file. (The General Public License restrictions do apply in other respects; for example, they cover modification of the file, and distribution when not linked into a combine executable.) Libgfortran 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 General Public License for more details. You should have received a copy of the GNU General Public License along with libgfortran; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #include "libgfortran.h" #ifndef HAVE_ACOSF float acosf(float x) { return (float) acos(x); } #endif #ifndef HAVE_ASINF float asinf(float x) { return (float) asin(x); } #endif #ifndef HAVE_ATAN2F float atan2f(float y, float x) { return (float) atan2(y, x); } #endif #ifndef HAVE_ATANF float atanf(float x) { return (float) atan(x); } #endif #ifndef HAVE_CEILF float ceilf(float x) { return (float) ceil(x); } #endif #ifndef HAVE_COPYSIGNF float copysignf(float x, float y) { return (float) copysign(x, y); } #endif #ifndef HAVE_COSF float cosf(float x) { return (float) cos(x); } #endif #ifndef HAVE_COSHF float coshf(float x) { return (float) cosh(x); } #endif #ifndef HAVE_EXPF float expf(float x) { return (float) exp(x); } #endif #ifndef HAVE_FABSF float fabsf(float x) { return (float) fabs(x); } #endif #ifndef HAVE_FLOORF float floorf(float x) { return (float) floor(x); } #endif #ifndef HAVE_FREXPF float frexpf(float x, int *exp) { return (float) frexp(x, exp); } #endif #ifndef HAVE_HYPOTF float hypotf(float x, float y) { return (float) hypot(x, y); } #endif #ifndef HAVE_LOGF float logf(float x) { return (float) log(x); } #endif #ifndef HAVE_LOG10F float log10f(float x) { return (float) log10(x); } #endif #ifndef HAVE_SCALBNF float scalbnf(float x, int y) { return (float) scalbn(x, y); } #endif #ifndef HAVE_SINF float sinf(float x) { return (float) sin(x); } #endif #ifndef HAVE_SINHF float sinhf(float x) { return (float) sinh(x); } #endif #ifndef HAVE_SQRTF float sqrtf(float x) { return (float) sqrt(x); } #endif #ifndef HAVE_TANF float tanf(float x) { return (float) tan(x); } #endif #ifndef HAVE_TANHF float tanhf(float x) { return (float) tanh(x); } #endif #ifndef HAVE_NEXTAFTERF /* This is a portable implementation of nextafterf that is intended to be independent of the floating point format or its in memory representation. This implementation works correctly with denormalized values. */ float nextafterf(float x, float y) { /* This variable is marked volatile to avoid excess precision problems on some platforms, including IA-32. */ volatile float delta; float absx, denorm_min; if (isnan(x) || isnan(y)) return x + y; if (x == y) return x; /* absx = fabsf (x); */ absx = (x < 0.0) ? -x : x; /* __FLT_DENORM_MIN__ is non-zero iff the target supports denormals. */ if (__FLT_DENORM_MIN__ == 0.0f) denorm_min = __FLT_MIN__; else denorm_min = __FLT_DENORM_MIN__; if (absx < __FLT_MIN__) delta = denorm_min; else { float frac; int exp; /* Discard the fraction from x. */ frac = frexpf (absx, &exp); delta = scalbnf (0.5f, exp); /* Scale x by the epsilon of the representation. By rights we should have been able to combine this with scalbnf, but some targets don't get that correct with denormals. */ delta *= __FLT_EPSILON__; /* If we're going to be reducing the absolute value of X, and doing so would reduce the exponent of X, then the delta to be applied is one exponent smaller. */ if (frac == 0.5f && (y < x) == (x > 0)) delta *= 0.5f; /* If that underflows to zero, then we're back to the minimum. */ if (delta == 0.0f) delta = denorm_min; } if (y < x) delta = -delta; return x + delta; } #endif #ifndef HAVE_POWF float powf(float x, float y) { return (float) pow(x, y); } #endif /* Note that if fpclassify is not defined, then NaN is not handled */ /* Algorithm by Steven G. Kargl. */ #ifndef HAVE_ROUND /* Round to nearest integral value. If the argument is halfway between two integral values then round away from zero. */ double round(double x) { double t; #if defined(fpclassify) int i; i = fpclassify(x); if (i == FP_INFINITE || i == FP_NAN) return (x); #endif if (x >= 0.0) { t = ceil(x); if (t - x > 0.5) t -= 1.0; return (t); } else { t = ceil(-x); if (t + x > 0.5) t -= 1.0; return (-t); } } #endif #ifndef HAVE_ROUNDF /* Round to nearest integral value. If the argument is halfway between two integral values then round away from zero. */ float roundf(float x) { float t; #if defined(fpclassify) int i; i = fpclassify(x); if (i == FP_INFINITE || i == FP_NAN) return (x); #endif if (x >= 0.0) { t = ceilf(x); if (t - x > 0.5) t -= 1.0; return (t); } else { t = ceilf(-x); if (t + x > 0.5) t -= 1.0; return (-t); } } #endif