diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..ec6e107d
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,21 @@
+# EditorConfig helps developers define and maintain consistent
+# coding styles between different editors and IDEs
+# editorconfig.org
+
+root = true
+
+[*]
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = space
+indent_size = 4
+
+[*.md]
+# double whitespace at end of line
+# denotes a line break in Markdown
+trim_trailing_whitespace = false
+
+[*.yml]
+indent_size = 2
diff --git a/src/lib.rs b/src/lib.rs
index 29742b45..4a17d3a7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,11 +12,13 @@
#![allow(clippy::eq_op)]
#![allow(clippy::assign_op_pattern)]
+mod libm_helper;
mod math;
use core::{f32, f64};
pub use self::math::*;
+pub use libm_helper::*;
/// Approximate equality with 1 ULP of tolerance
#[doc(hidden)]
diff --git a/src/libm_helper.rs b/src/libm_helper.rs
new file mode 100644
index 00000000..52d0c4c2
--- /dev/null
+++ b/src/libm_helper.rs
@@ -0,0 +1,171 @@
+use core::marker::PhantomData;
+
+use crate::*;
+
+/// Generic helper for libm functions, abstracting over f32 and f64.
+/// # Type Parameter:
+/// - `T`: Either `f32` or `f64`
+///
+/// # Examples
+/// ```rust
+/// use libm::{self, Libm};
+///
+/// const PI_F32: f32 = 3.1415927410e+00;
+/// const PI_F64: f64 = 3.1415926535897931160e+00;
+///
+/// assert!(Libm::::cos(0.0f32) == libm::cosf(0.0));
+/// assert!(Libm::::sin(PI_F32) == libm::sinf(PI_F32));
+///
+/// assert!(Libm::::cos(0.0f64) == libm::cos(0.0));
+/// assert!(Libm::::sin(PI_F64) == libm::sin(PI_F64));
+/// ```
+pub struct Libm(PhantomData);
+
+macro_rules! libm_helper {
+ ($t:ident, funcs: $funcs:tt) => {
+ impl Libm<$t> {
+ #![allow(unused_parens)]
+
+ libm_helper! { $funcs }
+ }
+ };
+
+ ({$($func:tt);*}) => {
+ $(
+ libm_helper! { $func }
+ )*
+ };
+
+ ((fn $func:ident($($arg:ident: $arg_typ:ty),*) -> ($($ret_typ:ty),*); => $libm_fn:ident)) => {
+ #[inline(always)]
+ pub fn $func($($arg: $arg_typ),*) -> ($($ret_typ),*) {
+ $libm_fn($($arg),*)
+ }
+ };
+}
+
+libm_helper! {
+ f32,
+ funcs: {
+ (fn acos(x: f32) -> (f32); => acosf);
+ (fn acosh(x: f32) -> (f32); => acoshf);
+ (fn asin(x: f32) -> (f32); => asinf);
+ (fn asinh(x: f32) -> (f32); => asinhf);
+ (fn atan(x: f32) -> (f32); => atanf);
+ (fn atan2(y: f32, x: f32) -> (f32); => atan2f);
+ (fn atanh(x: f32) -> (f32); => atanhf);
+ (fn cbrt(x: f32) -> (f32); => cbrtf);
+ (fn ceil(x: f32) -> (f32); => ceilf);
+ (fn copysign(x: f32, y: f32) -> (f32); => copysignf);
+ (fn cos(x: f32) -> (f32); => cosf);
+ (fn cosh(x: f32) -> (f32); => coshf);
+ (fn erf(x: f32) -> (f32); => erff);
+ (fn erfc(x: f32) -> (f32); => erfcf);
+ (fn exp(x: f32) -> (f32); => expf);
+ (fn exp2(x: f32) -> (f32); => exp2f);
+ (fn exp10(x: f32) -> (f32); => exp10f);
+ (fn expm1(x: f32) -> (f32); => expm1f);
+ (fn fabs(x: f32) -> (f32); => fabsf);
+ (fn fdim(x: f32, y: f32) -> (f32); => fdimf);
+ (fn floor(x: f32) -> (f32); => floorf);
+ (fn fma(x: f32, y: f32, z: f32) -> (f32); => fmaf);
+ (fn fmax(x: f32, y: f32) -> (f32); => fmaxf);
+ (fn fmin(x: f32, y: f32) -> (f32); => fminf);
+ (fn fmod(x: f32, y: f32) -> (f32); => fmodf);
+ (fn frexp(x: f32) -> (f32, i32); => frexpf);
+ (fn hypot(x: f32, y: f32) -> (f32); => hypotf);
+ (fn ilogb(x: f32) -> (i32); => ilogbf);
+ (fn j0(x: f32) -> (f32); => j0f);
+ (fn j1(x: f32) -> (f32); => j1f);
+ (fn jn(n: i32, x: f32) -> (f32); => jnf);
+ (fn ldexp(x: f32, n: i32) -> (f32); => ldexpf);
+ (fn lgamma_r(x: f32) -> (f32, i32); => lgammaf_r);
+ (fn lgamma(x: f32) -> (f32); => lgammaf);
+ (fn log(x: f32) -> (f32); => logf);
+ (fn log1p(x: f32) -> (f32); => log1pf);
+ (fn log2(x: f32) -> (f32); => log2f);
+ (fn log10(x: f32) -> (f32); => log10f);
+ (fn modf(x: f32) -> (f32, f32); => modff);
+ (fn nextafter(x: f32, y: f32) -> (f32); => nextafterf);
+ (fn pow(x: f32, y: f32) -> (f32); => powf);
+ (fn remainder(x: f32, y: f32) -> (f32); => remainderf);
+ (fn remquo(x: f32, y: f32) -> (f32, i32); => remquof);
+ (fn rint(x: f32) -> (f32); => rintf);
+ (fn round(x: f32) -> (f32); => roundf);
+ (fn scalbn(x: f32, n: i32) -> (f32); => scalbnf);
+ (fn sin(x: f32) -> (f32); => sinf);
+ (fn sincos(x: f32) -> (f32, f32); => sincosf);
+ (fn sinh(x: f32) -> (f32); => sinhf);
+ (fn sqrt(x: f32) -> (f32); => sqrtf);
+ (fn tan(x: f32) -> (f32); => tanf);
+ (fn tanh(x: f32) -> (f32); => tanhf);
+ (fn tgamma(x: f32) -> (f32); => tgammaf);
+ (fn trunc(x: f32) -> (f32); => truncf);
+ (fn y0(x: f32) -> (f32); => y0f);
+ (fn y1(x: f32) -> (f32); => y1f);
+ (fn yn(n: i32, x: f32) -> (f32); => ynf)
+ }
+}
+
+libm_helper! {
+ f64,
+ funcs: {
+ (fn acos(x: f64) -> (f64); => acos);
+ (fn acosh(x: f64) -> (f64); => acosh);
+ (fn asin(x: f64) -> (f64); => asin);
+ (fn asinh(x: f64) -> (f64); => asinh);
+ (fn atan(x: f64) -> (f64); => atan);
+ (fn atan2(y: f64, x: f64) -> (f64); => atan2);
+ (fn atanh(x: f64) -> (f64); => atanh);
+ (fn cbrt(x: f64) -> (f64); => cbrt);
+ (fn ceil(x: f64) -> (f64); => ceil);
+ (fn copysign(x: f64, y: f64) -> (f64); => copysign);
+ (fn cos(x: f64) -> (f64); => cos);
+ (fn cosh(x: f64) -> (f64); => cosh);
+ (fn erf(x: f64) -> (f64); => erf);
+ (fn erfc(x: f64) -> (f64); => erfc);
+ (fn exp(x: f64) -> (f64); => exp);
+ (fn exp2(x: f64) -> (f64); => exp2);
+ (fn exp10(x: f64) -> (f64); => exp10);
+ (fn expm1(x: f64) -> (f64); => expm1);
+ (fn fabs(x: f64) -> (f64); => fabs);
+ (fn fdim(x: f64, y: f64) -> (f64); => fdim);
+ (fn floor(x: f64) -> (f64); => floor);
+ (fn fma(x: f64, y: f64, z: f64) -> (f64); => fma);
+ (fn fmax(x: f64, y: f64) -> (f64); => fmax);
+ (fn fmin(x: f64, y: f64) -> (f64); => fmin);
+ (fn fmod(x: f64, y: f64) -> (f64); => fmod);
+ (fn frexp(x: f64) -> (f64, i32); => frexp);
+ (fn hypot(x: f64, y: f64) -> (f64); => hypot);
+ (fn ilogb(x: f64) -> (i32); => ilogb);
+ (fn j0(x: f64) -> (f64); => j0);
+ (fn j1(x: f64) -> (f64); => j1);
+ (fn jn(n: i32, x: f64) -> (f64); => jn);
+ (fn ldexp(x: f64, n: i32) -> (f64); => ldexp);
+ (fn lgamma_r(x: f64) -> (f64, i32); => lgamma_r);
+ (fn lgamma(x: f64) -> (f64); => lgamma);
+ (fn log(x: f64) -> (f64); => log);
+ (fn log1p(x: f64) -> (f64); => log1p);
+ (fn log2(x: f64) -> (f64); => log2);
+ (fn log10(x: f64) -> (f64); => log10);
+ (fn modf(x: f64) -> (f64, f64); => modf);
+ (fn nextafter(x: f64, y: f64) -> (f64); => nextafter);
+ (fn pow(x: f64, y: f64) -> (f64); => pow);
+ (fn remainder(x: f64, y: f64) -> (f64); => remainder);
+ (fn remquo(x: f64, y: f64) -> (f64, i32); => remquo);
+ (fn rint(x: f64) -> (f64); => rint);
+ (fn round(x: f64) -> (f64); => round);
+ (fn scalbn(x: f64, n: i32) -> (f64); => scalbn);
+ (fn sin(x: f64) -> (f64); => sin);
+ (fn sincos(x: f64) -> (f64, f64); => sincos);
+ (fn sinh(x: f64) -> (f64); => sinh);
+ (fn sqrt(x: f64) -> (f64); => sqrt);
+ (fn tan(x: f64) -> (f64); => tan);
+ (fn tanh(x: f64) -> (f64); => tanh);
+ (fn tgamma(x: f64) -> (f64); => tgamma);
+ (fn trunc(x: f64) -> (f64); => trunc);
+ (fn y0(x: f64) -> (f64); => y0);
+ (fn y1(x: f64) -> (f64); => y1);
+ (fn yn(n: i32, x: f64) -> (f64); => yn)
+ }
+}