fennec
Loading...
Searching...
No Matches
common.h File Reference

Common More...

#include <fennec/math/detail/_math.h>
#include <fennec/lang/limits.h>
#include <fennec/math/vector.h>

Go to the source code of this file.

Detailed Description

Author
Medusa Slockbower

Functions

Sign Related Functions
template<typename genType >
constexpr genType fennec::sign (genType x)
 Returns \(1\) if \(x > 0\), \(0\) if \(x = 0\), or \(-1\) if \(x<0\).
 
template<typename genType >
constexpr genType fennec::abs (genType x)
 Returns \(x\) if \(x \ge 0\), otherwise it returns \(-x\).
 
Rounding Functions
template<typename genType >
constexpr genType fennec::floor (genType x)
 Returns a value equal to the nearest integer that is less than or equal to \(x\).
 
template<typename genType >
constexpr genType fennec::ceil (genType x)
 Returns a value equal to the nearest integer that is greater than or equal to \(x\).
 
template<typename genType >
constexpr genType fennec::round (genType x)
 Returns a value equal to the nearest integer. In C++, a fractional part of \(0.5\) will always round up.
 
template<typename genType >
constexpr genType fennec::trunc (genType x)
 Returns a value equal to the nearest integer that is less than or equal to \(x\).
 
template<typename genType >
constexpr genType fennec::roundEven (genType x)
 Returns a value equal to the nearest integer. In C++, a fractional part of \(0.5\) will always round to the nearest even integer.
 
Floating Point Functions
template<typename genType >
constexpr genType fennec::fract (genType x)
 Returns \(x - floor(x)\).
 
template<typename genType >
constexpr genType fennec::mod (genType x, genType y)
 Modulus. Returns \(x-y\cdot floor (x/y)\).
 
template<typename genType >
constexpr genType fennec::modf (genType x, genType &i)
 Returns the fractional part of \(x\) and stores the integral part in \(i\).
 
template<typename genType , typename genBType = bool_t>
requires (is_bool_v<genBType>)
constexpr genBType fennec::isnan (genType x)
 Returns true if \(x\) holds a NaN. Returns false otherwise.
 
template<typename genType , typename genBType = bool_t>
requires (is_bool_v<genBType>)
constexpr genBType fennec::isinf (genType x)
 Returns true if \(x\) holds a positive or negative infinity. Returns false otherwise.


 
template<typename genType , typename genIType = int_t>
requires (is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
constexpr genIType fennec::floatBitsToInt (genType x)
 
template<typename genType , typename genUType = uint_t>
requires (is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
constexpr genUType fennec::floatBitsToUint (genType x)
 Returns a signed or unsigned integer value representing the encoding of a floating-point value. The float value's bit-level representation is preserved.
 
template<typename genType = float_t, typename genIType = int_t>
requires (is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
constexpr genType fennec::intBitsToFloat (genIType x)
 
template<typename genType = float_t, typename genUType = uint_t>
requires (is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
constexpr genType fennec::uintBitsToFloat (genUType x)
 Returns a floating-point value corresponding to a signed or unsigned integer encoding of a floating-point value.


 
template<typename genType >
constexpr genType fennec::fma (genType a, genType b, genType c)
 Computes and returns \(a \cdot b + c\).


 
template<typename genType , typename genIType = int_t>
requires (is_integral_v<genIType>)
constexpr genType fennec::frexp (genType x, genIType &exp)
 Splits \(x\) into a floating-point significand in the range \([0.5,1.0]\), and an integral exponent of two, such that \(x=sig \cdot 2^{exp}\).
 
template<typename genType , typename genIType = int_t>
requires (is_integral_v<genIType>)
constexpr genType fennec::ldexp (genType x, genIType exp)
 Builds a floating-point number from \(x\) and the corresponding integral exponent of two in \(exp\).
 
Comparison Functions
template<typename genType >
constexpr genType fennec::min (genType x, genType y)
 Returns \(y\) if \(x<y;\) otherwise it returns \(x\).
 
template<typename genType >
constexpr genType fennec::max (genType x, genType y)
 Returns \(y\) if \(y<x\), otherwise it returns \(x\).
 
template<typename genType >
constexpr genType fennec::clamp (genType x, genType minVal, genType maxVal)
 Returns \(min (max (x, minVal), maxVal)\).
 
Simple Curves
template<typename genType >
requires (is_floating_point_v<genType>)
constexpr genType fennec::step (genType edge, genType x)
 Returns \(0.0\) if \(x<edge\), otherwise, it returns \(1.0\).
 
template<typename genType >
requires (is_floating_point_v<genType>)
constexpr genType fennec::smoothstep (genType edge0, genType edge1, genType x)
 Returns \(0.0\) if \(x\le edge0\) and \(1.0\) if \(x\ge edge1\), and performs smooth Hermite interpolation between \(0\) and \(1\) when \(edge0<x<edge1\).
 
template<typename genType >
requires (is_floating_point_v<genType>)
constexpr genType fennec::mix (genType x, genType y, genType a)
 Returns the linear blend of \(x\) and \(y\), i.e., \(x \cdot (1-a) + y \cdot a\).
 
template<typename genType , typename genBType = bool_t>
requires (is_bool_v<genBType> and is_floating_point_v<genType>)
constexpr genType fennec::mix (genType x, genType y, genBType a)
 Selects which value to return. For Vectors, when the boolean is a scalar, it selects the vector, otherwise, each component is selected.
 

Function Documentation

◆ sign()

template<typename genType >
constexpr genType fennec::sign ( genType  x)
constexpr
Returns
\(1\) if \(x > 0\), \(0\) if \(x = 0\), or \(-1\) if \(x<0\)

We can express this as,

\(\text{sign}(x) = \text{sgn}(x) = \left\{\begin{array}{lr} -1 & x < 0, \\ 0 & x = 0, \\ 1 & x > 0.\end{array}\right.\)

Parameters
xinput value

◆ abs()

template<typename genType >
constexpr genType fennec::abs ( genType  x)
constexpr
Returns
\(x\) if \(x \ge 0\), otherwise it returns \(-x\).

We can express this as,

\(\text{abs}(x)=\left|x\right|\).

Parameters
xinput value

◆ floor()

template<typename genType >
constexpr genType fennec::floor ( genType  x)
constexpr
Returns
a value equal to the nearest integer that is less than or equal to \(x\)

We can express this as,

\(\text{floor}(x)=\lfloor x\rfloor\)

Parameters
xinput value

◆ ceil()

template<typename genType >
constexpr genType fennec::ceil ( genType  x)
constexpr
Returns
a value equal to the nearest integer that is greater than or equal to \(x\)

We can express this as,

\(\text{ceil}(x)=\lceil{x}\rceil\)

Parameters
xinput value

◆ round()

template<typename genType >
constexpr genType fennec::round ( genType  x)
constexpr
Returns
a value equal to the nearest integer.

In C++, a fractional part of \(0.5\) will always round up.

We can express this as,

\(\text{round}(x) = \text{sgn}(x) \cdot \lfloor \left| x \right| + 0.5 \rfloor\)

Parameters
xinput value

◆ trunc()

template<typename genType >
constexpr genType fennec::trunc ( genType  x)
constexpr
Returns
a value equal to the nearest integer that is less than or equal to \(x\)

We can express this as,

\(\text{trunc}(x) = \text{sgn}(x) \cdot \lceil \left| x \right| - 0.5 \rceil\)

Parameters
xinput value

◆ roundEven()

template<typename genType >
constexpr genType fennec::roundEven ( genType  x)
constexpr
Returns
a value equal to the nearest integer.

In C++, a fractional part of \(0.5\) will always round to the nearest even integer.

We can express this as,

\(\text{roundEven}() = \begin{cases}\lfloor{x}\rfloor + \text{mod}(\lfloor{x}\rfloor, 2.0) & \text{fract}(x) = 0.5, \\ \text{round}(x) \end{cases}\)

Parameters
xinput value

◆ fract()

template<typename genType >
constexpr genType fennec::fract ( genType  x)
constexpr
Returns
\(x - \text{floor}(x)\)

We can express this as,

\(\text{fract}(x)=x-\text{floor}\)

Parameters
xinput value

◆ mod()

template<typename genType >
constexpr genType fennec::mod ( genType  x,
genType  y 
)
constexpr
Returns
\(x-y\cdot\text{floor}(x/y)\)

We can express this as,

\(\text{fract}(x)=x-\text{floor}(\frac{x}{y})\)

Parameters
xdividend
ydivisor

◆ modf()

template<typename genType >
constexpr genType fennec::modf ( genType  x,
genType &  i 
)
constexpr
Returns
the fractional part of \(x\) and stores the integral part in \(i\).

We can express this as,

\(\text{modf}(x) = \text{trunc}(x),\, i := \text{fract}(x)\)

Parameters
xinput value
iintegral out

◆ isnan()

template<typename genType , typename genBType = bool_t>
requires (is_bool_v<genBType>)
constexpr genBType fennec::isnan ( genType  x)
constexpr
Returns
true if \(x\) holds a NaN. Returns false otherwise.

\(NaN\) is a concept unique to computing. It strictly means, and more specifically, floating point values can only represent real numbers. This is why some functions, like sqrt(), return \(NaN\) when an expression would return a value in a different coordinate space. There are other cases, such as \(\frac{1}{x}\), where \(x=0\) is undefined, and respectively the return value is also \(NaN\).

To learn more, see IEEE 754

Parameters
xinput value

◆ isinf()

template<typename genType , typename genBType = bool_t>
requires (is_bool_v<genBType>)
constexpr genBType fennec::isinf ( genType  x)
constexpr
Returns
true if \(x\) holds a positive or negative infinity. Returns false otherwise.

\(\inf\), or \(\infty\), is used to express any function that is boundless, endless, or larger than any natural number. This function has applications in Set Theory and Mathematical Analysis.

Parameters
xinput value

◆ floatBitsToInt()

template<typename genType , typename genIType = int_t>
requires (is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
constexpr genIType fennec::floatBitsToInt ( genType  x)
constexpr
Returns
a signed or unsigned integer value representing the encoding of a floating-point value. The float value's bit-level representation is preserved.

we can express this in set theory, i.e.

let \(B\) be a set, such that, \(B=\left\lbrace{b_{0},...b_{32}}\right\rbrace\) and \(b_{i} \in S\) where \(S=\left\lbrace{0, 1}\right\rbrace\)
let \(m_B=\frac{b_{0}}{2^1}+\cdots +\frac{b_{i}}{2^{i+1}}+\cdots +\frac{b_{22}}{2^{23}}\begin{cases}1&\end{cases}\)
let \(p_B=b_{23}\cdot 2^0+\cdots +b_i\cdot 2^{i-23}+\cdots +b_{30}\cdot 2^7-127\)
let \(s_B=\begin{cases}-1,&b_{31}=1 \\ 1\end{cases}\)

then, \(x_B=s_B m_B 2^{p_B}\)
and, \(i_B=-b_{31} 2^{31}+\sum_{i=0}^{30}{a_i 2^i}\)
and, \(u_B=\sum_{i=0}^{31}{a_i 2^i}\)

Parameters
xvalue to convert

◆ floatBitsToUint()

template<typename genType , typename genUType = uint_t>
requires (is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
constexpr genUType fennec::floatBitsToUint ( genType  x)
constexpr
Returns
a signed or unsigned integer value representing the encoding of a floating-point value. The float value's bit-level representation is preserved.

we can express this in set theory, i.e.

let \(B\) be a set, such that, \(B=\left\lbrace{b_{0},...b_{32}}\right\rbrace\) and \(b_{i} \in S\) where \(S=\left\lbrace{0, 1}\right\rbrace\)
let \(m_B=\frac{b_{0}}{2^1}+\cdots +\frac{b_{i}}{2^{i+1}}+\cdots +\frac{b_{22}}{2^{23}}\begin{cases}1&\end{cases}\)
let \(p_B=b_{23}\cdot 2^0+\cdots +b_i\cdot 2^{i-23}+\cdots +b_{30}\cdot 2^7-127\)
let \(s_B=\begin{cases}-1,&b_{31}=1 \\ 1\end{cases}\)

then, \(x_B=s_B m_B 2^{p_B}\)
and, \(i_B=-b_{31} 2^{31}+\sum_{i=0}^{30}{a_i 2^i}\)
and, \(u_B=\sum_{i=0}^{31}{a_i 2^i}\)

Parameters
xvalue to convert

◆ intBitsToFloat()

template<typename genType = float_t, typename genIType = int_t>
requires (is_floating_point_v<genType> and is_integral_v<genIType> and is_signed_v<genIType> and sizeof(genType) == sizeof(genIType))
constexpr genType fennec::intBitsToFloat ( genIType  x)
constexpr
Returns
a floating-point value corresponding to a signed or unsigned integer encoding of a floating-point value.

we can express this in set theory, i.e.

let \(B\) be a set, such that, \(B=\left\lbrace{b_{0},...b_{32}}\right\rbrace\) and \(b_{i} \in S\) where \(S=\left\lbrace{0, 1}\right\rbrace\)
let \(m_B=\frac{b_{0}}{2^1}+\cdots +\frac{b_{i}}{2^{i+1}}+\cdots +\frac{b_{22}}{2^{23}}\begin{cases}1&\end{cases}\)
let \(p_B=b_{23}\cdot 2^0+\cdots +b_i\cdot 2^{i-23}+\cdots +b_{30}\cdot 2^7-127\)
let \(s_B=\begin{cases}-1,&b_{31}=1 \\ 1\end{cases}\)

then, \(x_B=s_B m_B 2^{p_B}\)
and, \(i_B=-b_{31} 2^31+\sum_{i=0}^{30}{a_i 2^i}\)
and, \(u_B=\sum_{i=0}^{31}{a_i 2^i}\)

Parameters
xvalue to convert

◆ uintBitsToFloat()

template<typename genType = float_t, typename genUType = uint_t>
requires (is_floating_point_v<genType> and is_integral_v<genUType> and is_unsigned_v<genUType> and sizeof(genType) == sizeof(genUType))
constexpr genType fennec::uintBitsToFloat ( genUType  x)
constexpr
Returns
a floating-point value corresponding to a signed or unsigned integer encoding of a floating-point value.

we can express this in set theory, i.e.

let \(B\) be a set, such that, \(B=\left\lbrace{b_{0},...b_{32}}\right\rbrace\) and \(b_{i} \in S\) where \(S=\left\lbrace{0, 1}\right\rbrace\)
let \(m_B=\frac{b_{0}}{2^1}+\cdots +\frac{b_{i}}{2^{i+1}}+\cdots +\frac{b_{22}}{2^{23}}\begin{cases}1&\end{cases}\)
let \(p_B=b_{23}\cdot 2^0+\cdots +b_i\cdot 2^{i-23}+\cdots +b_{30}\cdot 2^7-127\)
let \(s_B=\begin{cases}-1,&b_{31}=1 \\ 1\end{cases}\)

then, \(x_B=s_B m_B 2^{p_B}\)
and, \(i_B=-b_{31} 2^31+\sum_{i=0}^{30}{a_i 2^i}\)
and, \(u_B=\sum_{i=0}^{31}{a_i 2^i}\)

Parameters
xvalue to convert

◆ fma()

template<typename genType >
constexpr genType fennec::fma ( genType  a,
genType  b,
genType  c 
)
constexpr
Returns
\(a \cdot b + c\).

In C++, this function will use the fused multiply-add, when the instruction is present on the target architecture.

Parameters
athe multiplicand
bthe multiplier
cthe addend

◆ frexp()

template<typename genType , typename genIType = int_t>
requires (is_integral_v<genIType>)
constexpr genType fennec::frexp ( genType  x,
genIType &  exp 
)
constexpr
Returns
The significand of the expression.

The significand is returned by the function and the exponent is returned in the parameter \(exp\). For a floating-point value of zero, the significand and exponent are both zero. If an implementation supports signed zero, an input value of minus zero should return a significand of minus zero. For a floating-point value that is an infinity or is not a number, the results are undefined. If the input \(x\) is a vector, this operation is performed in a component-wise manner; the value returned by the function and the value written to \(exp\) are vectors with the same number of components as \(x\).

Parameters
xThe floating-point value to split
expThe variable to store the exponent in

◆ ldexp()

template<typename genType , typename genIType = int_t>
requires (is_integral_v<genIType>)
constexpr genType fennec::ldexp ( genType  x,
genIType  exp 
)
constexpr
Returns
\({x}\cdot{2^{exp}}\)

Builds a floating-point number from x and the corresponding integral exponent of two in exp, returning: \({x}\cdot{2^{exp}}\). If this product is too large to be represented in the floating-point type, the result is undefined. If exp is greater than +128 (single-precision) or +1024 (double-precision), the value returned is undefined. If exp is less than -126 (single-precision) or -1022 (double-precision), the value returned may be flushed to zero. Additionally, splitting the value into a significand and exponent using frexp() and then reconstructing a floating-point value using ldexp() should yield the original input for zero and all finite non-subnormal values. If the input x is a vector, this operation is performed in a component-wise manner; the value passed in exp and returned by the function are vectors with the same number of components as x.

Parameters
xThe significand
expThe exponent

◆ min()

template<typename genType >
constexpr genType fennec::min ( genType  x,
genType  y 
)
constexpr
Returns
\(y\) if \(x<y\), otherwise it returns \(x\)

We can express this as,

\(\text{min}(x, y)=\begin{cases}y, & y < x \\ x\end{cases}\)

Parameters
xinput value \(x\)
yinput value \(y\)

◆ max()

template<typename genType >
constexpr genType fennec::max ( genType  x,
genType  y 
)
constexpr
Returns
\(y\) if \(y<x\), otherwise it returns \(x\)

We can express this as,

\(\text{max}(x, y)=\begin{cases}y, & x < y \\ x\end{cases}\)

Parameters
xfirst input value
ysecond input value

◆ clamp()

template<typename genType >
constexpr genType fennec::clamp ( genType  x,
genType  minVal,
genType  maxVal 
)
constexpr
Returns
\(\text{min}(\text{max}(x, minVal), maxVal)\). Results are undefined if \(minVal > maxVal\)

We can express this as,

\(\text{clamp}(x, min, max)=\begin{cases}min, & x < min \\ x \\ max, & x > max\end{cases}\)

Parameters
xinput value
minValminimum value
maxValmaximum value

◆ step()

template<typename genType >
requires (is_floating_point_v<genType>)
constexpr genType fennec::step ( genType  edge,
genType  x 
)
constexpr
Returns
\(0.0\) if \(x<edge\), otherwise, it returns \(1.0\)

We can express this as,

\(\text{step}(edge, x)=\begin{cases}0.0 & x < edge \\ 1.0 \end{cases}\)

Parameters
edgeThe \(x\) coordinate of the discontinuity
xThe coordinate of the sample location

◆ smoothstep()

template<typename genType >
requires (is_floating_point_v<genType>)
constexpr genType fennec::smoothstep ( genType  edge0,
genType  edge1,
genType  x 
)
constexpr
Returns
\(0.0\) if \(x\le edge0\) and \(1.0\) if \(x\ge edge1\), and performs smooth Hermite interpolation between \(0\) and \(1\) when \(edge0<x<edge1\).

This is useful in cases where you would want a threshold function with a smooth transition.

This is equivalent to:

genFType t;
t = clamp((x - edge0) / (edge1 - edge0), 0, 1);
return t * t * (3 - 2 * t);


Results are undefined if \(edge0\ge edge1\).

We can express this as,

\(\text{smoothstep}(e_0, e_1, x)=\begin{cases}0, & {x}\le{e_0} \\ 3{\frac{x-e_0}{e_1-e_0}}^{2} - 2{\frac{x-e_0}{e_1-e_0}}^{3}, & {e_0}\le{x}\le{e_1} \\ 1, & {1}\le{e_x}\end{cases}\)

Parameters
edge0\(x\) value where the function returns \(0.0\)
edge1\(x\) value where the function returns \(1.0\)
x\(x\) coordinate input

◆ mix() [1/2]

template<typename genType >
requires (is_floating_point_v<genType>)
constexpr genType fennec::mix ( genType  x,
genType  y,
genType  a 
)
constexpr
Returns
the linear blend of \(x\) and \(y\), i.e., \(x \cdot (1-a) + y \cdot a\)

We can express this as,

\(\text{mix}(x, y, a)=x+a \cdot (y - x)\)

The reason for the difference between the mathematical definition and the glsl definition is due to floating-point precision errors. Multiplying \(x\) and \(y\) separately preserves their precision before the addition happens.

Parameters
xFirst value
ySecond value
aInterpolant

◆ mix() [2/2]

template<typename genType , typename genBType = bool_t>
requires (is_bool_v<genBType> and is_floating_point_v<genType>)
constexpr genType fennec::mix ( genType  x,
genType  y,
genBType  a 
)
constexpr
Returns
\(x\) when \(a=T\), otherwise returns \(y\)

Selects which value to return. For Vectors, when the boolean is a scalar, it selects the vector, otherwise, each component is selected.

This implementation uses the ternary operator:

return a ? x : y;

Which will get reduced down to a conditional move instruction over branching.

We can express this as,

\(\text{mix}(x, y, A) = \begin{cases} x, & A=T \\ y & A=F \end{cases}\)

Parameters
xTrue Value
yFalse Value
aBoolean Value