2022-11-15 23:49:51 +00:00
|
|
|
/*
|
|
|
|
* Brickworks
|
|
|
|
*
|
2024-01-02 10:20:52 +00:00
|
|
|
* Copyright (C) 2021-2024 Orastron Srl unipersonale
|
2022-11-15 23:49:51 +00:00
|
|
|
*
|
|
|
|
* Brickworks 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, version 3 of the License.
|
|
|
|
*
|
|
|
|
* Brickworks 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
|
2022-12-06 08:01:34 +00:00
|
|
|
* along with Brickworks. If not, see <http://www.gnu.org/licenses/>.
|
2022-11-15 23:49:51 +00:00
|
|
|
*
|
|
|
|
* File author: Stefano D'Angelo
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* module_type {{{ utility }}}
|
2024-01-02 10:20:52 +00:00
|
|
|
* version {{{ 1.0.1 }}}
|
2023-07-21 06:56:27 +00:00
|
|
|
* requires {{{ bw_common }}}
|
2022-11-15 23:49:51 +00:00
|
|
|
* description {{{
|
|
|
|
* A collection of mathematical routines that strive to be better suited to
|
|
|
|
* DSP than, e.g., those supplied by your C standard library.
|
|
|
|
*
|
|
|
|
* Such a goal is hopefully accomplished by:
|
2023-08-09 11:11:09 +00:00
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* * being as branchless as reasonable/convenient;
|
2023-08-09 11:11:09 +00:00
|
|
|
* * not handling uninteresting corner cases, such as out-of-range,
|
|
|
|
* NaN, and sometimes infinity input values (out-of-range and NaN inputs
|
|
|
|
* are always considered invalid and lead to undefined behavior);
|
|
|
|
* * returning approximated results (indicated in this documentation);
|
|
|
|
* * making no distinction between `0.f` and `-0.f`.
|
2022-11-15 23:49:51 +00:00
|
|
|
*
|
|
|
|
* In practice they should guarantee fast and consistent performance, but
|
|
|
|
* always do your own benchmarking.
|
|
|
|
*
|
|
|
|
* All functions in this module are [reentrant](api#reentrant-function),
|
|
|
|
* [RT-safe](api#rt-safe-function), [thread-safe](api#thread-safe-function),
|
|
|
|
* and have [no side effects](api#no-side-effects).
|
|
|
|
* }}}
|
|
|
|
* changelog {{{
|
|
|
|
* <ul>
|
2024-01-02 10:20:52 +00:00
|
|
|
* <li>Version <strong>1.0.1</strong>:
|
|
|
|
* <ul>
|
|
|
|
* <li>Now using <code>BW_NULL</code>.</li>
|
2024-01-31 09:08:25 +00:00
|
|
|
* <li>Fixed sign-related warnings in <code>bw_truncf()</code>,
|
|
|
|
* <code>bw_roundf()</code>, and <code>bw_sqrtf()</code>.</li>
|
2024-01-02 10:20:52 +00:00
|
|
|
* </ul>
|
|
|
|
* </li>
|
2023-08-09 11:11:09 +00:00
|
|
|
* <li>Version <strong>1.0.0</strong>:
|
|
|
|
* <ul>
|
2023-08-10 05:48:14 +00:00
|
|
|
* <li>Renamed <code>bw_min0xf()</code> as <code>bw_min0f()</code> and
|
|
|
|
* <code>bw_max0xf()</code> as <code>bw_max0f()</code>.</li>
|
2023-08-10 06:00:44 +00:00
|
|
|
* <li>Removed precision suffixes from function names.</li>
|
2023-08-10 05:48:14 +00:00
|
|
|
* <li>New implementations for <code>bw_min0f()</code>,
|
|
|
|
* <code>bw_max0f()</code>, <code>bw_minf()</code>,
|
|
|
|
* <code>bw_maxf()</code>, and <code>bw_clipf()</code>.</li>
|
|
|
|
* <li>Fixed rounding bug in <code>bw_roundf()</code> when absolute
|
|
|
|
* value of input was in [<code>0.5f</code>,
|
|
|
|
* <code>1.f</code>].</li>
|
|
|
|
* <li>Fixed <code>bw_ceilf()</code> for negative input values.</li>
|
2023-08-11 08:15:43 +00:00
|
|
|
* <li>Fixed <code>bw_sqrtf()</code> for very large input values and
|
|
|
|
* improved implementation.</li>
|
|
|
|
* <li>Fixed input validity ranges in <code>bw_asinhf()</code> and
|
|
|
|
* <code>bw_acoshf()</code>.</li>
|
2023-08-14 07:57:06 +00:00
|
|
|
* <li>Added <code>BW_RESTRICT</code> specifiers to input
|
|
|
|
* arguments of <code>bw_intfracf()</code>.</li>
|
2023-08-10 05:48:14 +00:00
|
|
|
* <li>Removed usage of reserved identifiers and designated
|
|
|
|
* initializers.</li>
|
2023-08-11 10:49:05 +00:00
|
|
|
* <li>Added <code>extern "C"</code> to functions.</li>
|
2023-08-14 07:57:06 +00:00
|
|
|
* <li>Added more debugging checks in <code>bw_intfracf()</code>.</li>
|
2023-08-10 05:48:14 +00:00
|
|
|
* <li>Improved documentation w.r.t. validity of input values and
|
|
|
|
* approximation errors.</li>
|
2023-08-09 11:11:09 +00:00
|
|
|
* </ul>
|
|
|
|
* </li>
|
2023-07-21 06:56:27 +00:00
|
|
|
* <li>Version <strong>0.6.0</strong>:
|
|
|
|
* <ul>
|
2023-07-24 14:14:16 +00:00
|
|
|
* <li>Added debugging code.</li>
|
2023-07-21 06:56:27 +00:00
|
|
|
* <li>Removed dependency on bw_config.</li>
|
2023-07-24 14:14:16 +00:00
|
|
|
* <li>Removed <code>bw_omega_3log()</code> and
|
|
|
|
* <code>bw_omega_3lognr()</code>.
|
2023-07-24 14:39:57 +00:00
|
|
|
* <li>Fixed <code>bw_pow10f_3()</code> and
|
|
|
|
* <code>bw_acoshf_3()</code>.</li>
|
2023-07-21 06:56:27 +00:00
|
|
|
* </ul>
|
|
|
|
* </li>
|
2023-03-04 07:17:31 +00:00
|
|
|
* <li>Version <strong>0.4.0</strong>:
|
|
|
|
* <ul>
|
2023-04-19 23:46:41 +00:00
|
|
|
* <li>Added <code>bw_ceilf()</code>, <code>bw_intfracf()</code>,
|
|
|
|
* <code>bw_sinhf_3()</code>, <code>bw_coshf_3()</code>,
|
|
|
|
* <code>bw_asinhf_3()</code>, and <code>bw_acoshf_3()</code>.</li>
|
2023-03-04 07:17:31 +00:00
|
|
|
* </ul>
|
|
|
|
* </li>
|
2022-12-05 10:17:28 +00:00
|
|
|
* <li>Version <strong>0.3.0</strong>:
|
|
|
|
* <ul>
|
2023-04-19 23:46:41 +00:00
|
|
|
* <li>Added <code>bw_log10f_3()</code>, <code>bw_pow10f_3()</code>,
|
|
|
|
* <code>bw_dB2linf_3()</code>, and
|
|
|
|
* <code>bw_lin2dBf_3()</code>.</li>
|
|
|
|
* <li>Fixed computation bug in <code>bw_sqrtf_2()</code>.</li>
|
2022-12-05 10:17:28 +00:00
|
|
|
* </ul>
|
|
|
|
* </li>
|
|
|
|
* <li>Version <strong>0.2.0</strong>:
|
|
|
|
* <ul>
|
2023-04-19 23:46:41 +00:00
|
|
|
* <li>Added <code>bw_sin2pif_3()</code>, <code>bw_cos2pif_3()</code>,
|
|
|
|
* <code>bw_tan2pif_3()</code>, <code>bw_omega_3lognr()</code>, and
|
|
|
|
* <code>bw_tanhf_3()</code>.</li>
|
2022-12-05 10:17:28 +00:00
|
|
|
* </ul>
|
|
|
|
* </li>
|
2022-11-15 23:49:51 +00:00
|
|
|
* <li>Version <strong>0.1.0</strong>:
|
|
|
|
* <ul>
|
|
|
|
* <li>First release.</li>
|
|
|
|
* </ul>
|
|
|
|
* </li>
|
|
|
|
* </ul>
|
|
|
|
* }}}
|
|
|
|
*/
|
|
|
|
|
2023-08-09 11:11:09 +00:00
|
|
|
#ifndef BW_MATH_H
|
|
|
|
#define BW_MATH_H
|
2022-11-15 23:49:51 +00:00
|
|
|
|
2023-08-11 10:49:05 +00:00
|
|
|
#include <bw_common.h>
|
|
|
|
|
2022-11-15 23:49:51 +00:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2023-08-12 08:15:04 +00:00
|
|
|
/*** Public API ***/
|
|
|
|
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! api {{{
|
|
|
|
* #### bw_signfilli32()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline int32_t bw_signfilli32(
|
|
|
|
int32_t x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns `~0` if `x` is negative, `0` otherwise.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* #### bw_mini32()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline int32_t bw_mini32(
|
|
|
|
int32_t a,
|
|
|
|
int32_t b);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns the minimum of `a` and `b`.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* #### bw_maxi32()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline int32_t bw_maxi32(
|
|
|
|
int32_t a,
|
|
|
|
int32_t b);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns the maximum of `a` and `b`.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* #### bw_clipi32()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline int32_t bw_clipi32(
|
|
|
|
int32_t x,
|
|
|
|
int32_t m,
|
|
|
|
int32_t M);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns `x` unless it is smaller than `m`, in which case it returns `m`,
|
|
|
|
* or bigger than `M`, in which case it returns `M`.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* #### bw_minu32()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline uint32_t bw_minu32(
|
|
|
|
uint32_t a,
|
|
|
|
uint32_t b);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns the minimum of `a` and `b`.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* #### bw_maxu32()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline uint32_t bw_maxu32(
|
|
|
|
uint32_t a,
|
|
|
|
uint32_t b);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns the maximum of `a` and `b`.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* #### bw_clipu32()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline uint32_t bw_clipu32(
|
|
|
|
uint32_t x,
|
|
|
|
uint32_t m,
|
|
|
|
uint32_t M);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns `x` unless it is smaller than `m`, in which case it returns `m`,
|
|
|
|
* or bigger than `M`, in which case it returns `M`.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* #### bw_copysignf()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_copysignf(
|
|
|
|
float x,
|
|
|
|
float y);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns a value that has the absolute value of `x` and the sign of `y`.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* #### bw_signf()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_signf(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns `1.f` if `x > 0.f`, `-1.f` if `x < 0.f` and `0.f` if `x == 0.f`.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* #### bw_absf()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_absf(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns the absolute value of `x`.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2023-08-09 11:11:09 +00:00
|
|
|
* #### bw_min0f()
|
2022-11-15 23:49:51 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_min0f(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns the minimum of `0.f` and `x`.
|
|
|
|
*
|
2023-08-09 11:11:09 +00:00
|
|
|
* #### bw_max0f()
|
2022-11-15 23:49:51 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_max0f(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns the maximum of `0.f` and `x`.
|
|
|
|
*
|
|
|
|
* #### bw_minf()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_minf(
|
|
|
|
float a,
|
|
|
|
float b);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns the minimum of `a` and `b`.
|
|
|
|
*
|
|
|
|
* #### bw_maxf()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_maxf(
|
|
|
|
float a,
|
|
|
|
float b);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns the maximum of `a` and `b`.
|
|
|
|
*
|
|
|
|
* #### bw_clipf()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_clipf(
|
|
|
|
float x,
|
|
|
|
float m,
|
|
|
|
float M);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns `x` unless it is smaller than `m`, in which case it returns `m`,
|
|
|
|
* or bigger than `M`, in which case it returns `M`.
|
|
|
|
*
|
2023-08-09 11:11:09 +00:00
|
|
|
* `M` must be greater than or equal to `m`.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* #### bw_truncf()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_truncf(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns `x` with its fractional part set to zero (i.e., rounded towards
|
|
|
|
* zero).
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2023-08-09 11:11:09 +00:00
|
|
|
* `x` must be finite.
|
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* #### bw_roundf()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_roundf(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns `x` rounded to the nearest integer.
|
|
|
|
*
|
|
|
|
* Halfway cases are rounded away from zero. E.g., `bw_roundf(0.5f)` gives
|
|
|
|
* `1.f` and `bw_roundf(-0.5f)` gives `-1.f`.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2023-08-09 11:11:09 +00:00
|
|
|
* `x` must be finite.
|
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* #### bw_floorf()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_floorf(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
2023-03-04 07:17:31 +00:00
|
|
|
* Returns the biggest integer less or equal than `x` (i.e., `x` is rounded
|
2022-11-15 23:49:51 +00:00
|
|
|
* down).
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2023-08-09 11:11:09 +00:00
|
|
|
* `x` must be finite.
|
|
|
|
*
|
2023-03-04 07:17:31 +00:00
|
|
|
* #### bw_ceilf()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_ceilf(
|
|
|
|
float x);
|
2023-03-04 07:17:31 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns the smallest integer greater or equal than `x` (i.e., `x` is
|
|
|
|
* rounded up).
|
|
|
|
*
|
2023-08-09 11:11:09 +00:00
|
|
|
* `x` must be finite.
|
|
|
|
*
|
2023-04-05 09:56:42 +00:00
|
|
|
* #### bw_intfracf()
|
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline void bw_intfracf(
|
|
|
|
float x,
|
|
|
|
float * BW_RESTRICT i,
|
|
|
|
float * BW_RESTRICT f);
|
2023-04-05 09:56:42 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Puts the integer part (floor) of `x` in `i` and the fractional part in
|
|
|
|
* `f`.
|
|
|
|
*
|
2023-08-11 08:25:41 +00:00
|
|
|
* `x` must be finite.
|
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_rcpf()
|
2022-11-15 23:49:51 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_rcpf(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns the reciprocal of `x` (i.e., `1.f / x`).
|
|
|
|
*
|
2023-09-15 14:27:04 +00:00
|
|
|
* |`x`| must be in [`8.077935669463161e-28f`, `1.237940039285380e+27`].
|
2022-11-15 23:49:51 +00:00
|
|
|
*
|
|
|
|
* Relative error < 0.0013%.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_sin2pif()
|
2022-12-04 18:13:57 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_sin2pif(
|
|
|
|
float x);
|
2022-12-04 18:13:57 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the sine of 2 * pi * `x`, where `x` is given
|
|
|
|
* in radians.
|
|
|
|
*
|
2023-08-09 17:17:54 +00:00
|
|
|
* `x` must be finite.
|
|
|
|
*
|
2023-08-10 14:17:45 +00:00
|
|
|
* Absolute error < 0.011 or relative error < 1.7%, whatever is worse.
|
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_sinf()
|
2022-11-15 23:49:51 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_sinf(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the sine of `x`, where `x` is given in
|
|
|
|
* radians.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2023-08-09 17:17:54 +00:00
|
|
|
* `x` must be finite.
|
|
|
|
*
|
2023-08-10 14:17:45 +00:00
|
|
|
* Absolute error < 0.011 or relative error < 1.7%, whatever is worse.
|
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_cos2pif()
|
2022-12-04 18:13:57 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_cos2pif(
|
|
|
|
float x);
|
2022-12-04 18:13:57 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the cosine of 2 * pi * `x`, where `x` is given
|
|
|
|
* in radians.
|
|
|
|
*
|
2023-08-09 17:17:54 +00:00
|
|
|
* `x` must be finite.
|
2023-08-10 14:17:45 +00:00
|
|
|
*
|
|
|
|
* Absolute error < 0.011 or relative error < 1.7%, whatever is worse.
|
2023-08-09 17:17:54 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_cosf()
|
2022-11-15 23:49:51 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_cosf(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the cosine of `x`, where `x` is given in
|
|
|
|
* radians.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2023-08-09 17:17:54 +00:00
|
|
|
* `x` must be finite.
|
|
|
|
*
|
2023-08-10 14:17:45 +00:00
|
|
|
* Absolute error < 0.011 or relative error < 1.7%, whatever is worse.
|
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_tan2pif()
|
2022-12-04 18:13:57 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_tan2pif(
|
|
|
|
float x);
|
2022-12-04 18:13:57 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the tangent of 2 * pi * `x`, where `x` is
|
|
|
|
* given in radians.
|
|
|
|
*
|
2023-08-10 14:17:45 +00:00
|
|
|
* `x` must be finite and in [-1/4 + 5e-4f / pi, 1/4 - 5e-4f / pi] + k / 2,
|
|
|
|
* where k is any integer number.
|
|
|
|
*
|
2023-08-10 05:48:14 +00:00
|
|
|
* Absolute error < 0.06 or relative error < 0.8%, whatever is worse.
|
2022-12-04 18:13:57 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_tanf()
|
2022-11-15 23:49:51 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_tanf(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the tangent of `x`, where `x` is given in
|
|
|
|
* radians.
|
|
|
|
*
|
2023-08-10 14:17:45 +00:00
|
|
|
* `x` must be finite and in [-pi/2 + 1e-3f, pi/2 - 1e-3f] + k * pi, where k
|
|
|
|
* is any integer number.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2023-08-10 14:17:45 +00:00
|
|
|
* Absolute error < 0.06 or relative error < 0.8%, whatever is worse.
|
2023-08-09 17:17:54 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_log2f()
|
2022-11-15 23:49:51 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_log2f(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the base-2 logarithm of `x`.
|
2023-08-10 14:17:45 +00:00
|
|
|
*
|
|
|
|
* `x` must be finite and greater than or equal to `1.175494350822287e-38f`.
|
2022-11-15 23:49:51 +00:00
|
|
|
*
|
2023-08-10 14:17:45 +00:00
|
|
|
* Absolute error < 0.0055 or relative error < 1.2%, whatever is worse.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_logf()
|
2022-11-15 23:49:51 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_logf(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the natural logarithm of `x`.
|
|
|
|
*
|
2023-08-10 14:17:45 +00:00
|
|
|
* `x` must be finite and greater than or equal to `1.175494350822287e-38f`.
|
|
|
|
*
|
|
|
|
* Absolute error < 0.0038 or relative error < 1.2%, whatever is worse.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_log10f()
|
2022-12-05 10:17:28 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_log10f(
|
|
|
|
float x);
|
2022-12-05 10:17:28 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the base-10 logarithm of `x`.
|
2023-08-10 14:17:45 +00:00
|
|
|
*
|
|
|
|
* `x` must be finite and greater than or equal to `1.175494350822287e-38f`.
|
|
|
|
*
|
|
|
|
* Absolute error < 0.0017 or relative error < 1.2%, whatever is worse.
|
2022-12-05 10:17:28 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_pow2f()
|
2022-11-15 23:49:51 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_pow2f(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
2023-08-10 15:06:45 +00:00
|
|
|
* Returns an approximation of 2 raised to the power of `x`. For `x < -126.f`
|
|
|
|
* it just returns `0.f`.
|
|
|
|
*
|
|
|
|
* `x` must be less than or equal to `127.999f`.
|
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* Relative error < 0.062%.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_expf()
|
2022-11-15 23:49:51 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_expf(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of e (Euler's number) raised to the power of `x`.
|
2023-08-10 15:06:45 +00:00
|
|
|
* For `x < -87.3365447505531f` it just returns `0`.
|
|
|
|
*
|
|
|
|
* `x` must be less than or equal to `88.722f`.
|
|
|
|
*
|
2022-11-15 23:49:51 +00:00
|
|
|
* Relative error < 0.062%.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_pow10f()
|
2022-12-05 10:17:28 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_pow10f(
|
|
|
|
float x);
|
2022-12-05 10:17:28 +00:00
|
|
|
/*! <<<```
|
2023-08-10 15:06:45 +00:00
|
|
|
* Returns an approximation of 10 raised to the power of `x`. For
|
|
|
|
* `x < -37.92977945366162f` it just returns `0`.
|
|
|
|
*
|
|
|
|
* `x` must be less than or equal to `38.531f`.
|
|
|
|
*
|
2022-12-05 10:17:28 +00:00
|
|
|
* Relative error < 0.062%.
|
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_dB2linf()
|
2022-12-05 10:17:28 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_dB2linf(
|
|
|
|
float x);
|
2022-12-05 10:17:28 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of 10 raised to the power of `x` / 20 (dB to
|
2023-08-11 08:15:43 +00:00
|
|
|
* linear ratio conversion). For `x < -758.5955890732315f` it just returns
|
|
|
|
* `0.f`.
|
|
|
|
*
|
|
|
|
* `x` must be less than or equal to `770.630f`.
|
2022-12-05 10:17:28 +00:00
|
|
|
*
|
|
|
|
* Relative error < 0.062%.
|
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_lin2dBf()
|
2022-12-05 10:17:28 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_lin2dBf(
|
|
|
|
float x);
|
2022-12-05 10:17:28 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of 20 times the base-10 logarithm of `x` (linear
|
|
|
|
* ratio to dB conversion).
|
|
|
|
*
|
2023-08-11 08:15:43 +00:00
|
|
|
* `x` must be finite and greater than or equal to `1.175494350822287e-38f`.
|
|
|
|
*
|
|
|
|
* Absolute error < 0.032 or relative error < 1.2%, whatever is worse.
|
2022-12-05 10:17:28 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_sqrtf()
|
2022-11-15 23:49:51 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_sqrtf(
|
|
|
|
float x);
|
2022-11-15 23:49:51 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the square root of `x`.
|
2023-01-20 17:27:55 +00:00
|
|
|
*
|
2023-09-19 08:22:36 +00:00
|
|
|
* `x` must be finite and non-negative.
|
2023-08-11 08:15:43 +00:00
|
|
|
*
|
|
|
|
* Absolute error < 1.09e-19 or relative error < 0.0007%, whatever is worse.
|
2022-12-03 09:09:21 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_tanhf()
|
2022-12-03 09:09:21 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_tanhf(
|
|
|
|
float x);
|
2022-12-03 09:09:21 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the hyperbolic tangent of `x`.
|
|
|
|
*
|
2023-08-11 08:15:43 +00:00
|
|
|
* Absolute error < 0.035 or relative error < 6.5%, whatever is worse.
|
2023-03-23 08:52:19 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_sinhf()
|
2023-03-23 08:52:19 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_sinhf(
|
|
|
|
float x);
|
2023-03-23 08:52:19 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the hyperbolic sine of `x`.
|
|
|
|
*
|
2023-08-11 08:15:43 +00:00
|
|
|
* |`x`| must less than or equal to `88.722f`.
|
|
|
|
*
|
|
|
|
* Absolute error < 1e-7 or relative error < 0.07%, whatever is worse.
|
2023-03-23 08:52:19 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_coshf()
|
2023-03-23 08:52:19 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_coshf(
|
|
|
|
float x);
|
2023-03-23 08:52:19 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the hyperbolic cosine of `x`.
|
|
|
|
*
|
2023-08-11 08:15:43 +00:00
|
|
|
* |`x`| must less than or equal to `88.722f`.
|
|
|
|
*
|
2023-03-23 08:52:19 +00:00
|
|
|
* Relative error < 0.07%.
|
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_asinhf()
|
2023-03-23 08:52:19 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_asinhf(
|
|
|
|
float x);
|
2023-03-23 08:52:19 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the hyperbolic arcsine of `x`.
|
|
|
|
*
|
2023-08-11 08:15:43 +00:00
|
|
|
* |`x`| must less than or equal to `8.507059173023462e+37f`.
|
|
|
|
*
|
|
|
|
* Absolute error < 0.004 or relative error < 1.2%, whatever is worse.
|
2023-03-23 08:52:19 +00:00
|
|
|
*
|
2023-08-10 06:00:44 +00:00
|
|
|
* #### bw_acoshf()
|
2023-03-23 08:52:19 +00:00
|
|
|
* ```>>> */
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_acoshf(
|
|
|
|
float x);
|
2023-03-23 08:52:19 +00:00
|
|
|
/*! <<<```
|
|
|
|
* Returns an approximation of the hyperbolic arccosine of `x`.
|
|
|
|
*
|
2023-08-11 08:15:43 +00:00
|
|
|
* `x` must be in [1.f, 8.507059173023462e+37f].
|
|
|
|
*
|
|
|
|
* Absolute error < 0.004 or relative error < 0.8%, whatever is worse.
|
2022-11-15 23:49:51 +00:00
|
|
|
* }}} */
|
|
|
|
|
2023-08-11 10:49:05 +00:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-11-22 14:28:16 +00:00
|
|
|
/*** Implementation ***/
|
|
|
|
|
|
|
|
/* WARNING: This part of the file is not part of the public API. Its content may
|
|
|
|
* change at any time in future versions. Please, do not use it directly. */
|
2022-11-15 23:49:51 +00:00
|
|
|
|
2023-08-11 10:49:05 +00:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2022-11-15 23:49:51 +00:00
|
|
|
// I hope the target architecture and compiler will use conditional ops here
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline int32_t bw_signfilli32(
|
|
|
|
int32_t x) {
|
2022-11-15 23:49:51 +00:00
|
|
|
return x < 0 ? ~0 : 0;
|
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline int32_t bw_mini32(
|
|
|
|
int32_t a,
|
|
|
|
int32_t b) {
|
2022-11-15 23:49:51 +00:00
|
|
|
return a < b ? a : b;
|
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline int32_t bw_maxi32(
|
|
|
|
int32_t a,
|
|
|
|
int32_t b) {
|
2022-11-15 23:49:51 +00:00
|
|
|
return a > b ? a : b;
|
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline int32_t bw_clipi32(
|
|
|
|
int32_t x,
|
|
|
|
int32_t m,
|
|
|
|
int32_t M) {
|
2022-11-15 23:49:51 +00:00
|
|
|
return x < m ? m : (x > M ? M : x);
|
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline uint32_t bw_minu32(
|
|
|
|
uint32_t a,
|
|
|
|
uint32_t b) {
|
2022-11-15 23:49:51 +00:00
|
|
|
return a < b ? a : b;
|
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline uint32_t bw_maxu32(
|
|
|
|
uint32_t a,
|
|
|
|
uint32_t b) {
|
2022-11-15 23:49:51 +00:00
|
|
|
return a > b ? a : b;
|
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline uint32_t bw_clipu32(
|
|
|
|
uint32_t x,
|
|
|
|
uint32_t m,
|
|
|
|
uint32_t M) {
|
2022-11-15 23:49:51 +00:00
|
|
|
return x < m ? m : (x > M ? M : x);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Here instead I don't trust C semantics to get close to conditional ops for
|
|
|
|
// floating point numbers
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_copysignf(
|
|
|
|
float x,
|
|
|
|
float y) {
|
2023-08-09 11:11:09 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(x));
|
|
|
|
BW_ASSERT(!bw_is_nan(y));
|
|
|
|
union { float f; uint32_t u; } v, s;
|
|
|
|
v.f = x;
|
|
|
|
s.f = y;
|
|
|
|
v.u = (v.u & 0x7fffffffu) | (s.u & 0x80000000u);
|
|
|
|
BW_ASSERT(!bw_is_nan(v.f));
|
2022-11-15 23:49:51 +00:00
|
|
|
return v.f;
|
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_signf(
|
|
|
|
float x) {
|
2023-08-09 11:11:09 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(x));
|
2022-11-15 23:49:51 +00:00
|
|
|
static const float y[4] = { 0.f, 1.f, 0.f, -1.f };
|
2023-08-09 11:11:09 +00:00
|
|
|
union { float f; uint32_t u; } v;
|
|
|
|
v.f = x;
|
|
|
|
const float r = y[bw_minu32(v.u & 0x7fffffffu, 1) | ((v.u >> 30) & 0x2)];
|
|
|
|
BW_ASSERT(!bw_is_nan(r));
|
|
|
|
return r;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_absf(
|
|
|
|
float x) {
|
2023-08-09 11:11:09 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(x));
|
|
|
|
union { float f; uint32_t u; } v;
|
|
|
|
v.f = x;
|
|
|
|
v.u = v.u & 0x7fffffffu;
|
|
|
|
BW_ASSERT(!bw_is_nan(v.f));
|
2022-11-15 23:49:51 +00:00
|
|
|
return v.f;
|
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_min0f(
|
|
|
|
float x) {
|
2023-08-09 11:11:09 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(x));
|
|
|
|
union { float f; int32_t i; } v;
|
|
|
|
v.f = x;
|
|
|
|
v.i = bw_mini32(0, v.i);
|
|
|
|
BW_ASSERT(!bw_is_nan(v.f));
|
|
|
|
return v.f;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_max0f(
|
|
|
|
float x) {
|
2023-08-09 11:11:09 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(x));
|
|
|
|
union { float f; int32_t i; } v;
|
|
|
|
v.f = x;
|
|
|
|
v.i = bw_maxi32(0, v.i);
|
|
|
|
BW_ASSERT(!bw_is_nan(v.f));
|
|
|
|
return v.f;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_minf(
|
|
|
|
float a,
|
|
|
|
float b) {
|
2023-08-09 11:11:09 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(a));
|
|
|
|
BW_ASSERT(!bw_is_nan(b));
|
|
|
|
const float y = a < b ? a : b;
|
|
|
|
BW_ASSERT(!bw_is_nan(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_maxf(
|
|
|
|
float a,
|
|
|
|
float b) {
|
2023-08-09 11:11:09 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(a));
|
|
|
|
BW_ASSERT(!bw_is_nan(b));
|
|
|
|
const float y = a > b ? a : b;
|
|
|
|
BW_ASSERT(!bw_is_nan(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_clipf(
|
|
|
|
float x,
|
|
|
|
float m,
|
|
|
|
float M) {
|
2023-08-09 11:11:09 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(x));
|
|
|
|
BW_ASSERT(!bw_is_nan(m));
|
|
|
|
BW_ASSERT(!bw_is_nan(M));
|
|
|
|
BW_ASSERT(M >= m);
|
2023-07-24 14:14:16 +00:00
|
|
|
const float y = bw_minf(bw_maxf(x, m), M);
|
2023-08-09 11:11:09 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_truncf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-08-09 11:11:09 +00:00
|
|
|
union { float f; uint32_t u; } v;
|
|
|
|
v.f = x;
|
|
|
|
const int32_t ex = (v.u & 0x7f800000u) >> 23;
|
2023-12-06 13:40:16 +00:00
|
|
|
uint32_t m = (~0u) << bw_clipi32(150 - ex, 0, 23);
|
|
|
|
m &= (uint32_t)bw_signfilli32(126 - ex) | 0x80000000;
|
2023-08-09 11:11:09 +00:00
|
|
|
v.u &= m;
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(v.f));
|
2022-11-15 23:49:51 +00:00
|
|
|
return v.f;
|
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_roundf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-08-09 11:11:09 +00:00
|
|
|
union { float f; uint32_t u; } v, s;
|
|
|
|
v.f = x;
|
|
|
|
const int32_t ex = (v.u & 0x7f800000u) >> 23;
|
|
|
|
const int32_t sh = bw_clipi32(150 - ex, 0, 24);
|
2023-12-06 13:40:16 +00:00
|
|
|
uint32_t mt = (~0u) << sh;
|
|
|
|
mt &= (uint32_t)bw_signfilli32(126 - ex) | 0x80000000;
|
|
|
|
uint32_t mr = (1u << sh) >> 1;
|
|
|
|
mr &= (uint32_t)bw_signfilli32(125 - ex);
|
2023-08-09 11:11:09 +00:00
|
|
|
s.f = bw_copysignf(1.f, x);
|
2023-12-06 13:40:16 +00:00
|
|
|
uint32_t ms = (uint32_t)bw_signfilli32((int32_t)(((v.u | 0x00800000u) & mr) << (32 - sh)));
|
2023-08-09 11:11:09 +00:00
|
|
|
v.u &= mt;
|
|
|
|
s.u &= ms;
|
2023-07-24 14:14:16 +00:00
|
|
|
const float y = v.f + s.f;
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_floorf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-08-09 11:11:09 +00:00
|
|
|
union { float f; int32_t i; } t, y, s;
|
|
|
|
t.f = bw_truncf(x); // first bit set when t < 0
|
|
|
|
y.f = x - t.f; // first bit set when t > x
|
|
|
|
s.f = 1.f;
|
2022-11-15 23:49:51 +00:00
|
|
|
s.i &= bw_signfilli32(t.i & y.i);
|
2023-07-25 06:52:01 +00:00
|
|
|
const float r = t.f - s.f;
|
|
|
|
BW_ASSERT(bw_is_finite(r));
|
|
|
|
return r;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_ceilf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-08-09 11:11:09 +00:00
|
|
|
union { float f; int32_t i; } t, y, s;
|
|
|
|
t.f = bw_truncf(x); // first bit set when t < 0
|
|
|
|
y.f = t.f - x; // first bit set when t < x
|
|
|
|
s.f = 1.f;
|
2023-03-04 07:17:31 +00:00
|
|
|
s.i &= bw_signfilli32(~t.i & y.i);
|
2023-07-25 06:52:01 +00:00
|
|
|
const float r = t.f + s.f;
|
|
|
|
BW_ASSERT(bw_is_finite(r));
|
|
|
|
return r;
|
2023-03-04 07:17:31 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline void bw_intfracf(
|
|
|
|
float x,
|
|
|
|
float * BW_RESTRICT i,
|
|
|
|
float * BW_RESTRICT f) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2024-01-02 10:20:52 +00:00
|
|
|
BW_ASSERT(i != BW_NULL);
|
|
|
|
BW_ASSERT(f != BW_NULL);
|
2023-08-14 07:57:06 +00:00
|
|
|
BW_ASSERT(i != f);
|
2023-04-05 09:56:42 +00:00
|
|
|
*i = bw_floorf(x);
|
|
|
|
*f = x - *i;
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(*i));
|
|
|
|
BW_ASSERT(bw_is_finite(*f));
|
2023-04-05 09:56:42 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_rcpf(
|
|
|
|
float x) {
|
2023-08-09 17:17:54 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
|
|
|
BW_ASSERT((x >= 8.077935669e-28f && x <= 1.237940039e27f) || (x <= -8.077935669e-28f && x >= -1.237940039e27f));
|
2023-08-09 11:11:09 +00:00
|
|
|
union { float f; int32_t i; } v;
|
|
|
|
v.f = x;
|
2022-11-15 23:49:51 +00:00
|
|
|
v.i = 0x7ef0e840 - v.i;
|
|
|
|
v.f = v.f + v.f - x * v.f * v.f;
|
|
|
|
v.f = v.f + v.f - x * v.f * v.f;
|
2023-08-09 17:17:54 +00:00
|
|
|
BW_ASSERT(bw_is_finite(v.f));
|
2022-11-15 23:49:51 +00:00
|
|
|
return v.f;
|
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_sin2pif(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2022-11-15 23:49:51 +00:00
|
|
|
x = x - bw_floorf(x);
|
|
|
|
float xp1 = x + x - 1.f;
|
|
|
|
float xp2 = bw_absf(xp1);
|
|
|
|
float xp = 1.570796326794897f - 1.570796326794897f * bw_absf(xp2 + xp2 - 1.f);
|
2023-07-24 14:14:16 +00:00
|
|
|
const float y = -bw_copysignf(1.f, xp1) * (xp + xp * xp * (-0.05738534102710938f - 0.1107398163618408f * xp));
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_sinf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = bw_sin2pif(0.1591549430918953f * x);
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-12-04 18:13:57 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_cos2pif(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = bw_sin2pif(x + 0.25f);
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-12-04 18:13:57 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_cosf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = bw_cos2pif(0.1591549430918953f * x);
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-12-04 18:13:57 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_tan2pif(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-07-24 14:14:16 +00:00
|
|
|
BW_ASSERT((x - 0.5f * bw_floorf(x + x) <= 0.249840845056908f)
|
|
|
|
|| (x - 0.5f * bw_floorf(x + x) >= 0.250159154943092f));
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = bw_sin2pif(x) * bw_rcpf(bw_cos2pif(x));
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_tanf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-07-24 14:14:16 +00:00
|
|
|
BW_ASSERT((x - 3.141592653589793f * bw_floorf(0.318309886183791f * x) <= 1.569796326794897f)
|
|
|
|
|| (x - 3.141592653589793f * bw_floorf(0.318309886183791f * x) >= 1.571796326794896f));
|
2022-12-04 18:13:57 +00:00
|
|
|
x = 0.1591549430918953f * x;
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = bw_sin2pif(x) * bw_rcpf(bw_cos2pif(x));
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_log2f(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-07-24 14:14:16 +00:00
|
|
|
BW_ASSERT(x >= 1.175494350822287e-38f);
|
2023-08-09 11:11:09 +00:00
|
|
|
union { float f; int32_t i; } v;
|
|
|
|
v.f = x;
|
2022-11-15 23:49:51 +00:00
|
|
|
int e = v.i >> 23;
|
|
|
|
v.i = (v.i & 0x007fffff) | 0x3f800000;
|
2023-07-24 14:14:16 +00:00
|
|
|
const float y = (float)e - 129.213475204444817f + v.f * (3.148297929334117f + v.f * (-1.098865286222744f + v.f * 0.1640425613334452f));
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_logf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-07-24 14:14:16 +00:00
|
|
|
BW_ASSERT(x >= 1.175494350822287e-38f);
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = 0.693147180559945f * bw_log2f(x);
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_log10f(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-07-24 14:14:16 +00:00
|
|
|
BW_ASSERT(x >= 1.175494350822287e-38f);
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = 0.3010299956639811f * bw_log2f(x);
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-12-05 10:17:28 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_pow2f(
|
|
|
|
float x) {
|
2023-08-10 15:06:45 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(x));
|
2023-07-24 14:14:16 +00:00
|
|
|
BW_ASSERT(x <= 127.999f);
|
2022-11-15 23:49:51 +00:00
|
|
|
if (x < -126.f)
|
|
|
|
return 0.f;
|
2023-08-09 11:11:09 +00:00
|
|
|
union { float f; int32_t i; } v;
|
|
|
|
v.f = x;
|
2022-11-15 23:49:51 +00:00
|
|
|
int xi = (int)x;
|
|
|
|
int l = xi - ((v.i >> 31) & 1);
|
|
|
|
float f = x - (float)l;
|
|
|
|
v.i = (l + 127) << 23;
|
2023-07-24 14:14:16 +00:00
|
|
|
const float y = v.f + v.f * f * (0.6931471805599453f + f * (0.2274112777602189f + f * 0.07944154167983575f));
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_expf(
|
|
|
|
float x) {
|
2023-08-10 15:06:45 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(x));
|
2023-07-24 14:14:16 +00:00
|
|
|
BW_ASSERT(x <= 88.722f);
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = bw_pow2f(1.442695040888963f * x);
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-11-15 23:49:51 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_pow10f(
|
|
|
|
float x) {
|
2023-08-10 15:06:45 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(x));
|
2023-07-24 14:14:16 +00:00
|
|
|
BW_ASSERT(x <= 38.531f);
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = bw_pow2f(3.321928094887363f * x);
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-12-05 10:17:28 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_dB2linf(
|
|
|
|
float x) {
|
2023-08-11 08:15:43 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(x));
|
2023-07-24 14:14:16 +00:00
|
|
|
BW_ASSERT(x <= 770.630f);
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = bw_pow2f(0.1660964047443682f * x);
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-12-05 10:17:28 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_lin2dBf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-07-24 14:14:16 +00:00
|
|
|
BW_ASSERT(x >= 1.175494350822287e-38f);
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = 20.f * bw_log10f(x);
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-11-26 17:16:28 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_sqrtf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-07-24 14:14:16 +00:00
|
|
|
BW_ASSERT(x >= 0.f);
|
2023-08-11 08:15:43 +00:00
|
|
|
if (x < 1.1754943508222875e-38f)
|
|
|
|
return 0.f;
|
|
|
|
union { float f; int32_t i; } v;
|
2023-08-09 11:11:09 +00:00
|
|
|
v.f = x;
|
2023-08-11 08:15:43 +00:00
|
|
|
int i = (v.i >> 26) & 0x38;
|
2023-12-07 23:24:04 +00:00
|
|
|
v.i += (int32_t)((0x200000e0 << i) & (int32_t)0xff000000);
|
2023-08-11 08:15:43 +00:00
|
|
|
const float r = bw_rcpf(v.f);
|
|
|
|
v.i = (((v.i - 0x3f82a127) >> 1) + 0x3f7d8fc7) & 0x7fffffff;
|
2023-01-20 17:27:55 +00:00
|
|
|
v.f = v.f + v.f * (0.5f - 0.5f * r * v.f * v.f);
|
|
|
|
v.f = v.f + v.f * (0.5f - 0.5f * r * v.f * v.f);
|
2023-12-07 23:24:04 +00:00
|
|
|
v.i -= (int32_t)((0x100000f0 << i) & (int32_t)0xff000000);
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(v.f));
|
2022-11-15 23:49:51 +00:00
|
|
|
return v.f;
|
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_tanhf(
|
|
|
|
float x) {
|
2023-08-11 08:15:43 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(x));
|
2022-12-01 16:02:50 +00:00
|
|
|
const float xm = bw_clipf(x, -2.115287308554551f, 2.115287308554551f);
|
|
|
|
const float axm = bw_absf(xm);
|
2023-07-24 14:14:16 +00:00
|
|
|
const float y = xm * axm * (0.01218073260037716f * axm - 0.2750231331124371f) + xm;
|
2023-08-11 08:15:43 +00:00
|
|
|
BW_ASSERT(!bw_is_nan(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2022-12-01 16:02:50 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_sinhf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-07-24 14:14:16 +00:00
|
|
|
BW_ASSERT(x >= -88.722f && x <= 88.722f);
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = 0.5f * (bw_expf(x) - bw_expf(-x));
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2023-03-23 08:52:19 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_coshf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-07-24 14:14:16 +00:00
|
|
|
BW_ASSERT(x >= -88.722f && x <= 88.722f);
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = 0.5f * (bw_expf(x) + bw_expf(-x));
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2023-03-23 08:52:19 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_asinhf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-08-11 08:15:43 +00:00
|
|
|
BW_ASSERT(x >= -8.507059173023462e+37f && x <= 8.507059173023462e+37f);
|
2023-03-23 08:52:19 +00:00
|
|
|
float a = bw_absf(x);
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = bw_copysignf(bw_logf((a >= 4096.f ? a : bw_sqrtf(a * a + 1.f)) + a), x);
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2023-03-23 08:52:19 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 15:19:19 +00:00
|
|
|
static inline float bw_acoshf(
|
|
|
|
float x) {
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(x));
|
2023-08-11 08:15:43 +00:00
|
|
|
BW_ASSERT(x >= 1.f && x <= 8.507059173023462e+37f);
|
2023-08-10 06:00:44 +00:00
|
|
|
const float y = bw_logf((x >= 8192.f ? x : bw_sqrtf(x * x - 1.f)) + x);
|
2023-07-25 06:52:01 +00:00
|
|
|
BW_ASSERT(bw_is_finite(y));
|
2023-07-24 14:14:16 +00:00
|
|
|
return y;
|
2023-03-23 08:52:19 +00:00
|
|
|
}
|
|
|
|
|
2022-11-15 23:49:51 +00:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|