/******************************************************************************* * This file is part of SWIFT. * Copyright (c) 2016 Pedro Gonnet (pedro.gonnet@durham.ac.uk) * Matthieu Schaller (schaller@strw.leidenuniv.nl) * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License * along with this program. If not, see . * ******************************************************************************/ #ifndef SWIFT_CBRT_H #define SWIFT_CBRT_H /* Config parameters. */ #include /* Some standard headers. */ #include /* Local headers. */ #include "inline.h" /** * @brief Compute the inverse cube root of a single-precision floating-point * number. * * This function does not care about non-finite inputs. * * @warning This function is faster than both gcc and Intel's `cbrtf()` * functions on x86 systems. However, Other compilers or other architectures * may have faster implementations of the standard function `cbrtf()` that * will potentionally outperform this function. * * @param x_in The input value. * * @return The inverse cubic root of @c x_in (i.e. \f$x_{in}^{-1/3} \f$) . */ __attribute__((always_inline)) INLINE static float icbrtf(float x_in) { union { float as_float; unsigned int as_uint; int as_int; } cast; /* Extract the exponent. */ cast.as_float = x_in; const int exponent = ((cast.as_int & 0x7f800000) >> 23) - 127; /* Clear the exponent and sign to get the mantissa. */ cast.as_uint = (cast.as_uint & ~0xff800000) | 0x3f800000; const float x_norm = cast.as_float; /* Multiply by sqrt(1/2) and subtract one, should then be in the range [sqrt(1/2) - 1, sqrt(2) - 1). */ const float x = x_norm * (float)M_SQRT1_2 - 1.0f; /* Compute the polynomial interpolant. */ float res = 9.99976591940035e-01f + x * (-3.32901212909283e-01f + x * (2.24361110929912e-01f + x * (-1.88913279594895e-01f + x * 1.28384036492344e-01f))); /* Compute the new exponent and the correction factor. */ int exponent_new = exponent; if (exponent_new < 0) exponent_new -= 2; exponent_new = -exponent_new / 3; const int exponent_rem = exponent + 3 * exponent_new; cast.as_uint = (exponent_new + 127) << 23; static const float scale[3] = {8.90898718140339e-01f, 7.07106781186548e-01f, 5.61231024154687e-01f}; const float exponent_scale = cast.as_float * scale[exponent_rem]; /* Scale the result and set the correct sign. */ res = copysignf(res * exponent_scale, x_in); /* One step of Newton iteration to refine the result. */ res *= (1.0f / 3.0f) * (4.0f - x_in * res * res * res); /* We're done. */ return res; } #endif /* SWIFT_CBRT_H */