Skip to content

Commit 794bd5c

Browse files
authored
Added hyperbolic numeric builtins. (#28)
Fixes #14. 1. Added 5 new trait/function pairs following the existing `tanh` pattern 2. Each function has: - A trait (e.g., `NumericBuiltinAcosh`) - A free function (e.g., `pub fn acosh<T: NumericBuiltinAcosh>(e: T) -> T`) - Implementations for `f32`, `Vec2f`, `Vec3f`, `Vec4f` 3. Added 5 sanity tests (`sanity_acosh`, `sanity_asinh`, `sanity_atanh`, `sanity_cosh`, `sanity_sinh`) 4. Updated doc comment table to mark all 5 functions as implemented (`x`)
1 parent 80d10b2 commit 794bd5c

1 file changed

Lines changed: 224 additions & 5 deletions

File tree

crates/wgsl-rs/src/std/numeric_builtin_functions.rs

Lines changed: 224 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66
//! | --- | --- | --- | --- |
77
//! |x| fn abs(e: T ) -> T | S is AbstractInt, AbstractFloat, i32, u32, f32, or f16. T is S, or vecN<S> | The absolute value of e. Component-wise when T is a vector. <br> If e is a floating-point type, then the result is e with a positive sign bit.<br> If e is an unsigned integer scalar type, then the result is e.<br> If e is a signed integer scalar type and evaluates to the largest<br> negative value, then the result is e. |
88
//! |x| fn acos(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Note: The result is not mathematically meaningful when abs(e) > 1. |
9-
//! | | fn acosh(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Note: The result is not mathematically meaningful when e < 1. |
9+
//! |x| fn acosh(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Note: The result is not mathematically meaningful when e < 1. |
1010
//! |x| fn asin(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Note: The result is not mathematically meaningful when abs(e) > 1. |
11-
//! | | fn asinh(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns the inverse hyperbolic sine (sinh-1) of e, as a hyperbolic angle in radians. That is, approximates x such that sinh(x) = e. <br> Component-wise when T is a vector. |
11+
//! |x| fn asinh(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns the inverse hyperbolic sine (sinh-1) of e, as a hyperbolic angle in radians. That is, approximates x such that sinh(x) = e. <br> Component-wise when T is a vector. |
1212
//! |x| fn atan(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns the principal value, in radians, of the inverse tangent (tan-1) of e. That is, approximates x with π/2 ≤ x ≤ π/2, such that tan(x) = e. <br> Component-wise when T is a vector. |
13-
//! | | fn atanh(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Note: The result is not mathematically meaningful when abs(e) ≥ 1. |
13+
//! |x| fn atanh(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Note: The result is not mathematically meaningful when abs(e) ≥ 1. |
1414
//! | | fn atan2(y: T, x: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns an angle, in radians, in the interval [-π, π] whose tangent is y÷x. <br> The quadrant selected by the result depends on the signs of y and x.<br> For example, the function may be implemented as:<br> <br> <br> atan(y/x) when x > 0<br> <br> atan(y/x) + π when (x < 0) and (y > 0)<br> <br> atan(y/x) - π when (x < 0) and (y < 0)<br> <br> Note: atan2 is ill-defined when y/x is ill-defined, at the origin (x,y) = (0,0), and when y is non-normal or infinite.<br> Component-wise when T is a vector. |
1515
//! |x| fn ceil(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns the ceiling of e. Component-wise when T is a vector. |
1616
//! |x| fn clamp(e: T, low: T, high: T) -> T | S is AbstractInt, AbstractFloat, i32, u32, f32, or f16. T is S, or vecN<S> | Restricts the value of e within a range. <br> If T is an integer type, then the result is min(max(e, low), high).<br> If T is a floating-point type, then the result is either min(max(e, low), high), or the median of the three values e, low, high.<br> Component-wise when T is a vector.<br> If low is greater than high, then:<br> <br> <br> It is a shader-creation error if low and high are const-expressions.<br> <br> It is a pipeline-creation error if low and high are override-expressions. |
1717
//! |x| fn cos(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns the cosine of e, where e is in radians. Component-wise when T is a vector. |
18-
//! | | fn cosh(arg: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns the hyperbolic cosine of arg, where arg is a hyperbolic angle in radians.<br> Approximates the pure mathematical function (earg + e−arg)÷2,<br> but not necessarily computed that way. <br> Component-wise when T is a vector |
18+
//! |x| fn cosh(arg: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns the hyperbolic cosine of arg, where arg is a hyperbolic angle in radians.<br> Approximates the pure mathematical function (earg + e−arg)÷2,<br> but not necessarily computed that way. <br> Component-wise when T is a vector |
1919
//! | | fn countLeadingZeros(e: T) -> T | T is i32, u32, vecN<i32>, or vecN<u32> | The number of consecutive 0 bits starting from the most significant bit<br> of e, when T is a scalar type. Component-wise when T is a vector. Also known as "clz" in some languages. |
2020
//! | | fn countOneBits(e: T) -> T | T is i32, u32, vecN<i32>, or vecN<u32> | The number of 1 bits in the representation of e. Also known as "population count". Component-wise when T is a vector. |
2121
//! | | fn countTrailingZeros(e: T) -> T | T is i32, u32, vecN<i32>, or vecN<u32> | The number of consecutive 0 bits starting from the least significant bit<br> of e, when T is a scalar type. Component-wise when T is a vector. Also known as "ctz" in some languages. |
@@ -62,7 +62,7 @@
6262
//! |x| fn saturate(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns clamp(e, 0.0, 1.0). Component-wise when T is a vector. |
6363
//! |x| fn sign(e: T) -> T | S is AbstractInt, AbstractFloat, i32, f32, or f16. T is S, or vecN<S> | Result is: <br> <br> 1 when e > 0 <br> 0 when e = 0 <br> -1 when e < 0 <br> <br> Component-wise when T is a vector. |
6464
//! |x| fn sin(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns the sine of e, where e is in radians. Component-wise when T is a vector. |
65-
//! | | fn sinh(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns the hyperbolic sine of e, where e is a hyperbolic angle in radians.<br> Approximates the pure mathematical function<br> (earg − e−arg)÷2,<br> but not necessarily computed that way. <br> Component-wise when T is a vector. |
65+
//! |x| fn sinh(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns the hyperbolic sine of e, where e is a hyperbolic angle in radians.<br> Approximates the pure mathematical function<br> (earg − e−arg)÷2,<br> but not necessarily computed that way. <br> Component-wise when T is a vector. |
6666
//! | | fn smoothstep(low: T, high: T, x: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns the smooth Hermite interpolation between 0 and 1. Component-wise when T is a vector. <br> For scalar T, the result is t * t * (3.0 - 2.0 * t),<br> where t = clamp((x - low) / (high - low), 0.0, 1.0). |
6767
//! |x| fn sqrt(e: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns the square root of e. Component-wise when T is a vector. |
6868
//! |x| fn step(edge: T, x: T) -> T | S is AbstractFloat, f32, or f16. T is S or vecN<S> | Returns 1.0 if edge ≤ x, and 0.0 otherwise. Component-wise when T is a vector. |
@@ -881,6 +881,190 @@ mod tanh {
881881
impl_tanh_vec!(Vec4f);
882882
}
883883

884+
/// Provides the numeric built-in function `acosh`.
885+
pub trait NumericBuiltinAcosh {
886+
/// Returns the inverse hyperbolic cosine (cosh⁻¹) of e.
887+
/// Component-wise when T is a vector.
888+
/// Note: The result is not mathematically meaningful when e < 1.
889+
fn acosh(self) -> Self;
890+
}
891+
892+
/// Returns the inverse hyperbolic cosine (cosh⁻¹) of e.
893+
/// Component-wise when T is a vector.
894+
/// Note: The result is not mathematically meaningful when e < 1.
895+
pub fn acosh<T: NumericBuiltinAcosh>(e: T) -> T {
896+
<T as NumericBuiltinAcosh>::acosh(e)
897+
}
898+
899+
mod acosh {
900+
use super::*;
901+
impl NumericBuiltinAcosh for f32 {
902+
fn acosh(self) -> Self {
903+
self.acosh()
904+
}
905+
}
906+
macro_rules! impl_acosh_vec {
907+
($ty:ty) => {
908+
impl NumericBuiltinAcosh for $ty {
909+
fn acosh(self) -> Self {
910+
Self {
911+
inner: self.inner.map(|t| t.acosh()),
912+
}
913+
}
914+
}
915+
};
916+
}
917+
impl_acosh_vec!(Vec2f);
918+
impl_acosh_vec!(Vec3f);
919+
impl_acosh_vec!(Vec4f);
920+
}
921+
922+
/// Provides the numeric built-in function `asinh`.
923+
pub trait NumericBuiltinAsinh {
924+
/// Returns the inverse hyperbolic sine (sinh⁻¹) of e.
925+
/// Component-wise when T is a vector.
926+
fn asinh(self) -> Self;
927+
}
928+
929+
/// Returns the inverse hyperbolic sine (sinh⁻¹) of e.
930+
/// Component-wise when T is a vector.
931+
pub fn asinh<T: NumericBuiltinAsinh>(e: T) -> T {
932+
<T as NumericBuiltinAsinh>::asinh(e)
933+
}
934+
935+
mod asinh {
936+
use super::*;
937+
impl NumericBuiltinAsinh for f32 {
938+
fn asinh(self) -> Self {
939+
self.asinh()
940+
}
941+
}
942+
macro_rules! impl_asinh_vec {
943+
($ty:ty) => {
944+
impl NumericBuiltinAsinh for $ty {
945+
fn asinh(self) -> Self {
946+
Self {
947+
inner: self.inner.map(|t| t.asinh()),
948+
}
949+
}
950+
}
951+
};
952+
}
953+
impl_asinh_vec!(Vec2f);
954+
impl_asinh_vec!(Vec3f);
955+
impl_asinh_vec!(Vec4f);
956+
}
957+
958+
/// Provides the numeric built-in function `atanh`.
959+
pub trait NumericBuiltinAtanh {
960+
/// Returns the inverse hyperbolic tangent (tanh⁻¹) of e.
961+
/// Component-wise when T is a vector.
962+
/// Note: The result is not mathematically meaningful when abs(e) >= 1.
963+
fn atanh(self) -> Self;
964+
}
965+
966+
/// Returns the inverse hyperbolic tangent (tanh⁻¹) of e.
967+
/// Component-wise when T is a vector.
968+
/// Note: The result is not mathematically meaningful when abs(e) >= 1.
969+
pub fn atanh<T: NumericBuiltinAtanh>(e: T) -> T {
970+
<T as NumericBuiltinAtanh>::atanh(e)
971+
}
972+
973+
mod atanh {
974+
use super::*;
975+
impl NumericBuiltinAtanh for f32 {
976+
fn atanh(self) -> Self {
977+
self.atanh()
978+
}
979+
}
980+
macro_rules! impl_atanh_vec {
981+
($ty:ty) => {
982+
impl NumericBuiltinAtanh for $ty {
983+
fn atanh(self) -> Self {
984+
Self {
985+
inner: self.inner.map(|t| t.atanh()),
986+
}
987+
}
988+
}
989+
};
990+
}
991+
impl_atanh_vec!(Vec2f);
992+
impl_atanh_vec!(Vec3f);
993+
impl_atanh_vec!(Vec4f);
994+
}
995+
996+
/// Provides the numeric built-in function `cosh`.
997+
pub trait NumericBuiltinCosh {
998+
/// Returns the hyperbolic cosine of e, where e is a hyperbolic angle in
999+
/// radians. Component-wise when T is a vector.
1000+
fn cosh(self) -> Self;
1001+
}
1002+
1003+
/// Returns the hyperbolic cosine of e, where e is a hyperbolic angle in
1004+
/// radians. Component-wise when T is a vector.
1005+
pub fn cosh<T: NumericBuiltinCosh>(e: T) -> T {
1006+
<T as NumericBuiltinCosh>::cosh(e)
1007+
}
1008+
1009+
mod cosh {
1010+
use super::*;
1011+
impl NumericBuiltinCosh for f32 {
1012+
fn cosh(self) -> Self {
1013+
self.cosh()
1014+
}
1015+
}
1016+
macro_rules! impl_cosh_vec {
1017+
($ty:ty) => {
1018+
impl NumericBuiltinCosh for $ty {
1019+
fn cosh(self) -> Self {
1020+
Self {
1021+
inner: self.inner.map(|t| t.cosh()),
1022+
}
1023+
}
1024+
}
1025+
};
1026+
}
1027+
impl_cosh_vec!(Vec2f);
1028+
impl_cosh_vec!(Vec3f);
1029+
impl_cosh_vec!(Vec4f);
1030+
}
1031+
1032+
/// Provides the numeric built-in function `sinh`.
1033+
pub trait NumericBuiltinSinh {
1034+
/// Returns the hyperbolic sine of e, where e is a hyperbolic angle in
1035+
/// radians. Component-wise when T is a vector.
1036+
fn sinh(self) -> Self;
1037+
}
1038+
1039+
/// Returns the hyperbolic sine of e, where e is a hyperbolic angle in radians.
1040+
/// Component-wise when T is a vector.
1041+
pub fn sinh<T: NumericBuiltinSinh>(e: T) -> T {
1042+
<T as NumericBuiltinSinh>::sinh(e)
1043+
}
1044+
1045+
mod sinh {
1046+
use super::*;
1047+
impl NumericBuiltinSinh for f32 {
1048+
fn sinh(self) -> Self {
1049+
self.sinh()
1050+
}
1051+
}
1052+
macro_rules! impl_sinh_vec {
1053+
($ty:ty) => {
1054+
impl NumericBuiltinSinh for $ty {
1055+
fn sinh(self) -> Self {
1056+
Self {
1057+
inner: self.inner.map(|t| t.sinh()),
1058+
}
1059+
}
1060+
}
1061+
};
1062+
}
1063+
impl_sinh_vec!(Vec2f);
1064+
impl_sinh_vec!(Vec3f);
1065+
impl_sinh_vec!(Vec4f);
1066+
}
1067+
8841068
pub trait NumericBuiltinTrunc {
8851069
fn trunc(self) -> Self;
8861070
}
@@ -1590,6 +1774,41 @@ mod test {
15901774
assert_eq!(0.0, tanh_t);
15911775
}
15921776

1777+
#[test]
1778+
fn sanity_acosh() {
1779+
let t = 1.0f32;
1780+
let acosh_t = acosh(t);
1781+
assert_eq!(0.0, acosh_t);
1782+
}
1783+
1784+
#[test]
1785+
fn sanity_asinh() {
1786+
let t = 0.0f32;
1787+
let asinh_t = asinh(t);
1788+
assert_eq!(0.0, asinh_t);
1789+
}
1790+
1791+
#[test]
1792+
fn sanity_atanh() {
1793+
let t = 0.0f32;
1794+
let atanh_t = atanh(t);
1795+
assert_eq!(0.0, atanh_t);
1796+
}
1797+
1798+
#[test]
1799+
fn sanity_cosh() {
1800+
let t = 0.0f32;
1801+
let cosh_t = cosh(t);
1802+
assert_eq!(1.0, cosh_t);
1803+
}
1804+
1805+
#[test]
1806+
fn sanity_sinh() {
1807+
let t = 0.0f32;
1808+
let sinh_t = sinh(t);
1809+
assert_eq!(0.0, sinh_t);
1810+
}
1811+
15931812
#[test]
15941813
fn sanity_trunc() {
15951814
let t = 2.7f32;

0 commit comments

Comments
 (0)