/*******************************************************************************
* 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 */