SH4ZAM! 0.1.0
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_mag_sqr3f(float x, float y, float z) SHZ_NOEXCEPT
Takes a 3D vector as 3 floats and calculates its squared magnitude using a fast approximation.
float shz_powf(float x, float p) SHZ_NOEXCEPT
Fast approximation for C's powf().
bool shz_equalf_abs(float a, float b) SHZ_NOEXCEPT
Checks for equality based on the absolute tolerance using SHZ_FLT_EPSILON.
float shz_remquof(float num, float denom, float *quot) SHZ_NOEXCEPT
(Sorta) Replacement for the <math.h> routine, remquof().
float shz_expf(float p) SHZ_NOEXCEPT
Fast approximation for C's expf().
float shz_normalizef_fsrra(float current, float from, float to) SHZ_NOEXCEPT
Maps a value within the given range from to to, to be within the range of 0.0f + 1....
float shz_randf(int *seed) SHZ_NOEXCEPT
Returns a random floating-point number between 0.0f and 1.0f, using and updating the given seed.
float shz_log10f(float x) SHZ_NOEXCEPT
Fast approximation for C's log10f().
float shz_floorf(float x) SHZ_NOEXCEPT
Replacement for the <math.h> routine, floorf().
float shz_wrapf_fsrra(float value, float min, float max) SHZ_NOEXCEPT
Wraps the given value back to be within the range of min to max more quickly, provided max - min is a...
float shz_normalizef(float current, float from, float to) SHZ_NOEXCEPT
Maps a value within the given range from to to, to be within the range of 0.0f += 1....
float shz_log2f(float x) SHZ_NOEXCEPT
Fast approximation for C's log2f().
float shz_mag_sqr4f(float x, float y, float z, float w) SHZ_NOEXCEPT
Takes a 4D vector as 4 floats and calculates its squared magnitude using a fast approximation.
float shz_smoothstepf(float x, float edge0, float edge1) SHZ_NOEXCEPT
Returns 0.0f at/below edge0, 1.0f at/above edge1, smoothly varying in-between. edge0 must be less tha...
float shz_dot8f(float x1, float y1, float z1, float w1, float x2, float y2, float z2, float w2) SHZ_NOEXCEPT
Takes two sets of 4D vectors as 4 floats and calculates their dot product using an approximation.
float shz_fmaxf(float a, float b) SHZ_NOEXCEPT
Returns the maximum value of two given floats.
float shz_signf(float x) SHZ_NOEXCEPT
Returns -1.0f if x < 0, 0.0f if x == 0, or 1.0f if x > 0.
float shz_fdimf(float x, float y) SHZ_NOEXCEPT
Replacement for the <math.h> routine, fdimf(),.
float shz_sqrtf_fsrra(float x) SHZ_NOEXCEPT
Returns the fast approximate square root of the given value, x.
float shz_pow10f(float x) SHZ_NOEXCEPT
Fast approximation of POSIX's pow10f().
bool shz_quadratic_roots(float a, float b, float c, float *root1, float *root2) SHZ_NOEXCEPT
Uses the quadratic formula with the given coefficients to solve for the two roots,...
float shz_dot6f(float x1, float y1, float z1, float x2, float y2, float z2) SHZ_NOEXCEPT
Takes two sets of 3D vectors as 3 floats and calculates their dot product using an approximation.
float shz_ceilf(float x) SHZ_NOEXCEPT
Replacement for the <math.h> routine, ceilf().
float shz_remapf_fsrra(float value, float inputStart, float inputEnd, float outputStart, float outputEnd) SHZ_NOEXCEPT
Maps a value within the given range inputStart to inputEnd, to be within the range of outputStart to ...
float shz_hypotf(float x, float y) SHZ_NOEXCEPT
Replacement for the <math.h> routine, hypotf().
float shz_copysignf(float x, float y) SHZ_NOEXCEPT
Replacement for the <math.h> routine, copysignf().
float shz_invf(float x) SHZ_NOEXCEPT
Takes the inverse of x using a slighty faster approximation than doing a full division,...
float shz_wrapf(float value, float min, float max) SHZ_NOEXCEPT
Wraps the given value back to be within the range of min to max.
float shz_saturatef(float x) SHZ_NOEXCEPT
Clamps x to the range [0.0f, 1.0f].
float shz_truncf(float x) SHZ_NOEXCEPT
Replacement for the <math.h> routine, truncf().
float shz_invf_fsrra(float x) SHZ_NOEXCEPT
Takes the inverse of x using a very fast approximation, returning a positive result.
float shz_sqrtf(float x) SHZ_NOEXCEPT
Returns the fast approximate square root of the given value, x, safely returning 0....
float shz_fmaf(float a, float b, float c) SHZ_NOEXCEPT
Replacement for the <math.h> routine, fmaf().
float shz_barycentric_lerpf(float a, float b, float c, float u, float v) SHZ_NOEXCEPT
Returns a value that is barycentrically interpolated between a, b, and c using the given barycentric ...
bool shz_equalf(float a, float b) SHZ_NOEXCEPT
Checks for equality based on EITHER the absolute tolerance or relative tolerance, using SHZ_FLT_EPSIL...
float shz_smoothstepf_safe(float x, float edge0, float edge1) SHZ_NOEXCEPT
Returns 0.0f at/below edge0, 1.0f at/above edge1, smoothly varying in-between. Accepts inverse edges.
float shz_inv_sqrtf_fsrra(float x) SHZ_NOEXCEPT
Calculates 1.0f/sqrtf( x), using a fast approximation.
float shz_cbrtf(float x) SHZ_NOEXCEPT
Replacement for the <math.h> routine, cbrtf().
bool shz_equalf_rel(float a, float b) SHZ_NOEXCEPT
Checks for equality based on the relative tolerance using SHZ_FLT_EPSILON.
float shz_fractf(float x) SHZ_NOEXCEPT
Returns the fractional part of x, equivalent to GLSL fract().
float shz_fmodf(float num, float denom) SHZ_NOEXCEPT
Replacement for the <math.h> routine, fmodf().
float shz_lerpf(float a, float b, float t) SHZ_NOEXCEPT
Returns a value that is linearly interpolated between a and b by the given ratio, t.
float shz_remainderf(float num, float denom) SHZ_NOEXCEPT
Replacement for the <math.h> routine, remainderf().
float shz_divf_fsrra(float num, float denom) SHZ_NOEXCEPT
Divides num by denom using a very fast approximation, which requires denom be a positive value.
float shz_divf(float num, float denom) SHZ_NOEXCEPT
Divides num by denom using a slightly faster approximation, allowing denom to be negative.
float shz_fminf(float a, float b) SHZ_NOEXCEPT
Returns the minimum value of two given floats.
float shz_inv_sqrtf(float x) SHZ_NOEXCEPT
Calculates 1.0f/sqrtf( x ), using a fast approximation, while safely protecting against division-by-z...
float shz_randf_range(int *seed, float min, float max) SHZ_NOEXCEPT
Returns a random floating-point number between min and max, using and updating the given seed.
float shz_clampf(float value, float min, float max) SHZ_NOEXCEPT
Clamps a floating-point value by the given min and max values.
float shz_roundf(float x) SHZ_NOEXCEPT
Replacement for the <math.h> routine, roundf().
float shz_fabsf(float x) SHZ_NOEXCEPT
Replacement for the <math.h> routine, fabsf().
float shz_logf(float x) SHZ_NOEXCEPT
Fast approximation for C's logf().
float shz_remapf(float value, float inputStart, float inputEnd, float outputStart, float outputEnd) SHZ_NOEXCEPT
Maps a value within the given range inputStart to inputEnd, to be within the range of outputStart to ...
float shz_stepf(float x, float edge) SHZ_NOEXCEPT
returns 0.0f if x < edge, otherwise 1.0f
float shz_pow2f(float p) SHZ_NOEXCEPT
Fast approximation for raising 2 to a floating-point power.