SH4ZAM! 0.9.1
Fast math library for the Sega Dreamcast's SH4 CPU
Loading...
Searching...
No Matches
shz_scalar.h
Go to the documentation of this file.
1/*! \file
2 * \brief General-purpose scalar math routines.
3 * \ingroup scalar
4 *
5 * This file provides a collection of general-purpose math routines for
6 * operating on floating-point scalar values.
7 *
8 * \todo
9 * - Use FP rounding modes for rounding functionality.
10 *
11 * \author 2025, 2026 Falco Girgis
12 * \author 2025, 2026 Paul Cercueil
13 * \author 2026 Aleios
14 * \author 2026 jnmartin64
15 *
16 * \copyright MIT License
17 */
18
19#ifndef SHZ_SCALAR_H
20#define SHZ_SCALAR_H
21
22#include <math.h>
23#include <stdbool.h>
24
25#include "shz_cdefs.h"
26
27/*! \defgroup scalar Scalar
28 \brief Scalar functions and utilities.
29
30 This API is designed around performing various scalar operations, providing
31 alternatives for routines typically found within `<math.h>`.
32
33 \warning
34 Unlike the standard C floating-point routines, these routines are often saving
35 cycles by not handling NaN and INF values as well as by not reporting rounding
36 and domain errors back to the user.
37*/
38
39//! Floating-point epsilon used with inexact FP-based comparisons.
40#define SHZ_FLT_EPSILON 0.01f
41
42SHZ_DECLS_BEGIN
43
44/*! \name Comparisons
45 \brief Routines for comparing and classifying floating-point values.
46 @{
47*/
48
49//! Returns the minimum value of two given floats.
50SHZ_INLINE float shz_fminf(float a, float b) SHZ_NOEXCEPT;
51
52//! Returns the maximum value of two given floats.
53SHZ_INLINE float shz_fmaxf(float a, float b) SHZ_NOEXCEPT;
54
55//! Checks for equality based on EITHER the absolute tolerance or relative tolerance, using SHZ_FLT_EPSILON.
56SHZ_INLINE bool shz_equalf(float a, float b) SHZ_NOEXCEPT;
57
58//! Checks for equality based on the absolute tolerance using SHZ_FLT_EPSILON.
59SHZ_INLINE bool shz_equalf_abs(float a, float b) SHZ_NOEXCEPT;
60
61//! Checks for equality based on the relative tolerance using SHZ_FLT_EPSILON.
62SHZ_INLINE bool shz_equalf_rel(float a, float b) SHZ_NOEXCEPT;
63
64//! @}
65
66/*! \name Rounding
67 \brief Routines for rounding and manipulating floats.
68 @{
69 */
70
71/*! Replacement for the <math.h> routine, floorf().
72
73 Returns the closest integral value to \p x, rounded down, as a float.
74
75 \warning
76 This routine is only valid for for the range INT32_MIN <= \p x <= INT32_MAX.
77
78 \sa ceilf()
79*/
80SHZ_INLINE float shz_floorf(float x) SHZ_NOEXCEPT;
81
82/*! Replacement for the <math.h> routine, ceilf().
83
84 Returns the closest integral value to \p x, rounded up, as a float.
85
86 \warning
87 This routine only returns valid values for the input range
88 INT32_MIN <= \p x <= INT32_MAX.
89
90 \sa floorf()
91*/
92SHZ_INLINE float shz_ceilf(float x) SHZ_NOEXCEPT;
93
94/*! Replacement for the <math.h> routine, roundf().
95
96 Returns the value of \p x rounded to the nearest integer, as a float.
97
98 \warning
99 This routine only returns valid values for the input range
100 -UINT32_MAX <= \p x <= UINT32_MAX.
101*/
102SHZ_INLINE float shz_roundf(float x) SHZ_NOEXCEPT;
103
104/*! Replacement for the <math.h> routine, truncf().
105
106 Returns the value of \p with its fractional component discarded.
107
108 \warning
109 This routine only returns valid values for the input range
110 INT32_MIN <= \p x <= INT32_MAX.
111*/
112SHZ_INLINE float shz_truncf(float x) SHZ_NOEXCEPT;
113
114/*! Replacement for the <math.h> routine, remainderf().
115
116 Returns the floating-point remainder of \p num divided by \p denom,
117 rounded to the nearest integer (as a float).
118
119 \warning
120 This routine does not gracefully handle dividing by zero, and it is only
121 valid for the input range INT32_MIN <= \p num / \p denom <= INT32_MAX.
122
123 \sa shz_fmodf(), shz_remquof(), shz_truncf().
124*/
125SHZ_INLINE float shz_remainderf(float num, float denom) SHZ_NOEXCEPT;
126
127/*! Replacement for the <math.h> routine, fmodf().
128
129 Returns the floating-point remainder of \p num divided by \p denom,
130 rounded towards zero.
131
132 \warning
133 This routine does not gracefully handle dividing by zero.
134
135 \sa shz_remainderf()
136*/
137SHZ_INLINE float shz_fmodf(float num, float denom) SHZ_NOEXCEPT;
138
139/*! (Sorta) Replacement for the <math.h> routine, remquof().
140
141 Returns the floating-point remainder of \p num divided by \p denom,
142 rounded to the nearest integer (as a float). \p quot is set equal to
143 the quotient which is used as part of the calculation.
144
145 \note
146 \p quot is returning as a `float` rather than an `int` as with standard C.
147 Simply cast to an `int` manually afterwards if that is the desired behavior.
148
149 \warning
150 This routine does not gracefully handle dividing by zero.
151
152 \sa shz_remainderf()
153*/
154SHZ_INLINE float shz_remquof(float num, float denom, float* quot) SHZ_NOEXCEPT;
155
156//! @}
157
158/*! \name Mapping
159 \brief Routines for mapping a number to another range.
160 @{
161*/
162
163//! Clamps a floating-point value by the given \p min and \p max values.
164SHZ_INLINE float shz_clampf(float value, float min, float max) SHZ_NOEXCEPT;
165
166//! Maps a value within the given range \p from to \p to, to be within the range of `0.0f += 1.0f`.
167SHZ_INLINE float shz_normalizef(float current, float from, float to) SHZ_NOEXCEPT;
168
169//! Maps a value within the given range \p from to \p to, to be within the range of `0.0f + 1.0f` more quickly, provided \p to - \p from is a positive difference.
170SHZ_INLINE float shz_normalizef_fsrra(float current, float from, float to) SHZ_NOEXCEPT;
171
172//! Maps a value within the given range \p inputStart to \p inputEnd, to be within the range of \p outputStart to \p outputEnd.
173SHZ_INLINE float shz_remapf(float value, float inputStart, float inputEnd, float outputStart, float outputEnd) SHZ_NOEXCEPT;
174
175//! Maps a value within the given range \p inputStart to \p inputEnd, to be within the range of \p outputStart to \p outputEnd more quickly, provided the \p outputEnd - \p outputStart is a positive difference.
176SHZ_INLINE float shz_remapf_fsrra(float value, float inputStart, float inputEnd, float outputStart, float outputEnd) SHZ_NOEXCEPT;
177
178//! Wraps the given \p value back to be within the range of \p min to \p max.
179SHZ_INLINE float shz_wrapf(float value, float min, float max) SHZ_NOEXCEPT;
180
181//! Wraps the given \p value back to be within the range of \p min to \p max more quickly, provided \p max - \p min is a positive difference.
182SHZ_INLINE float shz_wrapf_fsrra(float value, float min, float max) SHZ_NOEXCEPT;
183
184//! Returns the fractional part of \p x, equivalent to GLSL `fract()`.
185SHZ_INLINE float shz_fractf(float x) SHZ_NOEXCEPT;
186
187//! Returns -1.0f if \p x < 0, 0.0f if \p x == 0, or 1.0f if \p x > 0.
188SHZ_INLINE float shz_signf(float x) SHZ_NOEXCEPT;
189
190//! Clamps \p x to the range [0.0f, 1.0f].
191SHZ_INLINE float shz_saturatef(float x) SHZ_NOEXCEPT;
192
193//! @}
194
195/*! \name Miscellaneous
196 * \brief Assorted routines implementing other fp operations.
197 * @{
198 */
199
200/*! Replacement for the <math.h> routine, fabsf().
201
202 Returns the absolute value of \p x.
203*/
204SHZ_INLINE float shz_fabsf(float x) SHZ_NOEXCEPT;
205
206/*! Replacement for the <math.h> routine, copysignf().
207
208 Returns the value of \p x with the sign of \p y.
209
210 \warning When `y == -0.0f`, a positive value is returned.
211*/
212SHZ_INLINE float shz_copysignf(float x, float y) SHZ_NOEXCEPT;
213
214/*! Replacement for the <math.h> routine, fmaf().
215
216 Returns \p a * \p b + \p c, performing an FP multiply + accumulate operation.
217*/
218SHZ_INLINE float shz_fmaf(float a, float b, float c) SHZ_NOEXCEPT;
219
220/*! Replacement for the <math.h> routine, fdimf(),
221
222 Returns the positive difference between \p x and \p y or zero if
223 y >= x.
224
225 \warning
226 Unlike fdimf(), this routine does not handle INF and NAN values.
227*/
228SHZ_INLINE float shz_fdimf(float x, float y) SHZ_NOEXCEPT;
229
230/*! Replacement for the <math.h> routine, hypotf().
231
232 Returns the hypoteneuse of the right triangle with the given legs.
233
234 \warning
235 Unlike hypotf(), this routine has no error or overflow handling.
236*/
237SHZ_INLINE float shz_hypotf(float x, float y) SHZ_NOEXCEPT;
238
239/*! Replacement for the <math.h> routine, cbrtf().
240
241 Returns the cubed root of \p x, using a fast approximation.
242*/
243SHZ_INLINE float shz_cbrtf(float x) SHZ_NOEXCEPT;
244
245//! Returns a value that is linearly interpolated between \p a and \p b by the given ratio, \p t.
246SHZ_INLINE float shz_lerpf(float a, float b, float t) SHZ_NOEXCEPT;
247
248//! Returns a value that is barycentrically interpolated between \p a, \p b, and \p c using the given barycentric coordinates, \p u and \p v.
249SHZ_INLINE float shz_barycentric_lerpf(float a, float b, float c, float u, float v) SHZ_NOEXCEPT;
250
251//! Uses the quadratic formula with the given coefficients to solve for the two roots, returning `true` if any real roots exist, and `false` if the roots are only imaginary.
252SHZ_INLINE bool shz_quadratic_roots(float a, float b, float c, float* root1, float* root2) SHZ_NOEXCEPT;
253
254//! Returns a random floating-point number between `0.0f` and `1.0f`, using and updating the given seed.
255SHZ_INLINE float shz_randf(int* seed) SHZ_NOEXCEPT;
256
257//! Returns a random floating-point number between \p min and \p max, using and updating the given seed.
258SHZ_INLINE float shz_randf_range(int* seed, float min, float max) SHZ_NOEXCEPT;
259
260//! returns 0.0f if x < edge, otherwise 1.0f
261SHZ_INLINE float shz_stepf(float x, float edge) SHZ_NOEXCEPT;
262
263//! Returns 0.0f at/below edge0, 1.0f at/above edge1, smoothly varying in-between. edge0 must be less than edge1 or result is undefined.
264SHZ_INLINE float shz_smoothstepf(float x, float edge0, float edge1) SHZ_NOEXCEPT;
265
266//! Returns 0.0f at/below edge0, 1.0f at/above edge1, smoothly varying in-between. Accepts inverse edges.
267SHZ_INLINE float shz_smoothstepf_safe(float x, float edge0, float edge1) SHZ_NOEXCEPT;
268
269//! @}
270
271/*! \name FSRRA
272 * \brief Routines built around fast reciprocal square root instruction.
273 * @{
274 */
275
276//! Calculates 1.0f/sqrtf( \p x), using a fast approximation.
277SHZ_INLINE float shz_inv_sqrtf_fsrra(float x) SHZ_NOEXCEPT;
278
279//! Calculates 1.0f/sqrtf( \p x ), using a fast approximation, while safely protecting against division-by-zero.
280SHZ_INLINE float shz_inv_sqrtf(float x) SHZ_NOEXCEPT;
281
282//! Returns the fast approximate square root of the given value, \p x.
283SHZ_INLINE float shz_sqrtf_fsrra(float x) SHZ_NOEXCEPT;
284
285//! Returns the fast approximate square root of the given value, \p x, safely returning `0.0f` is \p x == `0.0f`.
286SHZ_INLINE float shz_sqrtf(float x) SHZ_NOEXCEPT;
287
288//! Takes the inverse of \p x using a very fast approximation, returning a positive result.
289SHZ_INLINE float shz_invf_fsrra(float x) SHZ_NOEXCEPT;
290
291//! Takes the inverse of \p x using a slighty faster approximation than doing a full division, safely handling negative values.
292SHZ_INLINE float shz_invf(float x) SHZ_NOEXCEPT;
293
294//! Divides \p num by \p denom using a very fast approximation, which requires \p denom be a positive value.
295SHZ_INLINE float shz_divf_fsrra(float num, float denom) SHZ_NOEXCEPT;
296
297//! Divides \p num by \p denom using a slightly faster approximation, allowing \p denom to be negative.
298SHZ_INLINE float shz_divf(float num, float denom) SHZ_NOEXCEPT;
299
300//! @}
301
302/*! \name FIPR
303 * \brief Routines built around fast 4D dot product.
304 * \todo Generalize these with a macro that lets you choose vector FP regs.
305 * @{
306 */
307
308//! Takes two sets of 3D vectors as 3 floats and calculates their dot product using an approximation.
309SHZ_INLINE float shz_dot6f(float x1, float y1, float z1,
310 float x2, float y2, float z2) SHZ_NOEXCEPT;
311
312//! Takes two sets of 4D vectors as 4 floats and calculates their dot product using an approximation.
313SHZ_INLINE float shz_dot8f(float x1, float y1, float z1, float w1,
314 float x2, float y2, float z2, float w2) SHZ_NOEXCEPT;
315
316//! Takes a 3D vector as 3 floats and calculates its squared magnitude using a fast approximation.
317SHZ_INLINE float shz_mag_sqr3f(float x, float y, float z) SHZ_NOEXCEPT;
318
319//! Takes a 4D vector as 4 floats and calculates its squared magnitude using a fast approximation.
320SHZ_INLINE float shz_mag_sqr4f(float x, float y, float z, float w) SHZ_NOEXCEPT;
321
322//! @}
323
324/*! \name Transcendental
325 \brief Fast approximations for non-trig transcendental functions.
326 @{
327*/
328
329//! Fast approximation for raising 2 to a floating-point power.
330SHZ_INLINE float shz_pow2f(float p) SHZ_NOEXCEPT;
331
332//! Fast approximation for C's powf().
333SHZ_INLINE float shz_powf(float x, float p) SHZ_NOEXCEPT;
334
335//! Fast approximation of POSIX's pow10f().
336SHZ_INLINE float shz_pow10f(float x) SHZ_NOEXCEPT;
337
338//! Fast approximation for C's log2f().
339SHZ_INLINE float shz_log2f(float x) SHZ_NOEXCEPT;
340
341//! Fast approximation for C's logf().
342SHZ_INLINE float shz_logf(float x) SHZ_NOEXCEPT;
343
344//! Fast approximation for C's log10f().
345SHZ_INLINE float shz_log10f(float x) SHZ_NOEXCEPT;
346
347//! Fast approximation for C's expf().
348SHZ_INLINE float shz_expf(float p) SHZ_NOEXCEPT;
349
350//! @}
351
352#include "inline/shz_scalar.inl.h"
353
354SHZ_DECLS_END
355
356#endif
float shz_randf_range(int *seed, float min, float max) noexcept
Returns a random floating-point number between min and max, using and updating the given seed.
float shz_remquof(float num, float denom, float *quot) noexcept
(Sorta) Replacement for the <math.h> routine, remquof().
float shz_mag_sqr4f(float x, float y, float z, float w) noexcept
Takes a 4D vector as 4 floats and calculates its squared magnitude using a fast approximation.
float shz_smoothstepf_safe(float x, float edge0, float edge1) noexcept
Returns 0.0f at/below edge0, 1.0f at/above edge1, smoothly varying in-between. Accepts inverse edges.
float shz_divf_fsrra(float num, float denom) noexcept
Divides num by denom using a very fast approximation, which requires denom be a positive value.
float shz_clampf(float value, float min, float max) noexcept
Clamps a floating-point value by the given min and max values.
float shz_dot8f(float x1, float y1, float z1, float w1, float x2, float y2, float z2, float w2) noexcept
Takes two sets of 4D vectors as 4 floats and calculates their dot product using an approximation.
float shz_barycentric_lerpf(float a, float b, float c, float u, float v) noexcept
Returns a value that is barycentrically interpolated between a, b, and c using the given barycentric ...
float shz_logf(float x) noexcept
Fast approximation for C's logf().
float shz_pow10f(float x) noexcept
Fast approximation of POSIX's pow10f().
float shz_sqrtf_fsrra(float x) noexcept
Returns the fast approximate square root of the given value, x.
float shz_fmaxf(float a, float b) noexcept
Returns the maximum value of two given floats.
bool shz_equalf_rel(float a, float b) noexcept
Checks for equality based on the relative tolerance using SHZ_FLT_EPSILON.
float shz_invf_fsrra(float x) noexcept
Takes the inverse of x using a very fast approximation, returning a positive result.
float shz_fractf(float x) noexcept
Returns the fractional part of x, equivalent to GLSL fract().
float shz_normalizef(float current, float from, float to) noexcept
Maps a value within the given range from to to, to be within the range of 0.0f += 1....
float shz_fabsf(float x) noexcept
Replacement for the <math.h> routine, fabsf().
float shz_expf(float p) noexcept
Fast approximation for C's expf().
float shz_hypotf(float x, float y) noexcept
Replacement for the <math.h> routine, hypotf().
float shz_divf(float num, float denom) noexcept
Divides num by denom using a slightly faster approximation, allowing denom to be negative.
float shz_randf(int *seed) noexcept
Returns a random floating-point number between 0.0f and 1.0f, using and updating the given seed.
bool shz_quadratic_roots(float a, float b, float c, float *root1, float *root2) noexcept
Uses the quadratic formula with the given coefficients to solve for the two roots,...
float shz_roundf(float x) noexcept
Replacement for the <math.h> routine, roundf().
float shz_log2f(float x) noexcept
Fast approximation for C's log2f().
float shz_smoothstepf(float x, float edge0, float edge1) noexcept
Returns 0.0f at/below edge0, 1.0f at/above edge1, smoothly varying in-between. edge0 must be less tha...
float shz_fmaf(float a, float b, float c) noexcept
Replacement for the <math.h> routine, fmaf().
float shz_cbrtf(float x) noexcept
Replacement for the <math.h> routine, cbrtf().
float shz_fmodf(float num, float denom) noexcept
Replacement for the <math.h> routine, fmodf().
float shz_signf(float x) noexcept
Returns -1.0f if x < 0, 0.0f if x == 0, or 1.0f if x > 0.
float shz_floorf(float x) noexcept
Replacement for the <math.h> routine, floorf().
float shz_invf(float x) noexcept
Takes the inverse of x using a slighty faster approximation than doing a full division,...
float shz_sqrtf(float x) noexcept
Returns the fast approximate square root of the given value, x, safely returning 0....
float shz_stepf(float x, float edge) noexcept
returns 0.0f if x < edge, otherwise 1.0f
float shz_fdimf(float x, float y) noexcept
Replacement for the <math.h> routine, fdimf(),.
float shz_wrapf_fsrra(float value, float min, float max) noexcept
Wraps the given value back to be within the range of min to max more quickly, provided max - min is a...
float shz_pow2f(float p) noexcept
Fast approximation for raising 2 to a floating-point power.
float shz_dot6f(float x1, float y1, float z1, float x2, float y2, float z2) noexcept
Takes two sets of 3D vectors as 3 floats and calculates their dot product using an approximation.
bool shz_equalf(float a, float b) noexcept
Checks for equality based on EITHER the absolute tolerance or relative tolerance, using SHZ_FLT_EPSIL...
float shz_ceilf(float x) noexcept
Replacement for the <math.h> routine, ceilf().
float shz_inv_sqrtf(float x) noexcept
Calculates 1.0f/sqrtf( x ), using a fast approximation, while safely protecting against division-by-z...
float shz_mag_sqr3f(float x, float y, float z) noexcept
Takes a 3D vector as 3 floats and calculates its squared magnitude using a fast approximation.
float shz_truncf(float x) noexcept
Replacement for the <math.h> routine, truncf().
float shz_powf(float x, float p) noexcept
Fast approximation for C's powf().
float shz_wrapf(float value, float min, float max) noexcept
Wraps the given value back to be within the range of min to max.
float shz_inv_sqrtf_fsrra(float x) noexcept
Calculates 1.0f/sqrtf( x), using a fast approximation.
float shz_remainderf(float num, float denom) noexcept
Replacement for the <math.h> routine, remainderf().
bool shz_equalf_abs(float a, float b) noexcept
Checks for equality based on the absolute tolerance using SHZ_FLT_EPSILON.
float shz_log10f(float x) noexcept
Fast approximation for C's log10f().
float shz_normalizef_fsrra(float current, float from, float to) noexcept
Maps a value within the given range from to to, to be within the range of 0.0f + 1....
float shz_lerpf(float a, float b, float t) noexcept
Returns a value that is linearly interpolated between a and b by the given ratio, t.
float shz_saturatef(float x) noexcept
Clamps x to the range [0.0f, 1.0f].
float shz_remapf(float value, float inputStart, float inputEnd, float outputStart, float outputEnd) noexcept
Maps a value within the given range inputStart to inputEnd, to be within the range of outputStart to ...
float shz_remapf_fsrra(float value, float inputStart, float inputEnd, float outputStart, float outputEnd) noexcept
Maps a value within the given range inputStart to inputEnd, to be within the range of outputStart to ...
float shz_fminf(float a, float b) noexcept
Returns the minimum value of two given floats.
float shz_copysignf(float x, float y) noexcept
Replacement for the <math.h> routine, copysignf().