From c28c894f814c3179b656209a732726da4183b526 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Wed, 1 Nov 2023 18:22:19 -0700 Subject: [PATCH 01/93] removed println --- macros/libtrig-macros-core/mass_impl/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/macros/libtrig-macros-core/mass_impl/mod.rs b/macros/libtrig-macros-core/mass_impl/mod.rs index cfc830c..e49baf1 100644 --- a/macros/libtrig-macros-core/mass_impl/mod.rs +++ b/macros/libtrig-macros-core/mass_impl/mod.rs @@ -39,7 +39,6 @@ pub fn mass_impl>(cfg: T, input: T) -> TokenStream { } results = temp_results; } - println!("{:#?}", &results); let single_str = results.join("\n"); syn::parse_str::(&single_str).unwrap() } \ No newline at end of file From f0fed9ea472249c33d281e2958a9fa01fa13032c Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 3 Nov 2023 15:10:47 -0700 Subject: [PATCH 02/93] Major improvement + no_std --- Cargo.toml | 14 +- macros/README.md => README.md | 0 core/README.md | 0 core/llm/Cargo.toml | 15 + core/llm/README.md | 1 + core/llm/lib.rs | 53 ++ core/llm/math.rs | 370 ++++++++++ core/llm/math/acos.rs | 112 +++ core/llm/math/acosf.rs | 79 +++ core/llm/math/acosh.rs | 27 + core/llm/math/acoshf.rs | 26 + core/llm/math/asin.rs | 119 ++++ core/llm/math/asinf.rs | 72 ++ core/llm/math/asinh.rs | 40 ++ core/llm/math/asinhf.rs | 39 ++ core/llm/math/atan.rs | 184 +++++ core/llm/math/atan2.rs | 126 ++++ core/llm/math/atan2f.rs | 91 +++ core/llm/math/atanf.rs | 112 +++ core/llm/math/atanh.rs | 37 + core/llm/math/atanhf.rs | 37 + core/llm/math/cbrt.rs | 113 +++ core/llm/math/cbrtf.rs | 75 ++ core/llm/math/ceil.rs | 82 +++ core/llm/math/ceilf.rs | 65 ++ core/llm/math/copysign.rs | 12 + core/llm/math/copysignf.rs | 12 + core/llm/math/cos.rs | 73 ++ core/llm/math/cosf.rs | 83 +++ core/llm/math/cosh.rs | 38 + core/llm/math/coshf.rs | 38 + core/llm/math/erf.rs | 318 +++++++++ core/llm/math/erff.rs | 230 +++++++ core/llm/math/exp.rs | 154 +++++ core/llm/math/exp10.rs | 22 + core/llm/math/exp10f.rs | 22 + core/llm/math/exp2.rs | 394 +++++++++++ core/llm/math/exp2f.rs | 135 ++++ core/llm/math/expf.rs | 101 +++ core/llm/math/expm1.rs | 144 ++++ core/llm/math/expm1f.rs | 134 ++++ core/llm/math/expo2.rs | 14 + core/llm/math/fabs.rs | 41 ++ core/llm/math/fabsf.rs | 41 ++ core/llm/math/fdim.rs | 22 + core/llm/math/fdimf.rs | 22 + core/llm/math/fenv.rs | 27 + core/llm/math/floor.rs | 81 +++ core/llm/math/floorf.rs | 66 ++ core/llm/math/fma.rs | 232 +++++++ core/llm/math/fmaf.rs | 117 ++++ core/llm/math/fmax.rs | 12 + core/llm/math/fmaxf.rs | 12 + core/llm/math/fmin.rs | 12 + core/llm/math/fminf.rs | 12 + core/llm/math/fmod.rs | 80 +++ core/llm/math/fmodf.rs | 89 +++ core/llm/math/frexp.rs | 20 + core/llm/math/frexpf.rs | 21 + core/llm/math/hypot.rs | 74 ++ core/llm/math/hypotf.rs | 43 ++ core/llm/math/ilogb.rs | 32 + core/llm/math/ilogbf.rs | 32 + core/llm/math/j0.rs | 422 ++++++++++++ core/llm/math/j0f.rs | 359 ++++++++++ core/llm/math/j1.rs | 414 +++++++++++ core/llm/math/j1f.rs | 380 ++++++++++ core/llm/math/jn.rs | 343 +++++++++ core/llm/math/jnf.rs | 259 +++++++ core/llm/math/k_cos.rs | 62 ++ core/llm/math/k_cosf.rs | 29 + core/llm/math/k_expo2.rs | 14 + core/llm/math/k_expo2f.rs | 14 + core/llm/math/k_sin.rs | 57 ++ core/llm/math/k_sinf.rs | 30 + core/llm/math/k_tan.rs | 105 +++ core/llm/math/k_tanf.rs | 46 ++ core/llm/math/ldexp.rs | 4 + core/llm/math/ldexpf.rs | 4 + core/llm/math/lgamma.rs | 6 + core/llm/math/lgamma_r.rs | 320 +++++++++ core/llm/math/lgammaf.rs | 6 + core/llm/math/lgammaf_r.rs | 255 +++++++ core/llm/math/log.rs | 117 ++++ core/llm/math/log10.rs | 117 ++++ core/llm/math/log10f.rs | 91 +++ core/llm/math/log1p.rs | 143 ++++ core/llm/math/log1pf.rs | 98 +++ core/llm/math/log2.rs | 106 +++ core/llm/math/log2f.rs | 87 +++ core/llm/math/logf.rs | 65 ++ core/llm/math/modf.rs | 34 + core/llm/math/modff.rs | 33 + core/llm/math/nextafter.rs | 37 + core/llm/math/nextafterf.rs | 37 + core/llm/math/pow.rs | 637 +++++++++++++++++ core/llm/math/powf.rs | 342 +++++++++ core/llm/math/rem_pio2.rs | 233 +++++++ core/llm/math/rem_pio2_large.rs | 470 +++++++++++++ core/llm/math/rem_pio2f.rs | 67 ++ core/llm/math/remainder.rs | 5 + core/llm/math/remainderf.rs | 5 + core/llm/math/remquo.rs | 110 +++ core/llm/math/remquof.rs | 97 +++ core/llm/math/rint.rs | 58 ++ core/llm/math/rintf.rs | 58 ++ core/llm/math/round.rs | 28 + core/llm/math/roundf.rs | 30 + core/llm/math/scalbn.rs | 33 + core/llm/math/scalbnf.rs | 29 + core/llm/math/sin.rs | 88 +++ core/llm/math/sincos.rs | 134 ++++ core/llm/math/sincosf.rs | 185 +++++ core/llm/math/sinf.rs | 93 +++ core/llm/math/sinh.rs | 49 ++ core/llm/math/sinhf.rs | 30 + core/llm/math/sqrt.rs | 280 ++++++++ core/llm/math/sqrtf.rs | 170 +++++ core/llm/math/tan.rs | 70 ++ core/llm/math/tanf.rs | 78 +++ core/llm/math/tanh.rs | 53 ++ core/llm/math/tanhf.rs | 39 ++ core/llm/math/tgamma.rs | 208 ++++++ core/llm/math/tgammaf.rs | 6 + core/llm/math/trunc.rs | 40 ++ core/llm/math/truncf.rs | 42 ++ core/llm/types.rs | 14 + {macros => core/macros}/Cargo.toml | 0 core/macros/README.md | 0 {macros => core/macros}/lib.rs | 0 .../macros}/libtrig-macros-core/Cargo.toml | 0 .../macros}/libtrig-macros-core/ffi/mod.rs | 0 .../macros}/libtrig-macros-core/lib.rs | 0 .../libtrig-macros-core/mass_impl/args.rs | 0 .../libtrig-macros-core/mass_impl/mod.rs | 7 +- .../libtrig-macros-core/mass_impl/variants.rs | 0 example.rs | 44 ++ libtrig/README.md | 0 libtrig/angle.rs | 267 ++++++- libtrig/coords/coord2d.rs | 292 ++++++++ libtrig/coords/coord3d.rs | 9 + libtrig/coords/mod.rs | 5 + libtrig/main.rs | 21 +- libtrig/odo/FORMULA.md | 64 ++ libtrig/odo/config.rs | 79 +++ libtrig/odo/mod.rs | 11 + libtrig/odo/movement_calc.rs | 69 ++ libtrig/odo/pos/mod.rs | 3 + libtrig/odo/pos/pos2d.rs | 321 +++++++++ libtrig/traits/float.rs | 651 ++++++++++++++++++ libtrig/traits/mod.rs | 137 ++++ libtrig/traits/number.rs | 14 + libtrig/types.rs | 10 + libtrig/vectors/mod.rs | 5 + libtrig/{vectors.rs => vectors/vec2d.rs} | 69 +- libtrig/vectors/vec3d.rs | 224 ++++++ rust-toolchain | 1 + 157 files changed, 15026 insertions(+), 53 deletions(-) rename macros/README.md => README.md (100%) create mode 100644 core/README.md create mode 100644 core/llm/Cargo.toml create mode 100644 core/llm/README.md create mode 100644 core/llm/lib.rs create mode 100644 core/llm/math.rs create mode 100644 core/llm/math/acos.rs create mode 100644 core/llm/math/acosf.rs create mode 100644 core/llm/math/acosh.rs create mode 100644 core/llm/math/acoshf.rs create mode 100644 core/llm/math/asin.rs create mode 100644 core/llm/math/asinf.rs create mode 100644 core/llm/math/asinh.rs create mode 100644 core/llm/math/asinhf.rs create mode 100644 core/llm/math/atan.rs create mode 100644 core/llm/math/atan2.rs create mode 100644 core/llm/math/atan2f.rs create mode 100644 core/llm/math/atanf.rs create mode 100644 core/llm/math/atanh.rs create mode 100644 core/llm/math/atanhf.rs create mode 100644 core/llm/math/cbrt.rs create mode 100644 core/llm/math/cbrtf.rs create mode 100644 core/llm/math/ceil.rs create mode 100644 core/llm/math/ceilf.rs create mode 100644 core/llm/math/copysign.rs create mode 100644 core/llm/math/copysignf.rs create mode 100644 core/llm/math/cos.rs create mode 100644 core/llm/math/cosf.rs create mode 100644 core/llm/math/cosh.rs create mode 100644 core/llm/math/coshf.rs create mode 100644 core/llm/math/erf.rs create mode 100644 core/llm/math/erff.rs create mode 100644 core/llm/math/exp.rs create mode 100644 core/llm/math/exp10.rs create mode 100644 core/llm/math/exp10f.rs create mode 100644 core/llm/math/exp2.rs create mode 100644 core/llm/math/exp2f.rs create mode 100644 core/llm/math/expf.rs create mode 100644 core/llm/math/expm1.rs create mode 100644 core/llm/math/expm1f.rs create mode 100644 core/llm/math/expo2.rs create mode 100644 core/llm/math/fabs.rs create mode 100644 core/llm/math/fabsf.rs create mode 100644 core/llm/math/fdim.rs create mode 100644 core/llm/math/fdimf.rs create mode 100644 core/llm/math/fenv.rs create mode 100644 core/llm/math/floor.rs create mode 100644 core/llm/math/floorf.rs create mode 100644 core/llm/math/fma.rs create mode 100644 core/llm/math/fmaf.rs create mode 100644 core/llm/math/fmax.rs create mode 100644 core/llm/math/fmaxf.rs create mode 100644 core/llm/math/fmin.rs create mode 100644 core/llm/math/fminf.rs create mode 100644 core/llm/math/fmod.rs create mode 100644 core/llm/math/fmodf.rs create mode 100644 core/llm/math/frexp.rs create mode 100644 core/llm/math/frexpf.rs create mode 100644 core/llm/math/hypot.rs create mode 100644 core/llm/math/hypotf.rs create mode 100644 core/llm/math/ilogb.rs create mode 100644 core/llm/math/ilogbf.rs create mode 100644 core/llm/math/j0.rs create mode 100644 core/llm/math/j0f.rs create mode 100644 core/llm/math/j1.rs create mode 100644 core/llm/math/j1f.rs create mode 100644 core/llm/math/jn.rs create mode 100644 core/llm/math/jnf.rs create mode 100644 core/llm/math/k_cos.rs create mode 100644 core/llm/math/k_cosf.rs create mode 100644 core/llm/math/k_expo2.rs create mode 100644 core/llm/math/k_expo2f.rs create mode 100644 core/llm/math/k_sin.rs create mode 100644 core/llm/math/k_sinf.rs create mode 100644 core/llm/math/k_tan.rs create mode 100644 core/llm/math/k_tanf.rs create mode 100644 core/llm/math/ldexp.rs create mode 100644 core/llm/math/ldexpf.rs create mode 100644 core/llm/math/lgamma.rs create mode 100644 core/llm/math/lgamma_r.rs create mode 100644 core/llm/math/lgammaf.rs create mode 100644 core/llm/math/lgammaf_r.rs create mode 100644 core/llm/math/log.rs create mode 100644 core/llm/math/log10.rs create mode 100644 core/llm/math/log10f.rs create mode 100644 core/llm/math/log1p.rs create mode 100644 core/llm/math/log1pf.rs create mode 100644 core/llm/math/log2.rs create mode 100644 core/llm/math/log2f.rs create mode 100644 core/llm/math/logf.rs create mode 100644 core/llm/math/modf.rs create mode 100644 core/llm/math/modff.rs create mode 100644 core/llm/math/nextafter.rs create mode 100644 core/llm/math/nextafterf.rs create mode 100644 core/llm/math/pow.rs create mode 100644 core/llm/math/powf.rs create mode 100644 core/llm/math/rem_pio2.rs create mode 100644 core/llm/math/rem_pio2_large.rs create mode 100644 core/llm/math/rem_pio2f.rs create mode 100644 core/llm/math/remainder.rs create mode 100644 core/llm/math/remainderf.rs create mode 100644 core/llm/math/remquo.rs create mode 100644 core/llm/math/remquof.rs create mode 100644 core/llm/math/rint.rs create mode 100644 core/llm/math/rintf.rs create mode 100644 core/llm/math/round.rs create mode 100644 core/llm/math/roundf.rs create mode 100644 core/llm/math/scalbn.rs create mode 100644 core/llm/math/scalbnf.rs create mode 100644 core/llm/math/sin.rs create mode 100644 core/llm/math/sincos.rs create mode 100644 core/llm/math/sincosf.rs create mode 100644 core/llm/math/sinf.rs create mode 100644 core/llm/math/sinh.rs create mode 100644 core/llm/math/sinhf.rs create mode 100644 core/llm/math/sqrt.rs create mode 100644 core/llm/math/sqrtf.rs create mode 100644 core/llm/math/tan.rs create mode 100644 core/llm/math/tanf.rs create mode 100644 core/llm/math/tanh.rs create mode 100644 core/llm/math/tanhf.rs create mode 100644 core/llm/math/tgamma.rs create mode 100644 core/llm/math/tgammaf.rs create mode 100644 core/llm/math/trunc.rs create mode 100644 core/llm/math/truncf.rs create mode 100644 core/llm/types.rs rename {macros => core/macros}/Cargo.toml (100%) create mode 100644 core/macros/README.md rename {macros => core/macros}/lib.rs (100%) rename {macros => core/macros}/libtrig-macros-core/Cargo.toml (100%) rename {macros => core/macros}/libtrig-macros-core/ffi/mod.rs (100%) rename {macros => core/macros}/libtrig-macros-core/lib.rs (100%) rename {macros => core/macros}/libtrig-macros-core/mass_impl/args.rs (100%) rename {macros => core/macros}/libtrig-macros-core/mass_impl/mod.rs (86%) rename {macros => core/macros}/libtrig-macros-core/mass_impl/variants.rs (100%) create mode 100644 example.rs create mode 100644 libtrig/README.md create mode 100644 libtrig/coords/coord2d.rs create mode 100644 libtrig/coords/coord3d.rs create mode 100644 libtrig/coords/mod.rs create mode 100644 libtrig/odo/FORMULA.md create mode 100644 libtrig/odo/config.rs create mode 100644 libtrig/odo/mod.rs create mode 100644 libtrig/odo/movement_calc.rs create mode 100644 libtrig/odo/pos/mod.rs create mode 100644 libtrig/odo/pos/pos2d.rs create mode 100644 libtrig/traits/float.rs create mode 100644 libtrig/traits/mod.rs create mode 100644 libtrig/traits/number.rs create mode 100644 libtrig/types.rs create mode 100644 libtrig/vectors/mod.rs rename libtrig/{vectors.rs => vectors/vec2d.rs} (69%) create mode 100644 libtrig/vectors/vec3d.rs create mode 100644 rust-toolchain diff --git a/Cargo.toml b/Cargo.toml index bf28be9..5b31f3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,17 @@ name = "libtrig" version = "0.1.0" edition = "2021" +[dependencies.macros] +package = "libtrig-macros" +path = "./core/macros" + +[dependencies.math] +package = "libtrig-llm" +path = "./core/llm" + [lib] path = "./libtrig/main.rs" -[dependencies.macros] -package = "libtrig-macros" -path = "./macros" +[[bin]] +path = "./example.rs" +name = "example" diff --git a/macros/README.md b/README.md similarity index 100% rename from macros/README.md rename to README.md diff --git a/core/README.md b/core/README.md new file mode 100644 index 0000000..e69de29 diff --git a/core/llm/Cargo.toml b/core/llm/Cargo.toml new file mode 100644 index 0000000..58d6958 --- /dev/null +++ b/core/llm/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "libtrig-llm" +version = "0.1.0" +edition = "2021" + +[lib] +path = "lib.rs" + +[dependencies.macros] +package = "libtrig-macros" +path = "../macros" + +[features] +default = ["unstable"] +unstable = [] diff --git a/core/llm/README.md b/core/llm/README.md new file mode 100644 index 0000000..e066f00 --- /dev/null +++ b/core/llm/README.md @@ -0,0 +1 @@ +libm in pure Rust \ No newline at end of file diff --git a/core/llm/lib.rs b/core/llm/lib.rs new file mode 100644 index 0000000..a38b134 --- /dev/null +++ b/core/llm/lib.rs @@ -0,0 +1,53 @@ +#![doc = include_str!("./README.md")] + +#![no_std] +#![feature(core_intrinsics)] + +#![allow(clippy::unreadable_literal)] +#![allow(clippy::many_single_char_names)] +#![allow(clippy::needless_return)] +#![allow(clippy::int_plus_one)] +#![allow(clippy::deprecated_cfg_attr)] +#![allow(clippy::mixed_case_hex_literals)] +#![allow(clippy::float_cmp)] +#![allow(clippy::eq_op)] +#![allow(clippy::assign_op_pattern)] + +mod types; +mod math; + +pub use self::math::*; +pub use types::*; + +/// Approximate equality with 1 ULP of tolerance +#[doc(hidden)] +#[inline] +pub fn _eqf(a: Float32, b: Float32) -> Result<(), u32> { + if a.is_nan() && b.is_nan() { + Ok(()) + } else { + let err = (a.to_bits() as i32).wrapping_sub(b.to_bits() as i32).abs(); + + if err <= 1 { + Ok(()) + } else { + Err(err as u32) + } + } +} + +#[doc(hidden)] +#[inline] +pub fn _eq(a: Float, b: Float) -> Result<(), u64> { + if a.is_nan() && b.is_nan() { + Ok(()) + } else { + let err = (a.to_bits() as i64).wrapping_sub(b.to_bits() as i64).abs(); + + if err <= 1 { + Ok(()) + } else { + Err(err as u64) + } + } +} diff --git a/core/llm/math.rs b/core/llm/math.rs new file mode 100644 index 0000000..d0a004a --- /dev/null +++ b/core/llm/math.rs @@ -0,0 +1,370 @@ +macro_rules! force_eval { + ($e:expr) => { + unsafe { ::core::ptr::read_volatile(&$e) } + }; +} + +#[cfg(not(debug_assertions))] +macro_rules! i { + ($array:expr, $index:expr) => { + unsafe { *$array.get_unchecked($index) } + }; + ($array:expr, $index:expr, = , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) = $rhs; + } + }; + ($array:expr, $index:expr, += , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) += $rhs; + } + }; + ($array:expr, $index:expr, -= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) -= $rhs; + } + }; + ($array:expr, $index:expr, &= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) &= $rhs; + } + }; + ($array:expr, $index:expr, == , $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) == $rhs } + }; +} + +#[cfg(debug_assertions)] +macro_rules! i { + ($array:expr, $index:expr) => { + *$array.get($index).unwrap() + }; + ($array:expr, $index:expr, = , $rhs:expr) => { + *$array.get_mut($index).unwrap() = $rhs; + }; + ($array:expr, $index:expr, -= , $rhs:expr) => { + *$array.get_mut($index).unwrap() -= $rhs; + }; + ($array:expr, $index:expr, += , $rhs:expr) => { + *$array.get_mut($index).unwrap() += $rhs; + }; + ($array:expr, $index:expr, &= , $rhs:expr) => { + *$array.get_mut($index).unwrap() &= $rhs; + }; + ($array:expr, $index:expr, == , $rhs:expr) => { + *$array.get_mut($index).unwrap() == $rhs + }; +} + +// Temporary macro to avoid panic codegen for division (in debug mode too). At +// the time of this writing this is only used in a few places, and once +// rust-lang/rust#72751 is fixed then this macro will no longer be necessary and +// the native `/` operator can be used and panics won't be codegen'd. +#[cfg(any(debug_assertions, not(feature = "unstable")))] +macro_rules! div { + ($a:expr, $b:expr) => { + $a / $b + }; +} + +#[cfg(all(not(debug_assertions), feature = "unstable"))] +macro_rules! div { + ($a:expr, $b:expr) => { + unsafe { core::intrinsics::unchecked_div($a, $b) } + }; +} + +macro_rules! llvm_intrinsically_optimized { + (#[cfg($($clause:tt)*)] $e:expr) => { + #[cfg(all(feature = "unstable", $($clause)*))] + { + if true { // thwart the dead code lint + $e + } + } + }; +} + +// Public modules +mod acos; +mod acosf; +mod acosh; +mod acoshf; +mod asin; +mod asinf; +mod asinh; +mod asinhf; +mod atan; +mod atan2; +mod atan2f; +mod atanf; +mod atanh; +mod atanhf; +mod cbrt; +mod cbrtf; +mod ceil; +mod ceilf; +mod copysign; +mod copysignf; +mod cos; +mod cosf; +mod cosh; +mod coshf; +mod erf; +mod erff; +mod exp; +mod exp10; +mod exp10f; +mod exp2; +mod exp2f; +mod expf; +mod expm1; +mod expm1f; +mod fabs; +mod fabsf; +mod fdim; +mod fdimf; +mod floor; +mod floorf; +mod fma; +mod fmaf; +mod fmax; +mod fmaxf; +mod fmin; +mod fminf; +mod fmod; +mod fmodf; +mod frexp; +mod frexpf; +mod hypot; +mod hypotf; +mod ilogb; +mod ilogbf; +mod j0; +mod j0f; +mod j1; +mod j1f; +mod jn; +mod jnf; +mod ldexp; +mod ldexpf; +mod lgamma; +mod lgamma_r; +mod lgammaf; +mod lgammaf_r; +mod log; +mod log10; +mod log10f; +mod log1p; +mod log1pf; +mod log2; +mod log2f; +mod logf; +mod modf; +mod modff; +mod nextafter; +mod nextafterf; +mod pow; +mod powf; +mod remainder; +mod remainderf; +mod remquo; +mod remquof; +mod rint; +mod rintf; +mod round; +mod roundf; +mod scalbn; +mod scalbnf; +mod sin; +mod sincos; +mod sincosf; +mod sinf; +mod sinh; +mod sinhf; +mod sqrt; +mod sqrtf; +mod tan; +mod tanf; +mod tanh; +mod tanhf; +mod tgamma; +mod tgammaf; +mod trunc; +mod truncf; + +// Use separated imports instead of {}-grouped imports for easier merging. +pub use self::acos::acos; +pub use self::acosf::acosf; +pub use self::acosh::acosh; +pub use self::acoshf::acoshf; +pub use self::asin::asin; +pub use self::asinf::asinf; +pub use self::asinh::asinh; +pub use self::asinhf::asinhf; +pub use self::atan::atan; +pub use self::atan2::atan2; +pub use self::atan2f::atan2f; +pub use self::atanf::atanf; +pub use self::atanh::atanh; +pub use self::atanhf::atanhf; +pub use self::cbrt::cbrt; +pub use self::cbrtf::cbrtf; +pub use self::ceil::ceil; +pub use self::ceilf::ceilf; +pub use self::copysign::copysign; +pub use self::copysignf::copysignf; +pub use self::cos::cos; +pub use self::cosf::cosf; +pub use self::cosh::cosh; +pub use self::coshf::coshf; +pub use self::erf::erf; +pub use self::erf::erfc; +pub use self::erff::erfcf; +pub use self::erff::erff; +pub use self::exp::exp; +pub use self::exp10::exp10; +pub use self::exp10f::exp10f; +pub use self::exp2::exp2; +pub use self::exp2f::exp2f; +pub use self::expf::expf; +pub use self::expm1::expm1; +pub use self::expm1f::expm1f; +pub use self::fabs::fabs; +pub use self::fabsf::fabsf; +pub use self::fdim::fdim; +pub use self::fdimf::fdimf; +pub use self::floor::floor; +pub use self::floorf::floorf; +pub use self::fma::fma; +pub use self::fmaf::fmaf; +pub use self::fmax::fmax; +pub use self::fmaxf::fmaxf; +pub use self::fmin::fmin; +pub use self::fminf::fminf; +pub use self::fmod::fmod; +pub use self::fmodf::fmodf; +pub use self::frexp::frexp; +pub use self::frexpf::frexpf; +pub use self::hypot::hypot; +pub use self::hypotf::hypotf; +pub use self::ilogb::ilogb; +pub use self::ilogbf::ilogbf; +pub use self::j0::j0; +pub use self::j0::y0; +pub use self::j0f::j0f; +pub use self::j0f::y0f; +pub use self::j1::j1; +pub use self::j1::y1; +pub use self::j1f::j1f; +pub use self::j1f::y1f; +pub use self::jn::jn; +pub use self::jn::yn; +pub use self::jnf::jnf; +pub use self::jnf::ynf; +pub use self::ldexp::ldexp; +pub use self::ldexpf::ldexpf; +pub use self::lgamma::lgamma; +pub use self::lgamma_r::lgamma_r; +pub use self::lgammaf::lgammaf; +pub use self::lgammaf_r::lgammaf_r; +pub use self::log::log; +pub use self::log10::log10; +pub use self::log10f::log10f; +pub use self::log1p::log1p; +pub use self::log1pf::log1pf; +pub use self::log2::log2; +pub use self::log2f::log2f; +pub use self::logf::logf; +pub use self::modf::modf; +pub use self::modff::modff; +pub use self::nextafter::nextafter; +pub use self::nextafterf::nextafterf; +pub use self::pow::pow; +pub use self::powf::powf; +pub use self::remainder::remainder; +pub use self::remainderf::remainderf; +pub use self::remquo::remquo; +pub use self::remquof::remquof; +pub use self::rint::rint; +pub use self::rintf::rintf; +pub use self::round::round; +pub use self::roundf::roundf; +pub use self::scalbn::scalbn; +pub use self::scalbnf::scalbnf; +pub use self::sin::sin; +pub use self::sincos::sincos; +pub use self::sincosf::sincosf; +pub use self::sinf::sinf; +pub use self::sinh::sinh; +pub use self::sinhf::sinhf; +pub use self::sqrt::sqrt; +pub use self::sqrtf::sqrtf; +pub use self::tan::tan; +pub use self::tanf::tanf; +pub use self::tanh::tanh; +pub use self::tanhf::tanhf; +pub use self::tgamma::tgamma; +pub use self::tgammaf::tgammaf; +pub use self::trunc::trunc; +pub use self::truncf::truncf; + +// Private modules +mod expo2; +mod fenv; +mod k_cos; +mod k_cosf; +mod k_expo2; +mod k_expo2f; +mod k_sin; +mod k_sinf; +mod k_tan; +mod k_tanf; +mod rem_pio2; +mod rem_pio2_large; +mod rem_pio2f; + +// Private re-imports +use self::expo2::expo2; +use self::k_cos::k_cos; +use self::k_cosf::k_cosf; +use self::k_expo2::k_expo2; +use self::k_expo2f::k_expo2f; +use self::k_sin::k_sin; +use self::k_sinf::k_sinf; +use self::k_tan::k_tan; +use self::k_tanf::k_tanf; +use self::rem_pio2::rem_pio2; +use self::rem_pio2_large::rem_pio2_large; +use self::rem_pio2f::rem_pio2f; + +#[inline] +fn get_high_word(x: f64) -> u32 { + (x.to_bits() >> 32) as u32 +} + +#[inline] +fn get_low_word(x: f64) -> u32 { + x.to_bits() as u32 +} + +#[inline] +fn with_set_high_word(f: f64, hi: u32) -> f64 { + let mut tmp = f.to_bits(); + tmp &= 0x00000000_ffffffff; + tmp |= (hi as u64) << 32; + f64::from_bits(tmp) +} + +#[inline] +fn with_set_low_word(f: f64, lo: u32) -> f64 { + let mut tmp = f.to_bits(); + tmp &= 0xffffffff_00000000; + tmp |= lo as u64; + f64::from_bits(tmp) +} + +#[inline] +fn combine_words(hi: u32, lo: u32) -> f64 { + f64::from_bits((hi as u64) << 32 | lo as u64) +} diff --git a/core/llm/math/acos.rs b/core/llm/math/acos.rs new file mode 100644 index 0000000..23b1325 --- /dev/null +++ b/core/llm/math/acos.rs @@ -0,0 +1,112 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* acos(x) + * Method : + * acos(x) = pi/2 - asin(x) + * acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) + * For x>0.5 + * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + * = 2asin(sqrt((1-x)/2)) + * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) + * = 2f + (2c + 2s*z*R(z)) + * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + * for f so that f+c ~ sqrt(z). + * For x<-0.5 + * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +use super::sqrt; + +const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +const PS0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ +const PS1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ +const PS2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ +const PS3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ +const PS4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ +const PS5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ +const QS1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ +const QS2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ +const QS3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ +const QS4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +fn r(z: f64) -> f64 { + let p: f64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); + let q: f64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); + p / q +} + +/// Arccosine (f64) +/// +/// Computes the inverse cosine (arc cosine) of the input value. +/// Arguments must be in the range -1 to 1. +/// Returns values in radians, in the range of 0 to pi. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn acos(x: f64) -> f64 { + let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 + let z: f64; + let w: f64; + let s: f64; + let c: f64; + let df: f64; + let hx: u32; + let ix: u32; + + hx = (x.to_bits() >> 32) as u32; + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3ff00000 { + let lx: u32 = x.to_bits() as u32; + + if ((ix - 0x3ff00000) | lx) == 0 { + /* acos(1)=0, acos(-1)=pi */ + if (hx >> 31) != 0 { + return 2. * PIO2_HI + x1p_120f; + } + return 0.; + } + return 0. / (x - x); + } + /* |x| < 0.5 */ + if ix < 0x3fe00000 { + if ix <= 0x3c600000 { + /* |x| < 2**-57 */ + return PIO2_HI + x1p_120f; + } + return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); + } + /* x < -0.5 */ + if (hx >> 31) != 0 { + z = (1.0 + x) * 0.5; + s = sqrt(z); + w = r(z) * s - PIO2_LO; + return 2. * (PIO2_HI - (s + w)); + } + /* x > 0.5 */ + z = (1.0 - x) * 0.5; + s = sqrt(z); + // Set the low 4 bytes to zero + df = f64::from_bits(s.to_bits() & 0xff_ff_ff_ff_00_00_00_00); + + c = (z - df * df) / (s + df); + w = r(z) * s + c; + 2. * (df + w) +} diff --git a/core/llm/math/acosf.rs b/core/llm/math/acosf.rs new file mode 100644 index 0000000..1a60479 --- /dev/null +++ b/core/llm/math/acosf.rs @@ -0,0 +1,79 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::sqrtf::sqrtf; + +const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */ +const PIO2_LO: f32 = 7.5497894159e-08; /* 0x33a22168 */ +const P_S0: f32 = 1.6666586697e-01; +const P_S1: f32 = -4.2743422091e-02; +const P_S2: f32 = -8.6563630030e-03; +const Q_S1: f32 = -7.0662963390e-01; + +fn r(z: f32) -> f32 { + let p = z * (P_S0 + z * (P_S1 + z * P_S2)); + let q = 1. + z * Q_S1; + p / q +} + +/// Arccosine (f32) +/// +/// Computes the inverse cosine (arc cosine) of the input value. +/// Arguments must be in the range -1 to 1. +/// Returns values in radians, in the range of 0 to pi. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn acosf(x: f32) -> f32 { + let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) + + let z: f32; + let w: f32; + let s: f32; + + let mut hx = x.to_bits(); + let ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3f800000 { + if ix == 0x3f800000 { + if (hx >> 31) != 0 { + return 2. * PIO2_HI + x1p_120; + } + return 0.; + } + return 0. / (x - x); + } + /* |x| < 0.5 */ + if ix < 0x3f000000 { + if ix <= 0x32800000 { + /* |x| < 2**-26 */ + return PIO2_HI + x1p_120; + } + return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); + } + /* x < -0.5 */ + if (hx >> 31) != 0 { + z = (1. + x) * 0.5; + s = sqrtf(z); + w = r(z) * s - PIO2_LO; + return 2. * (PIO2_HI - (s + w)); + } + /* x > 0.5 */ + z = (1. - x) * 0.5; + s = sqrtf(z); + hx = s.to_bits(); + let df = f32::from_bits(hx & 0xfffff000); + let c = (z - df * df) / (s + df); + w = r(z) * s + c; + 2. * (df + w) +} diff --git a/core/llm/math/acosh.rs b/core/llm/math/acosh.rs new file mode 100644 index 0000000..d1f5b9f --- /dev/null +++ b/core/llm/math/acosh.rs @@ -0,0 +1,27 @@ +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/// Inverse hyperbolic cosine (f64) +/// +/// Calculates the inverse hyperbolic cosine of `x`. +/// Is defined as `log(x + sqrt(x*x-1))`. +/// `x` must be a number greater than or equal to 1. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn acosh(x: f64) -> f64 { + let u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + + /* x < 1 domain error is handled in the called functions */ + + if e < 0x3ff + 1 { + /* |x| < 2, up to 2ulp error in [1,1.125] */ + return log1p(x - 1.0 + sqrt((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); + } + if e < 0x3ff + 26 { + /* |x| < 0x1p26 */ + return log(2.0 * x - 1.0 / (x + sqrt(x * x - 1.0))); + } + /* |x| >= 0x1p26 or nan */ + return log(x) + LN2; +} diff --git a/core/llm/math/acoshf.rs b/core/llm/math/acoshf.rs new file mode 100644 index 0000000..ad3455f --- /dev/null +++ b/core/llm/math/acoshf.rs @@ -0,0 +1,26 @@ +use super::{log1pf, logf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/// Inverse hyperbolic cosine (f32) +/// +/// Calculates the inverse hyperbolic cosine of `x`. +/// Is defined as `log(x + sqrt(x*x-1))`. +/// `x` must be a number greater than or equal to 1. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn acoshf(x: f32) -> f32 { + let u = x.to_bits(); + let a = u & 0x7fffffff; + + if a < 0x3f800000 + (1 << 23) { + /* |x| < 2, invalid if x < 1 or nan */ + /* up to 2ulp error in [1,1.125] */ + return log1pf(x - 1.0 + sqrtf((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); + } + if a < 0x3f800000 + (12 << 23) { + /* |x| < 0x1p12 */ + return logf(2.0 * x - 1.0 / (x + sqrtf(x * x - 1.0))); + } + /* x >= 0x1p12 */ + return logf(x) + LN2; +} diff --git a/core/llm/math/asin.rs b/core/llm/math/asin.rs new file mode 100644 index 0000000..3e4b7c5 --- /dev/null +++ b/core/llm/math/asin.rs @@ -0,0 +1,119 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* asin(x) + * Method : + * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... + * we approximate asin(x) on [0,0.5] by + * asin(x) = x + x*x^2*R(x^2) + * where + * R(x^2) is a rational approximation of (asin(x)-x)/x^3 + * and its remez error is bounded by + * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) + * + * For x in [0.5,1] + * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) + * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; + * then for x>0.98 + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) + * For x<=0.98, let pio4_hi = pio2_hi/2, then + * f = hi part of s; + * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) + * and + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) + * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + */ + +use super::{fabs, get_high_word, get_low_word, sqrt, with_set_low_word}; + +const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +/* coefficients for R(x^2) */ +const P_S0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ +const P_S1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ +const P_S2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ +const P_S3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ +const P_S4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ +const P_S5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ +const Q_S1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ +const Q_S2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ +const Q_S3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ +const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +fn comp_r(z: f64) -> f64 { + let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); + let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); + p / q +} + +/// Arcsine (f64) +/// +/// Computes the inverse sine (arc sine) of the argument `x`. +/// Arguments to asin must be in the range -1 to 1. +/// Returns values in radians, in the range of -pi/2 to pi/2. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn asin(mut x: f64) -> f64 { + let z: f64; + let r: f64; + let s: f64; + let hx: u32; + let ix: u32; + + hx = get_high_word(x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3ff00000 { + let lx: u32; + lx = get_low_word(x); + if ((ix - 0x3ff00000) | lx) == 0 { + /* asin(1) = +-pi/2 with inexact */ + return x * PIO2_HI + f64::from_bits(0x3870000000000000); + } else { + return 0.0 / (x - x); + } + } + /* |x| < 0.5 */ + if ix < 0x3fe00000 { + /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ + if ix < 0x3e500000 && ix >= 0x00100000 { + return x; + } else { + return x + x * comp_r(x * x); + } + } + /* 1 > |x| >= 0.5 */ + z = (1.0 - fabs(x)) * 0.5; + s = sqrt(z); + r = comp_r(z); + if ix >= 0x3fef3333 { + /* if |x| > 0.975 */ + x = PIO2_HI - (2. * (s + s * r) - PIO2_LO); + } else { + let f: f64; + let c: f64; + /* f+c = sqrt(z) */ + f = with_set_low_word(s, 0); + c = (z - f * f) / (s + f); + x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f)); + } + if hx >> 31 != 0 { + -x + } else { + x + } +} diff --git a/core/llm/math/asinf.rs b/core/llm/math/asinf.rs new file mode 100644 index 0000000..6ec61b6 --- /dev/null +++ b/core/llm/math/asinf.rs @@ -0,0 +1,72 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::fabsf::fabsf; +use super::sqrt::sqrt; + +const PIO2: f64 = 1.570796326794896558e+00; + +/* coefficients for R(x^2) */ +const P_S0: f32 = 1.6666586697e-01; +const P_S1: f32 = -4.2743422091e-02; +const P_S2: f32 = -8.6563630030e-03; +const Q_S1: f32 = -7.0662963390e-01; + +fn r(z: f32) -> f32 { + let p = z * (P_S0 + z * (P_S1 + z * P_S2)); + let q = 1. + z * Q_S1; + p / q +} + +/// Arcsine (f32) +/// +/// Computes the inverse sine (arc sine) of the argument `x`. +/// Arguments to asin must be in the range -1 to 1. +/// Returns values in radians, in the range of -pi/2 to pi/2. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn asinf(mut x: f32) -> f32 { + let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) + + let hx = x.to_bits(); + let ix = hx & 0x7fffffff; + + if ix >= 0x3f800000 { + /* |x| >= 1 */ + if ix == 0x3f800000 { + /* |x| == 1 */ + return ((x as f64) * PIO2 + x1p_120) as f32; /* asin(+-1) = +-pi/2 with inexact */ + } + return 0. / (x - x); /* asin(|x|>1) is NaN */ + } + + if ix < 0x3f000000 { + /* |x| < 0.5 */ + /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ + if (ix < 0x39800000) && (ix >= 0x00800000) { + return x; + } + return x + x * r(x * x); + } + + /* 1 > |x| >= 0.5 */ + let z = (1. - fabsf(x)) * 0.5; + let s = sqrt(z as f64); + x = (PIO2 - 2. * (s + s * (r(z) as f64))) as f32; + if (hx >> 31) != 0 { + -x + } else { + x + } +} diff --git a/core/llm/math/asinh.rs b/core/llm/math/asinh.rs new file mode 100644 index 0000000..0abd80c --- /dev/null +++ b/core/llm/math/asinh.rs @@ -0,0 +1,40 @@ +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +/// Inverse hyperbolic sine (f64) +/// +/// Calculates the inverse hyperbolic sine of `x`. +/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn asinh(mut x: f64) -> f64 { + let mut u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + u &= (!0) >> 1; + x = f64::from_bits(u); + + if e >= 0x3ff + 26 { + /* |x| >= 0x1p26 or inf or nan */ + x = log(x) + LN2; + } else if e >= 0x3ff + 1 { + /* |x| >= 2 */ + x = log(2.0 * x + 1.0 / (sqrt(x * x + 1.0) + x)); + } else if e >= 0x3ff - 26 { + /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ + x = log1p(x + x * x / (sqrt(x * x + 1.0) + 1.0)); + } else { + /* |x| < 0x1p-26, raise inexact if x != 0 */ + let x1p120 = f64::from_bits(0x4770000000000000); + force_eval!(x + x1p120); + } + + if sign { + -x + } else { + x + } +} diff --git a/core/llm/math/asinhf.rs b/core/llm/math/asinhf.rs new file mode 100644 index 0000000..09c7782 --- /dev/null +++ b/core/llm/math/asinhf.rs @@ -0,0 +1,39 @@ +use super::{log1pf, logf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +/// Inverse hyperbolic sine (f32) +/// +/// Calculates the inverse hyperbolic sine of `x`. +/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn asinhf(mut x: f32) -> f32 { + let u = x.to_bits(); + let i = u & 0x7fffffff; + let sign = (u >> 31) != 0; + + /* |x| */ + x = f32::from_bits(i); + + if i >= 0x3f800000 + (12 << 23) { + /* |x| >= 0x1p12 or inf or nan */ + x = logf(x) + LN2; + } else if i >= 0x3f800000 + (1 << 23) { + /* |x| >= 2 */ + x = logf(2.0 * x + 1.0 / (sqrtf(x * x + 1.0) + x)); + } else if i >= 0x3f800000 - (12 << 23) { + /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ + x = log1pf(x + x * x / (sqrtf(x * x + 1.0) + 1.0)); + } else { + /* |x| < 0x1p-12, raise inexact if x!=0 */ + let x1p120 = f32::from_bits(0x7b800000); + force_eval!(x + x1p120); + } + + if sign { + -x + } else { + x + } +} diff --git a/core/llm/math/atan.rs b/core/llm/math/atan.rs new file mode 100644 index 0000000..4259dc7 --- /dev/null +++ b/core/llm/math/atan.rs @@ -0,0 +1,184 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* atan(x) + * Method + * 1. Reduce x to positive by atan(x) = -atan(-x). + * 2. According to the integer k=4t+0.25 chopped, t=x, the argument + * is further reduced to one of the following intervals and the + * arctangent of t is evaluated by the corresponding formula: + * + * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) + * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) + * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) + * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) + * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +use super::fabs; +use core::f64; + +const ATANHI: [f64; 4] = [ + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +]; + +const ATANLO: [f64; 4] = [ + 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ + 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ + 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ + 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +]; + +const AT: [f64; 11] = [ + 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ + 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ + 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ + 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ + 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ + 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +]; + +/// Arctangent (f64) +/// +/// Computes the inverse tangent (arc tangent) of the input value. +/// Returns a value in radians, in the range of -pi/2 to pi/2. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atan(x: f64) -> f64 { + let mut x = x; + let mut ix = (x.to_bits() >> 32) as u32; + let sign = ix >> 31; + ix &= 0x7fff_ffff; + if ix >= 0x4410_0000 { + if x.is_nan() { + return x; + } + + let z = ATANHI[3] + f64::from_bits(0x0380_0000); // 0x1p-120f + return if sign != 0 { -z } else { z }; + } + + let id = if ix < 0x3fdc_0000 { + /* |x| < 0.4375 */ + if ix < 0x3e40_0000 { + /* |x| < 2^-27 */ + if ix < 0x0010_0000 { + /* raise underflow for subnormal x */ + force_eval!(x as f32); + } + + return x; + } + + -1 + } else { + x = fabs(x); + if ix < 0x3ff30000 { + /* |x| < 1.1875 */ + if ix < 0x3fe60000 { + /* 7/16 <= |x| < 11/16 */ + x = (2. * x - 1.) / (2. + x); + 0 + } else { + /* 11/16 <= |x| < 19/16 */ + x = (x - 1.) / (x + 1.); + 1 + } + } else if ix < 0x40038000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 + } else { + /* 2.4375 <= |x| < 2^66 */ + x = -1. / x; + 3 + } + }; + + let z = x * x; + let w = z * z; + /* break sum from i=0 to 10 AT[i]z**(i+1) into odd and even poly */ + let s1 = z * (AT[0] + w * (AT[2] + w * (AT[4] + w * (AT[6] + w * (AT[8] + w * AT[10]))))); + let s2 = w * (AT[1] + w * (AT[3] + w * (AT[5] + w * (AT[7] + w * AT[9])))); + + if id < 0 { + return x - x * (s1 + s2); + } + + let z = i!(ATANHI, id as usize) - (x * (s1 + s2) - i!(ATANLO, id as usize) - x); + + if sign != 0 { + -z + } else { + z + } +} + +#[cfg(test)] +mod tests { + use super::atan; + use core::f64; + + #[test] + fn sanity_check() { + for (input, answer) in [ + (3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6), + (1.0, f64::consts::FRAC_PI_4), + (3.0_f64.sqrt(), f64::consts::FRAC_PI_3), + (-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6), + (-1.0, -f64::consts::FRAC_PI_4), + (-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3), + ] + .iter() + { + assert!( + (atan(*input) - answer) / answer < 1e-5, + "\natan({:.4}/16) = {:.4}, actual: {}", + input * 16.0, + answer, + atan(*input) + ); + } + } + + #[test] + fn zero() { + assert_eq!(atan(0.0), 0.0); + } + + #[test] + fn infinity() { + assert_eq!(atan(f64::INFINITY), f64::consts::FRAC_PI_2); + } + + #[test] + fn minus_infinity() { + assert_eq!(atan(f64::NEG_INFINITY), -f64::consts::FRAC_PI_2); + } + + #[test] + fn nan() { + assert!(atan(f64::NAN).is_nan()); + } +} diff --git a/core/llm/math/atan2.rs b/core/llm/math/atan2.rs new file mode 100644 index 0000000..fb2ea4e --- /dev/null +++ b/core/llm/math/atan2.rs @@ -0,0 +1,126 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* atan2(y,x) + * Method : + * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). + * 2. Reduce x to positive by (if x and y are unexceptional): + * ARG (x+iy) = arctan(y/x) ... if x > 0, + * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, + * + * Special cases: + * + * ATAN2((anything), NaN ) is NaN; + * ATAN2(NAN , (anything) ) is NaN; + * ATAN2(+-0, +(anything but NaN)) is +-0 ; + * ATAN2(+-0, -(anything but NaN)) is +-pi ; + * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; + * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; + * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; + * ATAN2(+-INF,+INF ) is +-pi/4 ; + * ATAN2(+-INF,-INF ) is +-3pi/4; + * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +use super::atan; +use super::fabs; + +const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ +const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +/// Arctangent of y/x (f64) +/// +/// Computes the inverse tangent (arc tangent) of `y/x`. +/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). +/// Returns a value in radians, in the range of -pi to pi. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atan2(y: f64, x: f64) -> f64 { + if x.is_nan() || y.is_nan() { + return x + y; + } + let mut ix = (x.to_bits() >> 32) as u32; + let lx = x.to_bits() as u32; + let mut iy = (y.to_bits() >> 32) as u32; + let ly = y.to_bits() as u32; + if ((ix.wrapping_sub(0x3ff00000)) | lx) == 0 { + /* x = 1.0 */ + return atan(y); + } + let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if (iy | ly) == 0 { + return match m { + 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ + 2 => PI, /* atan(+0,-anything) = PI */ + _ => -PI, /* atan(-0,-anything) =-PI */ + }; + } + /* when x = 0 */ + if (ix | lx) == 0 { + return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; + } + /* when x is INF */ + if ix == 0x7ff00000 { + if iy == 0x7ff00000 { + return match m { + 0 => PI / 4.0, /* atan(+INF,+INF) */ + 1 => -PI / 4.0, /* atan(-INF,+INF) */ + 2 => 3.0 * PI / 4.0, /* atan(+INF,-INF) */ + _ => -3.0 * PI / 4.0, /* atan(-INF,-INF) */ + }; + } else { + return match m { + 0 => 0.0, /* atan(+...,+INF) */ + 1 => -0.0, /* atan(-...,+INF) */ + 2 => PI, /* atan(+...,-INF) */ + _ => -PI, /* atan(-...,-INF) */ + }; + } + } + /* |y/x| > 0x1p64 */ + if ix.wrapping_add(64 << 20) < iy || iy == 0x7ff00000 { + return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; + } + + /* z = atan(|y/x|) without spurious underflow */ + let z = if (m & 2 != 0) && iy.wrapping_add(64 << 20) < ix { + /* |y/x| < 0x1p-64, x<0 */ + 0.0 + } else { + atan(fabs(y / x)) + }; + match m { + 0 => z, /* atan(+,+) */ + 1 => -z, /* atan(-,+) */ + 2 => PI - (z - PI_LO), /* atan(+,-) */ + _ => (z - PI_LO) - PI, /* atan(-,-) */ + } +} + +#[test] +fn sanity_check() { + assert_eq!(atan2(0.0, 1.0), 0.0); + assert_eq!(atan2(0.0, -1.0), PI); + assert_eq!(atan2(-0.0, -1.0), -PI); + assert_eq!(atan2(3.0, 2.0), atan(3.0 / 2.0)); + assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI); + assert_eq!(atan2(-2.0, -1.0), atan(-2.0 / -1.0) - PI); +} diff --git a/core/llm/math/atan2f.rs b/core/llm/math/atan2f.rs new file mode 100644 index 0000000..eae3b00 --- /dev/null +++ b/core/llm/math/atan2f.rs @@ -0,0 +1,91 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::atanf; +use super::fabsf; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ + +/// Arctangent of y/x (f32) +/// +/// Computes the inverse tangent (arc tangent) of `y/x`. +/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). +/// Returns a value in radians, in the range of -pi to pi. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atan2f(y: f32, x: f32) -> f32 { + if x.is_nan() || y.is_nan() { + return x + y; + } + let mut ix = x.to_bits(); + let mut iy = y.to_bits(); + + if ix == 0x3f800000 { + /* x=1.0 */ + return atanf(y); + } + let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if iy == 0 { + return match m { + 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ + 2 => PI, /* atan(+0,-anything) = pi */ + 3 | _ => -PI, /* atan(-0,-anything) =-pi */ + }; + } + /* when x = 0 */ + if ix == 0 { + return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + } + /* when x is INF */ + if ix == 0x7f800000 { + return if iy == 0x7f800000 { + match m { + 0 => PI / 4., /* atan(+INF,+INF) */ + 1 => -PI / 4., /* atan(-INF,+INF) */ + 2 => 3. * PI / 4., /* atan(+INF,-INF)*/ + 3 | _ => -3. * PI / 4., /* atan(-INF,-INF)*/ + } + } else { + match m { + 0 => 0., /* atan(+...,+INF) */ + 1 => -0., /* atan(-...,+INF) */ + 2 => PI, /* atan(+...,-INF) */ + 3 | _ => -PI, /* atan(-...,-INF) */ + } + }; + } + /* |y/x| > 0x1p26 */ + if (ix + (26 << 23) < iy) || (iy == 0x7f800000) { + return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + } + + /* z = atan(|y/x|) with correct underflow */ + let z = if (m & 2 != 0) && (iy + (26 << 23) < ix) { + /*|y/x| < 0x1p-26, x < 0 */ + 0. + } else { + atanf(fabsf(y / x)) + }; + match m { + 0 => z, /* atan(+,+) */ + 1 => -z, /* atan(-,+) */ + 2 => PI - (z - PI_LO), /* atan(+,-) */ + _ => (z - PI_LO) - PI, /* case 3 */ /* atan(-,-) */ + } +} diff --git a/core/llm/math/atanf.rs b/core/llm/math/atanf.rs new file mode 100644 index 0000000..d042b3b --- /dev/null +++ b/core/llm/math/atanf.rs @@ -0,0 +1,112 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::fabsf; + +const ATAN_HI: [f32; 4] = [ + 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ + 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ + 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ + 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ +]; + +const ATAN_LO: [f32; 4] = [ + 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ + 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ + 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ + 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ +]; + +const A_T: [f32; 5] = [ + 3.3333328366e-01, + -1.9999158382e-01, + 1.4253635705e-01, + -1.0648017377e-01, + 6.1687607318e-02, +]; + +/// Arctangent (f32) +/// +/// Computes the inverse tangent (arc tangent) of the input value. +/// Returns a value in radians, in the range of -pi/2 to pi/2. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atanf(mut x: f32) -> f32 { + let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) + + let z: f32; + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix >= 0x4c800000 { + /* if |x| >= 2**26 */ + if x.is_nan() { + return x; + } + z = i!(ATAN_HI, 3) + x1p_120; + return if sign { -z } else { z }; + } + let id = if ix < 0x3ee00000 { + /* |x| < 0.4375 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + if ix < 0x00800000 { + /* raise underflow for subnormal x */ + force_eval!(x * x); + } + return x; + } + -1 + } else { + x = fabsf(x); + if ix < 0x3f980000 { + /* |x| < 1.1875 */ + if ix < 0x3f300000 { + /* 7/16 <= |x| < 11/16 */ + x = (2. * x - 1.) / (2. + x); + 0 + } else { + /* 11/16 <= |x| < 19/16 */ + x = (x - 1.) / (x + 1.); + 1 + } + } else if ix < 0x401c0000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 + } else { + /* 2.4375 <= |x| < 2**26 */ + x = -1. / x; + 3 + } + }; + /* end of argument reduction */ + z = x * x; + let w = z * z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + let s1 = z * (i!(A_T, 0) + w * (i!(A_T, 2) + w * i!(A_T, 4))); + let s2 = w * (i!(A_T, 1) + w * i!(A_T, 3)); + if id < 0 { + return x - x * (s1 + s2); + } + let id = id as usize; + let z = i!(ATAN_HI, id) - ((x * (s1 + s2) - i!(ATAN_LO, id)) - x); + if sign { + -z + } else { + z + } +} diff --git a/core/llm/math/atanh.rs b/core/llm/math/atanh.rs new file mode 100644 index 0000000..b984c4a --- /dev/null +++ b/core/llm/math/atanh.rs @@ -0,0 +1,37 @@ +use super::log1p; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +/// Inverse hyperbolic tangent (f64) +/// +/// Calculates the inverse hyperbolic tangent of `x`. +/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atanh(x: f64) -> f64 { + let u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + let mut y = f64::from_bits(u & 0x7fff_ffff_ffff_ffff); + + if e < 0x3ff - 1 { + if e < 0x3ff - 32 { + /* handle underflow */ + if e == 0 { + force_eval!(y as f32); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5 * log1p(2.0 * y + 2.0 * y * y / (1.0 - y)); + } + } else { + /* avoid overflow */ + y = 0.5 * log1p(2.0 * (y / (1.0 - y))); + } + + if sign { + -y + } else { + y + } +} diff --git a/core/llm/math/atanhf.rs b/core/llm/math/atanhf.rs new file mode 100644 index 0000000..a1aa314 --- /dev/null +++ b/core/llm/math/atanhf.rs @@ -0,0 +1,37 @@ +use super::log1pf; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +/// Inverse hyperbolic tangent (f32) +/// +/// Calculates the inverse hyperbolic tangent of `x`. +/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn atanhf(mut x: f32) -> f32 { + let mut u = x.to_bits(); + let sign = (u >> 31) != 0; + + /* |x| */ + u &= 0x7fffffff; + x = f32::from_bits(u); + + if u < 0x3f800000 - (1 << 23) { + if u < 0x3f800000 - (32 << 23) { + /* handle underflow */ + if u < (1 << 23) { + force_eval!((x * x) as f32); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5 * log1pf(2.0 * x + 2.0 * x * x / (1.0 - x)); + } + } else { + /* avoid overflow */ + x = 0.5 * log1pf(2.0 * (x / (1.0 - x))); + } + + if sign { + -x + } else { + x + } +} diff --git a/core/llm/math/cbrt.rs b/core/llm/math/cbrt.rs new file mode 100644 index 0000000..b4e77ea --- /dev/null +++ b/core/llm/math/cbrt.rs @@ -0,0 +1,113 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +/* cbrt(x) + * Return cube root of x + */ + +use core::f64; + +const B1: u32 = 715094163; /* B1 = (1023-1023/3-0.03306235651)*2**20 */ +const B2: u32 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */ + +/* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */ +const P0: f64 = 1.87595182427177009643; /* 0x3ffe03e6, 0x0f61e692 */ +const P1: f64 = -1.88497979543377169875; /* 0xbffe28e0, 0x92f02420 */ +const P2: f64 = 1.621429720105354466140; /* 0x3ff9f160, 0x4a49d6c2 */ +const P3: f64 = -0.758397934778766047437; /* 0xbfe844cb, 0xbee751d9 */ +const P4: f64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ + +// Cube root (f64) +/// +/// Computes the cube root of the argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cbrt(x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui: u64 = x.to_bits(); + let mut r: f64; + let s: f64; + let mut t: f64; + let w: f64; + let mut hx: u32 = (ui >> 32) as u32 & 0x7fffffff; + + if hx >= 0x7ff00000 { + /* cbrt(NaN,INF) is itself */ + return x + x; + } + + /* + * Rough cbrt to 5 bits: + * cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3) + * where e is integral and >= 0, m is real and in [0, 1), and "/" and + * "%" are integer division and modulus with rounding towards minus + * infinity. The RHS is always >= the LHS and has a maximum relative + * error of about 1 in 16. Adding a bias of -0.03306235651 to the + * (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE + * floating point representation, for finite positive normal values, + * ordinary integer divison of the value in bits magically gives + * almost exactly the RHS of the above provided we first subtract the + * exponent bias (1023 for doubles) and later add it back. We do the + * subtraction virtually to keep e >= 0 so that ordinary integer + * division rounds towards minus infinity; this is also efficient. + */ + if hx < 0x00100000 { + /* zero or subnormal? */ + ui = (x * x1p54).to_bits(); + hx = (ui >> 32) as u32 & 0x7fffffff; + if hx == 0 { + return x; /* cbrt(0) is itself */ + } + hx = hx / 3 + B2; + } else { + hx = hx / 3 + B1; + } + ui &= 1 << 63; + ui |= (hx as u64) << 32; + t = f64::from_bits(ui); + + /* + * New cbrt to 23 bits: + * cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x) + * where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r) + * to within 2**-23.5 when |r - 1| < 1/10. The rough approximation + * has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this + * gives us bounds for r = t**3/x. + * + * Try to optimize for parallel evaluation as in __tanf.c. + */ + r = (t * t) * (t / x); + t = t * ((P0 + r * (P1 + r * P2)) + ((r * r) * r) * (P3 + r * P4)); + + /* + * Round t away from zero to 23 bits (sloppily except for ensuring that + * the result is larger in magnitude than cbrt(x) but not much more than + * 2 23-bit ulps larger). With rounding towards zero, the error bound + * would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps + * in the rounded t, the infinite-precision error in the Newton + * approximation barely affects third digit in the final error + * 0.667; the error in the rounded t can be up to about 3 23-bit ulps + * before the final error is larger than 0.667 ulps. + */ + ui = t.to_bits(); + ui = (ui + 0x80000000) & 0xffffffffc0000000; + t = f64::from_bits(ui); + + /* one step Newton iteration to 53 bits with error < 0.667 ulps */ + s = t * t; /* t*t is exact */ + r = x / s; /* error <= 0.5 ulps; |r| < |t| */ + w = t + t; /* t+t is exact */ + r = (r - t) / (w + r); /* r-t is exact; w+r ~= 3*t */ + t = t + t * r; /* error <= 0.5 + 0.5/3 + epsilon */ + t +} diff --git a/core/llm/math/cbrtf.rs b/core/llm/math/cbrtf.rs new file mode 100644 index 0000000..9d70305 --- /dev/null +++ b/core/llm/math/cbrtf.rs @@ -0,0 +1,75 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* cbrtf(x) + * Return cube root of x + */ + +use core::f32; + +const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ +const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ + +/// Cube root (f32) +/// +/// Computes the cube root of the argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cbrtf(x: f32) -> f32 { + let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 + + let mut r: f64; + let mut t: f64; + let mut ui: u32 = x.to_bits(); + let mut hx: u32 = ui & 0x7fffffff; + + if hx >= 0x7f800000 { + /* cbrt(NaN,INF) is itself */ + return x + x; + } + + /* rough cbrt to 5 bits */ + if hx < 0x00800000 { + /* zero or subnormal? */ + if hx == 0 { + return x; /* cbrt(+-0) is itself */ + } + ui = (x * x1p24).to_bits(); + hx = ui & 0x7fffffff; + hx = hx / 3 + B2; + } else { + hx = hx / 3 + B1; + } + ui &= 0x80000000; + ui |= hx; + + /* + * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In + * double precision so that its terms can be arranged for efficiency + * without causing overflow or underflow. + */ + t = f32::from_bits(ui) as f64; + r = t * t * t; + t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); + + /* + * Second step Newton iteration to 47 bits. In double precision for + * efficiency and accuracy. + */ + r = t * t * t; + t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); + + /* rounding to 24 bits is perfect in round-to-nearest mode */ + t as f32 +} diff --git a/core/llm/math/ceil.rs b/core/llm/math/ceil.rs new file mode 100644 index 0000000..22d8929 --- /dev/null +++ b/core/llm/math/ceil.rs @@ -0,0 +1,82 @@ +#![allow(unreachable_code)] +use core::f64; + +const TOINT: f64 = 1. / f64::EPSILON; + +/// Ceil (f64) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceil(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.ceil` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::ceilf64(x) } + } + } + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + { + //use an alternative implementation on x86, because the + //main implementation fails with the x87 FPU used by + //debian i386, probablly due to excess precision issues. + //basic implementation taken from https://github.com/rust-lang/libm/issues/219 + use super::fabs; + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated < x { + return truncated + 1.0; + } else { + return truncated; + } + } else { + return x; + } + } + let u: u64 = x.to_bits(); + let e: i64 = (u >> 52 & 0x7ff) as i64; + let y: f64; + + if e >= 0x3ff + 52 || x == 0. { + return x; + } + // y = int(x) - x, where int(x) is an integer neighbor of x + y = if (u >> 63) != 0 { + x - TOINT + TOINT - x + } else { + x + TOINT - TOINT - x + }; + // special case because of non-nearest rounding modes + if e < 0x3ff { + force_eval!(y); + return if (u >> 63) != 0 { -0. } else { 1. }; + } + if y < 0. { + x + y + 1. + } else { + x + y + } +} + +#[cfg(test)] +mod tests { + use super::*; + use core::f64::*; + + #[test] + fn sanity_check() { + assert_eq!(ceil(1.1), 2.0); + assert_eq!(ceil(2.9), 3.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil + #[test] + fn spec_tests() { + // Not Asserted: that the current rounding mode has no effect. + assert!(ceil(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(ceil(f), f); + } + } +} diff --git a/core/llm/math/ceilf.rs b/core/llm/math/ceilf.rs new file mode 100644 index 0000000..7bcc647 --- /dev/null +++ b/core/llm/math/ceilf.rs @@ -0,0 +1,65 @@ +use core::f32; + +/// Ceil (f32) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.ceil` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::ceilf32(x) } + } + } + let mut ui = x.to_bits(); + let e = (((ui >> 23) & 0xff).wrapping_sub(0x7f)) as i32; + + if e >= 23 { + return x; + } + if e >= 0 { + let m = 0x007fffff >> e; + if (ui & m) == 0 { + return x; + } + force_eval!(x + f32::from_bits(0x7b800000)); + if ui >> 31 == 0 { + ui += m; + } + ui &= !m; + } else { + force_eval!(x + f32::from_bits(0x7b800000)); + if ui >> 31 != 0 { + return -0.0; + } else if ui << 1 != 0 { + return 1.0; + } + } + f32::from_bits(ui) +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::*; + use core::f32::*; + + #[test] + fn sanity_check() { + assert_eq!(ceilf(1.1), 2.0); + assert_eq!(ceilf(2.9), 3.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil + #[test] + fn spec_tests() { + // Not Asserted: that the current rounding mode has no effect. + assert!(ceilf(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(ceilf(f), f); + } + } +} diff --git a/core/llm/math/copysign.rs b/core/llm/math/copysign.rs new file mode 100644 index 0000000..1f4a35a --- /dev/null +++ b/core/llm/math/copysign.rs @@ -0,0 +1,12 @@ +/// Sign of Y, magnitude of X (f64) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysign(x: f64, y: f64) -> f64 { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= (!0) >> 1; + ux |= uy & (1 << 63); + f64::from_bits(ux) +} diff --git a/core/llm/math/copysignf.rs b/core/llm/math/copysignf.rs new file mode 100644 index 0000000..6c346e3 --- /dev/null +++ b/core/llm/math/copysignf.rs @@ -0,0 +1,12 @@ +/// Sign of Y, magnitude of X (f32) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf(x: f32, y: f32) -> f32 { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= 0x7fffffff; + ux |= uy & 0x80000000; + f32::from_bits(ux) +} diff --git a/core/llm/math/cos.rs b/core/llm/math/cos.rs new file mode 100644 index 0000000..db8bc49 --- /dev/null +++ b/core/llm/math/cos.rs @@ -0,0 +1,73 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */ +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +use super::{k_cos, k_sin, rem_pio2}; + +// cos(x) +// Return cosine function of x. +// +// kernel function: +// k_sin ... sine function on [-pi/4,pi/4] +// k_cos ... cosine function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded +// +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cos(x: f64) -> f64 { + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e46a09e { + /* if x < 2**-27 * sqrt(2) */ + /* raise inexact if x != 0 */ + if x as i32 == 0 { + return 1.0; + } + } + return k_cos(x, 0.0); + } + + /* cos(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + match n & 3 { + 0 => k_cos(y0, y1), + 1 => -k_sin(y0, y1, 1), + 2 => -k_cos(y0, y1), + _ => k_sin(y0, y1, 1), + } +} diff --git a/core/llm/math/cosf.rs b/core/llm/math/cosf.rs new file mode 100644 index 0000000..424fa42 --- /dev/null +++ b/core/llm/math/cosf.rs @@ -0,0 +1,83 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{k_cosf, k_sinf, rem_pio2f}; + +use core::f64::consts::FRAC_PI_2; + +/* Small multiples of pi/2 rounded to double precision. */ +const C1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cosf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + force_eval!(x + x1p120); + return 1.; + } + return k_cosf(x64); + } + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix > 0x4016cbe3 { + /* |x| ~> 3*pi/4 */ + return -k_cosf(if sign { x64 + C2_PIO2 } else { x64 - C2_PIO2 }); + } else if sign { + return k_sinf(x64 + C1_PIO2); + } else { + return k_sinf(C1_PIO2 - x64); + } + } + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix > 0x40afeddf { + /* |x| ~> 7*pi/4 */ + return k_cosf(if sign { x64 + C4_PIO2 } else { x64 - C4_PIO2 }); + } else if sign { + return k_sinf(-x64 - C3_PIO2); + } else { + return k_sinf(x64 - C3_PIO2); + } + } + + /* cos(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x - x; + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + match n & 3 { + 0 => k_cosf(y), + 1 => k_sinf(-y), + 2 => -k_cosf(y), + _ => k_sinf(y), + } +} diff --git a/core/llm/math/cosh.rs b/core/llm/math/cosh.rs new file mode 100644 index 0000000..2fb568a --- /dev/null +++ b/core/llm/math/cosh.rs @@ -0,0 +1,38 @@ +use super::exp; +use super::expm1; +use super::k_expo2; + +/// Hyperbolic cosine (f64) +/// +/// Computes the hyperbolic cosine of the argument x. +/// Is defined as `(exp(x) + exp(-x))/2` +/// Angles are specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn cosh(mut x: f64) -> f64 { + /* |x| */ + let mut ix = x.to_bits(); + ix &= 0x7fffffffffffffff; + x = f64::from_bits(ix); + let w = ix >> 32; + + /* |x| < log(2) */ + if w < 0x3fe62e42 { + if w < 0x3ff00000 - (26 << 20) { + let x1p120 = f64::from_bits(0x4770000000000000); + force_eval!(x + x1p120); + return 1.; + } + let t = expm1(x); // exponential minus 1 + return 1. + t * t / (2. * (1. + t)); + } + + /* |x| < log(DBL_MAX) */ + if w < 0x40862e42 { + let t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5 * (t + 1. / t); + } + + /* |x| > log(DBL_MAX) or nan */ + k_expo2(x) +} diff --git a/core/llm/math/coshf.rs b/core/llm/math/coshf.rs new file mode 100644 index 0000000..e7b6845 --- /dev/null +++ b/core/llm/math/coshf.rs @@ -0,0 +1,38 @@ +use super::expf; +use super::expm1f; +use super::k_expo2f; + +/// Hyperbolic cosine (f64) +/// +/// Computes the hyperbolic cosine of the argument x. +/// Is defined as `(exp(x) + exp(-x))/2` +/// Angles are specified in radians. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn coshf(mut x: f32) -> f32 { + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + /* |x| */ + let mut ix = x.to_bits(); + ix &= 0x7fffffff; + x = f32::from_bits(ix); + let w = ix; + + /* |x| < log(2) */ + if w < 0x3f317217 { + if w < (0x3f800000 - (12 << 23)) { + force_eval!(x + x1p120); + return 1.; + } + let t = expm1f(x); + return 1. + t * t / (2. * (1. + t)); + } + + /* |x| < log(FLT_MAX) */ + if w < 0x42b17217 { + let t = expf(x); + return 0.5 * (t + 1. / t); + } + + /* |x| > log(FLT_MAX) or nan */ + k_expo2f(x) +} diff --git a/core/llm/math/erf.rs b/core/llm/math/erf.rs new file mode 100644 index 0000000..55569af --- /dev/null +++ b/core/llm/math/erf.rs @@ -0,0 +1,318 @@ +use super::{exp, fabs, get_high_word, with_set_low_word}; +/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +const ERX: f64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ +const PP0: f64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ +const PP1: f64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ +const PP2: f64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ +const PP3: f64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ +const PP4: f64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ +const QQ1: f64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ +const QQ2: f64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ +const QQ3: f64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ +const QQ4: f64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ +const QQ5: f64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ +const PA1: f64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ +const PA2: f64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ +const PA3: f64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ +const PA4: f64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ +const PA5: f64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ +const PA6: f64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ +const QA1: f64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ +const QA2: f64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ +const QA3: f64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ +const QA4: f64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ +const QA5: f64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ +const QA6: f64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ +const RA1: f64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ +const RA2: f64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ +const RA3: f64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ +const RA4: f64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ +const RA5: f64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ +const RA6: f64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ +const RA7: f64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ +const SA1: f64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ +const SA2: f64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ +const SA3: f64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ +const SA4: f64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ +const SA5: f64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ +const SA6: f64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ +const SA7: f64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ +const SA8: f64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ +const RB1: f64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ +const RB2: f64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ +const RB3: f64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ +const RB4: f64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ +const RB5: f64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ +const RB6: f64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ +const SB1: f64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ +const SB2: f64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ +const SB3: f64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ +const SB4: f64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ +const SB5: f64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ +const SB6: f64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ +const SB7: f64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +fn erfc1(x: f64) -> f64 { + let s: f64; + let p: f64; + let q: f64; + + s = fabs(x) - 1.0; + p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); + q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); + + 1.0 - ERX - p / q +} + +fn erfc2(ix: u32, mut x: f64) -> f64 { + let s: f64; + let r: f64; + let big_s: f64; + let z: f64; + + if ix < 0x3ff40000 { + /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabs(x); + s = 1.0 / (x * x); + if ix < 0x4006db6d { + /* |x| < 1/.35 ~ 2.85714 */ + r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); + big_s = 1.0 + + s * (SA1 + + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); + } else { + /* |x| > 1/.35 */ + r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); + big_s = + 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); + } + z = with_set_low_word(x, 0); + + exp(-z * z - 0.5625) * exp((z - x) * (z + x) + r / big_s) / x +} + +/// Error function (f64) +/// +/// Calculates an approximation to the “error function”, which estimates +/// the probability that an observation will fall within x standard +/// deviations of the mean (assuming a normal distribution). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn erf(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0 - 2.0 * (sign as f64) + 1.0 / x; + } + if ix < 0x3feb0000 { + /* |x| < 0.84375 */ + if ix < 0x3e300000 { + /* |x| < 2**-28 */ + /* avoid underflow */ + return 0.125 * (8.0 * x + EFX8 * x); + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + return x + x * y; + } + if ix < 0x40180000 { + /* 0.84375 <= |x| < 6 */ + y = 1.0 - erfc2(ix, x); + } else { + let x1p_1022 = f64::from_bits(0x0010000000000000); + y = 1.0 - x1p_1022; + } + + if sign != 0 { + -y + } else { + y + } +} + +/// Complementary error function (f64) +/// +/// Calculates the complementary probability. +/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid +/// the loss of precision that would result from subtracting +/// large probabilities (on large `x`) from 1. +pub fn erfc(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0 * (sign as f64) + 1.0 / x; + } + if ix < 0x3feb0000 { + /* |x| < 0.84375 */ + if ix < 0x3c700000 { + /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + if sign != 0 || ix < 0x3fd00000 { + /* x < 1/4 */ + return 1.0 - (x + x * y); + } + return 0.5 - (x - 0.5 + x * y); + } + if ix < 0x403c0000 { + /* 0.84375 <= |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix, x); + } else { + return erfc2(ix, x); + } + } + + let x1p_1022 = f64::from_bits(0x0010000000000000); + if sign != 0 { + 2.0 - x1p_1022 + } else { + x1p_1022 * x1p_1022 + } +} diff --git a/core/llm/math/erff.rs b/core/llm/math/erff.rs new file mode 100644 index 0000000..7b25474 --- /dev/null +++ b/core/llm/math/erff.rs @@ -0,0 +1,230 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{expf, fabsf}; + +const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f32 = 1.0270333290e+00; /* 0x3f8375d4 */ +const PP0: f32 = 1.2837916613e-01; /* 0x3e0375d4 */ +const PP1: f32 = -3.2504209876e-01; /* 0xbea66beb */ +const PP2: f32 = -2.8481749818e-02; /* 0xbce9528f */ +const PP3: f32 = -5.7702702470e-03; /* 0xbbbd1489 */ +const PP4: f32 = -2.3763017452e-05; /* 0xb7c756b1 */ +const QQ1: f32 = 3.9791721106e-01; /* 0x3ecbbbce */ +const QQ2: f32 = 6.5022252500e-02; /* 0x3d852a63 */ +const QQ3: f32 = 5.0813062117e-03; /* 0x3ba68116 */ +const QQ4: f32 = 1.3249473704e-04; /* 0x390aee49 */ +const QQ5: f32 = -3.9602282413e-06; /* 0xb684e21a */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f32 = -2.3621185683e-03; /* 0xbb1acdc6 */ +const PA1: f32 = 4.1485610604e-01; /* 0x3ed46805 */ +const PA2: f32 = -3.7220788002e-01; /* 0xbebe9208 */ +const PA3: f32 = 3.1834661961e-01; /* 0x3ea2fe54 */ +const PA4: f32 = -1.1089469492e-01; /* 0xbde31cc2 */ +const PA5: f32 = 3.5478305072e-02; /* 0x3d1151b3 */ +const PA6: f32 = -2.1663755178e-03; /* 0xbb0df9c0 */ +const QA1: f32 = 1.0642088205e-01; /* 0x3dd9f331 */ +const QA2: f32 = 5.4039794207e-01; /* 0x3f0a5785 */ +const QA3: f32 = 7.1828655899e-02; /* 0x3d931ae7 */ +const QA4: f32 = 1.2617121637e-01; /* 0x3e013307 */ +const QA5: f32 = 1.3637083583e-02; /* 0x3c5f6e13 */ +const QA6: f32 = 1.1984500103e-02; /* 0x3c445aa3 */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f32 = -9.8649440333e-03; /* 0xbc21a093 */ +const RA1: f32 = -6.9385856390e-01; /* 0xbf31a0b7 */ +const RA2: f32 = -1.0558626175e+01; /* 0xc128f022 */ +const RA3: f32 = -6.2375331879e+01; /* 0xc2798057 */ +const RA4: f32 = -1.6239666748e+02; /* 0xc322658c */ +const RA5: f32 = -1.8460508728e+02; /* 0xc3389ae7 */ +const RA6: f32 = -8.1287437439e+01; /* 0xc2a2932b */ +const RA7: f32 = -9.8143291473e+00; /* 0xc11d077e */ +const SA1: f32 = 1.9651271820e+01; /* 0x419d35ce */ +const SA2: f32 = 1.3765776062e+02; /* 0x4309a863 */ +const SA3: f32 = 4.3456588745e+02; /* 0x43d9486f */ +const SA4: f32 = 6.4538726807e+02; /* 0x442158c9 */ +const SA5: f32 = 4.2900814819e+02; /* 0x43d6810b */ +const SA6: f32 = 1.0863500214e+02; /* 0x42d9451f */ +const SA7: f32 = 6.5702495575e+00; /* 0x40d23f7c */ +const SA8: f32 = -6.0424413532e-02; /* 0xbd777f97 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f32 = -9.8649431020e-03; /* 0xbc21a092 */ +const RB1: f32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ +const RB2: f32 = -1.7757955551e+01; /* 0xc18e104b */ +const RB3: f32 = -1.6063638306e+02; /* 0xc320a2ea */ +const RB4: f32 = -6.3756646729e+02; /* 0xc41f6441 */ +const RB5: f32 = -1.0250950928e+03; /* 0xc480230b */ +const RB6: f32 = -4.8351919556e+02; /* 0xc3f1c275 */ +const SB1: f32 = 3.0338060379e+01; /* 0x41f2b459 */ +const SB2: f32 = 3.2579251099e+02; /* 0x43a2e571 */ +const SB3: f32 = 1.5367296143e+03; /* 0x44c01759 */ +const SB4: f32 = 3.1998581543e+03; /* 0x4547fdbb */ +const SB5: f32 = 2.5530502930e+03; /* 0x451f90ce */ +const SB6: f32 = 4.7452853394e+02; /* 0x43ed43a7 */ +const SB7: f32 = -2.2440952301e+01; /* 0xc1b38712 */ + +fn erfc1(x: f32) -> f32 { + let s: f32; + let p: f32; + let q: f32; + + s = fabsf(x) - 1.0; + p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); + q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); + return 1.0 - ERX - p / q; +} + +fn erfc2(mut ix: u32, mut x: f32) -> f32 { + let s: f32; + let r: f32; + let big_s: f32; + let z: f32; + + if ix < 0x3fa00000 { + /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabsf(x); + s = 1.0 / (x * x); + if ix < 0x4036db6d { + /* |x| < 1/0.35 */ + r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); + big_s = 1.0 + + s * (SA1 + + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); + } else { + /* |x| >= 1/0.35 */ + r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); + big_s = + 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); + } + ix = x.to_bits(); + z = f32::from_bits(ix & 0xffffe000); + + expf(-z * z - 0.5625) * expf((z - x) * (z + x) + r / big_s) / x +} + +/// Error function (f32) +/// +/// Calculates an approximation to the “error function”, which estimates +/// the probability that an observation will fall within x standard +/// deviations of the mean (assuming a normal distribution). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn erff(x: f32) -> f32 { + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0 - 2.0 * (sign as f32) + 1.0 / x; + } + if ix < 0x3f580000 { + /* |x| < 0.84375 */ + if ix < 0x31800000 { + /* |x| < 2**-28 */ + /*avoid underflow */ + return 0.125 * (8.0 * x + EFX8 * x); + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + return x + x * y; + } + if ix < 0x40c00000 { + /* |x| < 6 */ + y = 1.0 - erfc2(ix, x); + } else { + let x1p_120 = f32::from_bits(0x03800000); + y = 1.0 - x1p_120; + } + + if sign != 0 { + -y + } else { + y + } +} + +/// Complementary error function (f32) +/// +/// Calculates the complementary probability. +/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid +/// the loss of precision that would result from subtracting +/// large probabilities (on large `x`) from 1. +pub fn erfcf(x: f32) -> f32 { + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0 * (sign as f32) + 1.0 / x; + } + + if ix < 0x3f580000 { + /* |x| < 0.84375 */ + if ix < 0x23800000 { + /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + if sign != 0 || ix < 0x3e800000 { + /* x < 1/4 */ + return 1.0 - (x + x * y); + } + return 0.5 - (x - 0.5 + x * y); + } + if ix < 0x41e00000 { + /* |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix, x); + } else { + return erfc2(ix, x); + } + } + + let x1p_120 = f32::from_bits(0x03800000); + if sign != 0 { + 2.0 - x1p_120 + } else { + x1p_120 * x1p_120 + } +} diff --git a/core/llm/math/exp.rs b/core/llm/math/exp.rs new file mode 100644 index 0000000..d499427 --- /dev/null +++ b/core/llm/math/exp.rs @@ -0,0 +1,154 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: + * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on + * the interval [0,0.34658]: + * Write + * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + * We use a special Remez algorithm on [0,0.34658] to generate + * a polynomial of degree 5 to approximate R. The maximum error + * of this polynomial approximation is bounded by 2**-59. In + * other words, + * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + * (where z=r*r, and the values of P1 to P5 are listed below) + * and + * | 5 | -59 + * | 2.0+P1*z+...+P5*z - R(z) | <= 2 + * | | + * The computation of exp(r) thus becomes + * 2*r + * exp(r) = 1 + ---------- + * R(r) - r + * r*c(r) + * = 1 + r + ----------- (for better accuracy) + * 2 - c(r) + * where + * 2 4 10 + * c(r) = r - (P1*r + P2*r + ... + P5*r ). + * + * 3. Scale back to obtain exp(x): + * From step 1, we have + * exp(x) = 2^k * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 709.782712893383973096 then exp(x) overflows + * if x < -745.133219101941108420 then exp(x) underflows + */ + +use super::scalbn; + +const HALF: [f64; 2] = [0.5, -0.5]; +const LN2HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ +const P2: f64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ +const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +/// Exponential, base *e* (f64) +/// +/// Calculate the exponential of `x`, that is, *e* raised to the power `x` +/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp(mut x: f64) -> f64 { + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 + let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149 + + let hi: f64; + let lo: f64; + let c: f64; + let xx: f64; + let y: f64; + let k: i32; + let sign: i32; + let mut hx: u32; + + hx = (x.to_bits() >> 32) as u32; + sign = (hx >> 31) as i32; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if hx >= 0x4086232b { + /* if |x| >= 708.39... */ + if x.is_nan() { + return x; + } + if x > 709.782712893383973096 { + /* overflow if x!=inf */ + x *= x1p1023; + return x; + } + if x < -708.39641853226410622 { + /* underflow if x!=-inf */ + force_eval!((-x1p_149 / x) as f32); + if x < -745.13321910194110842 { + return 0.; + } + } + } + + /* argument reduction */ + if hx > 0x3fd62e42 { + /* if |x| > 0.5 ln2 */ + if hx >= 0x3ff0a2b2 { + /* if |x| >= 1.5 ln2 */ + k = (INVLN2 * x + i!(HALF, sign as usize)) as i32; + } else { + k = 1 - sign - sign; + } + hi = x - k as f64 * LN2HI; /* k*ln2hi is exact here */ + lo = k as f64 * LN2LO; + x = hi - lo; + } else if hx > 0x3e300000 { + /* if |x| > 2**-28 */ + k = 0; + hi = x; + lo = 0.; + } else { + /* inexact if x!=0 */ + force_eval!(x1p1023 + x); + return 1. + x; + } + + /* x is now in primary range */ + xx = x * x; + c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); + y = 1. + (x * c / (2. - c) - lo + hi); + if k == 0 { + y + } else { + scalbn(y, k) + } +} diff --git a/core/llm/math/exp10.rs b/core/llm/math/exp10.rs new file mode 100644 index 0000000..559930e --- /dev/null +++ b/core/llm/math/exp10.rs @@ -0,0 +1,22 @@ +use super::{exp2, modf, pow}; + +const LN10: f64 = 3.32192809488736234787031942948939; +const P10: &[f64] = &[ + 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, +]; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp10(x: f64) -> f64 { + let (mut y, n) = modf(x); + let u: u64 = n.to_bits(); + /* fabs(n) < 16 without raising invalid on nan */ + if (u >> 52 & 0x7ff) < 0x3ff + 4 { + if y == 0.0 { + return i!(P10, ((n as isize) + 15) as usize); + } + y = exp2(LN10 * y); + return y * i!(P10, ((n as isize) + 15) as usize); + } + return pow(10.0, x); +} diff --git a/core/llm/math/exp10f.rs b/core/llm/math/exp10f.rs new file mode 100644 index 0000000..1279bc6 --- /dev/null +++ b/core/llm/math/exp10f.rs @@ -0,0 +1,22 @@ +use super::{exp2, exp2f, modff}; + +const LN10_F32: f32 = 3.32192809488736234787031942948939; +const LN10_F64: f64 = 3.32192809488736234787031942948939; +const P10: &[f32] = &[ + 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, +]; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp10f(x: f32) -> f32 { + let (mut y, n) = modff(x); + let u = n.to_bits(); + /* fabsf(n) < 8 without raising invalid on nan */ + if (u >> 23 & 0xff) < 0x7f + 3 { + if y == 0.0 { + return i!(P10, ((n as isize) + 7) as usize); + } + y = exp2f(LN10_F32 * y); + return y * i!(P10, ((n as isize) + 7) as usize); + } + return exp2(LN10_F64 * (x as f64)) as f32; +} diff --git a/core/llm/math/exp2.rs b/core/llm/math/exp2.rs new file mode 100644 index 0000000..e0e385d --- /dev/null +++ b/core/llm/math/exp2.rs @@ -0,0 +1,394 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ +//- +// Copyright (c) 2005 David Schultz +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +use super::scalbn; + +const TBLSIZE: usize = 256; + +#[cfg_attr(rustfmt, rustfmt_skip)] +static TBL: [u64; TBLSIZE * 2] = [ + // exp2(z + eps) eps + 0x3fe6a09e667f3d5d, 0x3d39880000000000, + 0x3fe6b052fa751744, 0x3cd8000000000000, + 0x3fe6c012750bd9fe, 0xbd28780000000000, + 0x3fe6cfdcddd476bf, 0x3d1ec00000000000, + 0x3fe6dfb23c651a29, 0xbcd8000000000000, + 0x3fe6ef9298593ae3, 0xbcbc000000000000, + 0x3fe6ff7df9519386, 0xbd2fd80000000000, + 0x3fe70f7466f42da3, 0xbd2c880000000000, + 0x3fe71f75e8ec5fc3, 0x3d13c00000000000, + 0x3fe72f8286eacf05, 0xbd38300000000000, + 0x3fe73f9a48a58152, 0xbd00c00000000000, + 0x3fe74fbd35d7ccfc, 0x3d2f880000000000, + 0x3fe75feb564267f1, 0x3d03e00000000000, + 0x3fe77024b1ab6d48, 0xbd27d00000000000, + 0x3fe780694fde5d38, 0xbcdd000000000000, + 0x3fe790b938ac1d00, 0x3ce3000000000000, + 0x3fe7a11473eb0178, 0xbced000000000000, + 0x3fe7b17b0976d060, 0x3d20400000000000, + 0x3fe7c1ed0130c133, 0x3ca0000000000000, + 0x3fe7d26a62ff8636, 0xbd26900000000000, + 0x3fe7e2f336cf4e3b, 0xbd02e00000000000, + 0x3fe7f3878491c3e8, 0xbd24580000000000, + 0x3fe80427543e1b4e, 0x3d33000000000000, + 0x3fe814d2add1071a, 0x3d0f000000000000, + 0x3fe82589994ccd7e, 0xbd21c00000000000, + 0x3fe8364c1eb942d0, 0x3d29d00000000000, + 0x3fe8471a4623cab5, 0x3d47100000000000, + 0x3fe857f4179f5bbc, 0x3d22600000000000, + 0x3fe868d99b4491af, 0xbd32c40000000000, + 0x3fe879cad931a395, 0xbd23000000000000, + 0x3fe88ac7d98a65b8, 0xbd2a800000000000, + 0x3fe89bd0a4785800, 0xbced000000000000, + 0x3fe8ace5422aa223, 0x3d33280000000000, + 0x3fe8be05bad619fa, 0x3d42b40000000000, + 0x3fe8cf3216b54383, 0xbd2ed00000000000, + 0x3fe8e06a5e08664c, 0xbd20500000000000, + 0x3fe8f1ae99157807, 0x3d28280000000000, + 0x3fe902fed0282c0e, 0xbd1cb00000000000, + 0x3fe9145b0b91ff96, 0xbd05e00000000000, + 0x3fe925c353aa2ff9, 0x3cf5400000000000, + 0x3fe93737b0cdc64a, 0x3d17200000000000, + 0x3fe948b82b5f98ae, 0xbd09000000000000, + 0x3fe95a44cbc852cb, 0x3d25680000000000, + 0x3fe96bdd9a766f21, 0xbd36d00000000000, + 0x3fe97d829fde4e2a, 0xbd01000000000000, + 0x3fe98f33e47a23a3, 0x3d2d000000000000, + 0x3fe9a0f170ca0604, 0xbd38a40000000000, + 0x3fe9b2bb4d53ff89, 0x3d355c0000000000, + 0x3fe9c49182a3f15b, 0x3d26b80000000000, + 0x3fe9d674194bb8c5, 0xbcec000000000000, + 0x3fe9e86319e3238e, 0x3d17d00000000000, + 0x3fe9fa5e8d07f302, 0x3d16400000000000, + 0x3fea0c667b5de54d, 0xbcf5000000000000, + 0x3fea1e7aed8eb8f6, 0x3d09e00000000000, + 0x3fea309bec4a2e27, 0x3d2ad80000000000, + 0x3fea42c980460a5d, 0xbd1af00000000000, + 0x3fea5503b23e259b, 0x3d0b600000000000, + 0x3fea674a8af46213, 0x3d38880000000000, + 0x3fea799e1330b3a7, 0x3d11200000000000, + 0x3fea8bfe53c12e8d, 0x3d06c00000000000, + 0x3fea9e6b5579fcd2, 0xbd29b80000000000, + 0x3feab0e521356fb8, 0x3d2b700000000000, + 0x3feac36bbfd3f381, 0x3cd9000000000000, + 0x3fead5ff3a3c2780, 0x3ce4000000000000, + 0x3feae89f995ad2a3, 0xbd2c900000000000, + 0x3feafb4ce622f367, 0x3d16500000000000, + 0x3feb0e07298db790, 0x3d2fd40000000000, + 0x3feb20ce6c9a89a9, 0x3d12700000000000, + 0x3feb33a2b84f1a4b, 0x3d4d470000000000, + 0x3feb468415b747e7, 0xbd38380000000000, + 0x3feb59728de5593a, 0x3c98000000000000, + 0x3feb6c6e29f1c56a, 0x3d0ad00000000000, + 0x3feb7f76f2fb5e50, 0x3cde800000000000, + 0x3feb928cf22749b2, 0xbd04c00000000000, + 0x3feba5b030a10603, 0xbd0d700000000000, + 0x3febb8e0b79a6f66, 0x3d0d900000000000, + 0x3febcc1e904bc1ff, 0x3d02a00000000000, + 0x3febdf69c3f3a16f, 0xbd1f780000000000, + 0x3febf2c25bd71db8, 0xbd10a00000000000, + 0x3fec06286141b2e9, 0xbd11400000000000, + 0x3fec199bdd8552e0, 0x3d0be00000000000, + 0x3fec2d1cd9fa64ee, 0xbd09400000000000, + 0x3fec40ab5fffd02f, 0xbd0ed00000000000, + 0x3fec544778fafd15, 0x3d39660000000000, + 0x3fec67f12e57d0cb, 0xbd1a100000000000, + 0x3fec7ba88988c1b6, 0xbd58458000000000, + 0x3fec8f6d9406e733, 0xbd1a480000000000, + 0x3feca3405751c4df, 0x3ccb000000000000, + 0x3fecb720dcef9094, 0x3d01400000000000, + 0x3feccb0f2e6d1689, 0x3cf0200000000000, + 0x3fecdf0b555dc412, 0x3cf3600000000000, + 0x3fecf3155b5bab3b, 0xbd06900000000000, + 0x3fed072d4a0789bc, 0x3d09a00000000000, + 0x3fed1b532b08c8fa, 0xbd15e00000000000, + 0x3fed2f87080d8a85, 0x3d1d280000000000, + 0x3fed43c8eacaa203, 0x3d01a00000000000, + 0x3fed5818dcfba491, 0x3cdf000000000000, + 0x3fed6c76e862e6a1, 0xbd03a00000000000, + 0x3fed80e316c9834e, 0xbd0cd80000000000, + 0x3fed955d71ff6090, 0x3cf4c00000000000, + 0x3feda9e603db32ae, 0x3cff900000000000, + 0x3fedbe7cd63a8325, 0x3ce9800000000000, + 0x3fedd321f301b445, 0xbcf5200000000000, + 0x3fede7d5641c05bf, 0xbd1d700000000000, + 0x3fedfc97337b9aec, 0xbd16140000000000, + 0x3fee11676b197d5e, 0x3d0b480000000000, + 0x3fee264614f5a3e7, 0x3d40ce0000000000, + 0x3fee3b333b16ee5c, 0x3d0c680000000000, + 0x3fee502ee78b3fb4, 0xbd09300000000000, + 0x3fee653924676d68, 0xbce5000000000000, + 0x3fee7a51fbc74c44, 0xbd07f80000000000, + 0x3fee8f7977cdb726, 0xbcf3700000000000, + 0x3feea4afa2a490e8, 0x3ce5d00000000000, + 0x3feeb9f4867ccae4, 0x3d161a0000000000, + 0x3feecf482d8e680d, 0x3cf5500000000000, + 0x3feee4aaa2188514, 0x3cc6400000000000, + 0x3feefa1bee615a13, 0xbcee800000000000, + 0x3fef0f9c1cb64106, 0xbcfa880000000000, + 0x3fef252b376bb963, 0xbd2c900000000000, + 0x3fef3ac948dd7275, 0x3caa000000000000, + 0x3fef50765b6e4524, 0xbcf4f00000000000, + 0x3fef6632798844fd, 0x3cca800000000000, + 0x3fef7bfdad9cbe38, 0x3cfabc0000000000, + 0x3fef91d802243c82, 0xbcd4600000000000, + 0x3fefa7c1819e908e, 0xbd0b0c0000000000, + 0x3fefbdba3692d511, 0xbcc0e00000000000, + 0x3fefd3c22b8f7194, 0xbd10de8000000000, + 0x3fefe9d96b2a23ee, 0x3cee430000000000, + 0x3ff0000000000000, 0x0, + 0x3ff00b1afa5abcbe, 0xbcb3400000000000, + 0x3ff0163da9fb3303, 0xbd12170000000000, + 0x3ff02168143b0282, 0x3cba400000000000, + 0x3ff02c9a3e77806c, 0x3cef980000000000, + 0x3ff037d42e11bbca, 0xbcc7400000000000, + 0x3ff04315e86e7f89, 0x3cd8300000000000, + 0x3ff04e5f72f65467, 0xbd1a3f0000000000, + 0x3ff059b0d315855a, 0xbd02840000000000, + 0x3ff0650a0e3c1f95, 0x3cf1600000000000, + 0x3ff0706b29ddf71a, 0x3d15240000000000, + 0x3ff07bd42b72a82d, 0xbce9a00000000000, + 0x3ff0874518759bd0, 0x3ce6400000000000, + 0x3ff092bdf66607c8, 0xbd00780000000000, + 0x3ff09e3ecac6f383, 0xbc98000000000000, + 0x3ff0a9c79b1f3930, 0x3cffa00000000000, + 0x3ff0b5586cf988fc, 0xbcfac80000000000, + 0x3ff0c0f145e46c8a, 0x3cd9c00000000000, + 0x3ff0cc922b724816, 0x3d05200000000000, + 0x3ff0d83b23395dd8, 0xbcfad00000000000, + 0x3ff0e3ec32d3d1f3, 0x3d1bac0000000000, + 0x3ff0efa55fdfa9a6, 0xbd04e80000000000, + 0x3ff0fb66affed2f0, 0xbd0d300000000000, + 0x3ff1073028d7234b, 0x3cf1500000000000, + 0x3ff11301d0125b5b, 0x3cec000000000000, + 0x3ff11edbab5e2af9, 0x3d16bc0000000000, + 0x3ff12abdc06c31d5, 0x3ce8400000000000, + 0x3ff136a814f2047d, 0xbd0ed00000000000, + 0x3ff1429aaea92de9, 0x3ce8e00000000000, + 0x3ff14e95934f3138, 0x3ceb400000000000, + 0x3ff15a98c8a58e71, 0x3d05300000000000, + 0x3ff166a45471c3df, 0x3d03380000000000, + 0x3ff172b83c7d5211, 0x3d28d40000000000, + 0x3ff17ed48695bb9f, 0xbd05d00000000000, + 0x3ff18af9388c8d93, 0xbd1c880000000000, + 0x3ff1972658375d66, 0x3d11f00000000000, + 0x3ff1a35beb6fcba7, 0x3d10480000000000, + 0x3ff1af99f81387e3, 0xbd47390000000000, + 0x3ff1bbe084045d54, 0x3d24e40000000000, + 0x3ff1c82f95281c43, 0xbd0a200000000000, + 0x3ff1d4873168b9b2, 0x3ce3800000000000, + 0x3ff1e0e75eb44031, 0x3ceac00000000000, + 0x3ff1ed5022fcd938, 0x3d01900000000000, + 0x3ff1f9c18438cdf7, 0xbd1b780000000000, + 0x3ff2063b88628d8f, 0x3d2d940000000000, + 0x3ff212be3578a81e, 0x3cd8000000000000, + 0x3ff21f49917ddd41, 0x3d2b340000000000, + 0x3ff22bdda2791323, 0x3d19f80000000000, + 0x3ff2387a6e7561e7, 0xbd19c80000000000, + 0x3ff2451ffb821427, 0x3d02300000000000, + 0x3ff251ce4fb2a602, 0xbd13480000000000, + 0x3ff25e85711eceb0, 0x3d12700000000000, + 0x3ff26b4565e27d16, 0x3d11d00000000000, + 0x3ff2780e341de00f, 0x3d31ee0000000000, + 0x3ff284dfe1f5633e, 0xbd14c00000000000, + 0x3ff291ba7591bb30, 0xbd13d80000000000, + 0x3ff29e9df51fdf09, 0x3d08b00000000000, + 0x3ff2ab8a66d10e9b, 0xbd227c0000000000, + 0x3ff2b87fd0dada3a, 0x3d2a340000000000, + 0x3ff2c57e39771af9, 0xbd10800000000000, + 0x3ff2d285a6e402d9, 0xbd0ed00000000000, + 0x3ff2df961f641579, 0xbcf4200000000000, + 0x3ff2ecafa93e2ecf, 0xbd24980000000000, + 0x3ff2f9d24abd8822, 0xbd16300000000000, + 0x3ff306fe0a31b625, 0xbd32360000000000, + 0x3ff31432edeea50b, 0xbd70df8000000000, + 0x3ff32170fc4cd7b8, 0xbd22480000000000, + 0x3ff32eb83ba8e9a2, 0xbd25980000000000, + 0x3ff33c08b2641766, 0x3d1ed00000000000, + 0x3ff3496266e3fa27, 0xbcdc000000000000, + 0x3ff356c55f929f0f, 0xbd30d80000000000, + 0x3ff36431a2de88b9, 0x3d22c80000000000, + 0x3ff371a7373aaa39, 0x3d20600000000000, + 0x3ff37f26231e74fe, 0xbd16600000000000, + 0x3ff38cae6d05d838, 0xbd0ae00000000000, + 0x3ff39a401b713ec3, 0xbd44720000000000, + 0x3ff3a7db34e5a020, 0x3d08200000000000, + 0x3ff3b57fbfec6e95, 0x3d3e800000000000, + 0x3ff3c32dc313a8f2, 0x3cef800000000000, + 0x3ff3d0e544ede122, 0xbd17a00000000000, + 0x3ff3dea64c1234bb, 0x3d26300000000000, + 0x3ff3ec70df1c4ecc, 0xbd48a60000000000, + 0x3ff3fa4504ac7e8c, 0xbd3cdc0000000000, + 0x3ff40822c367a0bb, 0x3d25b80000000000, + 0x3ff4160a21f72e95, 0x3d1ec00000000000, + 0x3ff423fb27094646, 0xbd13600000000000, + 0x3ff431f5d950a920, 0x3d23980000000000, + 0x3ff43ffa3f84b9eb, 0x3cfa000000000000, + 0x3ff44e0860618919, 0xbcf6c00000000000, + 0x3ff45c2042a7d201, 0xbd0bc00000000000, + 0x3ff46a41ed1d0016, 0xbd12800000000000, + 0x3ff4786d668b3326, 0x3d30e00000000000, + 0x3ff486a2b5c13c00, 0xbd2d400000000000, + 0x3ff494e1e192af04, 0x3d0c200000000000, + 0x3ff4a32af0d7d372, 0xbd1e500000000000, + 0x3ff4b17dea6db801, 0x3d07800000000000, + 0x3ff4bfdad53629e1, 0xbd13800000000000, + 0x3ff4ce41b817c132, 0x3d00800000000000, + 0x3ff4dcb299fddddb, 0x3d2c700000000000, + 0x3ff4eb2d81d8ab96, 0xbd1ce00000000000, + 0x3ff4f9b2769d2d02, 0x3d19200000000000, + 0x3ff508417f4531c1, 0xbd08c00000000000, + 0x3ff516daa2cf662a, 0xbcfa000000000000, + 0x3ff5257de83f51ea, 0x3d4a080000000000, + 0x3ff5342b569d4eda, 0xbd26d80000000000, + 0x3ff542e2f4f6ac1a, 0xbd32440000000000, + 0x3ff551a4ca5d94db, 0x3d483c0000000000, + 0x3ff56070dde9116b, 0x3d24b00000000000, + 0x3ff56f4736b529de, 0x3d415a0000000000, + 0x3ff57e27dbe2c40e, 0xbd29e00000000000, + 0x3ff58d12d497c76f, 0xbd23080000000000, + 0x3ff59c0827ff0b4c, 0x3d4dec0000000000, + 0x3ff5ab07dd485427, 0xbcc4000000000000, + 0x3ff5ba11fba87af4, 0x3d30080000000000, + 0x3ff5c9268a59460b, 0xbd26c80000000000, + 0x3ff5d84590998e3f, 0x3d469a0000000000, + 0x3ff5e76f15ad20e1, 0xbd1b400000000000, + 0x3ff5f6a320dcebca, 0x3d17700000000000, + 0x3ff605e1b976dcb8, 0x3d26f80000000000, + 0x3ff6152ae6cdf715, 0x3d01000000000000, + 0x3ff6247eb03a5531, 0xbd15d00000000000, + 0x3ff633dd1d1929b5, 0xbd12d00000000000, + 0x3ff6434634ccc313, 0xbcea800000000000, + 0x3ff652b9febc8efa, 0xbd28600000000000, + 0x3ff6623882553397, 0x3d71fe0000000000, + 0x3ff671c1c708328e, 0xbd37200000000000, + 0x3ff68155d44ca97e, 0x3ce6800000000000, + 0x3ff690f4b19e9471, 0xbd29780000000000, +]; + +// exp2(x): compute the base 2 exponential of x +// +// Accuracy: Peak error < 0.503 ulp for normalized results. +// +// Method: (accurate tables) +// +// Reduce x: +// x = k + y, for integer k and |y| <= 1/2. +// Thus we have exp2(x) = 2**k * exp2(y). +// +// Reduce y: +// y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. +// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), +// with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. +// +// We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via +// a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. +// The values in exp2t[] and eps[] are chosen such that +// exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such +// that exp2t[i] is accurate to 2**-64. +// +// Note that the range of i is +-TBLSIZE/2, so we actually index the tables +// by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are +// virtual tables, interleaved in the real table tbl[]. +// +// This method is due to Gal, with many details due to Gal and Bachelis: +// +// Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library +// for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + +/// Exponential, base 2 (f64) +/// +/// Calculate `2^x`, that is, 2 raised to the power `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp2(mut x: f64) -> f64 { + let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; + let p1 = f64::from_bits(0x3fe62e42fefa39ef); + let p2 = f64::from_bits(0x3fcebfbdff82c575); + let p3 = f64::from_bits(0x3fac6b08d704a0a6); + let p4 = f64::from_bits(0x3f83b2ab88f70400); + let p5 = f64::from_bits(0x3f55d88003875c74); + + // double_t r, t, z; + // uint32_t ix, i0; + // union {double f; uint64_t i;} u = {x}; + // union {uint32_t u; int32_t i;} k; + let x1p1023 = f64::from_bits(0x7fe0000000000000); + let x1p52 = f64::from_bits(0x4330000000000000); + let _0x1p_149 = f64::from_bits(0xb6a0000000000000); + + /* Filter out exceptional cases. */ + let ui = f64::to_bits(x); + let ix = ui >> 32 & 0x7fffffff; + if ix >= 0x408ff000 { + /* |x| >= 1022 or nan */ + if ix >= 0x40900000 && ui >> 63 == 0 { + /* x >= 1024 or nan */ + /* overflow */ + x *= x1p1023; + return x; + } + if ix >= 0x7ff00000 { + /* -inf or -nan */ + return -1.0 / x; + } + if ui >> 63 != 0 { + /* x <= -1022 */ + /* underflow */ + if x <= -1075.0 || x - x1p52 + x1p52 != x { + force_eval!((_0x1p_149 / x) as f32); + } + if x <= -1075.0 { + return 0.0; + } + } + } else if ix < 0x3c900000 { + /* |x| < 0x1p-54 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + let ui = f64::to_bits(x + redux); + let mut i0 = ui as u32; + i0 = i0.wrapping_add(TBLSIZE as u32 / 2); + let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; + let ki = div!(ku as i32, TBLSIZE as i32); + i0 %= TBLSIZE as u32; + let uf = f64::from_bits(ui) - redux; + let mut z = x - uf; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + let t = f64::from_bits(i!(TBL, 2 * i0 as usize)); /* exp2t[i0] */ + z -= f64::from_bits(i!(TBL, 2 * i0 as usize + 1)); /* eps[i0] */ + let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5)))); + + scalbn(r, ki) +} + +#[test] +fn i0_wrap_test() { + let x = -3.0 / 256.0; + assert_eq!(exp2(x), f64::from_bits(0x3fefbdba3692d514)); +} diff --git a/core/llm/math/exp2f.rs b/core/llm/math/exp2f.rs new file mode 100644 index 0000000..f4867b8 --- /dev/null +++ b/core/llm/math/exp2f.rs @@ -0,0 +1,135 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c +//- +// Copyright (c) 2005 David Schultz +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +const TBLSIZE: usize = 16; + +static EXP2FT: [u64; TBLSIZE] = [ + 0x3fe6a09e667f3bcd, + 0x3fe7a11473eb0187, + 0x3fe8ace5422aa0db, + 0x3fe9c49182a3f090, + 0x3feae89f995ad3ad, + 0x3fec199bdd85529c, + 0x3fed5818dcfba487, + 0x3feea4afa2a490da, + 0x3ff0000000000000, + 0x3ff0b5586cf9890f, + 0x3ff172b83c7d517b, + 0x3ff2387a6e756238, + 0x3ff306fe0a31b715, + 0x3ff3dea64c123422, + 0x3ff4bfdad5362a27, + 0x3ff5ab07dd485429, +]; + +// exp2f(x): compute the base 2 exponential of x +// +// Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. +// +// Method: (equally-spaced tables) +// +// Reduce x: +// x = k + y, for integer k and |y| <= 1/2. +// Thus we have exp2f(x) = 2**k * exp2(y). +// +// Reduce y: +// y = i/TBLSIZE + z for integer i near y * TBLSIZE. +// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), +// with |z| <= 2**-(TBLSIZE+1). +// +// We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a +// degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. +// Using double precision for everything except the reduction makes +// roundoff error insignificant and simplifies the scaling step. +// +// This method is due to Tang, but I do not use his suggested parameters: +// +// Tang, P. Table-driven Implementation of the Exponential Function +// in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). + +/// Exponential, base 2 (f32) +/// +/// Calculate `2^x`, that is, 2 raised to the power `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn exp2f(mut x: f32) -> f32 { + let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; + let p1 = f32::from_bits(0x3f317218); + let p2 = f32::from_bits(0x3e75fdf0); + let p3 = f32::from_bits(0x3d6359a4); + let p4 = f32::from_bits(0x3c1d964e); + + // double_t t, r, z; + // uint32_t ix, i0, k; + + let x1p127 = f32::from_bits(0x7f000000); + + /* Filter out exceptional cases. */ + let ui = f32::to_bits(x); + let ix = ui & 0x7fffffff; + if ix > 0x42fc0000 { + /* |x| > 126 */ + if ix > 0x7f800000 { + /* NaN */ + return x; + } + if ui >= 0x43000000 && ui < 0x80000000 { + /* x >= 128 */ + x *= x1p127; + return x; + } + if ui >= 0x80000000 { + /* x < -126 */ + if ui >= 0xc3160000 || (ui & 0x0000ffff != 0) { + force_eval!(f32::from_bits(0x80000001) / x); + } + if ui >= 0xc3160000 { + /* x <= -150 */ + return 0.0; + } + } + } else if ix <= 0x33000000 { + /* |x| <= 0x1p-25 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + let ui = f32::to_bits(x + redux); + let mut i0 = ui; + i0 += TBLSIZE as u32 / 2; + let k = i0 / TBLSIZE as u32; + let ukf = f64::from_bits(((0x3ff + k) as u64) << 52); + i0 &= TBLSIZE as u32 - 1; + let mut uf = f32::from_bits(ui); + uf -= redux; + let z: f64 = (x - uf) as f64; + /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ + let r: f64 = f64::from_bits(i!(EXP2FT, i0 as usize)); + let t: f64 = r as f64 * z; + let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); + + /* Scale by 2**k */ + (r * ukf) as f32 +} diff --git a/core/llm/math/expf.rs b/core/llm/math/expf.rs new file mode 100644 index 0000000..a53aa90 --- /dev/null +++ b/core/llm/math/expf.rs @@ -0,0 +1,101 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::scalbnf; + +const HALF: [f32; 2] = [0.5, -0.5]; +const LN2_HI: f32 = 6.9314575195e-01; /* 0x3f317200 */ +const LN2_LO: f32 = 1.4286067653e-06; /* 0x35bfbe8e */ +const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: + * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 + */ +const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ +const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ + +/// Exponential, base *e* (f32) +/// +/// Calculate the exponential of `x`, that is, *e* raised to the power `x` +/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn expf(mut x: f32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ + let mut hx = x.to_bits(); + let sign = (hx >> 31) as i32; /* sign bit of x */ + let signb: bool = sign != 0; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if hx >= 0x42aeac50 { + /* if |x| >= -87.33655f or NaN */ + if hx > 0x7f800000 { + /* NaN */ + return x; + } + if (hx >= 0x42b17218) && (!signb) { + /* x >= 88.722839f */ + /* overflow */ + x *= x1p127; + return x; + } + if signb { + /* underflow */ + force_eval!(-x1p_126 / x); + if hx >= 0x42cff1b5 { + /* x <= -103.972084f */ + return 0.; + } + } + } + + /* argument reduction */ + let k: i32; + let hi: f32; + let lo: f32; + if hx > 0x3eb17218 { + /* if |x| > 0.5 ln2 */ + if hx > 0x3f851592 { + /* if |x| > 1.5 ln2 */ + k = (INV_LN2 * x + i!(HALF, sign as usize)) as i32; + } else { + k = 1 - sign - sign; + } + let kf = k as f32; + hi = x - kf * LN2_HI; /* k*ln2hi is exact here */ + lo = kf * LN2_LO; + x = hi - lo; + } else if hx > 0x39000000 { + /* |x| > 2**-14 */ + k = 0; + hi = x; + lo = 0.; + } else { + /* raise inexact */ + force_eval!(x1p127 + x); + return 1. + x; + } + + /* x is now in primary range */ + let xx = x * x; + let c = x - xx * (P1 + xx * P2); + let y = 1. + (x * c / (2. - c) - lo + hi); + if k == 0 { + y + } else { + scalbnf(y, k) + } +} diff --git a/core/llm/math/expm1.rs b/core/llm/math/expm1.rs new file mode 100644 index 0000000..4260850 --- /dev/null +++ b/core/llm/math/expm1.rs @@ -0,0 +1,144 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f64; + +const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ +const Q1: f64 = -3.33333333333331316428e-02; /* BFA11111 111110F4 */ +const Q2: f64 = 1.58730158725481460165e-03; /* 3F5A01A0 19FE5585 */ +const Q3: f64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ +const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ +const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +/// Exponential, base *e*, of x-1 (f64) +/// +/// Calculates the exponential of `x` and subtract 1, that is, *e* raised +/// to the power `x` minus 1 (where *e* is the base of the natural +/// system of logarithms, approximately 2.71828). +/// The result is accurate even for small values of `x`, +/// where using `exp(x)-1` would lose many significant digits. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn expm1(mut x: f64) -> f64 { + let hi: f64; + let lo: f64; + let k: i32; + let c: f64; + let mut t: f64; + let mut y: f64; + + let mut ui = x.to_bits(); + let hx = ((ui >> 32) & 0x7fffffff) as u32; + let sign = (ui >> 63) as i32; + + /* filter out huge and non-finite argument */ + if hx >= 0x4043687A { + /* if |x|>=56*ln2 */ + if x.is_nan() { + return x; + } + if sign != 0 { + return -1.0; + } + if x > O_THRESHOLD { + x *= f64::from_bits(0x7fe0000000000000); + return x; + } + } + + /* argument reduction */ + if hx > 0x3fd62e42 { + /* if |x| > 0.5 ln2 */ + if hx < 0x3FF0A2B2 { + /* and |x| < 1.5 ln2 */ + if sign == 0 { + hi = x - LN2_HI; + lo = LN2_LO; + k = 1; + } else { + hi = x + LN2_HI; + lo = -LN2_LO; + k = -1; + } + } else { + k = (INVLN2 * x + if sign != 0 { -0.5 } else { 0.5 }) as i32; + t = k as f64; + hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ + lo = t * LN2_LO; + } + x = hi - lo; + c = (hi - x) - lo; + } else if hx < 0x3c900000 { + /* |x| < 2**-54, return x */ + if hx < 0x00100000 { + force_eval!(x); + } + return x; + } else { + c = 0.0; + k = 0; + } + + /* x is now in primary range */ + let hfx = 0.5 * x; + let hxs = x * hfx; + let r1 = 1.0 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5)))); + t = 3.0 - r1 * hfx; + let mut e = hxs * ((r1 - t) / (6.0 - x * t)); + if k == 0 { + /* c is 0 */ + return x - (x * e - hxs); + } + e = x * (e - c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if k == -1 { + return 0.5 * (x - e) - 0.5; + } + if k == 1 { + if x < -0.25 { + return -2.0 * (e - (x + 0.5)); + } + return 1.0 + 2.0 * (x - e); + } + ui = ((0x3ff + k) as u64) << 52; /* 2^k */ + let twopk = f64::from_bits(ui); + if k < 0 || k > 56 { + /* suffice to return exp(x)-1 */ + y = x - e + 1.0; + if k == 1024 { + y = y * 2.0 * f64::from_bits(0x7fe0000000000000); + } else { + y = y * twopk; + } + return y - 1.0; + } + ui = ((0x3ff - k) as u64) << 52; /* 2^-k */ + let uf = f64::from_bits(ui); + if k < 20 { + y = (x - e + (1.0 - uf)) * twopk; + } else { + y = (x - (e + uf) + 1.0) * twopk; + } + y +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::expm1(1.1), 2.0041660239464334); + } +} diff --git a/core/llm/math/expm1f.rs b/core/llm/math/expm1f.rs new file mode 100644 index 0000000..3fc2a24 --- /dev/null +++ b/core/llm/math/expm1f.rs @@ -0,0 +1,134 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +const O_THRESHOLD: f32 = 8.8721679688e+01; /* 0x42b17180 */ +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: + * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 + * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): + */ +const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */ +const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ + +/// Exponential, base *e*, of x-1 (f32) +/// +/// Calculates the exponential of `x` and subtract 1, that is, *e* raised +/// to the power `x` minus 1 (where *e* is the base of the natural +/// system of logarithms, approximately 2.71828). +/// The result is accurate even for small values of `x`, +/// where using `exp(x)-1` would lose many significant digits. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn expm1f(mut x: f32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + + let mut hx = x.to_bits(); + let sign = (hx >> 31) != 0; + hx &= 0x7fffffff; + + /* filter out huge and non-finite argument */ + if hx >= 0x4195b844 { + /* if |x|>=27*ln2 */ + if hx > 0x7f800000 { + /* NaN */ + return x; + } + if sign { + return -1.; + } + if x > O_THRESHOLD { + x *= x1p127; + return x; + } + } + + let k: i32; + let hi: f32; + let lo: f32; + let mut c = 0f32; + /* argument reduction */ + if hx > 0x3eb17218 { + /* if |x| > 0.5 ln2 */ + if hx < 0x3F851592 { + /* and |x| < 1.5 ln2 */ + if !sign { + hi = x - LN2_HI; + lo = LN2_LO; + k = 1; + } else { + hi = x + LN2_HI; + lo = -LN2_LO; + k = -1; + } + } else { + k = (INV_LN2 * x + (if sign { -0.5 } else { 0.5 })) as i32; + let t = k as f32; + hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ + lo = t * LN2_LO; + } + x = hi - lo; + c = (hi - x) - lo; + } else if hx < 0x33000000 { + /* when |x|<2**-25, return x */ + if hx < 0x00800000 { + force_eval!(x * x); + } + return x; + } else { + k = 0; + } + + /* x is now in primary range */ + let hfx = 0.5 * x; + let hxs = x * hfx; + let r1 = 1. + hxs * (Q1 + hxs * Q2); + let t = 3. - r1 * hfx; + let mut e = hxs * ((r1 - t) / (6. - x * t)); + if k == 0 { + /* c is 0 */ + return x - (x * e - hxs); + } + e = x * (e - c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if k == -1 { + return 0.5 * (x - e) - 0.5; + } + if k == 1 { + if x < -0.25 { + return -2. * (e - (x + 0.5)); + } + return 1. + 2. * (x - e); + } + let twopk = f32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */ + if (k < 0) || (k > 56) { + /* suffice to return exp(x)-1 */ + let mut y = x - e + 1.; + if k == 128 { + y = y * 2. * x1p127; + } else { + y = y * twopk; + } + return y - 1.; + } + let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ + if k < 23 { + (x - e + (1. - uf)) * twopk + } else { + (x - (e + uf) + 1.) * twopk + } +} diff --git a/core/llm/math/expo2.rs b/core/llm/math/expo2.rs new file mode 100644 index 0000000..82e9b36 --- /dev/null +++ b/core/llm/math/expo2.rs @@ -0,0 +1,14 @@ +use super::{combine_words, exp}; + +/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn expo2(x: f64) -> f64 { + /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ + const K: i32 = 2043; + let kln2 = f64::from_bits(0x40962066151add8b); + + /* note that k is odd and scale*scale overflows */ + let scale = combine_words(((0x3ff + K / 2) as u32) << 20, 0); + /* exp(x - k ln2) * 2**(k-1) */ + exp(x - kln2) * scale * scale +} diff --git a/core/llm/math/fabs.rs b/core/llm/math/fabs.rs new file mode 100644 index 0000000..b2255ad --- /dev/null +++ b/core/llm/math/fabs.rs @@ -0,0 +1,41 @@ +use core::u64; + +/// Absolute value (magnitude) (f64) +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabs(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.abs` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::fabsf64(x) } + } + } + f64::from_bits(x.to_bits() & (u64::MAX / 2)) +} + +#[cfg(test)] +mod tests { + use super::*; + use core::f64::*; + + #[test] + fn sanity_check() { + assert_eq!(fabs(-1.0), 1.0); + assert_eq!(fabs(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabs(NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabs(f), 0.0); + } + for f in [INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(fabs(f), INFINITY); + } + } +} diff --git a/core/llm/math/fabsf.rs b/core/llm/math/fabsf.rs new file mode 100644 index 0000000..23f3646 --- /dev/null +++ b/core/llm/math/fabsf.rs @@ -0,0 +1,41 @@ +/// Absolute value (magnitude) (f32) +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.abs` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::fabsf32(x) } + } + } + f32::from_bits(x.to_bits() & 0x7fffffff) +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::*; + use core::f32::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf(-1.0), 1.0); + assert_eq!(fabsf(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf(NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf(f), 0.0); + } + for f in [INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(fabsf(f), INFINITY); + } + } +} diff --git a/core/llm/math/fdim.rs b/core/llm/math/fdim.rs new file mode 100644 index 0000000..0149300 --- /dev/null +++ b/core/llm/math/fdim.rs @@ -0,0 +1,22 @@ +use core::f64; + +/// Positive difference (f64) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdim(x: f64, y: f64) -> f64 { + if x.is_nan() { + x + } else if y.is_nan() { + y + } else if x > y { + x - y + } else { + 0.0 + } +} diff --git a/core/llm/math/fdimf.rs b/core/llm/math/fdimf.rs new file mode 100644 index 0000000..ea0b592 --- /dev/null +++ b/core/llm/math/fdimf.rs @@ -0,0 +1,22 @@ +use core::f32; + +/// Positive difference (f32) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf(x: f32, y: f32) -> f32 { + if x.is_nan() { + x + } else if y.is_nan() { + y + } else if x > y { + x - y + } else { + 0.0 + } +} diff --git a/core/llm/math/fenv.rs b/core/llm/math/fenv.rs new file mode 100644 index 0000000..c91272e --- /dev/null +++ b/core/llm/math/fenv.rs @@ -0,0 +1,27 @@ +// src: musl/src/fenv/fenv.c +/* Dummy functions for archs lacking fenv implementation */ + +pub(crate) const FE_UNDERFLOW: i32 = 0; +pub(crate) const FE_INEXACT: i32 = 0; + +pub(crate) const FE_TONEAREST: i32 = 0; + +#[inline] +pub(crate) fn feclearexcept(_mask: i32) -> i32 { + 0 +} + +#[inline] +pub(crate) fn feraiseexcept(_mask: i32) -> i32 { + 0 +} + +#[inline] +pub(crate) fn fetestexcept(_mask: i32) -> i32 { + 0 +} + +#[inline] +pub(crate) fn fegetround() -> i32 { + FE_TONEAREST +} diff --git a/core/llm/math/floor.rs b/core/llm/math/floor.rs new file mode 100644 index 0000000..d09f9a1 --- /dev/null +++ b/core/llm/math/floor.rs @@ -0,0 +1,81 @@ +#![allow(unreachable_code)] +use core::f64; + +const TOINT: f64 = 1. / f64::EPSILON; + +/// Floor (f64) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floor(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.floor` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::floorf64(x) } + } + } + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + { + //use an alternative implementation on x86, because the + //main implementation fails with the x87 FPU used by + //debian i386, probablly due to excess precision issues. + //basic implementation taken from https://github.com/rust-lang/libm/issues/219 + use super::fabs; + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated > x { + return truncated - 1.0; + } else { + return truncated; + } + } else { + return x; + } + } + let ui = x.to_bits(); + let e = ((ui >> 52) & 0x7ff) as i32; + + if (e >= 0x3ff + 52) || (x == 0.) { + return x; + } + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + let y = if (ui >> 63) != 0 { + x - TOINT + TOINT - x + } else { + x + TOINT - TOINT - x + }; + /* special case because of non-nearest rounding modes */ + if e < 0x3ff { + force_eval!(y); + return if (ui >> 63) != 0 { -1. } else { 0. }; + } + if y > 0. { + x + y - 1. + } else { + x + y + } +} + +#[cfg(test)] +mod tests { + use super::*; + use core::f64::*; + + #[test] + fn sanity_check() { + assert_eq!(floor(1.1), 1.0); + assert_eq!(floor(2.9), 2.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor + #[test] + fn spec_tests() { + // Not Asserted: that the current rounding mode has no effect. + assert!(floor(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(floor(f), f); + } + } +} diff --git a/core/llm/math/floorf.rs b/core/llm/math/floorf.rs new file mode 100644 index 0000000..dfdab91 --- /dev/null +++ b/core/llm/math/floorf.rs @@ -0,0 +1,66 @@ +use core::f32; + +/// Floor (f32) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.floor` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::floorf32(x) } + } + } + let mut ui = x.to_bits(); + let e = (((ui >> 23) as i32) & 0xff) - 0x7f; + + if e >= 23 { + return x; + } + if e >= 0 { + let m: u32 = 0x007fffff >> e; + if (ui & m) == 0 { + return x; + } + force_eval!(x + f32::from_bits(0x7b800000)); + if ui >> 31 != 0 { + ui += m; + } + ui &= !m; + } else { + force_eval!(x + f32::from_bits(0x7b800000)); + if ui >> 31 == 0 { + ui = 0; + } else if ui << 1 != 0 { + return -1.0; + } + } + f32::from_bits(ui) +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::*; + use core::f32::*; + + #[test] + fn sanity_check() { + assert_eq!(floorf(0.5), 0.0); + assert_eq!(floorf(1.1), 1.0); + assert_eq!(floorf(2.9), 2.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor + #[test] + fn spec_tests() { + // Not Asserted: that the current rounding mode has no effect. + assert!(floorf(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(floorf(f), f); + } + } +} diff --git a/core/llm/math/fma.rs b/core/llm/math/fma.rs new file mode 100644 index 0000000..940ee2d --- /dev/null +++ b/core/llm/math/fma.rs @@ -0,0 +1,232 @@ +use core::{f32, f64}; + +use super::scalbn; + +const ZEROINFNAN: i32 = 0x7ff - 0x3ff - 52 - 1; + +struct Num { + m: u64, + e: i32, + sign: i32, +} + +fn normalize(x: f64) -> Num { + let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 + + let mut ix: u64 = x.to_bits(); + let mut e: i32 = (ix >> 52) as i32; + let sign: i32 = e & 0x800; + e &= 0x7ff; + if e == 0 { + ix = (x * x1p63).to_bits(); + e = (ix >> 52) as i32 & 0x7ff; + e = if e != 0 { e - 63 } else { 0x800 }; + } + ix &= (1 << 52) - 1; + ix |= 1 << 52; + ix <<= 1; + e -= 0x3ff + 52 + 1; + Num { m: ix, e, sign } +} + +#[inline] +fn mul(x: u64, y: u64) -> (u64, u64) { + let t = (x as u128).wrapping_mul(y as u128); + ((t >> 64) as u64, t as u64) +} + +/// Floating multiply add (f64) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation: +/// Computes the value (as if) to infinite precision and rounds once to the result format, +/// according to the rounding mode characterized by the value of FLT_ROUNDS. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fma(x: f64, y: f64, z: f64) -> f64 { + let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 + let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 + + /* normalize so top 10bits and last bit are 0 */ + let nx = normalize(x); + let ny = normalize(y); + let nz = normalize(z); + + if nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN { + return x * y + z; + } + if nz.e >= ZEROINFNAN { + if nz.e > ZEROINFNAN { + /* z==0 */ + return x * y + z; + } + return z; + } + + /* mul: r = x*y */ + let zhi: u64; + let zlo: u64; + let (mut rhi, mut rlo) = mul(nx.m, ny.m); + /* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */ + + /* align exponents */ + let mut e: i32 = nx.e + ny.e; + let mut d: i32 = nz.e - e; + /* shift bits z<<=kz, r>>=kr, so kz+kr == d, set e = e+kr (== ez-kz) */ + if d > 0 { + if d < 64 { + zlo = nz.m << d; + zhi = nz.m >> (64 - d); + } else { + zlo = 0; + zhi = nz.m; + e = nz.e - 64; + d -= 64; + if d == 0 { + } else if d < 64 { + rlo = rhi << (64 - d) | rlo >> d | ((rlo << (64 - d)) != 0) as u64; + rhi = rhi >> d; + } else { + rlo = 1; + rhi = 0; + } + } + } else { + zhi = 0; + d = -d; + if d == 0 { + zlo = nz.m; + } else if d < 64 { + zlo = nz.m >> d | ((nz.m << (64 - d)) != 0) as u64; + } else { + zlo = 1; + } + } + + /* add */ + let mut sign: i32 = nx.sign ^ ny.sign; + let samesign: bool = (sign ^ nz.sign) == 0; + let mut nonzero: i32 = 1; + if samesign { + /* r += z */ + rlo = rlo.wrapping_add(zlo); + rhi += zhi + (rlo < zlo) as u64; + } else { + /* r -= z */ + let (res, borrow) = rlo.overflowing_sub(zlo); + rlo = res; + rhi = rhi.wrapping_sub(zhi.wrapping_add(borrow as u64)); + if (rhi >> 63) != 0 { + rlo = (rlo as i64).wrapping_neg() as u64; + rhi = (rhi as i64).wrapping_neg() as u64 - (rlo != 0) as u64; + sign = (sign == 0) as i32; + } + nonzero = (rhi != 0) as i32; + } + + /* set rhi to top 63bit of the result (last bit is sticky) */ + if nonzero != 0 { + e += 64; + d = rhi.leading_zeros() as i32 - 1; + /* note: d > 0 */ + rhi = rhi << d | rlo >> (64 - d) | ((rlo << d) != 0) as u64; + } else if rlo != 0 { + d = rlo.leading_zeros() as i32 - 1; + if d < 0 { + rhi = rlo >> 1 | (rlo & 1); + } else { + rhi = rlo << d; + } + } else { + /* exact +-0 */ + return x * y + z; + } + e -= d; + + /* convert to double */ + let mut i: i64 = rhi as i64; /* i is in [1<<62,(1<<63)-1] */ + if sign != 0 { + i = -i; + } + let mut r: f64 = i as f64; /* |r| is in [0x1p62,0x1p63] */ + + if e < -1022 - 62 { + /* result is subnormal before rounding */ + if e == -1022 - 63 { + let mut c: f64 = x1p63; + if sign != 0 { + c = -c; + } + if r == c { + /* min normal after rounding, underflow depends + on arch behaviour which can be imitated by + a double to float conversion */ + let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * r) as f32; + return f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64; + } + /* one bit is lost when scaled, add another top bit to + only round once at conversion if it is inexact */ + if (rhi << 53) != 0 { + i = (rhi >> 1 | (rhi & 1) | 1 << 62) as i64; + if sign != 0 { + i = -i; + } + r = i as f64; + r = 2. * r - c; /* remove top bit */ + + /* raise underflow portably, such that it + cannot be optimized away */ + { + let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * r; + r += (tiny * tiny) * (r - r); + } + } + } else { + /* only round once when scaled */ + d = 10; + i = ((rhi >> d | ((rhi << (64 - d)) != 0) as u64) << d) as i64; + if sign != 0 { + i = -i; + } + r = i as f64; + } + } + scalbn(r, e) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn fma_segfault() { + // These two inputs cause fma to segfault on release due to overflow: + assert_eq!( + fma( + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313 + ), + -0.00000000000000022204460492503126, + ); + + let result = fma(-0.992, -0.992, -0.992); + //force rounding to storage format on x87 to prevent superious errors. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let result = force_eval!(result); + assert_eq!(result, -0.007936000000000007,); + } + + #[test] + fn fma_sbb() { + assert_eq!( + fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), + -3991680619069439e277 + ); + } + + #[test] + fn fma_underflow() { + assert_eq!( + fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), + 0.0, + ); + } +} diff --git a/core/llm/math/fmaf.rs b/core/llm/math/fmaf.rs new file mode 100644 index 0000000..2848f2a --- /dev/null +++ b/core/llm/math/fmaf.rs @@ -0,0 +1,117 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_fmaf.c */ +/*- + * Copyright (c) 2005-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +use core::f32; +use core::ptr::read_volatile; + +use super::fenv::{ + feclearexcept, fegetround, feraiseexcept, fetestexcept, FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, +}; + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * A double has more than twice as much precision than a float, so + * direct double-precision arithmetic suffices, except where double + * rounding occurs. + */ + +/// Floating multiply add (f32) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation: +/// Computes the value (as if) to infinite precision and rounds once to the result format, +/// according to the rounding mode characterized by the value of FLT_ROUNDS. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { + let xy: f64; + let mut result: f64; + let mut ui: u64; + let e: i32; + + xy = x as f64 * y as f64; + result = xy + z as f64; + ui = result.to_bits(); + e = (ui >> 52) as i32 & 0x7ff; + /* Common case: The double precision result is fine. */ + if ( + /* not a halfway case */ + ui & 0x1fffffff) != 0x10000000 || + /* NaN */ + e == 0x7ff || + /* exact */ + (result - xy == z as f64 && result - z as f64 == xy) || + /* not round-to-nearest */ + fegetround() != FE_TONEAREST + { + /* + underflow may not be raised correctly, example: + fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) + */ + if e < 0x3ff - 126 && e >= 0x3ff - 149 && fetestexcept(FE_INEXACT) != 0 { + feclearexcept(FE_INEXACT); + // prevent `xy + vz` from being CSE'd with `xy + z` above + let vz: f32 = unsafe { read_volatile(&z) }; + result = xy + vz as f64; + if fetestexcept(FE_INEXACT) != 0 { + feraiseexcept(FE_UNDERFLOW); + } else { + feraiseexcept(FE_INEXACT); + } + } + z = result as f32; + return z; + } + + /* + * If result is inexact, and exactly halfway between two float values, + * we need to adjust the low-order bit in the direction of the error. + */ + let neg = ui >> 63 != 0; + let err = if neg == (z as f64 > xy) { + xy - result + z as f64 + } else { + z as f64 - result + xy + }; + if neg == (err < 0.0) { + ui += 1; + } else { + ui -= 1; + } + f64::from_bits(ui) as f32 +} + +#[cfg(test)] +mod tests { + #[test] + fn issue_263() { + let a = f32::from_bits(1266679807); + let b = f32::from_bits(1300234242); + let c = f32::from_bits(1115553792); + let expected = f32::from_bits(1501560833); + assert_eq!(super::fmaf(a, b, c), expected); + } +} diff --git a/core/llm/math/fmax.rs b/core/llm/math/fmax.rs new file mode 100644 index 0000000..93c97bc --- /dev/null +++ b/core/llm/math/fmax.rs @@ -0,0 +1,12 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmax(x: f64, y: f64) -> f64 { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x.is_nan() || x < y { y } else { x }) * 1.0 +} diff --git a/core/llm/math/fmaxf.rs b/core/llm/math/fmaxf.rs new file mode 100644 index 0000000..6077466 --- /dev/null +++ b/core/llm/math/fmaxf.rs @@ -0,0 +1,12 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf(x: f32, y: f32) -> f32 { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x.is_nan() || x < y { y } else { x }) * 1.0 +} diff --git a/core/llm/math/fmin.rs b/core/llm/math/fmin.rs new file mode 100644 index 0000000..ab1509f --- /dev/null +++ b/core/llm/math/fmin.rs @@ -0,0 +1,12 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmin(x: f64, y: f64) -> f64 { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if y.is_nan() || x < y { x } else { y }) * 1.0 +} diff --git a/core/llm/math/fminf.rs b/core/llm/math/fminf.rs new file mode 100644 index 0000000..0049e71 --- /dev/null +++ b/core/llm/math/fminf.rs @@ -0,0 +1,12 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf(x: f32, y: f32) -> f32 { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if y.is_nan() || x < y { x } else { y }) * 1.0 +} diff --git a/core/llm/math/fmod.rs b/core/llm/math/fmod.rs new file mode 100644 index 0000000..d892ffd --- /dev/null +++ b/core/llm/math/fmod.rs @@ -0,0 +1,80 @@ +use core::u64; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmod(x: f64, y: f64) -> f64 { + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let mut ex = (uxi >> 52 & 0x7ff) as i64; + let mut ey = (uyi >> 52 & 0x7ff) as i64; + let sx = uxi >> 63; + let mut i; + + if uyi << 1 == 0 || y.is_nan() || ex == 0x7ff { + return (x * y) / (x * y); + } + if uxi << 1 <= uyi << 1 { + if uxi << 1 == uyi << 1 { + return 0.0 * x; + } + return x; + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 12; + while i >> 63 == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= u64::MAX >> 12; + uxi |= 1 << 52; + } + if ey == 0 { + i = uyi << 12; + while i >> 63 == 0 { + ey -= 1; + i <<= 1; + } + uyi <<= -ey + 1; + } else { + uyi &= u64::MAX >> 12; + uyi |= 1 << 52; + } + + /* x mod y */ + while ex > ey { + i = uxi.wrapping_sub(uyi); + if i >> 63 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + uxi <<= 1; + ex -= 1; + } + i = uxi.wrapping_sub(uyi); + if i >> 63 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + while uxi >> 52 == 0 { + uxi <<= 1; + ex -= 1; + } + + /* scale result */ + if ex > 0 { + uxi -= 1 << 52; + uxi |= (ex as u64) << 52; + } else { + uxi >>= -ex + 1; + } + uxi |= (sx as u64) << 63; + + f64::from_bits(uxi) +} diff --git a/core/llm/math/fmodf.rs b/core/llm/math/fmodf.rs new file mode 100644 index 0000000..c53dc18 --- /dev/null +++ b/core/llm/math/fmodf.rs @@ -0,0 +1,89 @@ +use core::f32; +use core::u32; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf(x: f32, y: f32) -> f32 { + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let mut ex = (uxi >> 23 & 0xff) as i32; + let mut ey = (uyi >> 23 & 0xff) as i32; + let sx = uxi & 0x80000000; + let mut i; + + if uyi << 1 == 0 || y.is_nan() || ex == 0xff { + return (x * y) / (x * y); + } + + if uxi << 1 <= uyi << 1 { + if uxi << 1 == uyi << 1 { + return 0.0 * x; + } + + return x; + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 9; + while i >> 31 == 0 { + ex -= 1; + i <<= 1; + } + + uxi <<= -ex + 1; + } else { + uxi &= u32::MAX >> 9; + uxi |= 1 << 23; + } + + if ey == 0 { + i = uyi << 9; + while i >> 31 == 0 { + ey -= 1; + i <<= 1; + } + + uyi <<= -ey + 1; + } else { + uyi &= u32::MAX >> 9; + uyi |= 1 << 23; + } + + /* x mod y */ + while ex > ey { + i = uxi.wrapping_sub(uyi); + if i >> 31 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + uxi <<= 1; + + ex -= 1; + } + + i = uxi.wrapping_sub(uyi); + if i >> 31 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + + while uxi >> 23 == 0 { + uxi <<= 1; + ex -= 1; + } + + /* scale result up */ + if ex > 0 { + uxi -= 1 << 23; + uxi |= (ex as u32) << 23; + } else { + uxi >>= -ex + 1; + } + uxi |= sx; + + f32::from_bits(uxi) +} diff --git a/core/llm/math/frexp.rs b/core/llm/math/frexp.rs new file mode 100644 index 0000000..badad78 --- /dev/null +++ b/core/llm/math/frexp.rs @@ -0,0 +1,20 @@ +pub fn frexp(x: f64) -> (f64, i32) { + let mut y = x.to_bits(); + let ee = ((y >> 52) & 0x7ff) as i32; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f64::from_bits(0x43f0000000000000); + let (x, e) = frexp(x * x1p64); + return (x, e - 64); + } + return (x, 0); + } else if ee == 0x7ff { + return (x, 0); + } + + let e = ee - 0x3fe; + y &= 0x800fffffffffffff; + y |= 0x3fe0000000000000; + return (f64::from_bits(y), e); +} diff --git a/core/llm/math/frexpf.rs b/core/llm/math/frexpf.rs new file mode 100644 index 0000000..2919c0a --- /dev/null +++ b/core/llm/math/frexpf.rs @@ -0,0 +1,21 @@ +pub fn frexpf(x: f32) -> (f32, i32) { + let mut y = x.to_bits(); + let ee: i32 = ((y >> 23) & 0xff) as i32; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f32::from_bits(0x5f800000); + let (x, e) = frexpf(x * x1p64); + return (x, e - 64); + } else { + return (x, 0); + } + } else if ee == 0xff { + return (x, 0); + } + + let e = ee - 0x7e; + y &= 0x807fffff; + y |= 0x3f000000; + (f32::from_bits(y), e) +} diff --git a/core/llm/math/hypot.rs b/core/llm/math/hypot.rs new file mode 100644 index 0000000..da458ea --- /dev/null +++ b/core/llm/math/hypot.rs @@ -0,0 +1,74 @@ +use core::f64; + +use super::sqrt; + +const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 + +fn sq(x: f64) -> (f64, f64) { + let xh: f64; + let xl: f64; + let xc: f64; + + xc = x * SPLIT; + xh = x - xc + xc; + xl = x - xh; + let hi = x * x; + let lo = xh * xh - hi + 2. * xh * xl + xl * xl; + (hi, lo) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn hypot(mut x: f64, mut y: f64) -> f64 { + let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 + let x1p_700 = f64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700 + + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let uti; + let ex: i64; + let ey: i64; + let mut z: f64; + + /* arrange |x| >= |y| */ + uxi &= -1i64 as u64 >> 1; + uyi &= -1i64 as u64 >> 1; + if uxi < uyi { + uti = uxi; + uxi = uyi; + uyi = uti; + } + + /* special cases */ + ex = (uxi >> 52) as i64; + ey = (uyi >> 52) as i64; + x = f64::from_bits(uxi); + y = f64::from_bits(uyi); + /* note: hypot(inf,nan) == inf */ + if ey == 0x7ff { + return y; + } + if ex == 0x7ff || uyi == 0 { + return x; + } + /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ + /* 64 difference is enough for ld80 double_t */ + if ex - ey > 64 { + return x + y; + } + + /* precise sqrt argument in nearest rounding mode without overflow */ + /* xh*xh must not overflow and xl*xl must not underflow in sq */ + z = 1.; + if ex > 0x3ff + 510 { + z = x1p700; + x *= x1p_700; + y *= x1p_700; + } else if ey < 0x3ff - 450 { + z = x1p_700; + x *= x1p700; + y *= x1p700; + } + let (hx, lx) = sq(x); + let (hy, ly) = sq(y); + z * sqrt(ly + lx + hy + hx) +} diff --git a/core/llm/math/hypotf.rs b/core/llm/math/hypotf.rs new file mode 100644 index 0000000..576eebb --- /dev/null +++ b/core/llm/math/hypotf.rs @@ -0,0 +1,43 @@ +use core::f32; + +use super::sqrtf; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn hypotf(mut x: f32, mut y: f32) -> f32 { + let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 + let x1p_90 = f32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90 + + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let uti; + let mut z: f32; + + uxi &= -1i32 as u32 >> 1; + uyi &= -1i32 as u32 >> 1; + if uxi < uyi { + uti = uxi; + uxi = uyi; + uyi = uti; + } + + x = f32::from_bits(uxi); + y = f32::from_bits(uyi); + if uyi == 0xff << 23 { + return y; + } + if uxi >= 0xff << 23 || uyi == 0 || uxi - uyi >= 25 << 23 { + return x + y; + } + + z = 1.; + if uxi >= (0x7f + 60) << 23 { + z = x1p90; + x *= x1p_90; + y *= x1p_90; + } else if uyi < (0x7f - 60) << 23 { + z = x1p_90; + x *= x1p90; + y *= x1p90; + } + z * sqrtf((x as f64 * x as f64 + y as f64 * y as f64) as f32) +} diff --git a/core/llm/math/ilogb.rs b/core/llm/math/ilogb.rs new file mode 100644 index 0000000..7d74dcf --- /dev/null +++ b/core/llm/math/ilogb.rs @@ -0,0 +1,32 @@ +const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; +const FP_ILOGB0: i32 = FP_ILOGBNAN; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ilogb(x: f64) -> i32 { + let mut i: u64 = x.to_bits(); + let e = ((i >> 52) & 0x7ff) as i32; + + if e == 0 { + i <<= 12; + if i == 0 { + force_eval!(0.0 / 0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x3ff; + while (i >> 63) == 0 { + e -= 1; + i <<= 1; + } + e + } else if e == 0x7ff { + force_eval!(0.0 / 0.0); + if (i << 12) != 0 { + FP_ILOGBNAN + } else { + i32::max_value() + } + } else { + e - 0x3ff + } +} diff --git a/core/llm/math/ilogbf.rs b/core/llm/math/ilogbf.rs new file mode 100644 index 0000000..0fa5874 --- /dev/null +++ b/core/llm/math/ilogbf.rs @@ -0,0 +1,32 @@ +const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; +const FP_ILOGB0: i32 = FP_ILOGBNAN; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ilogbf(x: f32) -> i32 { + let mut i = x.to_bits(); + let e = ((i >> 23) & 0xff) as i32; + + if e == 0 { + i <<= 9; + if i == 0 { + force_eval!(0.0 / 0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x7f; + while (i >> 31) == 0 { + e -= 1; + i <<= 1; + } + e + } else if e == 0xff { + force_eval!(0.0 / 0.0); + if (i << 9) != 0 { + FP_ILOGBNAN + } else { + i32::max_value() + } + } else { + e - 0x7f + } +} diff --git a/core/llm/math/j0.rs b/core/llm/math/j0.rs new file mode 100644 index 0000000..c4258cc --- /dev/null +++ b/core/llm/math/j0.rs @@ -0,0 +1,422 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j0(x), y0(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j0(x): + * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... + * 2. Reduce x to |x| since j0(x)=j0(-x), and + * for x in (0,2) + * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; + * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) + * for x in (2,inf) + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * as follow: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (cos(x) + sin(x)) + * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j0(nan)= nan + * j0(0) = 1 + * j0(inf) = 0 + * + * Method -- y0(x): + * 1. For x<2. + * Since + * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) + * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. + * We use the following function to approximate y0, + * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 + * where + * U(z) = u00 + u01*z + ... + u06*z^6 + * V(z) = 1 + v01*z + ... + v04*z^4 + * with absolute approximation error bounded by 2**-72. + * Note: For tiny x, U/V = u0 and j0(x)~1, hence + * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) + * 2. For x>=2. + * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * by the method mentioned above. + * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. + */ + +use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +/* common method when |x|>=2 */ +fn common(ix: u32, x: f64, y0: bool) -> f64 { + let s: f64; + let mut c: f64; + let mut ss: f64; + let mut cc: f64; + let z: f64; + + /* + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) + * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) + * + * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) + * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + c = cos(x); + if y0 { + c = -c; + } + cc = s + c; + /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ + if ix < 0x7fe00000 { + ss = s - c; + z = -cos(2.0 * x); + if s * c < 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x48000000 { + if y0 { + ss = -ss; + } + cc = pzero(x) * cc - qzero(x) * ss; + } + } + return INVSQRTPI * cc / sqrt(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ +const R03: f64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ +const R04: f64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ +const R05: f64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ +const S01: f64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ +const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ +const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ +const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ + +pub fn j0(mut x: f64) -> f64 { + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* j0(+-inf)=0, j0(nan)=nan */ + if ix >= 0x7ff00000 { + return 1.0 / (x * x); + } + x = fabs(x); + + if ix >= 0x40000000 { + /* |x| >= 2 */ + /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ + return common(ix, x, false); + } + + /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ + if ix >= 0x3f200000 { + /* |x| >= 2**-13 */ + /* up to 4ulp error close to 2 */ + z = x * x; + r = z * (R02 + z * (R03 + z * (R04 + z * R05))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); + return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); + } + + /* 1 - x*x/4 */ + /* prevent underflow */ + /* inexact should be raised when x!=0, this is not done correctly */ + if ix >= 0x38000000 { + /* |x| >= 2**-127 */ + x = 0.25 * x * x; + } + return 1.0 - x; +} + +const U00: f64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ +const U01: f64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ +const U02: f64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ +const U03: f64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ +const U04: f64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ +const U05: f64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ +const U06: f64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ +const V01: f64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ +const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ +const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ +const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ + +pub fn y0(x: f64) -> f64 { + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ + if ((ix << 1) | lx) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7ff00000 { + return 1.0 / x; + } + + if ix >= 0x40000000 { + /* x >= 2 */ + /* large ulp errors near zeros: 3.958, 7.086,.. */ + return common(ix, x, true); + } + + /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ + if ix >= 0x3e400000 { + /* x >= 2**-27 */ + /* large ulp error near the first zero, x ~= 0.89 */ + z = x * x; + u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); + v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); + return u / v + TPI * (j0(x) * log(x)); + } + return U00 + TPI * log(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ + -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ + -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ + -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ + -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ +]; +const PS8: [f64; 5] = [ + 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ + 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ + 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ + 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ + 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ +]; + +const PR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ + -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ + -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ + -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ + -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ + -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ +]; +const PS5: [f64; 5] = [ + 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ + 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ + 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ + 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ + 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ +]; + +const PR3: [f64; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ + -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ + -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ + -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ + -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ + -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ +]; +const PS3: [f64; 5] = [ + 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ + 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ + 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ + 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ + 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ +]; + +const PR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ + -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ + -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ + -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ + -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ + -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ +]; +const PS2: [f64; 5] = [ + 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ + 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ + 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ + 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ + 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ +]; + +fn pzero(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x40122E8B { + p = &PR5; + q = &PS5; + } else if ix >= 0x4006DB6D { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ + 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ + 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ + 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ + 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ +]; +const QS8: [f64; 6] = [ + 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ + 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ + 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ + 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ + 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ + -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ +]; + +const QR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ + 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ + 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ + 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ + 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ + 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ +]; +const QS5: [f64; 6] = [ + 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ + 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ + 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ + 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ + 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ + -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ +]; + +const QR3: [f64; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ + 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ + 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ + 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ + 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ + 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ +]; +const QS3: [f64; 6] = [ + 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ + 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ + 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ + 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ + 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ + -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ +]; + +const QR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ + 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ + 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ + 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ + 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ + 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ +]; +const QS2: [f64; 6] = [ + 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ + 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ + 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ + 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ + 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ + -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ +]; + +fn qzero(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x40122E8B { + p = &QR5; + q = &QS5; + } else if ix >= 0x4006DB6D { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (-0.125 + r / s) / x; +} diff --git a/core/llm/math/j0f.rs b/core/llm/math/j0f.rs new file mode 100644 index 0000000..91c03db --- /dev/null +++ b/core/llm/math/j0f.rs @@ -0,0 +1,359 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y0: bool) -> f32 { + let z: f32; + let s: f32; + let mut c: f32; + let mut ss: f32; + let mut cc: f32; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + s = sinf(x); + c = cosf(x); + if y0 { + c = -c; + } + cc = s + c; + if ix < 0x7f000000 { + ss = s - c; + z = -cosf(2.0 * x); + if s * c < 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x58800000 { + if y0 { + ss = -ss; + } + cc = pzerof(x) * cc - qzerof(x) * ss; + } + } + return INVSQRTPI * cc / sqrtf(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f32 = 1.5625000000e-02; /* 0x3c800000 */ +const R03: f32 = -1.8997929874e-04; /* 0xb947352e */ +const R04: f32 = 1.8295404516e-06; /* 0x35f58e88 */ +const R05: f32 = -4.6183270541e-09; /* 0xb19eaf3c */ +const S01: f32 = 1.5619102865e-02; /* 0x3c7fe744 */ +const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ +const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ +const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ + +pub fn j0f(mut x: f32) -> f32 { + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0 / (x * x); + } + x = fabsf(x); + + if ix >= 0x40000000 { + /* |x| >= 2 */ + /* large ulp error near zeros */ + return common(ix, x, false); + } + if ix >= 0x3a000000 { + /* |x| >= 2**-11 */ + /* up to 4ulp error near 2 */ + z = x * x; + r = z * (R02 + z * (R03 + z * (R04 + z * R05))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); + return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); + } + if ix >= 0x21800000 { + /* |x| >= 2**-60 */ + x = 0.25 * x * x; + } + return 1.0 - x; +} + +const U00: f32 = -7.3804296553e-02; /* 0xbd9726b5 */ +const U01: f32 = 1.7666645348e-01; /* 0x3e34e80d */ +const U02: f32 = -1.3818567619e-02; /* 0xbc626746 */ +const U03: f32 = 3.4745343146e-04; /* 0x39b62a69 */ +const U04: f32 = -3.8140706238e-06; /* 0xb67ff53c */ +const U05: f32 = 1.9559013964e-08; /* 0x32a802ba */ +const U06: f32 = -3.9820518410e-11; /* 0xae2f21eb */ +const V01: f32 = 1.2730483897e-02; /* 0x3c509385 */ +const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ +const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ +const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ + +pub fn y0f(x: f32) -> f32 { + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7f800000 { + return 1.0 / x; + } + if ix >= 0x40000000 { + /* |x| >= 2.0 */ + /* large ulp error near zeros */ + return common(ix, x, true); + } + if ix >= 0x39000000 { + /* x >= 2**-13 */ + /* large ulp error at x ~= 0.89 */ + z = x * x; + u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); + v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); + return u / v + TPI * (j0f(x) * logf(x)); + } + return U00 + TPI * logf(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -7.0312500000e-02, /* 0xbd900000 */ + -8.0816707611e+00, /* 0xc1014e86 */ + -2.5706311035e+02, /* 0xc3808814 */ + -2.4852163086e+03, /* 0xc51b5376 */ + -5.2530439453e+03, /* 0xc5a4285a */ +]; +const PS8: [f32; 5] = [ + 1.1653436279e+02, /* 0x42e91198 */ + 3.8337448730e+03, /* 0x456f9beb */ + 4.0597855469e+04, /* 0x471e95db */ + 1.1675296875e+05, /* 0x47e4087c */ + 4.7627726562e+04, /* 0x473a0bba */ +]; +const PR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.1412546255e-11, /* 0xad48c58a */ + -7.0312492549e-02, /* 0xbd8fffff */ + -4.1596107483e+00, /* 0xc0851b88 */ + -6.7674766541e+01, /* 0xc287597b */ + -3.3123129272e+02, /* 0xc3a59d9b */ + -3.4643338013e+02, /* 0xc3ad3779 */ +]; +const PS5: [f32; 5] = [ + 6.0753936768e+01, /* 0x42730408 */ + 1.0512523193e+03, /* 0x44836813 */ + 5.9789707031e+03, /* 0x45bad7c4 */ + 9.6254453125e+03, /* 0x461665c8 */ + 2.4060581055e+03, /* 0x451660ee */ +]; + +const PR3: [f32; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.5470459075e-09, /* 0xb12f081b */ + -7.0311963558e-02, /* 0xbd8fffb8 */ + -2.4090321064e+00, /* 0xc01a2d95 */ + -2.1965976715e+01, /* 0xc1afba52 */ + -5.8079170227e+01, /* 0xc2685112 */ + -3.1447946548e+01, /* 0xc1fb9565 */ +]; +const PS3: [f32; 5] = [ + 3.5856033325e+01, /* 0x420f6c94 */ + 3.6151397705e+02, /* 0x43b4c1ca */ + 1.1936077881e+03, /* 0x44953373 */ + 1.1279968262e+03, /* 0x448cffe6 */ + 1.7358093262e+02, /* 0x432d94b8 */ +]; + +const PR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.8753431271e-08, /* 0xb3be98b7 */ + -7.0303097367e-02, /* 0xbd8ffb12 */ + -1.4507384300e+00, /* 0xbfb9b1cc */ + -7.6356959343e+00, /* 0xc0f4579f */ + -1.1193166733e+01, /* 0xc1331736 */ + -3.2336456776e+00, /* 0xc04ef40d */ +]; +const PS2: [f32; 5] = [ + 2.2220300674e+01, /* 0x41b1c32d */ + 1.3620678711e+02, /* 0x430834f0 */ + 2.7047027588e+02, /* 0x43873c32 */ + 1.5387539673e+02, /* 0x4319e01a */ + 1.4657617569e+01, /* 0x416a859a */ +]; + +fn pzerof(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x409173eb { + p = &PR5; + q = &PS5; + } else if ix >= 0x4036d917 { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 7.3242187500e-02, /* 0x3d960000 */ + 1.1768206596e+01, /* 0x413c4a93 */ + 5.5767340088e+02, /* 0x440b6b19 */ + 8.8591972656e+03, /* 0x460a6cca */ + 3.7014625000e+04, /* 0x471096a0 */ +]; +const QS8: [f32; 6] = [ + 1.6377603149e+02, /* 0x4323c6aa */ + 8.0983447266e+03, /* 0x45fd12c2 */ + 1.4253829688e+05, /* 0x480b3293 */ + 8.0330925000e+05, /* 0x49441ed4 */ + 8.4050156250e+05, /* 0x494d3359 */ + -3.4389928125e+05, /* 0xc8a7eb69 */ +]; + +const QR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.8408595828e-11, /* 0x2da1ec79 */ + 7.3242180049e-02, /* 0x3d95ffff */ + 5.8356351852e+00, /* 0x40babd86 */ + 1.3511157227e+02, /* 0x43071c90 */ + 1.0272437744e+03, /* 0x448067cd */ + 1.9899779053e+03, /* 0x44f8bf4b */ +]; +const QS5: [f32; 6] = [ + 8.2776611328e+01, /* 0x42a58da0 */ + 2.0778142090e+03, /* 0x4501dd07 */ + 1.8847289062e+04, /* 0x46933e94 */ + 5.6751113281e+04, /* 0x475daf1d */ + 3.5976753906e+04, /* 0x470c88c1 */ + -5.3543427734e+03, /* 0xc5a752be */ +]; + +const QR3: [f32; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.3774099900e-09, /* 0x3196681b */ + 7.3241114616e-02, /* 0x3d95ff70 */ + 3.3442313671e+00, /* 0x405607e3 */ + 4.2621845245e+01, /* 0x422a7cc5 */ + 1.7080809021e+02, /* 0x432acedf */ + 1.6673394775e+02, /* 0x4326bbe4 */ +]; +const QS3: [f32; 6] = [ + 4.8758872986e+01, /* 0x42430916 */ + 7.0968920898e+02, /* 0x44316c1c */ + 3.7041481934e+03, /* 0x4567825f */ + 6.4604252930e+03, /* 0x45c9e367 */ + 2.5163337402e+03, /* 0x451d4557 */ + -1.4924745178e+02, /* 0xc3153f59 */ +]; + +const QR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.5044444979e-07, /* 0x342189db */ + 7.3223426938e-02, /* 0x3d95f62a */ + 1.9981917143e+00, /* 0x3fffc4bf */ + 1.4495602608e+01, /* 0x4167edfd */ + 3.1666231155e+01, /* 0x41fd5471 */ + 1.6252708435e+01, /* 0x4182058c */ +]; +const QS2: [f32; 6] = [ + 3.0365585327e+01, /* 0x41f2ecb8 */ + 2.6934811401e+02, /* 0x4386ac8f */ + 8.4478375244e+02, /* 0x44533229 */ + 8.8293585205e+02, /* 0x445cbbe5 */ + 2.1266638184e+02, /* 0x4354aa98 */ + -5.3109550476e+00, /* 0xc0a9f358 */ +]; + +fn qzerof(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x409173eb { + p = &QR5; + q = &QS5; + } else if ix >= 0x4036d917 { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (-0.125 + r / s) / x; +} diff --git a/core/llm/math/j1.rs b/core/llm/math/j1.rs new file mode 100644 index 0000000..02a65ca --- /dev/null +++ b/core/llm/math/j1.rs @@ -0,0 +1,414 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j1(x), y1(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j1(x): + * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... + * 2. Reduce x to |x| since j1(x)=-j1(-x), and + * for x in (0,2) + * j1(x) = x/2 + x*z*R0/S0, where z = x*x; + * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) + * for x in (2,inf) + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * as follow: + * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (sin(x) + cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j1(nan)= nan + * j1(0) = 0 + * j1(inf) = 0 + * + * Method -- y1(x): + * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN + * 2. For x<2. + * Since + * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) + * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. + * We use the following function to approximate y1, + * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 + * where for x in [0,2] (abs err less than 2**-65.89) + * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 + * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 + * Note: For tiny x, 1/x dominate y1 and hence + * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) + * 3. For x>=2. + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * by method mentioned above. + */ + +use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 { + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + /* + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) + * + * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) + * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + if y1 { + s = -s; + } + c = cos(x); + cc = s - c; + if ix < 0x7fe00000 { + /* avoid overflow in 2*x */ + ss = -s - c; + z = cos(2.0 * x); + if s * c > 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x48000000 { + if y1 { + ss = -ss; + } + cc = pone(x) * cc - qone(x) * ss; + } + } + if sign { + cc = -cc; + } + return INVSQRTPI * cc / sqrt(x); +} + +/* R0/S0 on [0,2] */ +const R00: f64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ +const R01: f64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ +const R02: f64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ +const R03: f64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ +const S01: f64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ +const S02: f64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ +const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ +const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ +const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ + +pub fn j1(x: f64) -> f64 { + let mut z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + let sign: bool; + + ix = get_high_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + return 1.0 / (x * x); + } + if ix >= 0x40000000 { + /* |x| >= 2 */ + return common(ix, fabs(x), false, sign); + } + if ix >= 0x38000000 { + /* |x| >= 2**-127 */ + z = x * x; + r = z * (R00 + z * (R01 + z * (R02 + z * R03))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); + z = r / s; + } else { + /* avoid underflow, raise inexact if x!=0 */ + z = x; + } + return (0.5 + z) * x; +} + +const U0: [f64; 5] = [ + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ +]; +const V0: [f64; 5] = [ + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ +]; + +pub fn y1(x: f64) -> f64 { + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ + if (ix << 1 | lx) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7ff00000 { + return 1.0 / x; + } + + if ix >= 0x40000000 { + /* x >= 2 */ + return common(ix, x, true, false); + } + if ix < 0x3c900000 { + /* x < 2**-54 */ + return -TPI / x; + } + z = x * x; + u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + return x * (u / v) + TPI * (j1(x) * log(x) - 1.0 / x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ +]; +const PS8: [f64; 5] = [ + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ +]; + +const PR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ +]; +const PS5: [f64; 5] = [ + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ +]; + +const PR3: [f64; 6] = [ + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ +]; +const PS3: [f64; 5] = [ + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ +]; + +const PR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ +]; +const PS2: [f64; 5] = [ + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ +]; + +fn pone(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x40122E8B { + p = &PR5; + q = &PS5; + } else if ix >= 0x4006DB6D { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ + -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ + -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ + -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ + -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ +]; +const QS8: [f64; 6] = [ + 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ + 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ + 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ + 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ + 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ + -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ +]; + +const QR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ + -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ + -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ + -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ + -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ + -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ +]; +const QS5: [f64; 6] = [ + 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ + 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ + 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ + 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ + 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ + -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ +]; + +const QR3: [f64; 6] = [ + -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ + -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ + -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ + -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ + -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ + -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ +]; +const QS3: [f64; 6] = [ + 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ + 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ + 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ + 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ + 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ + -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ +]; + +const QR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ + -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ + -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ + -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ + -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ + -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ +]; +const QS2: [f64; 6] = [ + 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ + 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ + 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ + 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ + 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ + -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ +]; + +fn qone(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x40122E8B { + p = &QR5; + q = &QS5; + } else if ix >= 0x4006DB6D { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (0.375 + r / s) / x; +} diff --git a/core/llm/math/j1f.rs b/core/llm/math/j1f.rs new file mode 100644 index 0000000..c39f8ff --- /dev/null +++ b/core/llm/math/j1f.rs @@ -0,0 +1,380 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 { + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + s = sinf(x) as f64; + if y1 { + s = -s; + } + c = cosf(x) as f64; + cc = s - c; + if ix < 0x7f000000 { + ss = -s - c; + z = cosf(2.0 * x) as f64; + if s * c > 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x58800000 { + if y1 { + ss = -ss; + } + cc = (ponef(x) as f64) * cc - (qonef(x) as f64) * ss; + } + } + if sign { + cc = -cc; + } + return (((INVSQRTPI as f64) * cc) / (sqrtf(x) as f64)) as f32; +} + +/* R0/S0 on [0,2] */ +const R00: f32 = -6.2500000000e-02; /* 0xbd800000 */ +const R01: f32 = 1.4070566976e-03; /* 0x3ab86cfd */ +const R02: f32 = -1.5995563444e-05; /* 0xb7862e36 */ +const R03: f32 = 4.9672799207e-08; /* 0x335557d2 */ +const S01: f32 = 1.9153760746e-02; /* 0x3c9ce859 */ +const S02: f32 = 1.8594678841e-04; /* 0x3942fab6 */ +const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ +const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ +const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ + +pub fn j1f(x: f32) -> f32 { + let mut z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0 / (x * x); + } + if ix >= 0x40000000 { + /* |x| >= 2 */ + return common(ix, fabsf(x), false, sign); + } + if ix >= 0x39000000 { + /* |x| >= 2**-13 */ + z = x * x; + r = z * (R00 + z * (R01 + z * (R02 + z * R03))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); + z = 0.5 + r / s; + } else { + z = 0.5; + } + return z * x; +} + +const U0: [f32; 5] = [ + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ +]; +const V0: [f32; 5] = [ + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ +]; + +pub fn y1f(x: f32) -> f32 { + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7f800000 { + return 1.0 / x; + } + if ix >= 0x40000000 { + /* |x| >= 2.0 */ + return common(ix, x, true, false); + } + if ix < 0x33000000 { + /* x < 2**-25 */ + return -TPI / x; + } + z = x * x; + u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + return x * (u / v) + TPI * (j1f(x) * logf(x) - 1.0 / x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ +]; +const PS8: [f32; 5] = [ + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ +]; + +const PR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ +]; +const PS5: [f32; 5] = [ + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ +]; + +const PR3: [f32; 6] = [ + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ +]; +const PS3: [f32; 5] = [ + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ +]; + +const PR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ +]; +const PS2: [f32; 5] = [ + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ +]; + +fn ponef(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x409173eb { + p = &PR5; + q = &PS5; + } else if ix >= 0x4036d917 { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ +]; +const QS8: [f32; 6] = [ + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ +]; + +const QR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ +]; +const QS5: [f32; 6] = [ + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ +]; + +const QR3: [f32; 6] = [ + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ +]; +const QS3: [f32; 6] = [ + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ +]; + +const QR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ +]; +const QS2: [f32; 6] = [ + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ +]; + +fn qonef(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x409173eb { + p = &QR5; + q = &QS5; + } else if ix >= 0x4036d917 { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (0.375 + r / s) / x; +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::{j1f, y1f}; + #[test] + fn test_j1f_2488() { + // 0x401F3E49 + assert_eq!(j1f(2.4881766_f32), 0.49999475_f32); + } + #[test] + fn test_y1f_2002() { + //allow slightly different result on x87 + let res = y1f(2.0000002_f32); + if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && (res == -0.10703231_f32) + { + return; + } + assert_eq!(res, -0.10703229_f32); + } +} diff --git a/core/llm/math/jn.rs b/core/llm/math/jn.rs new file mode 100644 index 0000000..1be167f --- /dev/null +++ b/core/llm/math/jn.rs @@ -0,0 +1,343 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * jn(n, x), yn(n, x) + * floating point Bessel's function of the 1st and 2nd kind + * of order n + * + * Special cases: + * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; + * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. + * Note 2. About jn(n,x), yn(n,x) + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for n<=x, forward recursion is used starting + * from values of j0(x) and j1(x). + * for n>x, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all + * values of n>1. + */ + +use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, y1}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ + +pub fn jn(n: i32, mut x: f64) -> f64 { + let mut ix: u32; + let lx: u32; + let nm1: i32; + let mut i: i32; + let mut sign: bool; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if (ix | (lx | ((!lx).wrapping_add(1))) >> 31) > 0x7ff00000 { + /* nan */ + return x; + } + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ + if n == 0 { + return j0(x); + } + if n < 0 { + nm1 = -(n + 1); + x = -x; + sign = !sign; + } else { + nm1 = n - 1; + } + if nm1 == 0 { + return j1(x); + } + + sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabs(x); + if (ix | lx) == 0 || ix == 0x7ff00000 { + /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f64) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + if ix >= 0x52d00000 { + /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1 & 3 { + 0 => -cos(x) + sin(x), + 1 => -cos(x) - sin(x), + 2 => cos(x) - sin(x), + 3 | _ => cos(x) + sin(x), + }; + b = INVSQRTPI * temp / sqrt(x); + } else { + a = j0(x); + b = j1(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b * (2.0 * (i as f64) / x) - a; /* avoid underflow */ + a = temp; + } + } + } else { + if ix < 0x3e100000 { + /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 32 { + /* underflow */ + b = 0.0; + } else { + temp = x * 0.5; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f64; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f64; + let mut q0: f64; + let mut q1: f64; + let mut w: f64; + let h: f64; + let mut z: f64; + let mut tmp: f64; + let nf: f64; + + let mut k: i32; + + nf = (nm1 as f64) + 1.0; + w = 2.0 * nf / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e9 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f64) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * log(fabs(w)); + if tmp < 7.09782712893383973096e+02 { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 + if b > x1p500 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0(x); + w = j1(x); + if fabs(z) >= fabs(w) { + b = t * z / b; + } else { + b = t * w / a; + } + } + } + + if sign { + -b + } else { + b + } +} + +pub fn yn(n: i32, x: f64) -> f64 { + let mut ix: u32; + let lx: u32; + let mut ib: u32; + let nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if (ix | (lx | ((!lx).wrapping_add(1))) >> 31) > 0x7ff00000 { + /* nan */ + return x; + } + if sign && (ix | lx) != 0 { + /* x < 0 */ + return 0.0 / 0.0; + } + if ix == 0x7ff00000 { + return 0.0; + } + + if n == 0 { + return y0(x); + } + if n < 0 { + nm1 = -(n + 1); + sign = (n & 1) != 0; + } else { + nm1 = n - 1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1(x); + } else { + return y1(x); + } + } + + if ix >= 0x52d00000 { + /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1 & 3 { + 0 => -sin(x) - cos(x), + 1 => -sin(x) + cos(x), + 2 => sin(x) + cos(x), + 3 | _ => sin(x) - cos(x), + }; + b = INVSQRTPI * temp / sqrt(x); + } else { + a = y0(x); + b = y1(x); + /* quit if b is -inf */ + ib = get_high_word(b); + i = 0; + while i < nm1 && ib != 0xfff00000 { + i += 1; + temp = b; + b = (2.0 * (i as f64) / x) * b - a; + ib = get_high_word(b); + a = temp; + } + } + + if sign { + -b + } else { + b + } +} diff --git a/core/llm/math/jnf.rs b/core/llm/math/jnf.rs new file mode 100644 index 0000000..360f62e --- /dev/null +++ b/core/llm/math/jnf.rs @@ -0,0 +1,259 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{fabsf, j0f, j1f, logf, y0f, y1f}; + +pub fn jnf(n: i32, mut x: f32) -> f32 { + let mut ix: u32; + let mut nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { + /* nan */ + return x; + } + + /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ + if n == 0 { + return j0f(x); + } + if n < 0 { + nm1 = -(n + 1); + x = -x; + sign = !sign; + } else { + nm1 = n - 1; + } + if nm1 == 0 { + return j1f(x); + } + + sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabsf(x); + if ix == 0 || ix == 0x7f800000 { + /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f32) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = j0f(x); + b = j1f(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b * (2.0 * (i as f32) / x) - a; + a = temp; + } + } else { + if ix < 0x35800000 { + /* x < 2**-20 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 8 { + /* underflow */ + nm1 = 8; + } + temp = 0.5 * x; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f32; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f32; + let mut q0: f32; + let mut q1: f32; + let mut w: f32; + let h: f32; + let mut z: f32; + let mut tmp: f32; + let nf: f32; + let mut k: i32; + + nf = (nm1 as f32) + 1.0; + w = 2.0 * (nf as f32) / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e4 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f32) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * logf(fabsf(w)); + if tmp < 88.721679688 { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 + if b > x1p60 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0f(x); + w = j1f(x); + if fabsf(z) >= fabsf(w) { + b = t * z / b; + } else { + b = t * w / a; + } + } + } + + if sign { + -b + } else { + b + } +} + +pub fn ynf(n: i32, x: f32) -> f32 { + let mut ix: u32; + let mut ib: u32; + let nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { + /* nan */ + return x; + } + if sign && ix != 0 { + /* x < 0 */ + return 0.0 / 0.0; + } + if ix == 0x7f800000 { + return 0.0; + } + + if n == 0 { + return y0f(x); + } + if n < 0 { + nm1 = -(n + 1); + sign = (n & 1) != 0; + } else { + nm1 = n - 1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1f(x); + } else { + return y1f(x); + } + } + + a = y0f(x); + b = y1f(x); + /* quit if b is -inf */ + ib = b.to_bits(); + i = 0; + while i < nm1 && ib != 0xff800000 { + i += 1; + temp = b; + b = (2.0 * (i as f32) / x) * b - a; + ib = b.to_bits(); + a = temp; + } + + if sign { + -b + } else { + b + } +} diff --git a/core/llm/math/k_cos.rs b/core/llm/math/k_cos.rs new file mode 100644 index 0000000..49b2fc6 --- /dev/null +++ b/core/llm/math/k_cos.rs @@ -0,0 +1,62 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_cos.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunSoft, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ +const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ +const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ +const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ +const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ +const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// +// Algorithm +// 1. Since cos(-x) = cos(x), we need only to consider positive x. +// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. +// 3. cos(x) is approximated by a polynomial of degree 14 on +// [0,pi/4] +// 4 14 +// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x +// where the remez error is +// +// | 2 4 6 8 10 12 14 | -58 +// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 +// | | +// +// 4 6 8 10 12 14 +// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then +// cos(x) ~ 1 - x*x/2 + r +// since cos(x+y) ~ cos(x) - sin(x)*y +// ~ cos(x) - x*y, +// a correction term is necessary in cos(x) and hence +// cos(x+y) = 1 - (x*x/2 - (r - x*y)) +// For better accuracy, rearrange to +// cos(x+y) ~ w + (tmp + (r-x*y)) +// where w = 1 - x*x/2 and tmp is a tiny correction term +// (1 - x*x/2 == w + tmp exactly in infinite precision). +// The exactness of w + tmp in infinite precision depends on w +// and tmp having the same precision as x. If they have extra +// precision due to compiler bugs, then the extra precision is +// only good provided it is retained in all terms of the final +// expression for cos(). Retention happens in all cases tested +// under FreeBSD, so don't pessimize things by forcibly clipping +// any extra precision in w. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_cos(x: f64, y: f64) -> f64 { + let z = x * x; + let w = z * z; + let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); + let hz = 0.5 * z; + let w = 1.0 - hz; + w + (((1.0 - w) - hz) + (z * r - x * y)) +} diff --git a/core/llm/math/k_cosf.rs b/core/llm/math/k_cosf.rs new file mode 100644 index 0000000..e99f234 --- /dev/null +++ b/core/llm/math/k_cosf.rs @@ -0,0 +1,29 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +const C0: f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ +const C1: f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ +const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ +const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_cosf(x: f64) -> f32 { + let z = x * x; + let w = z * z; + let r = C2 + z * C3; + (((1.0 + z * C0) + w * C1) + (w * z) * r) as f32 +} diff --git a/core/llm/math/k_expo2.rs b/core/llm/math/k_expo2.rs new file mode 100644 index 0000000..7345075 --- /dev/null +++ b/core/llm/math/k_expo2.rs @@ -0,0 +1,14 @@ +use super::exp; + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +const K: i32 = 2043; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_expo2(x: f64) -> f64 { + let k_ln2 = f64::from_bits(0x40962066151add8b); + /* note that k is odd and scale*scale overflows */ + let scale = f64::from_bits(((((0x3ff + K / 2) as u32) << 20) as u64) << 32); + /* exp(x - k ln2) * 2**(k-1) */ + exp(x - k_ln2) * scale * scale +} diff --git a/core/llm/math/k_expo2f.rs b/core/llm/math/k_expo2f.rs new file mode 100644 index 0000000..fbd7b27 --- /dev/null +++ b/core/llm/math/k_expo2f.rs @@ -0,0 +1,14 @@ +use super::expf; + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +const K: i32 = 235; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_expo2f(x: f32) -> f32 { + let k_ln2 = f32::from_bits(0x4322e3bc); + /* note that k is odd and scale*scale overflows */ + let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); + /* exp(x - k ln2) * 2**(k-1) */ + expf(x - k_ln2) * scale * scale +} diff --git a/core/llm/math/k_sin.rs b/core/llm/math/k_sin.rs new file mode 100644 index 0000000..9dd96c9 --- /dev/null +++ b/core/llm/math/k_sin.rs @@ -0,0 +1,57 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_sin.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunSoft, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ +const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ +const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ +const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ +const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ +const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// Input iy indicates whether y is 0. (if iy=0, y assume to be 0). +// +// Algorithm +// 1. Since sin(-x) = -sin(x), we need only to consider positive x. +// 2. Callers must return sin(-0) = -0 without calling here since our +// odd polynomial is not evaluated in a way that preserves -0. +// Callers may do the optimization sin(x) ~ x for tiny x. +// 3. sin(x) is approximated by a polynomial of degree 13 on +// [0,pi/4] +// 3 13 +// sin(x) ~ x + S1*x + ... + S6*x +// where +// +// |sin(x) 2 4 6 8 10 12 | -58 +// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 +// | x | +// +// 4. sin(x+y) = sin(x) + sin'(x')*y +// ~ sin(x) + (1-x*x/2)*y +// For better accuracy, let +// 3 2 2 2 2 +// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) +// then 3 2 +// sin(x) = x + (S1*x + (x *(r-y/2)+y)) +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { + let z = x * x; + let w = z * z; + let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); + let v = z * x; + if iy == 0 { + x + v * (S1 + z * r) + } else { + x - ((z * (0.5 * y - v * r) - y) - v * S1) + } +} diff --git a/core/llm/math/k_sinf.rs b/core/llm/math/k_sinf.rs new file mode 100644 index 0000000..88d10ca --- /dev/null +++ b/core/llm/math/k_sinf.rs @@ -0,0 +1,30 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +const S1: f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ +const S2: f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ +const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ +const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_sinf(x: f64) -> f32 { + let z = x * x; + let w = z * z; + let r = S3 + z * S4; + let s = z * x; + ((x + s * (S1 + z * S2)) + s * w * r) as f32 +} diff --git a/core/llm/math/k_tan.rs b/core/llm/math/k_tan.rs new file mode 100644 index 0000000..d177010 --- /dev/null +++ b/core/llm/math/k_tan.rs @@ -0,0 +1,105 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +// +// ==================================================== +// Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. +// +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +// kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. +// +// Algorithm +// 1. Since tan(-x) = -tan(x), we need only to consider positive x. +// 2. Callers must return tan(-0) = -0 without calling here since our +// odd polynomial is not evaluated in a way that preserves -0. +// Callers may do the optimization tan(x) ~ x for tiny x. +// 3. tan(x) is approximated by a odd polynomial of degree 27 on +// [0,0.67434] +// 3 27 +// tan(x) ~ x + T1*x + ... + T13*x +// where +// +// |tan(x) 2 4 26 | -59.2 +// |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 +// | x | +// +// Note: tan(x+y) = tan(x) + tan'(x)*y +// ~ tan(x) + (1+x*x)*y +// Therefore, for better accuracy in computing tan(x+y), let +// 3 2 2 2 2 +// r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) +// then +// 3 2 +// tan(x+y) = x + (T1*x + (x *(r+y)+y)) +// +// 4. For x in [0.67434,pi/4], let y = pi/4 - x, then +// tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) +// = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) +static T: [f64; 13] = [ + 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ + 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ + 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ + 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ + 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ + 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ + 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ + 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ + 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ + 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ + 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ + -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ + 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ +]; +const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ +const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { + let hx = (f64::to_bits(x) >> 32) as u32; + let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ + if big { + let sign = hx >> 31; + if sign != 0 { + x = -x; + y = -y; + } + x = (PIO4 - x) + (PIO4_LO - y); + y = 0.0; + } + let z = x * x; + let w = z * z; + /* + * Break x^5*(T[1]+x^2*T[2]+...) into + * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) + */ + let r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11])))); + let v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12]))))); + let s = z * x; + let r = y + z * (s * (r + v) + y) + s * T[0]; + let w = x + r; + if big { + let sign = hx >> 31; + let s = 1.0 - 2.0 * odd as f64; + let v = s - 2.0 * (x + (r - w * w / (w + s))); + return if sign != 0 { -v } else { v }; + } + if odd == 0 { + return w; + } + /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ + let w0 = zero_low_word(w); + let v = r - (w0 - x); /* w0+v = r+x */ + let a = -1.0 / w; + let a0 = zero_low_word(a); + a0 + a * (1.0 + a0 * w0 + a0 * v) +} + +fn zero_low_word(x: f64) -> f64 { + f64::from_bits(f64::to_bits(x) & 0xFFFF_FFFF_0000_0000) +} diff --git a/core/llm/math/k_tanf.rs b/core/llm/math/k_tanf.rs new file mode 100644 index 0000000..af8db53 --- /dev/null +++ b/core/llm/math/k_tanf.rs @@ -0,0 +1,46 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ +const T: [f64; 6] = [ + 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ + 0.133392002712976742718, /* 0x1112fd38999f72.0p-55 */ + 0.0533812378445670393523, /* 0x1b54c91d865afe.0p-57 */ + 0.0245283181166547278873, /* 0x191df3908c33ce.0p-58 */ + 0.00297435743359967304927, /* 0x185dadfcecf44e.0p-61 */ + 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ +]; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { + let z = x * x; + /* + * Split up the polynomial into small independent terms to give + * opportunities for parallel evaluation. The chosen splitting is + * micro-optimized for Athlons (XP, X64). It costs 2 multiplications + * relative to Horner's method on sequential machines. + * + * We add the small terms from lowest degree up for efficiency on + * non-sequential machines (the lowest degree terms tend to be ready + * earlier). Apart from this, we don't care about order of + * operations, and don't need to to care since we have precision to + * spare. However, the chosen splitting is good for accuracy too, + * and would give results as accurate as Horner's method if the + * small terms were added from highest degree down. + */ + let mut r = T[4] + z * T[5]; + let t = T[2] + z * T[3]; + let w = z * z; + let s = z * x; + let u = T[0] + z * T[1]; + r = (x + s * u) + (s * w) * (t + w * r); + (if odd { -1. / r } else { r }) as f32 +} diff --git a/core/llm/math/ldexp.rs b/core/llm/math/ldexp.rs new file mode 100644 index 0000000..e46242e --- /dev/null +++ b/core/llm/math/ldexp.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexp(x: f64, n: i32) -> f64 { + super::scalbn(x, n) +} diff --git a/core/llm/math/ldexpf.rs b/core/llm/math/ldexpf.rs new file mode 100644 index 0000000..95b27fc --- /dev/null +++ b/core/llm/math/ldexpf.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf(x: f32, n: i32) -> f32 { + super::scalbnf(x, n) +} diff --git a/core/llm/math/lgamma.rs b/core/llm/math/lgamma.rs new file mode 100644 index 0000000..a08bc5b --- /dev/null +++ b/core/llm/math/lgamma.rs @@ -0,0 +1,6 @@ +use super::lgamma_r; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn lgamma(x: f64) -> f64 { + lgamma_r(x).0 +} diff --git a/core/llm/math/lgamma_r.rs b/core/llm/math/lgamma_r.rs new file mode 100644 index 0000000..b26177e --- /dev/null +++ b/core/llm/math/lgamma_r.rs @@ -0,0 +1,320 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = PI/sin(PI*x), + * we have + * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(PI*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); + * Note: one should avoid compute PI*(-x) directly in the + * computation of sin(PI*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +use super::{floor, k_cos, k_sin, log}; + +const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ +const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ +const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ +const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ +const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ +const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ +const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ +const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ +const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ +const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ +const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ +const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ +const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ +const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ +const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of TF) */ +const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ +const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ +const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ +const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ +const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ +const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ +const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ +const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ +const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ +const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ +const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ +const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ +const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ +const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ +const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ +const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ +const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ +const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ +const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ +const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ +const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ +const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ +const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ +const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ +const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ +const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ +const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ +const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ +const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ +const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ +const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ +const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ +const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ +const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ +const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ +const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ +const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ +const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ +const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ +const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ +const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ +const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ +const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ +const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ +const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f64) -> f64 { + let mut n: i32; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as i32; + n = div!(n + 1, 2); + x -= (n as f64) * 0.5; + x *= PI; + + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + 0 | _ => k_sin(x, 0.0, 0), + } +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn lgamma_r(mut x: f64) -> (f64, i32) { + let u: u64 = x.to_bits(); + let mut t: f64; + let y: f64; + let mut z: f64; + let nadj: f64; + let p: f64; + let p1: f64; + let p2: f64; + let p3: f64; + let q: f64; + let mut r: f64; + let w: f64; + let ix: u32; + let sign: bool; + let i: i32; + let mut signgam: i32; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 63) != 0; + ix = ((u >> 32) as u32) & 0x7fffffff; + if ix >= 0x7ff00000 { + return (x * x, signgam); + } + if ix < (0x3ff - 70) << 20 { + /* |x|<2**-70, return -log(|x|) */ + if sign { + x = -x; + signgam = -1; + } + return (-log(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = log(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3feccccc { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if ix >= 0x3FE76944 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3FCDA661 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3FFBB4C3 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3FF3B4C4 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => {} + } + } else if ix < 0x40200000 { + /* x < 8.0 */ + i = x as i32; + y = x - (i as f64); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += log(z); + } + } else if ix < 0x43900000 { + /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (log(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/core/llm/math/lgammaf.rs b/core/llm/math/lgammaf.rs new file mode 100644 index 0000000..a9c2da7 --- /dev/null +++ b/core/llm/math/lgammaf.rs @@ -0,0 +1,6 @@ +use super::lgammaf_r; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn lgammaf(x: f32) -> f32 { + lgammaf_r(x).0 +} diff --git a/core/llm/math/lgammaf_r.rs b/core/llm/math/lgammaf_r.rs new file mode 100644 index 0000000..723c90d --- /dev/null +++ b/core/llm/math/lgammaf_r.rs @@ -0,0 +1,255 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{floorf, k_cosf, k_sinf, logf}; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ +const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ +const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ +const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ +const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ +const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ +const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ +const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ +const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ +const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ +const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ +const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ +const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ +const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ +/* TT = -(tail of TF) */ +const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ +const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ +const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ +const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ +const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ +const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ +const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ +const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ +const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ +const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ +const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ +const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ +const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ +const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ +const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ +const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ +const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ +const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ +const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ +const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ +const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ +const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ +const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ +const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ +const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ +const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ +const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ +const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ +const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ +const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ +const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ +const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ +const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ +const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ +const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ +const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ +const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ +const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ +const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ +const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ +const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ +const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ +const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ +const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f32) -> f32 { + let mut y: f64; + let mut n: isize; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as isize; + n = div!(n + 1, 2); + y = (x as f64) - (n as f64) * 0.5; + y *= 3.14159265358979323846; + match n { + 1 => k_cosf(y), + 2 => k_sinf(-y), + 3 => -k_cosf(y), + 0 | _ => k_sinf(y), + } +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn lgammaf_r(mut x: f32) -> (f32, i32) { + let u = x.to_bits(); + let mut t: f32; + let y: f32; + let mut z: f32; + let nadj: f32; + let p: f32; + let p1: f32; + let p2: f32; + let p3: f32; + let q: f32; + let mut r: f32; + let w: f32; + let ix: u32; + let i: i32; + let sign: bool; + let mut signgam: i32; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 31) != 0; + ix = u & 0x7fffffff; + if ix >= 0x7f800000 { + return (x * x, signgam); + } + if ix < 0x35000000 { + /* |x| < 2**-21, return -log(|x|) */ + if sign { + signgam = -1; + x = -x; + } + return (-logf(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = logf(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if ix == 0x3f800000 || ix == 0x40000000 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3f666666 { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if ix >= 0x3f3b4a20 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3e6d3308 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3fdda618 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3F9da620 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => {} + } + } else if ix < 0x41000000 { + /* x < 8.0 */ + i = x as i32; + y = x - (i as f32); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += logf(z); + } + } else if ix < 0x5c800000 { + /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (logf(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/core/llm/math/log.rs b/core/llm/math/log.rs new file mode 100644 index 0000000..27a26da --- /dev/null +++ b/core/llm/math/log.rs @@ -0,0 +1,117 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* log(x) + * Return the logarithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Remez algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui = x.to_bits(); + let mut hx: u32 = (ui >> 32) as u32; + let mut k: i32 = 0; + + if (hx < 0x00100000) || ((hx >> 31) != 0) { + /* x < 2**-126 */ + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if hx >> 31 != 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += ((hx >> 20) as i32) - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = ((hx as u64) << 32) | (ui & 0xffffffff); + x = f64::from_bits(ui); + + let f: f64 = x - 1.0; + let hfsq: f64 = 0.5 * f * f; + let s: f64 = f / (2.0 + f); + let z: f64 = s * s; + let w: f64 = z * z; + let t1: f64 = w * (LG2 + w * (LG4 + w * LG6)); + let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + let r: f64 = t2 + t1; + let dk: f64 = k as f64; + s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI +} diff --git a/core/llm/math/log10.rs b/core/llm/math/log10.rs new file mode 100644 index 0000000..40dacf2 --- /dev/null +++ b/core/llm/math/log10.rs @@ -0,0 +1,117 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 10 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) + */ + +use core::f64; + +const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ +const IVLN10LO: f64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ +const LOG10_2HI: f64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ +const LOG10_2LO: f64 = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log10(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let f: f64; + let s: f64; + let z: f64; + let r: f64; + let mut w: f64; + let t1: f64; + let t2: f64; + let dk: f64; + let y: f64; + let mut hi: f64; + let lo: f64; + let mut val_hi: f64; + let mut val_lo: f64; + let mut hx: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 0; + if hx < 0x00100000 || (hx >> 31) > 0 { + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (hx >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (hx >> 20) as i32 - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = (hx as u64) << 32 | (ui & 0xffffffff); + x = f64::from_bits(ui); + + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + + /* See log2.c for details. */ + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + ui = hi.to_bits(); + ui &= (-1i64 as u64) << 32; + hi = f64::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + + /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ + val_hi = hi * IVLN10HI; + dk = k as f64; + y = dk * LOG10_2HI; + val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI; + + /* + * Extra precision in for adding y is not strictly needed + * since there is no very large cancellation near x = sqrt(2) or + * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs + * with some parallelism and it reduces the error for many args. + */ + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + val_lo + val_hi +} diff --git a/core/llm/math/log10f.rs b/core/llm/math/log10f.rs new file mode 100644 index 0000000..108dfa8 --- /dev/null +++ b/core/llm/math/log10f.rs @@ -0,0 +1,91 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log10.c. + */ + +use core::f32; + +const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */ +const IVLN10LO: f32 = -3.1689971365e-05; /* 0xb804ead9 */ +const LOG10_2HI: f32 = 3.0102920532e-01; /* 0x3e9a2080 */ +const LOG10_2LO: f32 = 7.9034151668e-07; /* 0x355427db */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log10f(mut x: f32) -> f32 { + let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 + + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let f: f32; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let dk: f32; + let mut hi: f32; + let lo: f32; + let mut ix: u32; + let mut k: i32; + + ix = ui; + k = 0; + if ix < 0x00800000 || (ix >> 31) > 0 { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (ix >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25f; + ui = x.to_bits(); + ix = ui; + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (ix >> 23) as i32 - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + ui = ix; + x = f32::from_bits(ui); + + f = x - 1.0; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + + hi = f - hfsq; + ui = hi.to_bits(); + ui &= 0xfffff000; + hi = f32::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + dk = k as f32; + dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI +} diff --git a/core/llm/math/log1p.rs b/core/llm/math/log1p.rs new file mode 100644 index 0000000..4fd1c73 --- /dev/null +++ b/core/llm/math/log1p.rs @@ -0,0 +1,143 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double log1p(double x) + * Return the natural logarithm of 1+x. + * + * Method : + * 1. Argument Reduction: find k and f such that + * 1+x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * Note. If k=0, then f=x is exact. However, if k!=0, then f + * may not be representable exactly. In that case, a correction + * term is need. Let u=1+x rounded. Let c = (1+x)-u, then + * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + * and add back the correction term c/u. + * (Note: when x > 2**53, one can simply return log(x)) + * + * 2. Approximation of log(1+f): See log.c + * + * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c + * + * Special cases: + * log1p(x) is NaN with signal if x < -1 (including -INF) ; + * log1p(+INF) is +INF; log1p(-1) is -INF with signal; + * log1p(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + * algorithm can be used to compute log1p(x) to within a few ULP: + * + * u = 1+x; + * if(u==1.0) return x ; else + * return log(u)*(x/(u-1.0)); + * + * See HP-15C Advanced Functions Handbook, p.193. + */ + +use core::f64; + +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log1p(x: f64) -> f64 { + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let mut f: f64 = 0.; + let mut c: f64 = 0.; + let s: f64; + let z: f64; + let r: f64; + let w: f64; + let t1: f64; + let t2: f64; + let dk: f64; + let hx: u32; + let mut hu: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 1; + if hx < 0x3fda827a || (hx >> 31) > 0 { + /* 1+x < sqrt(2)+ */ + if hx >= 0xbff00000 { + /* x <= -1.0 */ + if x == -1. { + return x / 0.0; /* log1p(-1) = -inf */ + } + return (x - x) / 0.0; /* log1p(x<-1) = NaN */ + } + if hx << 1 < 0x3ca00000 << 1 { + /* |x| < 2**-53 */ + /* underflow if subnormal */ + if (hx & 0x7ff00000) == 0 { + force_eval!(x as f32); + } + return x; + } + if hx <= 0xbfd2bec4 { + /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0.; + f = x; + } + } else if hx >= 0x7ff00000 { + return x; + } + if k > 0 { + ui = (1. + x).to_bits(); + hu = (ui >> 32) as u32; + hu += 0x3ff00000 - 0x3fe6a09e; + k = (hu >> 20) as i32 - 0x3ff; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if k < 54 { + c = if k >= 2 { + 1. - (f64::from_bits(ui) - x) + } else { + x - (f64::from_bits(ui) - 1.) + }; + c /= f64::from_bits(ui); + } else { + c = 0.; + } + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + hu = (hu & 0x000fffff) + 0x3fe6a09e; + ui = (hu as u64) << 32 | (ui & 0xffffffff); + f = f64::from_bits(ui) - 1.; + } + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + dk = k as f64; + s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI +} diff --git a/core/llm/math/log1pf.rs b/core/llm/math/log1pf.rs new file mode 100644 index 0000000..500e8ee --- /dev/null +++ b/core/llm/math/log1pf.rs @@ -0,0 +1,98 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use core::f32; + +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log1pf(x: f32) -> f32 { + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let mut f: f32 = 0.; + let mut c: f32 = 0.; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let dk: f32; + let ix: u32; + let mut iu: u32; + let mut k: i32; + + ix = ui; + k = 1; + if ix < 0x3ed413d0 || (ix >> 31) > 0 { + /* 1+x < sqrt(2)+ */ + if ix >= 0xbf800000 { + /* x <= -1.0 */ + if x == -1. { + return x / 0.0; /* log1p(-1)=+inf */ + } + return (x - x) / 0.0; /* log1p(x<-1)=NaN */ + } + if ix << 1 < 0x33800000 << 1 { + /* |x| < 2**-24 */ + /* underflow if subnormal */ + if (ix & 0x7f800000) == 0 { + force_eval!(x * x); + } + return x; + } + if ix <= 0xbe95f619 { + /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0.; + f = x; + } + } else if ix >= 0x7f800000 { + return x; + } + if k > 0 { + ui = (1. + x).to_bits(); + iu = ui; + iu += 0x3f800000 - 0x3f3504f3; + k = (iu >> 23) as i32 - 0x7f; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if k < 25 { + c = if k >= 2 { + 1. - (f32::from_bits(ui) - x) + } else { + x - (f32::from_bits(ui) - 1.) + }; + c /= f32::from_bits(ui); + } else { + c = 0.; + } + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + iu = (iu & 0x007fffff) + 0x3f3504f3; + ui = iu; + f = f32::from_bits(ui) - 1.; + } + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + dk = k as f32; + s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI +} diff --git a/core/llm/math/log2.rs b/core/llm/math/log2.rs new file mode 100644 index 0000000..83da3a1 --- /dev/null +++ b/core/llm/math/log2.rs @@ -0,0 +1,106 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 2 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log2(x) = (f - f*f/2 + r)/log(2) + k + */ + +use core::f64; + +const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ +const IVLN2LO: f64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log2(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let f: f64; + let s: f64; + let z: f64; + let r: f64; + let mut w: f64; + let t1: f64; + let t2: f64; + let y: f64; + let mut hi: f64; + let lo: f64; + let mut val_hi: f64; + let mut val_lo: f64; + let mut hx: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 0; + if hx < 0x00100000 || (hx >> 31) > 0 { + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (hx >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (hx >> 20) as i32 - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = (hx as u64) << 32 | (ui & 0xffffffff); + x = f64::from_bits(ui); + + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + ui = hi.to_bits(); + ui &= (-1i64 as u64) << 32; + hi = f64::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + + val_hi = hi * IVLN2HI; + val_lo = (lo + hi) * IVLN2LO + lo * IVLN2HI; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + y = k.into(); + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + val_lo + val_hi +} diff --git a/core/llm/math/log2f.rs b/core/llm/math/log2f.rs new file mode 100644 index 0000000..3a20fb1 --- /dev/null +++ b/core/llm/math/log2f.rs @@ -0,0 +1,87 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log2.c. + */ + +use core::f32; + +const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */ +const IVLN2LO: f32 = -1.7605285393e-04; /* 0xb9389ad4 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn log2f(mut x: f32) -> f32 { + let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 + + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let f: f32; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let mut hi: f32; + let lo: f32; + let mut ix: u32; + let mut k: i32; + + ix = ui; + k = 0; + if ix < 0x00800000 || (ix >> 31) > 0 { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (ix >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25f; + ui = x.to_bits(); + ix = ui; + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (ix >> 23) as i32 - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + ui = ix; + x = f32::from_bits(ui); + + f = x - 1.0; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + + hi = f - hfsq; + ui = hi.to_bits(); + ui &= 0xfffff000; + hi = f32::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as f32 +} diff --git a/core/llm/math/logf.rs b/core/llm/math/logf.rs new file mode 100644 index 0000000..2b57b93 --- /dev/null +++ b/core/llm/math/logf.rs @@ -0,0 +1,65 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn logf(mut x: f32) -> f32 { + let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 + + let mut ix = x.to_bits(); + let mut k = 0i32; + + if (ix < 0x00800000) || ((ix >> 31) != 0) { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (ix >> 31) != 0 { + return (x - x) / 0.; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25; + ix = x.to_bits(); + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += ((ix >> 23) as i32) - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + x = f32::from_bits(ix); + + let f = x - 1.; + let s = f / (2. + f); + let z = s * s; + let w = z * z; + let t1 = w * (LG2 + w * LG4); + let t2 = z * (LG1 + w * LG3); + let r = t2 + t1; + let hfsq = 0.5 * f * f; + let dk = k as f32; + s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI +} diff --git a/core/llm/math/modf.rs b/core/llm/math/modf.rs new file mode 100644 index 0000000..bcab33a --- /dev/null +++ b/core/llm/math/modf.rs @@ -0,0 +1,34 @@ +pub fn modf(x: f64) -> (f64, f64) { + let rv2: f64; + let mut u = x.to_bits(); + let mask: u64; + let e = ((u >> 52 & 0x7ff) as i32) - 0x3ff; + + /* no fractional part */ + if e >= 52 { + rv2 = x; + if e == 0x400 && (u << 12) != 0 { + /* nan */ + return (x, rv2); + } + u &= 1 << 63; + return (f64::from_bits(u), rv2); + } + + /* no integral part*/ + if e < 0 { + u &= 1 << 63; + rv2 = f64::from_bits(u); + return (x, rv2); + } + + mask = ((!0) >> 12) >> e; + if (u & mask) == 0 { + rv2 = x; + u &= 1 << 63; + return (f64::from_bits(u), rv2); + } + u &= !mask; + rv2 = f64::from_bits(u); + return (x - rv2, rv2); +} diff --git a/core/llm/math/modff.rs b/core/llm/math/modff.rs new file mode 100644 index 0000000..56ece12 --- /dev/null +++ b/core/llm/math/modff.rs @@ -0,0 +1,33 @@ +pub fn modff(x: f32) -> (f32, f32) { + let rv2: f32; + let mut u: u32 = x.to_bits(); + let mask: u32; + let e = ((u >> 23 & 0xff) as i32) - 0x7f; + + /* no fractional part */ + if e >= 23 { + rv2 = x; + if e == 0x80 && (u << 9) != 0 { + /* nan */ + return (x, rv2); + } + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + /* no integral part */ + if e < 0 { + u &= 0x80000000; + rv2 = f32::from_bits(u); + return (x, rv2); + } + + mask = 0x007fffff >> e; + if (u & mask) == 0 { + rv2 = x; + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + u &= !mask; + rv2 = f32::from_bits(u); + return (x - rv2, rv2); +} diff --git a/core/llm/math/nextafter.rs b/core/llm/math/nextafter.rs new file mode 100644 index 0000000..0576261 --- /dev/null +++ b/core/llm/math/nextafter.rs @@ -0,0 +1,37 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn nextafter(x: f64, y: f64) -> f64 { + if x.is_nan() || y.is_nan() { + return x + y; + } + + let mut ux_i = x.to_bits(); + let uy_i = y.to_bits(); + if ux_i == uy_i { + return y; + } + + let ax = ux_i & !1_u64 / 2; + let ay = uy_i & !1_u64 / 2; + if ax == 0 { + if ay == 0 { + return y; + } + ux_i = (uy_i & 1_u64 << 63) | 1; + } else if ax > ay || ((ux_i ^ uy_i) & 1_u64 << 63) != 0 { + ux_i -= 1; + } else { + ux_i += 1; + } + + let e = ux_i >> 52 & 0x7ff; + // raise overflow if ux.f is infinite and x is finite + if e == 0x7ff { + force_eval!(x + x); + } + let ux_f = f64::from_bits(ux_i); + // raise underflow if ux.f is subnormal or zero + if e == 0 { + force_eval!(x * x + ux_f * ux_f); + } + ux_f +} diff --git a/core/llm/math/nextafterf.rs b/core/llm/math/nextafterf.rs new file mode 100644 index 0000000..8ba3833 --- /dev/null +++ b/core/llm/math/nextafterf.rs @@ -0,0 +1,37 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn nextafterf(x: f32, y: f32) -> f32 { + if x.is_nan() || y.is_nan() { + return x + y; + } + + let mut ux_i = x.to_bits(); + let uy_i = y.to_bits(); + if ux_i == uy_i { + return y; + } + + let ax = ux_i & 0x7fff_ffff_u32; + let ay = uy_i & 0x7fff_ffff_u32; + if ax == 0 { + if ay == 0 { + return y; + } + ux_i = (uy_i & 0x8000_0000_u32) | 1; + } else if ax > ay || ((ux_i ^ uy_i) & 0x8000_0000_u32) != 0 { + ux_i -= 1; + } else { + ux_i += 1; + } + + let e = ux_i & 0x7f80_0000_u32; + // raise overflow if ux_f is infinite and x is finite + if e == 0x7f80_0000_u32 { + force_eval!(x + x); + } + let ux_f = f32::from_bits(ux_i); + // raise underflow if ux_f is subnormal or zero + if e == 0 { + force_eval!(x * x + ux_f * ux_f); + } + ux_f +} diff --git a/core/llm/math/pow.rs b/core/llm/math/pow.rs new file mode 100644 index 0000000..6a19ae6 --- /dev/null +++ b/core/llm/math/pow.rs @@ -0,0 +1,637 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +// pow(x,y) return x**y +// +// n +// Method: Let x = 2 * (1+f) +// 1. Compute and return log2(x) in two pieces: +// log2(x) = w1 + w2, +// where w1 has 53-24 = 29 bit trailing zeros. +// 2. Perform y*log2(x) = n+y' by simulating muti-precision +// arithmetic, where |y'|<=0.5. +// 3. Return x**y = 2**n*exp(y'*log2) +// +// Special cases: +// 1. (anything) ** 0 is 1 +// 2. 1 ** (anything) is 1 +// 3. (anything except 1) ** NAN is NAN +// 4. NAN ** (anything except 0) is NAN +// 5. +-(|x| > 1) ** +INF is +INF +// 6. +-(|x| > 1) ** -INF is +0 +// 7. +-(|x| < 1) ** +INF is +0 +// 8. +-(|x| < 1) ** -INF is +INF +// 9. -1 ** +-INF is 1 +// 10. +0 ** (+anything except 0, NAN) is +0 +// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 +// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero +// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero +// 14. -0 ** (+odd integer) is -0 +// 15. -0 ** (-odd integer) is -INF, raise divbyzero +// 16. +INF ** (+anything except 0,NAN) is +INF +// 17. +INF ** (-anything except 0,NAN) is +0 +// 18. -INF ** (+odd integer) is -INF +// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) +// 20. (anything) ** 1 is (anything) +// 21. (anything) ** -1 is 1/(anything) +// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) +// 23. (-anything except 0 and inf) ** (non-integer) is NAN +// +// Accuracy: +// pow(x,y) returns x**y nearly rounded. In particular +// pow(integer,integer) +// always returns the correct integer provided it is +// representable. +// +// Constants : +// The hexadecimal values are the intended ones for the following +// constants. The decimal values may be used, provided that the +// compiler will convert from decimal to binary accurately enough +// to produce the hexadecimal values shown. +// +use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; + +const BP: [f64; 2] = [1.0, 1.5]; +const DP_H: [f64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ +const DP_L: [f64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ +const TWO53: f64 = 9007199254740992.0; /* 0x43400000_00000000 */ +const HUGE: f64 = 1.0e300; +const TINY: f64 = 1.0e-300; + +// poly coefs for (3/2)*(log(x)-2s-2/3*s**3: +const L1: f64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ +const L2: f64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ +const L3: f64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ +const L4: f64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ +const L5: f64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ +const L6: f64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ +const P2: f64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ +const P4: f64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ +const LG2: f64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ +const LG2_H: f64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ +const LG2_L: f64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ +const OVT: f64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ +const CP: f64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ +const CP_H: f64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ +const CP_L: f64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ +const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ +const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ +const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn pow(x: f64, y: f64) -> f64 { + let t1: f64; + let t2: f64; + + let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); + let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); + + let mut ix: i32 = (hx & 0x7fffffff) as i32; + let iy: i32 = (hy & 0x7fffffff) as i32; + + /* x**0 = 1, even if x is NaN */ + if ((iy as u32) | ly) == 0 { + return 1.0; + } + + /* 1**y = 1, even if y is NaN */ + if hx == 0x3ff00000 && lx == 0 { + return 1.0; + } + + /* NaN if either arg is NaN */ + if ix > 0x7ff00000 + || (ix == 0x7ff00000 && lx != 0) + || iy > 0x7ff00000 + || (iy == 0x7ff00000 && ly != 0) + { + return x + y; + } + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + let mut yisint: i32 = 0; + let mut k: i32; + let mut j: i32; + if hx < 0 { + if iy >= 0x43400000 { + yisint = 2; /* even integer y */ + } else if iy >= 0x3ff00000 { + k = (iy >> 20) - 0x3ff; /* exponent */ + + if k > 20 { + j = (ly >> (52 - k)) as i32; + + if (j << (52 - k)) == (ly as i32) { + yisint = 2 - (j & 1); + } + } else if ly == 0 { + j = iy >> (20 - k); + + if (j << (20 - k)) == iy { + yisint = 2 - (j & 1); + } + } + } + } + + if ly == 0 { + /* special value of y */ + if iy == 0x7ff00000 { + /* y is +-inf */ + + return if ((ix - 0x3ff00000) | (lx as i32)) == 0 { + /* (-1)**+-inf is 1 */ + 1.0 + } else if ix >= 0x3ff00000 { + /* (|x|>1)**+-inf = inf,0 */ + if hy >= 0 { + y + } else { + 0.0 + } + } else { + /* (|x|<1)**+-inf = 0,inf */ + if hy >= 0 { + 0.0 + } else { + -y + } + }; + } + + if iy == 0x3ff00000 { + /* y is +-1 */ + return if hy >= 0 { x } else { 1.0 / x }; + } + + if hy == 0x40000000 { + /* y is 2 */ + return x * x; + } + + if hy == 0x3fe00000 { + /* y is 0.5 */ + if hx >= 0 { + /* x >= +0 */ + return sqrt(x); + } + } + } + + let mut ax: f64 = fabs(x); + if lx == 0 { + /* special value of x */ + if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { + /* x is +-0,+-inf,+-1 */ + let mut z: f64 = ax; + + if hy < 0 { + /* z = (1/|x|) */ + z = 1.0 / z; + } + + if hx < 0 { + if ((ix - 0x3ff00000) | yisint) == 0 { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if yisint == 1 { + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + } + + return z; + } + } + + let mut s: f64 = 1.0; /* sign of result */ + if hx < 0 { + if yisint == 0 { + /* (x<0)**(non-int) is NaN */ + return (x - x) / (x - x); + } + + if yisint == 1 { + /* (x<0)**(odd int) */ + s = -1.0; + } + } + + /* |y| is HUGE */ + if iy > 0x41e00000 { + /* if |y| > 2**31 */ + if iy > 0x43f00000 { + /* if |y| > 2**64, must o/uflow */ + if ix <= 0x3fefffff { + return if hy < 0 { HUGE * HUGE } else { TINY * TINY }; + } + + if ix >= 0x3ff00000 { + return if hy > 0 { HUGE * HUGE } else { TINY * TINY }; + } + } + + /* over/underflow if x is not close to one */ + if ix < 0x3fefffff { + return if hy < 0 { + s * HUGE * HUGE + } else { + s * TINY * TINY + }; + } + if ix > 0x3ff00000 { + return if hy > 0 { + s * HUGE * HUGE + } else { + s * TINY * TINY + }; + } + + /* now |1-x| is TINY <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ + let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); + let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ + let v: f64 = t * IVLN2_L - w * IVLN2; + t1 = with_set_low_word(u + v, 0); + t2 = v - (t1 - u); + } else { + // double ss,s2,s_h,s_l,t_h,t_l; + let mut n: i32 = 0; + + if ix < 0x00100000 { + /* take care subnormal number */ + ax *= TWO53; + n -= 53; + ix = get_high_word(ax) as i32; + } + + n += (ix >> 20) - 0x3ff; + j = ix & 0x000fffff; + + /* determine interval */ + let k: i32; + ix = j | 0x3ff00000; /* normalize ix */ + if j <= 0x3988E { + /* |x|> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18), + ); + let t_l: f64 = ax - (t_h - i!(BP, k as usize)); + let s_l: f64 = v * ((u - s_h * t_h) - s_h * t_l); + + /* compute log(ax) */ + let s2: f64 = ss * ss; + let mut r: f64 = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); + r += s_l * (s_h + ss); + let s2: f64 = s_h * s_h; + let t_h: f64 = with_set_low_word(3.0 + s2 + r, 0); + let t_l: f64 = r - ((t_h - 3.0) - s2); + + /* u+v = ss*(1+...) */ + let u: f64 = s_h * t_h; + let v: f64 = s_l * t_h + t_l * ss; + + /* 2/(3log2)*(ss+...) */ + let p_h: f64 = with_set_low_word(u + v, 0); + let p_l = v - (p_h - u); + let z_h: f64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ + let z_l: f64 = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); + + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + let t: f64 = n as f64; + t1 = with_set_low_word(((z_h + z_l) + i!(DP_H, k as usize)) + t, 0); + t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + let y1: f64 = with_set_low_word(y, 0); + let p_l: f64 = (y - y1) * t1 + y * t2; + let mut p_h: f64 = y1 * t1; + let z: f64 = p_l + p_h; + let mut j: i32 = (z.to_bits() >> 32) as i32; + let i: i32 = z.to_bits() as i32; + // let (j, i): (i32, i32) = ((z.to_bits() >> 32) as i32, z.to_bits() as i32); + + if j >= 0x40900000 { + /* z >= 1024 */ + if (j - 0x40900000) | i != 0 { + /* if z > 1024 */ + return s * HUGE * HUGE; /* overflow */ + } + + if p_l + OVT > z - p_h { + return s * HUGE * HUGE; /* overflow */ + } + } else if (j & 0x7fffffff) >= 0x4090cc00 { + /* z <= -1075 */ + // FIXME: instead of abs(j) use unsigned j + + if (((j as u32) - 0xc090cc00) | (i as u32)) != 0 { + /* z < -1075 */ + return s * TINY * TINY; /* underflow */ + } + + if p_l <= z - p_h { + return s * TINY * TINY; /* underflow */ + } + } + + /* compute 2**(p_h+p_l) */ + let i: i32 = j & (0x7fffffff as i32); + k = (i >> 20) - 0x3ff; + let mut n: i32 = 0; + + if i > 0x3fe00000 { + /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00100000 >> (k + 1)); + k = ((n & 0x7fffffff) >> 20) - 0x3ff; /* new k for n */ + let t: f64 = with_set_high_word(0.0, (n & !(0x000fffff >> k)) as u32); + n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); + if j < 0 { + n = -n; + } + p_h -= t; + } + + let t: f64 = with_set_low_word(p_l + p_h, 0); + let u: f64 = t * LG2_H; + let v: f64 = (p_l - (t - p_h)) * LG2 + t * LG2_L; + let mut z: f64 = u + v; + let w: f64 = v - (z - u); + let t: f64 = z * z; + let t1: f64 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + let r: f64 = (z * t1) / (t1 - 2.0) - (w + z * w); + z = 1.0 - (r - z); + j = get_high_word(z) as i32; + j += n << 20; + + if (j >> 20) <= 0 { + /* subnormal output */ + z = scalbn(z, n); + } else { + z = with_set_high_word(z, j as u32); + } + + s * z +} + +#[cfg(test)] +mod tests { + extern crate core; + + use self::core::f64::consts::{E, PI}; + use self::core::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; + use super::pow; + + const POS_ZERO: &[f64] = &[0.0]; + const NEG_ZERO: &[f64] = &[-0.0]; + const POS_ONE: &[f64] = &[1.0]; + const NEG_ONE: &[f64] = &[-1.0]; + const POS_FLOATS: &[f64] = &[99.0 / 70.0, E, PI]; + const NEG_FLOATS: &[f64] = &[-99.0 / 70.0, -E, -PI]; + const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), MIN_POSITIVE, EPSILON]; + const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -MIN_POSITIVE, -EPSILON]; + const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, MAX]; + const NEG_EVENS: &[f64] = &[MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; + const POS_ODDS: &[f64] = &[3.0, 7.0]; + const NEG_ODDS: &[f64] = &[-7.0, -3.0]; + const NANS: &[f64] = &[NAN]; + const POS_INF: &[f64] = &[INFINITY]; + const NEG_INF: &[f64] = &[NEG_INFINITY]; + + const ALL: &[&[f64]] = &[ + POS_ZERO, + NEG_ZERO, + NANS, + NEG_SMALL_FLOATS, + POS_SMALL_FLOATS, + NEG_FLOATS, + POS_FLOATS, + NEG_EVENS, + POS_EVENS, + NEG_ODDS, + POS_ODDS, + NEG_INF, + POS_INF, + NEG_ONE, + POS_ONE, + ]; + const POS: &[&[f64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; + const NEG: &[&[f64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; + + fn pow_test(base: f64, exponent: f64, expected: f64) { + let res = pow(base, exponent); + assert!( + if expected.is_nan() { + res.is_nan() + } else { + pow(base, exponent) == expected + }, + "{} ** {} was {} instead of {}", + base, + exponent, + res, + expected + ); + } + + fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { + sets.iter() + .for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); + } + + fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { + sets.iter() + .for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); + } + + fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { + sets.iter().for_each(|s| { + s.iter().for_each(|val| { + let exp = expected(*val); + let res = computed(*val); + + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let exp = force_eval!(exp); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let res = force_eval!(res); + assert!( + if exp.is_nan() { + res.is_nan() + } else { + exp == res + }, + "test for {} was {} instead of {}", + val, + res, + exp + ); + }) + }); + } + + #[test] + fn zero_as_exponent() { + test_sets_as_base(ALL, 0.0, 1.0); + test_sets_as_base(ALL, -0.0, 1.0); + } + + #[test] + fn one_as_base() { + test_sets_as_exponent(1.0, ALL, 1.0); + } + + #[test] + fn nan_inputs() { + // NAN as the base: + // (NAN ^ anything *but 0* should be NAN) + test_sets_as_exponent(NAN, &ALL[2..], NAN); + + // NAN as the exponent: + // (anything *but 1* ^ NAN should be NAN) + test_sets_as_base(&ALL[..(ALL.len() - 2)], NAN, NAN); + } + + #[test] + fn infinity_as_base() { + // Positive Infinity as the base: + // (+Infinity ^ positive anything but 0 and NAN should be +Infinity) + test_sets_as_exponent(INFINITY, &POS[1..], INFINITY); + + // (+Infinity ^ negative anything except 0 and NAN should be 0.0) + test_sets_as_exponent(INFINITY, &NEG[1..], 0.0); + + // Negative Infinity as the base: + // (-Infinity ^ positive odd ints should be -Infinity) + test_sets_as_exponent(NEG_INFINITY, &[POS_ODDS], NEG_INFINITY); + + // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) + // We can lump in pos/neg odd ints here because they don't seem to + // cause panics (div by zero) in release mode (I think). + test_sets(ALL, &|v: f64| pow(NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); + } + + #[test] + fn infinity_as_exponent() { + // Positive/Negative base greater than 1: + // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes NAN as the base) + test_sets_as_base(&ALL[5..(ALL.len() - 2)], INFINITY, INFINITY); + + // (pos/neg > 1 ^ -Infinity should be 0.0) + test_sets_as_base(&ALL[5..ALL.len() - 2], NEG_INFINITY, 0.0); + + // Positive/Negative base less than 1: + let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; + + // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes NAN as the base) + test_sets_as_base(base_below_one, INFINITY, 0.0); + + // (pos/neg < 1 ^ -Infinity should be Infinity) + test_sets_as_base(base_below_one, NEG_INFINITY, INFINITY); + + // Positive/Negative 1 as the base: + // (pos/neg 1 ^ Infinity should be 1) + test_sets_as_base(&[NEG_ONE, POS_ONE], INFINITY, 1.0); + + // (pos/neg 1 ^ -Infinity should be 1) + test_sets_as_base(&[NEG_ONE, POS_ONE], NEG_INFINITY, 1.0); + } + + #[test] + fn zero_as_base() { + // Positive Zero as the base: + // (+0 ^ anything positive but 0 and NAN should be +0) + test_sets_as_exponent(0.0, &POS[1..], 0.0); + + // (+0 ^ anything negative but 0 and NAN should be Infinity) + // (this should panic because we're dividing by zero) + test_sets_as_exponent(0.0, &NEG[1..], INFINITY); + + // Negative Zero as the base: + // (-0 ^ anything positive but 0, NAN, and odd ints should be +0) + test_sets_as_exponent(-0.0, &POS[3..], 0.0); + + // (-0 ^ anything negative but 0, NAN, and odd ints should be Infinity) + // (should panic because of divide by zero) + test_sets_as_exponent(-0.0, &NEG[3..], INFINITY); + + // (-0 ^ positive odd ints should be -0) + test_sets_as_exponent(-0.0, &[POS_ODDS], -0.0); + + // (-0 ^ negative odd ints should be -Infinity) + // (should panic because of divide by zero) + test_sets_as_exponent(-0.0, &[NEG_ODDS], NEG_INFINITY); + } + + #[test] + fn special_cases() { + // One as the exponent: + // (anything ^ 1 should be anything - i.e. the base) + test_sets(ALL, &|v: f64| pow(v, 1.0), &|v: f64| v); + + // Negative One as the exponent: + // (anything ^ -1 should be 1/anything) + test_sets(ALL, &|v: f64| pow(v, -1.0), &|v: f64| 1.0 / v); + + // Factoring -1 out: + // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) + (&[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS]) + .iter() + .for_each(|int_set| { + int_set.iter().for_each(|int| { + test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| { + pow(-1.0, *int) * pow(v, *int) + }); + }) + }); + + // Negative base (imaginary results): + // (-anything except 0 and Infinity ^ non-integer should be NAN) + (&NEG[1..(NEG.len() - 1)]).iter().for_each(|set| { + set.iter().for_each(|val| { + test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| NAN); + }) + }); + } + + #[test] + fn normal_cases() { + assert_eq!(pow(2.0, 20.0), (1 << 20) as f64); + assert_eq!(pow(-1.0, 9.0), -1.0); + assert!(pow(-1.0, 2.2).is_nan()); + assert!(pow(-1.0, -1.14).is_nan()); + } +} diff --git a/core/llm/math/powf.rs b/core/llm/math/powf.rs new file mode 100644 index 0000000..68d2083 --- /dev/null +++ b/core/llm/math/powf.rs @@ -0,0 +1,342 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{fabsf, scalbnf, sqrtf}; + +const BP: [f32; 2] = [1.0, 1.5]; +const DP_H: [f32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ +const DP_L: [f32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ +const TWO24: f32 = 16777216.0; /* 0x4b800000 */ +const HUGE: f32 = 1.0e30; +const TINY: f32 = 1.0e-30; +const L1: f32 = 6.0000002384e-01; /* 0x3f19999a */ +const L2: f32 = 4.2857143283e-01; /* 0x3edb6db7 */ +const L3: f32 = 3.3333334327e-01; /* 0x3eaaaaab */ +const L4: f32 = 2.7272811532e-01; /* 0x3e8ba305 */ +const L5: f32 = 2.3066075146e-01; /* 0x3e6c3255 */ +const L6: f32 = 2.0697501302e-01; /* 0x3e53f142 */ +const P1: f32 = 1.6666667163e-01; /* 0x3e2aaaab */ +const P2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const P3: f32 = 6.6137559770e-05; /* 0x388ab355 */ +const P4: f32 = -1.6533901999e-06; /* 0xb5ddea0e */ +const P5: f32 = 4.1381369442e-08; /* 0x3331bb4c */ +const LG2: f32 = 6.9314718246e-01; /* 0x3f317218 */ +const LG2_H: f32 = 6.93145752e-01; /* 0x3f317200 */ +const LG2_L: f32 = 1.42860654e-06; /* 0x35bfbe8c */ +const OVT: f32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ +const CP: f32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ +const CP_H: f32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ +const CP_L: f32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ +const IVLN2: f32 = 1.4426950216e+00; +const IVLN2_H: f32 = 1.4426879883e+00; +const IVLN2_L: f32 = 7.0526075433e-06; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn powf(x: f32, y: f32) -> f32 { + let mut z: f32; + let mut ax: f32; + let z_h: f32; + let z_l: f32; + let mut p_h: f32; + let mut p_l: f32; + let y1: f32; + let mut t1: f32; + let t2: f32; + let mut r: f32; + let s: f32; + let mut sn: f32; + let mut t: f32; + let mut u: f32; + let mut v: f32; + let mut w: f32; + let i: i32; + let mut j: i32; + let mut k: i32; + let mut yisint: i32; + let mut n: i32; + let hx: i32; + let hy: i32; + let mut ix: i32; + let iy: i32; + let mut is: i32; + + hx = x.to_bits() as i32; + hy = y.to_bits() as i32; + + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if iy == 0 { + return 1.0; + } + + /* 1**y = 1, even if y is NaN */ + if hx == 0x3f800000 { + return 1.0; + } + + /* NaN if either arg is NaN */ + if ix > 0x7f800000 || iy > 0x7f800000 { + return x + y; + } + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if hx < 0 { + if iy >= 0x4b800000 { + yisint = 2; /* even integer y */ + } else if iy >= 0x3f800000 { + k = (iy >> 23) - 0x7f; /* exponent */ + j = iy >> (23 - k); + if (j << (23 - k)) == iy { + yisint = 2 - (j & 1); + } + } + } + + /* special value of y */ + if iy == 0x7f800000 { + /* y is +-inf */ + if ix == 0x3f800000 { + /* (-1)**+-inf is 1 */ + return 1.0; + } else if ix > 0x3f800000 { + /* (|x|>1)**+-inf = inf,0 */ + return if hy >= 0 { y } else { 0.0 }; + } else { + /* (|x|<1)**+-inf = 0,inf */ + return if hy >= 0 { 0.0 } else { -y }; + } + } + if iy == 0x3f800000 { + /* y is +-1 */ + return if hy >= 0 { x } else { 1.0 / x }; + } + + if hy == 0x40000000 { + /* y is 2 */ + return x * x; + } + + if hy == 0x3f000000 + /* y is 0.5 */ + && hx >= 0 + { + /* x >= +0 */ + return sqrtf(x); + } + + ax = fabsf(x); + /* special value of x */ + if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { + /* x is +-0,+-inf,+-1 */ + z = ax; + if hy < 0 { + /* z = (1/|x|) */ + z = 1.0 / z; + } + + if hx < 0 { + if ((ix - 0x3f800000) | yisint) == 0 { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if yisint == 1 { + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + } + return z; + } + + sn = 1.0; /* sign of result */ + if hx < 0 { + if yisint == 0 { + /* (x<0)**(non-int) is NaN */ + return (x - x) / (x - x); + } + + if yisint == 1 { + /* (x<0)**(odd int) */ + sn = -1.0; + } + } + + /* |y| is HUGE */ + if iy > 0x4d000000 { + /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if ix < 0x3f7ffff8 { + return if hy < 0 { + sn * HUGE * HUGE + } else { + sn * TINY * TINY + }; + } + + if ix > 0x3f800007 { + return if hy > 0 { + sn * HUGE * HUGE + } else { + sn * TINY * TINY + }; + } + + /* now |1-x| is TINY <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1.; /* t has 20 trailing zeros */ + w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); + u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ + v = t * IVLN2_L - w * IVLN2; + t1 = u + v; + is = t1.to_bits() as i32; + t1 = f32::from_bits(is as u32 & 0xfffff000); + t2 = v - (t1 - u); + } else { + let mut s2: f32; + let mut s_h: f32; + let s_l: f32; + let mut t_h: f32; + let mut t_l: f32; + + n = 0; + /* take care subnormal number */ + if ix < 0x00800000 { + ax *= TWO24; + n -= 24; + ix = ax.to_bits() as i32; + } + n += ((ix) >> 23) - 0x7f; + j = ix & 0x007fffff; + /* determine interval */ + ix = j | 0x3f800000; /* normalize ix */ + if j <= 0x1cc471 { + /* |x|> 1) & 0xfffff000) | 0x20000000) as i32; + t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); + t_l = ax - (t_h - i!(BP, k as usize)); + s_l = v * ((u - s_h * t_h) - s_h * t_l); + /* compute log(ax) */ + s2 = s * s; + r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); + r += s_l * (s_h + s); + s2 = s_h * s_h; + t_h = 3.0 + s2 + r; + is = t_h.to_bits() as i32; + t_h = f32::from_bits(is as u32 & 0xfffff000); + t_l = r - ((t_h - 3.0) - s2); + /* u+v = s*(1+...) */ + u = s_h * t_h; + v = s_l * t_h + t_l * s; + /* 2/(3log2)*(s+...) */ + p_h = u + v; + is = p_h.to_bits() as i32; + p_h = f32::from_bits(is as u32 & 0xfffff000); + p_l = v - (p_h - u); + z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = n as f32; + t1 = ((z_h + z_l) + i!(DP_H, k as usize)) + t; + is = t1.to_bits() as i32; + t1 = f32::from_bits(is as u32 & 0xfffff000); + t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); + }; + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + is = y.to_bits() as i32; + y1 = f32::from_bits(is as u32 & 0xfffff000); + p_l = (y - y1) * t1 + y * t2; + p_h = y1 * t1; + z = p_l + p_h; + j = z.to_bits() as i32; + if j > 0x43000000 { + /* if z > 128 */ + return sn * HUGE * HUGE; /* overflow */ + } else if j == 0x43000000 { + /* if z == 128 */ + if p_l + OVT > z - p_h { + return sn * HUGE * HUGE; /* overflow */ + } + } else if (j & 0x7fffffff) > 0x43160000 { + /* z < -150 */ + // FIXME: check should be (uint32_t)j > 0xc3160000 + return sn * TINY * TINY; /* underflow */ + } else if j as u32 == 0xc3160000 + /* z == -150 */ + && p_l <= z - p_h + { + return sn * TINY * TINY; /* underflow */ + } + + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i >> 23) - 0x7f; + n = 0; + if i > 0x3f000000 { + /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00800000 >> (k + 1)); + k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */ + t = f32::from_bits(n as u32 & !(0x007fffff >> k)); + n = ((n & 0x007fffff) | 0x00800000) >> (23 - k); + if j < 0 { + n = -n; + } + p_h -= t; + } + t = p_l + p_h; + is = t.to_bits() as i32; + t = f32::from_bits(is as u32 & 0xffff8000); + u = t * LG2_H; + v = (p_l - (t - p_h)) * LG2 + t * LG2_L; + z = u + v; + w = v - (z - u); + t = z * z; + t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + r = (z * t1) / (t1 - 2.0) - (w + z * w); + z = 1.0 - (r - z); + j = z.to_bits() as i32; + j += n << 23; + if (j >> 23) <= 0 { + /* subnormal output */ + z = scalbnf(z, n); + } else { + z = f32::from_bits(j as u32); + } + sn * z +} diff --git a/core/llm/math/rem_pio2.rs b/core/llm/math/rem_pio2.rs new file mode 100644 index 0000000..644616f --- /dev/null +++ b/core/llm/math/rem_pio2.rs @@ -0,0 +1,233 @@ +// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== +// +// Optimized by Bruce D. Evans. */ +use super::rem_pio2_large; + +// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +// #define EPS DBL_EPSILON +const EPS: f64 = 2.2204460492503131e-16; +// #elif FLT_EVAL_METHOD==2 +// #define EPS LDBL_EPSILON +// #endif + +// TODO: Support FLT_EVAL_METHOD? + +const TO_INT: f64 = 1.5 / EPS; +/// 53 bits of 2/pi +const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +/// first 33 bits of pi/2 +const PIO2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ +/// pi/2 - PIO2_1 +const PIO2_1T: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ +/// second 33 bits of pi/2 +const PIO2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ +/// pi/2 - (PIO2_1+PIO2_2) +const PIO2_2T: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ +/// third 33 bits of pi/2 +const PIO2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ +/// pi/2 - (PIO2_1+PIO2_2+PIO2_3) +const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +// return the remainder of x rem pi/2 in y[0]+y[1] +// use rem_pio2_large() for large x +// +// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { + let x1p24 = f64::from_bits(0x4170000000000000); + + let sign = (f64::to_bits(x) >> 63) as i32; + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + fn medium(x: f64, ix: u32) -> (i32, f64, f64) { + /* rint(x/(pi/2)), Assume round-to-nearest. */ + let tmp = x as f64 * INV_PIO2 + TO_INT; + // force rounding of tmp to it's storage format on x87 to avoid + // excess precision issues. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let tmp = force_eval!(tmp); + let f_n = tmp - TO_INT; + let n = f_n as i32; + let mut r = x - f_n * PIO2_1; + let mut w = f_n * PIO2_1T; /* 1st round, good to 85 bits */ + let mut y0 = r - w; + let ui = f64::to_bits(y0); + let ey = (ui >> 52) as i32 & 0x7ff; + let ex = (ix >> 20) as i32; + if ex - ey > 16 { + /* 2nd round, good to 118 bits */ + let t = r; + w = f_n * PIO2_2; + r = t - w; + w = f_n * PIO2_2T - ((t - r) - w); + y0 = r - w; + let ey = (f64::to_bits(y0) >> 52) as i32 & 0x7ff; + if ex - ey > 49 { + /* 3rd round, good to 151 bits, covers all cases */ + let t = r; + w = f_n * PIO2_3; + r = t - w; + w = f_n * PIO2_3T - ((t - r) - w); + y0 = r - w; + } + } + let y1 = (r - y0) - w; + (n, y0, y1) + } + + if ix <= 0x400f6a7a { + /* |x| ~<= 5pi/4 */ + if (ix & 0xfffff) == 0x921fb { + /* |x| ~= pi/2 or 2pi/2 */ + return medium(x, ix); /* cancellation -- use medium case */ + } + if ix <= 0x4002d97c { + /* |x| ~<= 3pi/4 */ + if sign == 0 { + let z = x - PIO2_1; /* one round good to 85 bits */ + let y0 = z - PIO2_1T; + let y1 = (z - y0) - PIO2_1T; + return (1, y0, y1); + } else { + let z = x + PIO2_1; + let y0 = z + PIO2_1T; + let y1 = (z - y0) + PIO2_1T; + return (-1, y0, y1); + } + } else if sign == 0 { + let z = x - 2.0 * PIO2_1; + let y0 = z - 2.0 * PIO2_1T; + let y1 = (z - y0) - 2.0 * PIO2_1T; + return (2, y0, y1); + } else { + let z = x + 2.0 * PIO2_1; + let y0 = z + 2.0 * PIO2_1T; + let y1 = (z - y0) + 2.0 * PIO2_1T; + return (-2, y0, y1); + } + } + if ix <= 0x401c463b { + /* |x| ~<= 9pi/4 */ + if ix <= 0x4015fdbc { + /* |x| ~<= 7pi/4 */ + if ix == 0x4012d97c { + /* |x| ~= 3pi/2 */ + return medium(x, ix); + } + if sign == 0 { + let z = x - 3.0 * PIO2_1; + let y0 = z - 3.0 * PIO2_1T; + let y1 = (z - y0) - 3.0 * PIO2_1T; + return (3, y0, y1); + } else { + let z = x + 3.0 * PIO2_1; + let y0 = z + 3.0 * PIO2_1T; + let y1 = (z - y0) + 3.0 * PIO2_1T; + return (-3, y0, y1); + } + } else { + if ix == 0x401921fb { + /* |x| ~= 4pi/2 */ + return medium(x, ix); + } + if sign == 0 { + let z = x - 4.0 * PIO2_1; + let y0 = z - 4.0 * PIO2_1T; + let y1 = (z - y0) - 4.0 * PIO2_1T; + return (4, y0, y1); + } else { + let z = x + 4.0 * PIO2_1; + let y0 = z + 4.0 * PIO2_1T; + let y1 = (z - y0) + 4.0 * PIO2_1T; + return (-4, y0, y1); + } + } + } + if ix < 0x413921fb { + /* |x| ~< 2^20*(pi/2), medium size */ + return medium(x, ix); + } + /* + * all other (large) arguments + */ + if ix >= 0x7ff00000 { + /* x is inf or NaN */ + let y0 = x - x; + let y1 = y0; + return (0, y0, y1); + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + let mut ui = f64::to_bits(x); + ui &= (!1) >> 12; + ui |= (0x3ff + 23) << 52; + let mut z = f64::from_bits(ui); + let mut tx = [0.0; 3]; + for i in 0..2 { + i!(tx,i, =, z as i32 as f64); + z = (z - i!(tx, i)) * x1p24; + } + i!(tx,2, =, z); + /* skip zero terms, first term is non-zero */ + let mut i = 2; + while i != 0 && i!(tx, i) == 0.0 { + i -= 1; + } + let mut ty = [0.0; 3]; + let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1); + if sign != 0 { + return (-n, -i!(ty, 0), -i!(ty, 1)); + } + (n, i!(ty, 0), i!(ty, 1)) +} + +#[cfg(test)] +mod tests { + use super::rem_pio2; + + #[test] + fn test_near_pi() { + let arg = 3.141592025756836; + let arg = force_eval!(arg); + assert_eq!( + rem_pio2(arg), + (2, -6.278329573009626e-7, -2.1125998133974653e-23) + ); + let arg = 3.141592033207416; + let arg = force_eval!(arg); + assert_eq!( + rem_pio2(arg), + (2, -6.20382377148128e-7, -2.1125998133974653e-23) + ); + let arg = 3.141592144966125; + let arg = force_eval!(arg); + assert_eq!( + rem_pio2(arg), + (2, -5.086236681942706e-7, -2.1125998133974653e-23) + ); + let arg = 3.141592979431152; + let arg = force_eval!(arg); + assert_eq!( + rem_pio2(arg), + (2, 3.2584135866119817e-7, -2.1125998133974653e-23) + ); + } + + #[test] + fn test_overflow_b9b847() { + let _ = rem_pio2(-3054214.5490637687); + } + + #[test] + fn test_overflow_4747b9() { + let _ = rem_pio2(917340800458.2274); + } +} diff --git a/core/llm/math/rem_pio2_large.rs b/core/llm/math/rem_pio2_large.rs new file mode 100644 index 0000000..db97a39 --- /dev/null +++ b/core/llm/math/rem_pio2_large.rs @@ -0,0 +1,470 @@ +#![allow(unused_unsafe)] +/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::floor; +use super::scalbn; + +// initial value for jk +const INIT_JK: [usize; 4] = [3, 4, 4, 6]; + +// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi +// +// integer array, contains the (24*i)-th to (24*i+23)-th +// bit of 2/pi after binary point. The corresponding +// floating value is +// +// ipio2[i] * 2^(-24(i+1)). +// +// NB: This table must have at least (e0-3)/24 + jk terms. +// For quad precision (e0 <= 16360, jk = 6), this is 686. +#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] +const IPIO2: [i32; 66] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, + 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, + 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, + 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, + 0x73A8C9, 0x60E27B, 0xC08C6B, +]; + +#[cfg(target_pointer_width = "64")] +const IPIO2: [i32; 690] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, + 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, + 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, + 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, + 0x73A8C9, 0x60E27B, 0xC08C6B, 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, + 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, 0xDE4F98, 0x327DBB, 0xC33D26, + 0xEF6B1E, 0x5EF89F, 0x3A1F35, 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, + 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, 0x467D86, 0x2D71E3, 0x9AC69B, + 0x006233, 0x7CD2B4, 0x97A7B4, 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, + 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, 0xCB2324, 0x778AD6, 0x23545A, + 0xB91F00, 0x1B0AF1, 0xDFCE19, 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, + 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, 0xDE3B58, 0x929BDE, 0x2822D2, + 0xE88628, 0x4D58E2, 0x32CAC6, 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, + 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, 0xD36710, 0xD8DDAA, 0x425FAE, + 0xCE616A, 0xA4280A, 0xB499D3, 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, + 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, 0x36D9CA, 0xD2A828, 0x8D61C2, + 0x77C912, 0x142604, 0x9B4612, 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, + 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, 0xC3E7B3, 0x28F8C7, 0x940593, + 0x3E71C1, 0xB3092E, 0xF3450B, 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, + 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, 0x9794E8, 0x84E6E2, 0x973199, + 0x6BED88, 0x365F5F, 0x0EFDBB, 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, + 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, 0x90AA47, 0x02E774, 0x24D6BD, + 0xA67DF7, 0x72486E, 0xEF169F, 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, + 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, 0x10D86D, 0x324832, 0x754C5B, + 0xD4714E, 0x6E5445, 0xC1090B, 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, + 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, 0x6AE290, 0x89D988, 0x50722C, + 0xBEA404, 0x940777, 0x7030F3, 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, + 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, 0x3BDF08, 0x2B3715, 0xA0805C, + 0x93805A, 0x921110, 0xD8E80F, 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, + 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, 0xAA140A, 0x2F2689, 0x768364, + 0x333B09, 0x1A940E, 0xAA3A51, 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, + 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, 0x5BC3D8, 0xC492F5, 0x4BADC6, + 0xA5CA4E, 0xCD37A7, 0x36A9E6, 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, + 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, 0x306529, 0xBF5657, 0x3AFF47, + 0xB9F96A, 0xF3BE75, 0xDF9328, 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, + 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, 0xA8654F, 0xA5C1D2, 0x0F3F0B, + 0xCD785B, 0x76F923, 0x048B7B, 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, + 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, 0xDA4886, 0xA05DF7, 0xF480C6, + 0x2FF0AC, 0x9AECDD, 0xBC5C3F, 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, + 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, 0x2A1216, 0x2DB7DC, 0xFDE5FA, + 0xFEDB89, 0xFDBE89, 0x6C76E4, 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, + 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, 0x48D784, 0x16DF30, 0x432DC7, + 0x356125, 0xCE70C9, 0xB8CB30, 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, + 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, 0xC4F133, 0x5F6E13, 0xE4305D, + 0xA92E85, 0xC3B21D, 0x3632A1, 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, + 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, 0xCBDA11, 0xD0BE7D, 0xC1DB9B, + 0xBD17AB, 0x81A2CA, 0x5C6A08, 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, + 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, 0x4F6A68, 0xA82A4A, 0x5AC44F, + 0xBCF82D, 0x985AD7, 0x95C7F4, 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, + 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, 0xD0C0B2, 0x485551, 0x0EFB1E, + 0xC37295, 0x3B06A3, 0x3540C0, 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, + 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, 0x3C3ABA, 0x461846, 0x5F7555, + 0xF5BDD2, 0xC6926E, 0x5D2EAC, 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, + 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, 0x745D7C, 0xB2AD6B, 0x9D6ECD, + 0x7B723E, 0x6A11C6, 0xA9CFF7, 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, + 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, 0xBEFDFD, 0xEF4556, 0x367ED9, + 0x13D9EC, 0xB9BA8B, 0xFC97C4, 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, + 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, 0x9C2A3E, 0xCC5F11, 0x4A0BFD, + 0xFBF4E1, 0x6D3B8E, 0x2C86E2, 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, + 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, 0xCC2254, 0xDC552A, 0xD6C6C0, + 0x96190B, 0xB8701A, 0x649569, 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, + 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, 0x9B5861, 0xBC57E1, 0xC68351, + 0x103ED8, 0x4871DD, 0xDD1C2D, 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, + 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, 0x382682, 0x9BE7CA, 0xA40D51, + 0xB13399, 0x0ED7A9, 0x480569, 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, + 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, 0x5FD45E, 0xA4677B, 0x7AACBA, + 0xA2F655, 0x23882B, 0x55BA41, 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, + 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, 0xAE5ADB, 0x86C547, 0x624385, + 0x3B8621, 0x94792C, 0x876110, 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, + 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, 0xB1933D, 0x0B7CBD, 0xDC51A4, + 0x63DD27, 0xDDE169, 0x19949A, 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, + 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, 0x4D7E6F, 0x5119A5, 0xABF9B5, + 0xD6DF82, 0x61DD96, 0x023616, 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, + 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, +]; + +const PIO2: [f64; 8] = [ + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +]; + +// fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 +// +// Input parameters: +// x[] The input value (must be positive) is broken into nx +// pieces of 24-bit integers in double precision format. +// x[i] will be the i-th 24 bit of x. The scaled exponent +// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 +// match x's up to 24 bits. +// +// Example of breaking a double positive z into x[0]+x[1]+x[2]: +// e0 = ilogb(z)-23 +// z = scalbn(z,-e0) +// for i = 0,1,2 +// x[i] = floor(z) +// z = (z-x[i])*2**24 +// +// y[] ouput result in an array of double precision numbers. +// The dimension of y[] is: +// 24-bit precision 1 +// 53-bit precision 2 +// 64-bit precision 2 +// 113-bit precision 3 +// The actual value is the sum of them. Thus for 113-bit +// precison, one may have to do something like: +// +// long double t,w,r_head, r_tail; +// t = (long double)y[2] + (long double)y[1]; +// w = (long double)y[0]; +// r_head = t+w; +// r_tail = w - (r_head - t); +// +// e0 The exponent of x[0]. Must be <= 16360 or you need to +// expand the ipio2 table. +// +// prec an integer indicating the precision: +// 0 24 bits (single) +// 1 53 bits (double) +// 2 64 bits (extended) +// 3 113 bits (quad) +// +// Here is the description of some local variables: +// +// jk jk+1 is the initial number of terms of ipio2[] needed +// in the computation. The minimum and recommended value +// for jk is 3,4,4,6 for single, double, extended, and quad. +// jk+1 must be 2 larger than you might expect so that our +// recomputation test works. (Up to 24 bits in the integer +// part (the 24 bits of it that we compute) and 23 bits in +// the fraction part may be lost to cancelation before we +// recompute.) +// +// jz local integer variable indicating the number of +// terms of ipio2[] used. +// +// jx nx - 1 +// +// jv index for pointing to the suitable ipio2[] for the +// computation. In general, we want +// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 +// is an integer. Thus +// e0-3-24*jv >= 0 or (e0-3)/24 >= jv +// Hence jv = max(0,(e0-3)/24). +// +// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. +// +// q[] double array with integral value, representing the +// 24-bits chunk of the product of x and 2/pi. +// +// q0 the corresponding exponent of q[0]. Note that the +// exponent for q[i] would be q0-24*i. +// +// PIo2[] double precision array, obtained by cutting pi/2 +// into 24 bits chunks. +// +// f[] ipio2[] in floating point +// +// iq[] integer array by breaking up q[] in 24-bits chunk. +// +// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] +// +// ih integer. If >0 it indicates q[] is >= 0.5, hence +// it also indicates the *sign* of the result. + +/// Return the last three digits of N with y = x - N*pi/2 +/// so that |y| < pi/2. +/// +/// The method is to compute the integer (mod 8) and fraction parts of +/// (2/pi)*x without doing the full multiplication. In general we +/// skip the part of the product that are known to be a huge integer ( +/// more accurately, = 0 mod 8 ). Thus the number of operations are +/// independent of the exponent of the input. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { + let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 + let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) + + #[cfg(all(target_pointer_width = "64", feature = "checked"))] + assert!(e0 <= 16360); + + let nx = x.len(); + + let mut fw: f64; + let mut n: i32; + let mut ih: i32; + let mut z: f64; + let mut f: [f64; 20] = [0.; 20]; + let mut fq: [f64; 20] = [0.; 20]; + let mut q: [f64; 20] = [0.; 20]; + let mut iq: [i32; 20] = [0; 20]; + + /* initialize jk*/ + let jk = i!(INIT_JK, prec); + let jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + let jx = nx - 1; + let mut jv = div!(e0 - 3, 24); + if jv < 0 { + jv = 0; + } + let mut q0 = e0 - 24 * (jv + 1); + let jv = jv as usize; + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + let mut j = (jv as i32) - (jx as i32); + let m = jx + jk; + for i in 0..=m { + i!(f, i, =, if j < 0 { + 0. + } else { + i!(IPIO2, j as usize) as f64 + }); + j += 1; + } + + /* compute q[0],q[1],...q[jk] */ + for i in 0..=jk { + fw = 0f64; + for j in 0..=jx { + fw += i!(x, j) * i!(f, jx + i - j); + } + i!(q, i, =, fw); + } + + let mut jz = jk; + + 'recompute: loop { + /* distill q[] into iq[] reversingly */ + let mut i = 0i32; + z = i!(q, jz); + for j in (1..=jz).rev() { + fw = (x1p_24 * z) as i32 as f64; + i!(iq, i as usize, =, (z - x1p24 * fw) as i32); + z = i!(q, j - 1) + fw; + i += 1; + } + + /* compute n */ + z = scalbn(z, q0); /* actual value of z */ + z -= 8.0 * floor(z * 0.125); /* trim off integer >= 8 */ + n = z as i32; + z -= n as f64; + ih = 0; + if q0 > 0 { + /* need iq[jz-1] to determine n */ + i = i!(iq, jz - 1) >> (24 - q0); + n += i; + i!(iq, jz - 1, -=, i << (24 - q0)); + ih = i!(iq, jz - 1) >> (23 - q0); + } else if q0 == 0 { + ih = i!(iq, jz - 1) >> 23; + } else if z >= 0.5 { + ih = 2; + } + + if ih > 0 { + /* q > 0.5 */ + n += 1; + let mut carry = 0i32; + for i in 0..jz { + /* compute 1-q */ + let j = i!(iq, i); + if carry == 0 { + if j != 0 { + carry = 1; + i!(iq, i, =, 0x1000000 - j); + } + } else { + i!(iq, i, =, 0xffffff - j); + } + } + if q0 > 0 { + /* rare case: chance is 1 in 12 */ + match q0 { + 1 => { + i!(iq, jz - 1, &=, 0x7fffff); + } + 2 => { + i!(iq, jz - 1, &=, 0x3fffff); + } + _ => {} + } + } + if ih == 2 { + z = 1. - z; + if carry != 0 { + z -= scalbn(1., q0); + } + } + } + + /* check if recomputation is needed */ + if z == 0. { + let mut j = 0; + for i in (jk..=jz - 1).rev() { + j |= i!(iq, i); + } + if j == 0 { + /* need recomputation */ + let mut k = 1; + while i!(iq, jk - k, ==, 0) { + k += 1; /* k = no. of terms needed */ + } + + for i in (jz + 1)..=(jz + k) { + /* add q[jz+1] to q[jz+k] */ + i!(f, jx + i, =, i!(IPIO2, jv + i) as f64); + fw = 0f64; + for j in 0..=jx { + fw += i!(x, j) * i!(f, jx + i - j); + } + i!(q, i, =, fw); + } + jz += k; + continue 'recompute; + } + } + + break; + } + + /* chop off zero terms */ + if z == 0. { + jz -= 1; + q0 -= 24; + while i!(iq, jz) == 0 { + jz -= 1; + q0 -= 24; + } + } else { + /* break z into 24-bit if necessary */ + z = scalbn(z, -q0); + if z >= x1p24 { + fw = (x1p_24 * z) as i32 as f64; + i!(iq, jz, =, (z - x1p24 * fw) as i32); + jz += 1; + q0 += 24; + i!(iq, jz, =, fw as i32); + } else { + i!(iq, jz, =, z as i32); + } + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(1., q0); + for i in (0..=jz).rev() { + i!(q, i, =, fw * (i!(iq, i) as f64)); + fw *= x1p_24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for i in (0..=jz).rev() { + fw = 0f64; + let mut k = 0; + while (k <= jp) && (k <= jz - i) { + fw += i!(PIO2, k) * i!(q, i + k); + k += 1; + } + i!(fq, jz - i, =, fw); + } + + /* compress fq[] into y[] */ + match prec { + 0 => { + fw = 0f64; + for i in (0..=jz).rev() { + fw += i!(fq, i); + } + i!(y, 0, =, if ih == 0 { fw } else { -fw }); + } + 1 | 2 => { + fw = 0f64; + for i in (0..=jz).rev() { + fw += i!(fq, i); + } + // TODO: drop excess precision here once double_t is used + fw = fw as f64; + i!(y, 0, =, if ih == 0 { fw } else { -fw }); + fw = i!(fq, 0) - fw; + for i in 1..=jz { + fw += i!(fq, i); + } + i!(y, 1, =, if ih == 0 { fw } else { -fw }); + } + 3 => { + /* painful */ + for i in (1..=jz).rev() { + fw = i!(fq, i - 1) + i!(fq, i); + i!(fq, i, +=, i!(fq, i - 1) - fw); + i!(fq, i - 1, =, fw); + } + for i in (2..=jz).rev() { + fw = i!(fq, i - 1) + i!(fq, i); + i!(fq, i, +=, i!(fq, i - 1) - fw); + i!(fq, i - 1, =, fw); + } + fw = 0f64; + for i in (2..=jz).rev() { + fw += i!(fq, i); + } + if ih == 0 { + i!(y, 0, =, i!(fq, 0)); + i!(y, 1, =, i!(fq, 1)); + i!(y, 2, =, fw); + } else { + i!(y, 0, =, -i!(fq, 0)); + i!(y, 1, =, -i!(fq, 1)); + i!(y, 2, =, -fw); + } + } + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => {} + } + n & 7 +} diff --git a/core/llm/math/rem_pio2f.rs b/core/llm/math/rem_pio2f.rs new file mode 100644 index 0000000..775f5d7 --- /dev/null +++ b/core/llm/math/rem_pio2f.rs @@ -0,0 +1,67 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::rem_pio2_large; + +use core::f64; + +const TOINT: f64 = 1.5 / f64::EPSILON; + +/// 53 bits of 2/pi +const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +/// first 25 bits of pi/2 +const PIO2_1: f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ +/// pi/2 - pio2_1 +const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + +/// Return the remainder of x rem pi/2 in *y +/// +/// use double precision for everything except passing x +/// use __rem_pio2_large() for large x +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { + let x64 = x as f64; + + let mut tx: [f64; 1] = [0.]; + let mut ty: [f64; 1] = [0.]; + + let ix = x.to_bits() & 0x7fffffff; + /* 25+53 bit pi is good enough for medium size */ + if ix < 0x4dc90fdb { + /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + let tmp = x64 * INV_PIO2 + TOINT; + // force rounding of tmp to it's storage format on x87 to avoid + // excess precision issues. + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let tmp = force_eval!(tmp); + let f_n = tmp - TOINT; + return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); + } + if ix >= 0x7f800000 { + /* x is inf or NaN */ + return (0, x64 - x64); + } + /* scale x into [2^23, 2^24-1] */ + let sign = (x.to_bits() >> 31) != 0; + let e0 = ((ix >> 23) - (0x7f + 23)) as i32; /* e0 = ilogb(|x|)-23, positive */ + tx[0] = f32::from_bits(ix - (e0 << 23) as u32) as f64; + let n = rem_pio2_large(&tx, &mut ty, e0, 0); + if sign { + return (-n, -ty[0]); + } + (n, ty[0]) +} diff --git a/core/llm/math/remainder.rs b/core/llm/math/remainder.rs new file mode 100644 index 0000000..9e966c9 --- /dev/null +++ b/core/llm/math/remainder.rs @@ -0,0 +1,5 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remainder(x: f64, y: f64) -> f64 { + let (result, _) = super::remquo(x, y); + result +} diff --git a/core/llm/math/remainderf.rs b/core/llm/math/remainderf.rs new file mode 100644 index 0000000..b1407cf --- /dev/null +++ b/core/llm/math/remainderf.rs @@ -0,0 +1,5 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remainderf(x: f32, y: f32) -> f32 { + let (result, _) = super::remquof(x, y); + result +} diff --git a/core/llm/math/remquo.rs b/core/llm/math/remquo.rs new file mode 100644 index 0000000..0afd1f7 --- /dev/null +++ b/core/llm/math/remquo.rs @@ -0,0 +1,110 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { + let ux: u64 = x.to_bits(); + let mut uy: u64 = y.to_bits(); + let mut ex = ((ux >> 52) & 0x7ff) as i32; + let mut ey = ((uy >> 52) & 0x7ff) as i32; + let sx = (ux >> 63) != 0; + let sy = (uy >> 63) != 0; + let mut q: u32; + let mut i: u64; + let mut uxi: u64 = ux; + + if (uy << 1) == 0 || y.is_nan() || ex == 0x7ff { + return ((x * y) / (x * y), 0); + } + if (ux << 1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 12; + while (i >> 63) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 12; + uxi |= 1 << 52; + } + if ey == 0 { + i = uy << 12; + while (i >> 63) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 12; + uy |= 1 << 52; + } + + q = 0; + + if ex + 1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi.wrapping_sub(uy); + if (i >> 63) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi.wrapping_sub(uy); + if (i >> 63) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -60; + } else { + while (uxi >> 52) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 52; + uxi |= (ex as u64) << 52; + } else { + uxi >>= -ex + 1; + } + x = f64::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { + x -= y; + // TODO: this matches musl behavior, but it is incorrect + q = q.wrapping_add(1); + } + q &= 0x7fffffff; + let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; + if sx { + (-x, quo) + } else { + (x, quo) + } +} + +#[cfg(test)] +mod tests { + use super::remquo; + + #[test] + fn test_q_overflow() { + // 0xc000000000000001, 0x04c0000000000004 + let _ = remquo(-2.0000000000000004, 8.406091369059082e-286); + } +} diff --git a/core/llm/math/remquof.rs b/core/llm/math/remquof.rs new file mode 100644 index 0000000..d71bd38 --- /dev/null +++ b/core/llm/math/remquof.rs @@ -0,0 +1,97 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { + let ux: u32 = x.to_bits(); + let mut uy: u32 = y.to_bits(); + let mut ex = ((ux >> 23) & 0xff) as i32; + let mut ey = ((uy >> 23) & 0xff) as i32; + let sx = (ux >> 31) != 0; + let sy = (uy >> 31) != 0; + let mut q: u32; + let mut i: u32; + let mut uxi: u32 = ux; + + if (uy << 1) == 0 || y.is_nan() || ex == 0xff { + return ((x * y) / (x * y), 0); + } + if (ux << 1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 9; + while (i >> 31) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 9; + uxi |= 1 << 23; + } + if ey == 0 { + i = uy << 9; + while (i >> 31) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 9; + uy |= 1 << 23; + } + + q = 0; + if ex + 1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi.wrapping_sub(uy); + if (i >> 31) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi.wrapping_sub(uy); + if (i >> 31) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -30; + } else { + while (uxi >> 23) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 23; + uxi |= (ex as u32) << 23; + } else { + uxi >>= -ex + 1; + } + x = f32::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { + x -= y; + q += 1; + } + q &= 0x7fffffff; + let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; + if sx { + (-x, quo) + } else { + (x, quo) + } +} diff --git a/core/llm/math/rint.rs b/core/llm/math/rint.rs new file mode 100644 index 0000000..8edbe34 --- /dev/null +++ b/core/llm/math/rint.rs @@ -0,0 +1,58 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rint(x: f64) -> f64 { + let one_over_e = 1.0 / f64::EPSILON; + let as_u64: u64 = x.to_bits(); + let exponent: u64 = as_u64 >> 52 & 0x7ff; + let is_positive = (as_u64 >> 63) == 0; + if exponent >= 0x3ff + 52 { + x + } else { + let ans = if is_positive { + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let x = force_eval!(x); + let xplusoneovere = x + one_over_e; + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let xplusoneovere = force_eval!(xplusoneovere); + xplusoneovere - one_over_e + } else { + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let x = force_eval!(x); + let xminusoneovere = x - one_over_e; + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let xminusoneovere = force_eval!(xminusoneovere); + xminusoneovere + one_over_e + }; + + if ans == 0.0 { + if is_positive { + 0.0 + } else { + -0.0 + } + } else { + ans + } + } +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::rint; + + #[test] + fn negative_zero() { + assert_eq!(rint(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); + } + + #[test] + fn sanity_check() { + assert_eq!(rint(-1.0), -1.0); + assert_eq!(rint(2.8), 3.0); + assert_eq!(rint(-0.5), -0.0); + assert_eq!(rint(0.5), 0.0); + assert_eq!(rint(-1.5), -2.0); + assert_eq!(rint(1.5), 2.0); + } +} diff --git a/core/llm/math/rintf.rs b/core/llm/math/rintf.rs new file mode 100644 index 0000000..7a7da61 --- /dev/null +++ b/core/llm/math/rintf.rs @@ -0,0 +1,58 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf(x: f32) -> f32 { + let one_over_e = 1.0 / f32::EPSILON; + let as_u32: u32 = x.to_bits(); + let exponent: u32 = as_u32 >> 23 & 0xff; + let is_positive = (as_u32 >> 31) == 0; + if exponent >= 0x7f + 23 { + x + } else { + let ans = if is_positive { + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let x = force_eval!(x); + let xplusoneovere = x + one_over_e; + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let xplusoneovere = force_eval!(xplusoneovere); + xplusoneovere - one_over_e + } else { + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let x = force_eval!(x); + let xminusoneovere = x - one_over_e; + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let xminusoneovere = force_eval!(xminusoneovere); + xminusoneovere + one_over_e + }; + + if ans == 0.0 { + if is_positive { + 0.0 + } else { + -0.0 + } + } else { + ans + } + } +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::rintf; + + #[test] + fn negative_zero() { + assert_eq!(rintf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); + } + + #[test] + fn sanity_check() { + assert_eq!(rintf(-1.0), -1.0); + assert_eq!(rintf(2.8), 3.0); + assert_eq!(rintf(-0.5), -0.0); + assert_eq!(rintf(0.5), 0.0); + assert_eq!(rintf(-1.5), -2.0); + assert_eq!(rintf(1.5), 2.0); + } +} diff --git a/core/llm/math/round.rs b/core/llm/math/round.rs new file mode 100644 index 0000000..46fabc9 --- /dev/null +++ b/core/llm/math/round.rs @@ -0,0 +1,28 @@ +use super::copysign; +use super::trunc; +use core::f64; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn round(x: f64) -> f64 { + trunc(x + copysign(0.5 - 0.25 * f64::EPSILON, x)) +} + +#[cfg(test)] +mod tests { + use super::round; + + #[test] + fn negative_zero() { + assert_eq!(round(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); + } + + #[test] + fn sanity_check() { + assert_eq!(round(-1.0), -1.0); + assert_eq!(round(2.8), 3.0); + assert_eq!(round(-0.5), -1.0); + assert_eq!(round(0.5), 1.0); + assert_eq!(round(-1.5), -2.0); + assert_eq!(round(1.5), 2.0); + } +} diff --git a/core/llm/math/roundf.rs b/core/llm/math/roundf.rs new file mode 100644 index 0000000..becdb56 --- /dev/null +++ b/core/llm/math/roundf.rs @@ -0,0 +1,30 @@ +use super::copysignf; +use super::truncf; +use core::f32; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf(x: f32) -> f32 { + truncf(x + copysignf(0.5 - 0.25 * f32::EPSILON, x)) +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::roundf; + + #[test] + fn negative_zero() { + assert_eq!(roundf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); + } + + #[test] + fn sanity_check() { + assert_eq!(roundf(-1.0), -1.0); + assert_eq!(roundf(2.8), 3.0); + assert_eq!(roundf(-0.5), -1.0); + assert_eq!(roundf(0.5), 1.0); + assert_eq!(roundf(-1.5), -2.0); + assert_eq!(roundf(1.5), 2.0); + } +} diff --git a/core/llm/math/scalbn.rs b/core/llm/math/scalbn.rs new file mode 100644 index 0000000..00c455a --- /dev/null +++ b/core/llm/math/scalbn.rs @@ -0,0 +1,33 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbn(x: f64, mut n: i32) -> f64 { + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 + let x1p53 = f64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 + let x1p_1022 = f64::from_bits(0x0010000000000000); // 0x1p-1022 === 2 ^ (-1022) + + let mut y = x; + + if n > 1023 { + y *= x1p1023; + n -= 1023; + if n > 1023 { + y *= x1p1023; + n -= 1023; + if n > 1023 { + n = 1023; + } + } + } else if n < -1022 { + /* make sure final n < -53 to avoid double + rounding in the subnormal range */ + y *= x1p_1022 * x1p53; + n += 1022 - 53; + if n < -1022 { + y *= x1p_1022 * x1p53; + n += 1022 - 53; + if n < -1022 { + n = -1022; + } + } + } + y * f64::from_bits(((0x3ff + n) as u64) << 52) +} diff --git a/core/llm/math/scalbnf.rs b/core/llm/math/scalbnf.rs new file mode 100644 index 0000000..73f4bb5 --- /dev/null +++ b/core/llm/math/scalbnf.rs @@ -0,0 +1,29 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 + let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 + + if n > 127 { + x *= x1p127; + n -= 127; + if n > 127 { + x *= x1p127; + n -= 127; + if n > 127 { + n = 127; + } + } + } else if n < -126 { + x *= x1p_126 * x1p24; + n += 126 - 24; + if n < -126 { + x *= x1p_126 * x1p24; + n += 126 - 24; + if n < -126 { + n = -126; + } + } + } + x * f32::from_bits(((0x7f + n) as u32) << 23) +} diff --git a/core/llm/math/sin.rs b/core/llm/math/sin.rs new file mode 100644 index 0000000..a53843d --- /dev/null +++ b/core/llm/math/sin.rs @@ -0,0 +1,88 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +use super::{k_cos, k_sin, rem_pio2}; + +// sin(x) +// Return sine function of x. +// +// kernel function: +// k_sin ... sine function on [-pi/4,pi/4] +// k_cos ... cose function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sin(x: f64) -> f64 { + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 + + /* High word of x. */ + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e500000 { + /* |x| < 2**-26 */ + /* raise inexact if x != 0 and underflow if subnormal*/ + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return x; + } + return k_sin(x, 0.0, 0); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + match n & 3 { + 0 => k_sin(y0, y1, 1), + 1 => k_cos(y0, y1), + 2 => -k_sin(y0, y1, 1), + _ => -k_cos(y0, y1), + } +} + +#[test] +fn test_near_pi() { + let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 + let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 + let result = sin(x); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let result = force_eval!(result); + assert_eq!(result, sx); +} diff --git a/core/llm/math/sincos.rs b/core/llm/math/sincos.rs new file mode 100644 index 0000000..ff5d87a --- /dev/null +++ b/core/llm/math/sincos.rs @@ -0,0 +1,134 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{get_high_word, k_cos, k_sin, rem_pio2}; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sincos(x: f64) -> (f64, f64) { + let s: f64; + let c: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + /* if |x| < 2**-27 * sqrt(2) */ + if ix < 0x3e46a09e { + /* raise inexact if x!=0 and underflow if subnormal */ + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return (x, 1.0); + } + return (k_sin(x, 0.0, 0), k_cos(x, 0.0)); + } + + /* sincos(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + let rv = x - x; + return (rv, rv); + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + s = k_sin(y0, y1, 1); + c = k_cos(y0, y1); + match n & 3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => (0.0, 1.0), + } +} + +// These tests are based on those from sincosf.rs +#[cfg(test)] +mod tests { + use super::sincos; + + const TOLERANCE: f64 = 1e-6; + + #[test] + fn with_pi() { + let (s, c) = sincos(core::f64::consts::PI); + assert!( + (s - 0.0).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + 0.0, + (s - 0.0).abs(), + TOLERANCE + ); + assert!( + (c + 1.0).abs() < TOLERANCE, + "|{} + {}| = {} >= {}", + c, + 1.0, + (s + 1.0).abs(), + TOLERANCE + ); + } + + #[test] + fn rotational_symmetry() { + use core::f64::consts::PI; + const N: usize = 24; + for n in 0..N { + let theta = 2. * PI * (n as f64) / (N as f64); + let (s, c) = sincos(theta); + let (s_plus, c_plus) = sincos(theta + 2. * PI); + let (s_minus, c_minus) = sincos(theta - 2. * PI); + + assert!( + (s - s_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_plus, + (s - s_plus).abs(), + TOLERANCE + ); + assert!( + (s - s_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_minus, + (s - s_minus).abs(), + TOLERANCE + ); + assert!( + (c - c_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_plus, + (c - c_plus).abs(), + TOLERANCE + ); + assert!( + (c - c_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_minus, + (c - c_minus).abs(), + TOLERANCE + ); + } + } +} diff --git a/core/llm/math/sincosf.rs b/core/llm/math/sincosf.rs new file mode 100644 index 0000000..9a4c361 --- /dev/null +++ b/core/llm/math/sincosf.rs @@ -0,0 +1,185 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{k_cosf, k_sinf, rem_pio2f}; + +/* Small multiples of pi/2 rounded to double precision. */ +const PI_2: f32 = 0.5 * 3.1415926535897931160E+00; +const S1PIO2: f32 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2PIO2: f32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ +const S3PIO2: f32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4PIO2: f32 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sincosf(x: f32) -> (f32, f32) { + let s: f32; + let c: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + /* |x| ~<= pi/4 */ + if ix <= 0x3f490fda { + /* |x| < 2**-12 */ + if ix < 0x39800000 { + /* raise inexact if x!=0 and underflow if subnormal */ + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return (x, 1.0); + } + return (k_sinf(x as f64), k_cosf(x as f64)); + } + + /* |x| ~<= 5*pi/4 */ + if ix <= 0x407b53d1 { + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + if sign { + s = -k_cosf((x + S1PIO2) as f64); + c = k_sinf((x + S1PIO2) as f64); + } else { + s = k_cosf((S1PIO2 - x) as f64); + c = k_sinf((S1PIO2 - x) as f64); + } + } + /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ + else { + if sign { + s = -k_sinf((x + S2PIO2) as f64); + c = -k_cosf((x + S2PIO2) as f64); + } else { + s = -k_sinf((x - S2PIO2) as f64); + c = -k_cosf((x - S2PIO2) as f64); + } + } + + return (s, c); + } + + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40e231d5 { + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + if sign { + s = k_cosf((x + S3PIO2) as f64); + c = -k_sinf((x + S3PIO2) as f64); + } else { + s = -k_cosf((x - S3PIO2) as f64); + c = k_sinf((x - S3PIO2) as f64); + } + } else { + if sign { + s = k_sinf((x + S4PIO2) as f64); + c = k_cosf((x + S4PIO2) as f64); + } else { + s = k_sinf((x - S4PIO2) as f64); + c = k_cosf((x - S4PIO2) as f64); + } + } + + return (s, c); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + let rv = x - x; + return (rv, rv); + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + s = k_sinf(y); + c = k_cosf(y); + match n & 3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(debug_assertions)] + _ => unreachable!(), + #[cfg(not(debug_assertions))] + _ => (0.0, 1.0), + } +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::sincosf; + use crate::_eqf; + + #[test] + fn with_pi() { + let (s, c) = sincosf(core::f32::consts::PI); + _eqf(s.abs(), 0.0).unwrap(); + _eqf(c, -1.0).unwrap(); + } + + #[test] + fn rotational_symmetry() { + use core::f32::consts::PI; + const N: usize = 24; + for n in 0..N { + let theta = 2. * PI * (n as f32) / (N as f32); + let (s, c) = sincosf(theta); + let (s_plus, c_plus) = sincosf(theta + 2. * PI); + let (s_minus, c_minus) = sincosf(theta - 2. * PI); + + const TOLERANCE: f32 = 1e-6; + assert!( + (s - s_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_plus, + (s - s_plus).abs(), + TOLERANCE + ); + assert!( + (s - s_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_minus, + (s - s_minus).abs(), + TOLERANCE + ); + assert!( + (c - c_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_plus, + (c - c_plus).abs(), + TOLERANCE + ); + assert!( + (c - c_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_minus, + (c - c_minus).abs(), + TOLERANCE + ); + } + } +} diff --git a/core/llm/math/sinf.rs b/core/llm/math/sinf.rs new file mode 100644 index 0000000..6e20be2 --- /dev/null +++ b/core/llm/math/sinf.rs @@ -0,0 +1,93 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{k_cosf, k_sinf, rem_pio2f}; + +use core::f64::consts::FRAC_PI_2; + +/* Small multiples of pi/2 rounded to double precision. */ +const S1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sinf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00800000 { + x / x1p120 + } else { + x + x1p120 + }); + return x; + } + return k_sinf(x64); + } + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + if sign { + return -k_cosf(x64 + S1_PIO2); + } else { + return k_cosf(x64 - S1_PIO2); + } + } + return k_sinf(if sign { + -(x64 + S2_PIO2) + } else { + -(x64 - S2_PIO2) + }); + } + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + if sign { + return k_cosf(x64 + S3_PIO2); + } else { + return -k_cosf(x64 - S3_PIO2); + } + } + return k_sinf(if sign { x64 + S4_PIO2 } else { x64 - S4_PIO2 }); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x - x; + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + match n & 3 { + 0 => k_sinf(y), + 1 => k_cosf(y), + 2 => k_sinf(-y), + _ => -k_cosf(y), + } +} diff --git a/core/llm/math/sinh.rs b/core/llm/math/sinh.rs new file mode 100644 index 0000000..fd24fd2 --- /dev/null +++ b/core/llm/math/sinh.rs @@ -0,0 +1,49 @@ +use super::{expm1, expo2}; + +// sinh(x) = (exp(x) - 1/exp(x))/2 +// = (exp(x)-1 + (exp(x)-1)/exp(x))/2 +// = x + x^3/6 + o(x^5) +// +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sinh(x: f64) -> f64 { + // union {double f; uint64_t i;} u = {.f = x}; + // uint32_t w; + // double t, h, absx; + + let mut uf: f64 = x; + let mut ui: u64 = f64::to_bits(uf); + let w: u32; + let t: f64; + let mut h: f64; + let absx: f64; + + h = 0.5; + if ui >> 63 != 0 { + h = -h; + } + /* |x| */ + ui &= !1 / 2; + uf = f64::from_bits(ui); + absx = uf; + w = (ui >> 32) as u32; + + /* |x| < log(DBL_MAX) */ + if w < 0x40862e42 { + t = expm1(absx); + if w < 0x3ff00000 { + if w < 0x3ff00000 - (26 << 20) { + /* note: inexact and underflow are raised by expm1 */ + /* note: this branch avoids spurious underflow */ + return x; + } + return h * (2.0 * t - t * t / (t + 1.0)); + } + /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ + return h * (t + t / (t + 1.0)); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = 2.0 * h * expo2(absx); + t +} diff --git a/core/llm/math/sinhf.rs b/core/llm/math/sinhf.rs new file mode 100644 index 0000000..24f863c --- /dev/null +++ b/core/llm/math/sinhf.rs @@ -0,0 +1,30 @@ +use super::expm1f; +use super::k_expo2f; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sinhf(x: f32) -> f32 { + let mut h = 0.5f32; + let mut ix = x.to_bits(); + if (ix >> 31) != 0 { + h = -h; + } + /* |x| */ + ix &= 0x7fffffff; + let absx = f32::from_bits(ix); + let w = ix; + + /* |x| < log(FLT_MAX) */ + if w < 0x42b17217 { + let t = expm1f(absx); + if w < 0x3f800000 { + if w < (0x3f800000 - (12 << 23)) { + return x; + } + return h * (2. * t - t * t / (t + 1.)); + } + return h * (t + t / (t + 1.)); + } + + /* |x| > logf(FLT_MAX) or nan */ + 2. * h * k_expo2f(absx) +} diff --git a/core/llm/math/sqrt.rs b/core/llm/math/sqrt.rs new file mode 100644 index 0000000..3733ba0 --- /dev/null +++ b/core/llm/math/sqrt.rs @@ -0,0 +1,280 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* sqrt(x) + * Return correctly rounded sqrt. + * ------------------------------------------ + * | Use the hardware sqrt if you have one | + * ------------------------------------------ + * Method: + * Bit by bit method using integer arithmetic. (Slow, but portable) + * 1. Normalization + * Scale x to y in [1,4) with even powers of 2: + * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then + * sqrt(x) = 2^k * sqrt(y) + * 2. Bit by bit computation + * Let q = sqrt(y) truncated to i bit after binary point (q = 1), + * i 0 + * i+1 2 + * s = 2*q , and y = 2 * ( y - q ). (1) + * i i i i + * + * To compute q from q , one checks whether + * i+1 i + * + * -(i+1) 2 + * (q + 2 ) <= y. (2) + * i + * -(i+1) + * If (2) is false, then q = q ; otherwise q = q + 2 . + * i+1 i i+1 i + * + * With some algebraic manipulation, it is not difficult to see + * that (2) is equivalent to + * -(i+1) + * s + 2 <= y (3) + * i i + * + * The advantage of (3) is that s and y can be computed by + * i i + * the following recurrence formula: + * if (3) is false + * + * s = s , y = y ; (4) + * i+1 i i+1 i + * + * otherwise, + * -i -(i+1) + * s = s + 2 , y = y - s - 2 (5) + * i+1 i i+1 i i + * + * One may easily use induction to prove (4) and (5). + * Note. Since the left hand side of (3) contain only i+2 bits, + * it does not necessary to do a full (53-bit) comparison + * in (3). + * 3. Final rounding + * After generating the 53 bits result, we compute one more bit. + * Together with the remainder, we can decide whether the + * result is exact, bigger than 1/2ulp, or less than 1/2ulp + * (it will never equal to 1/2ulp). + * The rounding mode can be detected by checking whether + * huge + tiny is equal to huge, and whether huge - tiny is + * equal to huge for some floating point number "huge" and "tiny". + * + * Special cases: + * sqrt(+-0) = +-0 ... exact + * sqrt(inf) = inf + * sqrt(-ve) = NaN ... with invalid signal + * sqrt(NaN) = NaN ... with invalid signal for signaling NaN + */ + +use core::f64; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrt(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.sqrt` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return if x < 0.0 { + f64::NAN + } else { + unsafe { ::core::intrinsics::sqrtf64(x) } + } + } + } + #[cfg(target_feature = "sse2")] + { + // Note: This path is unlikely since LLVM will usually have already + // optimized sqrt calls into hardware instructions if sse2 is available, + // but if someone does end up here they'll apprected the speed increase. + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + unsafe { + let m = _mm_set_sd(x); + let m_sqrt = _mm_sqrt_pd(m); + _mm_cvtsd_f64(m_sqrt) + } + } + #[cfg(not(target_feature = "sse2"))] + { + use core::num::Wrapping; + + const TINY: f64 = 1.0e-300; + + let mut z: f64; + let sign: Wrapping = Wrapping(0x80000000); + let mut ix0: i32; + let mut s0: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: Wrapping; + let mut t1: Wrapping; + let mut s1: Wrapping; + let mut ix1: Wrapping; + let mut q1: Wrapping; + + ix0 = (x.to_bits() >> 32) as i32; + ix1 = Wrapping(x.to_bits() as u32); + + /* take care of Inf and NaN */ + if (ix0 & 0x7ff00000) == 0x7ff00000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if ix0 <= 0 { + if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix0 < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } + /* normalize x */ + m = ix0 >> 20; + if m == 0 { + /* subnormal x */ + while ix0 == 0 { + m -= 21; + ix0 |= (ix1 >> 11).0 as i32; + ix1 <<= 21; + } + i = 0; + while (ix0 & 0x00100000) == 0 { + i += 1; + ix0 <<= 1; + } + m -= i - 1; + ix0 |= (ix1 >> (32 - i) as usize).0 as i32; + ix1 = ix1 << i as usize; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0 & 0x000fffff) | 0x00100000; + if (m & 1) == 1 { + /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + q = 0; /* [q,q1] = sqrt(x) */ + q1 = Wrapping(0); + s0 = 0; + s1 = Wrapping(0); + r = Wrapping(0x00200000); /* r = moving bit from right to left */ + + while r != Wrapping(0) { + t = s0 + r.0 as i32; + if t <= ix0 { + s0 = t + r.0 as i32; + ix0 -= t; + q += r.0 as i32; + } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } + + r = sign; + while r != Wrapping(0) { + t1 = s1 + r; + t = s0; + if t < ix0 || (t == ix0 && t1 <= ix1) { + s1 = t1 + r; + if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { + s0 += 1; + } + ix0 -= t; + if ix1 < t1 { + ix0 -= 1; + } + ix1 -= t1; + q1 += r; + } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if (ix0 as u32 | ix1.0) != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if q1.0 == 0xffffffff { + q1 = Wrapping(0); + q += 1; + } else if z > 1.0 { + if q1.0 == 0xfffffffe { + q += 1; + } + q1 += Wrapping(2); + } else { + q1 += q1 & Wrapping(1); + } + } + } + ix0 = (q >> 1) + 0x3fe00000; + ix1 = q1 >> 1; + if (q & 1) == 1 { + ix1 |= sign; + } + ix0 += m << 20; + f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use core::f64::*; + + #[test] + fn sanity_check() { + assert_eq!(sqrt(100.0), 10.0); + assert_eq!(sqrt(4.0), 2.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt + #[test] + fn spec_tests() { + // Not Asserted: FE_INVALID exception is raised if argument is negative. + assert!(sqrt(-1.0).is_nan()); + assert!(sqrt(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY].iter().copied() { + assert_eq!(sqrt(f), f); + } + } + + #[test] + fn conformance_tests() { + let values = [3.14159265359, 10000.0, f64::from_bits(0x0000000f), INFINITY]; + let results = [ + 4610661241675116657u64, + 4636737291354636288u64, + 2197470602079456986u64, + 9218868437227405312u64, + ]; + + for i in 0..values.len() { + let bits = f64::to_bits(sqrt(values[i])); + assert_eq!(results[i], bits); + } + } +} diff --git a/core/llm/math/sqrtf.rs b/core/llm/math/sqrtf.rs new file mode 100644 index 0000000..8ec72fb --- /dev/null +++ b/core/llm/math/sqrtf.rs @@ -0,0 +1,170 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.sqrt` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return if x < 0.0 { + ::core::f32::NAN + } else { + unsafe { ::core::intrinsics::sqrtf32(x) } + } + } + } + #[cfg(target_feature = "sse")] + { + // Note: This path is unlikely since LLVM will usually have already + // optimized sqrt calls into hardware instructions if sse is available, + // but if someone does end up here they'll apprected the speed increase. + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + unsafe { + let m = _mm_set_ss(x); + let m_sqrt = _mm_sqrt_ss(m); + _mm_cvtss_f32(m_sqrt) + } + } + #[cfg(not(target_feature = "sse"))] + { + const TINY: f32 = 1.0e-30; + + let mut z: f32; + let sign: i32 = 0x80000000u32 as i32; + let mut ix: i32; + let mut s: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: u32; + + ix = x.to_bits() as i32; + + /* take care of Inf and NaN */ + if (ix as u32 & 0x7f800000) == 0x7f800000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + + /* take care of zero */ + if ix <= 0 { + if (ix & !sign) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } + + /* normalize x */ + m = ix >> 23; + if m == 0 { + /* subnormal x */ + i = 0; + while ix & 0x00800000 == 0 { + ix <<= 1; + i = i + 1; + } + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if m & 1 == 1 { + /* odd m, double x to make it even */ + ix += ix; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = 0; + s = 0; + r = 0x01000000; /* r = moving bit from right to left */ + + while r != 0 { + t = s + r as i32; + if t <= ix { + s = t + r as i32; + ix -= t; + q += r as i32; + } + ix += ix; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if ix != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if z > 1.0 { + q += 2; + } else { + q += q & 1; + } + } + } + + ix = (q >> 1) + 0x3f000000; + ix += m << 23; + f32::from_bits(ix as u32) + } +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::*; + use core::f32::*; + + #[test] + fn sanity_check() { + assert_eq!(sqrtf(100.0), 10.0); + assert_eq!(sqrtf(4.0), 2.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt + #[test] + fn spec_tests() { + // Not Asserted: FE_INVALID exception is raised if argument is negative. + assert!(sqrtf(-1.0).is_nan()); + assert!(sqrtf(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY].iter().copied() { + assert_eq!(sqrtf(f), f); + } + } + + #[test] + fn conformance_tests() { + let values = [ + 3.14159265359f32, + 10000.0f32, + f32::from_bits(0x0000000f), + INFINITY, + ]; + let results = [1071833029u32, 1120403456u32, 456082799u32, 2139095040u32]; + + for i in 0..values.len() { + let bits = f32::to_bits(sqrtf(values[i])); + assert_eq!(results[i], bits); + } + } +} diff --git a/core/llm/math/tan.rs b/core/llm/math/tan.rs new file mode 100644 index 0000000..5a72f68 --- /dev/null +++ b/core/llm/math/tan.rs @@ -0,0 +1,70 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */ +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +use super::{k_tan, rem_pio2}; + +// tan(x) +// Return tangent function of x. +// +// kernel function: +// k_tan ... tangent function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tan(x: f64) -> f64 { + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e400000 { + /* |x| < 2**-27 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00100000 { + x / x1p120 as f64 + } else { + x + x1p120 as f64 + }); + return x; + } + return k_tan(x, 0.0, 0); + } + + /* tan(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction */ + let (n, y0, y1) = rem_pio2(x); + k_tan(y0, y1, n & 1) +} diff --git a/core/llm/math/tanf.rs b/core/llm/math/tanf.rs new file mode 100644 index 0000000..10de59c --- /dev/null +++ b/core/llm/math/tanf.rs @@ -0,0 +1,78 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +use super::{k_tanf, rem_pio2f}; + +use core::f64::consts::FRAC_PI_2; + +/* Small multiples of pi/2 rounded to double precision. */ +const T1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tanf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00800000 { + x / x1p120 + } else { + x + x1p120 + }); + return x; + } + return k_tanf(x64, false); + } + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + return k_tanf(if sign { x64 + T1_PIO2 } else { x64 - T1_PIO2 }, true); + } else { + return k_tanf(if sign { x64 + T2_PIO2 } else { x64 - T2_PIO2 }, false); + } + } + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + return k_tanf(if sign { x64 + T3_PIO2 } else { x64 - T3_PIO2 }, true); + } else { + return k_tanf(if sign { x64 + T4_PIO2 } else { x64 - T4_PIO2 }, false); + } + } + + /* tan(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x - x; + } + + /* argument reduction */ + let (n, y) = rem_pio2f(x); + k_tanf(y, n & 1 != 0) +} diff --git a/core/llm/math/tanh.rs b/core/llm/math/tanh.rs new file mode 100644 index 0000000..980c685 --- /dev/null +++ b/core/llm/math/tanh.rs @@ -0,0 +1,53 @@ +use super::expm1; + +/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) + * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) + * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) + */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tanh(mut x: f64) -> f64 { + let mut uf: f64 = x; + let mut ui: u64 = f64::to_bits(uf); + + let w: u32; + let sign: bool; + let mut t: f64; + + /* x = |x| */ + sign = ui >> 63 != 0; + ui &= !1 / 2; + uf = f64::from_bits(ui); + x = uf; + w = (ui >> 32) as u32; + + if w > 0x3fe193ea { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if w > 0x40340000 { + /* |x| > 20 or nan */ + /* note: this branch avoids raising overflow */ + t = 1.0 - 0.0 / x; + } else { + t = expm1(2.0 * x); + t = 1.0 - 2.0 / (t + 2.0); + } + } else if w > 0x3fd058ae { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1(2.0 * x); + t = t / (t + 2.0); + } else if w >= 0x00100000 { + /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ + t = expm1(-2.0 * x); + t = -t / (t + 2.0); + } else { + /* |x| is subnormal */ + /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ + force_eval!(x as f32); + t = x; + } + + if sign { + -t + } else { + t + } +} diff --git a/core/llm/math/tanhf.rs b/core/llm/math/tanhf.rs new file mode 100644 index 0000000..fc94e3d --- /dev/null +++ b/core/llm/math/tanhf.rs @@ -0,0 +1,39 @@ +use super::expm1f; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tanhf(mut x: f32) -> f32 { + /* x = |x| */ + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + x = f32::from_bits(ix); + let w = ix; + + let tt = if w > 0x3f0c9f54 { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if w > 0x41200000 { + /* |x| > 10 */ + 1. + 0. / x + } else { + let t = expm1f(2. * x); + 1. - 2. / (t + 2.) + } + } else if w > 0x3e82c578 { + /* |x| > log(5/3)/2 ~= 0.2554 */ + let t = expm1f(2. * x); + t / (t + 2.) + } else if w >= 0x00800000 { + /* |x| >= 0x1p-126 */ + let t = expm1f(-2. * x); + -t / (t + 2.) + } else { + /* |x| is subnormal */ + force_eval!(x * x); + x + }; + if sign { + -tt + } else { + tt + } +} diff --git a/core/llm/math/tgamma.rs b/core/llm/math/tgamma.rs new file mode 100644 index 0000000..e64eff6 --- /dev/null +++ b/core/llm/math/tgamma.rs @@ -0,0 +1,208 @@ +/* +"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) +"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) +"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) + +approximation method: + + (x - 0.5) S(x) +Gamma(x) = (x + g - 0.5) * ---------------- + exp(x + g - 0.5) + +with + a1 a2 a3 aN +S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] + x + 1 x + 2 x + 3 x + N + +with a0, a1, a2, a3,.. aN constants which depend on g. + +for x < 0 the following reflection formula is used: + +Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) + +most ideas and constants are from boost and python +*/ +extern crate core; +use super::{exp, floor, k_cos, k_sin, pow}; + +const PI: f64 = 3.141592653589793238462643383279502884; + +/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ +fn sinpi(mut x: f64) -> f64 { + let mut n: isize; + + /* argument reduction: x = |x| mod 2 */ + /* spurious inexact when x is odd int */ + x = x * 0.5; + x = 2.0 * (x - floor(x)); + + /* reduce x into [-.25,.25] */ + n = (4.0 * x) as isize; + n = div!(n + 1, 2); + x -= (n as f64) * 0.5; + + x *= PI; + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + 0 | _ => k_sin(x, 0.0, 0), + } +} + +const N: usize = 12; +//static const double g = 6.024680040776729583740234375; +const GMHALF: f64 = 5.524680040776729583740234375; +const SNUM: [f64; N + 1] = [ + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, +]; +const SDEN: [f64; N + 1] = [ + 0.0, + 39916800.0, + 120543840.0, + 150917976.0, + 105258076.0, + 45995730.0, + 13339535.0, + 2637558.0, + 357423.0, + 32670.0, + 1925.0, + 66.0, + 1.0, +]; +/* n! for small integer n */ +const FACT: [f64; 23] = [ + 1.0, + 1.0, + 2.0, + 6.0, + 24.0, + 120.0, + 720.0, + 5040.0, + 40320.0, + 362880.0, + 3628800.0, + 39916800.0, + 479001600.0, + 6227020800.0, + 87178291200.0, + 1307674368000.0, + 20922789888000.0, + 355687428096000.0, + 6402373705728000.0, + 121645100408832000.0, + 2432902008176640000.0, + 51090942171709440000.0, + 1124000727777607680000.0, +]; + +/* S(x) rational function for positive x */ +fn s(x: f64) -> f64 { + let mut num: f64 = 0.0; + let mut den: f64 = 0.0; + + /* to avoid overflow handle large x differently */ + if x < 8.0 { + for i in (0..=N).rev() { + num = num * x + i!(SNUM, i); + den = den * x + i!(SDEN, i); + } + } else { + for i in 0..=N { + num = num / x + i!(SNUM, i); + den = den / x + i!(SDEN, i); + } + } + return num / den; +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tgamma(mut x: f64) -> f64 { + let u: u64 = x.to_bits(); + let absx: f64; + let mut y: f64; + let mut dy: f64; + let mut z: f64; + let mut r: f64; + let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; + let sign: bool = (u >> 63) != 0; + + /* special cases */ + if ix >= 0x7ff00000 { + /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ + return x + core::f64::INFINITY; + } + if ix < ((0x3ff - 54) << 20) { + /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ + return 1.0 / x; + } + + /* integer arguments */ + /* raise inexact when non-integer */ + if x == floor(x) { + if sign { + return 0.0 / 0.0; + } + if x <= FACT.len() as f64 { + return i!(FACT, (x as usize) - 1); + } + } + + /* x >= 172: tgamma(x)=inf with overflow */ + /* x =< -184: tgamma(x)=+-0 with underflow */ + if ix >= 0x40670000 { + /* |x| >= 184 */ + if sign { + let x1p_126 = f64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 + force_eval!((x1p_126 / x) as f32); + if floor(x) * 0.5 == floor(x * 0.5) { + return 0.0; + } else { + return -0.0; + } + } + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 + x *= x1p1023; + return x; + } + + absx = if sign { -x } else { x }; + + /* handle the error of x + g - 0.5 */ + y = absx + GMHALF; + if absx > GMHALF { + dy = y - absx; + dy -= GMHALF; + } else { + dy = y - GMHALF; + dy -= absx; + } + + z = absx - 0.5; + r = s(absx) * exp(-y); + if x < 0.0 { + /* reflection formula for negative x */ + /* sinpi(absx) is not 0, integers are already handled */ + r = -PI / (sinpi(absx) * absx * r); + dy = -dy; + z = -z; + } + r += dy * (GMHALF + 0.5) * r / y; + z = pow(y, 0.5 * z); + y = r * z * z; + return y; +} diff --git a/core/llm/math/tgammaf.rs b/core/llm/math/tgammaf.rs new file mode 100644 index 0000000..23e3814 --- /dev/null +++ b/core/llm/math/tgammaf.rs @@ -0,0 +1,6 @@ +use super::tgamma; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn tgammaf(x: f32) -> f32 { + tgamma(x as f64) as f32 +} diff --git a/core/llm/math/trunc.rs b/core/llm/math/trunc.rs new file mode 100644 index 0000000..f7892a2 --- /dev/null +++ b/core/llm/math/trunc.rs @@ -0,0 +1,40 @@ +use core::f64; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn trunc(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.trunc` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::truncf64(x) } + } + } + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 + + let mut i: u64 = x.to_bits(); + let mut e: i64 = (i >> 52 & 0x7ff) as i64 - 0x3ff + 12; + let m: u64; + + if e >= 52 + 12 { + return x; + } + if e < 12 { + e = 1; + } + m = -1i64 as u64 >> e; + if (i & m) == 0 { + return x; + } + force_eval!(x + x1p120); + i &= !m; + f64::from_bits(i) +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::trunc(1.1), 1.0); + } +} diff --git a/core/llm/math/truncf.rs b/core/llm/math/truncf.rs new file mode 100644 index 0000000..20d5b73 --- /dev/null +++ b/core/llm/math/truncf.rs @@ -0,0 +1,42 @@ +use core::f32; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.trunc` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::truncf32(x) } + } + } + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut i: u32 = x.to_bits(); + let mut e: i32 = (i >> 23 & 0xff) as i32 - 0x7f + 9; + let m: u32; + + if e >= 23 + 9 { + return x; + } + if e < 9 { + e = 1; + } + m = -1i32 as u32 >> e; + if (i & m) == 0 { + return x; + } + force_eval!(x + x1p120); + i &= !m; + f32::from_bits(i) +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::truncf(1.1), 1.0); + } +} diff --git a/core/llm/types.rs b/core/llm/types.rs new file mode 100644 index 0000000..fde5d99 --- /dev/null +++ b/core/llm/types.rs @@ -0,0 +1,14 @@ +type __Float64 = f64; +type __Float32 = f32; + +/// Radians +pub type Radian =__Float64; + +/// Radians (32bit) +pub type Radian32 = __Float32; + +/// A floating point number +pub type Float = __Float64; + +/// A floating point number (32bit) +pub type Float32 =__Float32; diff --git a/macros/Cargo.toml b/core/macros/Cargo.toml similarity index 100% rename from macros/Cargo.toml rename to core/macros/Cargo.toml diff --git a/core/macros/README.md b/core/macros/README.md new file mode 100644 index 0000000..e69de29 diff --git a/macros/lib.rs b/core/macros/lib.rs similarity index 100% rename from macros/lib.rs rename to core/macros/lib.rs diff --git a/macros/libtrig-macros-core/Cargo.toml b/core/macros/libtrig-macros-core/Cargo.toml similarity index 100% rename from macros/libtrig-macros-core/Cargo.toml rename to core/macros/libtrig-macros-core/Cargo.toml diff --git a/macros/libtrig-macros-core/ffi/mod.rs b/core/macros/libtrig-macros-core/ffi/mod.rs similarity index 100% rename from macros/libtrig-macros-core/ffi/mod.rs rename to core/macros/libtrig-macros-core/ffi/mod.rs diff --git a/macros/libtrig-macros-core/lib.rs b/core/macros/libtrig-macros-core/lib.rs similarity index 100% rename from macros/libtrig-macros-core/lib.rs rename to core/macros/libtrig-macros-core/lib.rs diff --git a/macros/libtrig-macros-core/mass_impl/args.rs b/core/macros/libtrig-macros-core/mass_impl/args.rs similarity index 100% rename from macros/libtrig-macros-core/mass_impl/args.rs rename to core/macros/libtrig-macros-core/mass_impl/args.rs diff --git a/macros/libtrig-macros-core/mass_impl/mod.rs b/core/macros/libtrig-macros-core/mass_impl/mod.rs similarity index 86% rename from macros/libtrig-macros-core/mass_impl/mod.rs rename to core/macros/libtrig-macros-core/mass_impl/mod.rs index e49baf1..dd09978 100644 --- a/macros/libtrig-macros-core/mass_impl/mod.rs +++ b/core/macros/libtrig-macros-core/mass_impl/mod.rs @@ -40,5 +40,10 @@ pub fn mass_impl>(cfg: T, input: T) -> TokenStream { results = temp_results; } let single_str = results.join("\n"); - syn::parse_str::(&single_str).unwrap() + match syn::parse_str::(&single_str) { + Ok(ts) => ts, + Err(err) => { + err.to_compile_error() + } + } } \ No newline at end of file diff --git a/macros/libtrig-macros-core/mass_impl/variants.rs b/core/macros/libtrig-macros-core/mass_impl/variants.rs similarity index 100% rename from macros/libtrig-macros-core/mass_impl/variants.rs rename to core/macros/libtrig-macros-core/mass_impl/variants.rs diff --git a/example.rs b/example.rs new file mode 100644 index 0000000..8aac1a8 --- /dev/null +++ b/example.rs @@ -0,0 +1,44 @@ +use libtrig::odo::*; +use libtrig::*; + +const CONFIG: OdometryConfig = OdometryConfig::new() + .set_lateral_wheel_distance(20.12) + .set_longitudinal_wheel_distance(11.5) + .set_wheel_radius(3.0) + .set_ticks_per_revolution(8192.0); + +struct Robot { + left_encoder: float, + right_encoder: float, + back_encoder: float, + + odo: Odometry, +} + +impl Robot { + fn new() -> Self { Self { + left_encoder: 0.0, + right_encoder: 0.0, + back_encoder: 0.0, + + odo: Odometry::new(CONFIG), + } } + fn update(&mut self, movement: (float, float, float)) { + self.left_encoder += movement.0; + self.right_encoder += movement.1; + self.back_encoder += movement.2; + + self.odo.update(Vec3D::new( + self.left_encoder, self.right_encoder, self.back_encoder + )); + } +} + +fn main() { + let mut robot = Robot::new(); + robot.odo.setCurrentPositionToOrigin(); + + robot.update((10.0, 10.0, 0.0)); + + println!("{}", robot.odo.current_position()); +} \ No newline at end of file diff --git a/libtrig/README.md b/libtrig/README.md new file mode 100644 index 0000000..e69de29 diff --git a/libtrig/angle.rs b/libtrig/angle.rs index 8d42879..4ed11c0 100644 --- a/libtrig/angle.rs +++ b/libtrig/angle.rs @@ -1,35 +1,47 @@ use crate::*; -/// A wrapper around a `Float` value that represents an angle. +/// A wrapper around a `float` value that represents an angle. /// /// It can be created from either radians or degrees, and can be converted to either radians or degrees. #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Angle(Float, bool); +pub struct Angle2D(float, bool); -impl Angle { - /// Creates a new `Angle` from the given `value` and `is_radians` flag. +impl Angle2D { + /// Creates a new `Angle2D` from the given `value` and `is_radians` flag. #[inline] #[must_use] - pub const fn new(value: Float, is_radians: bool) -> Self { + pub const fn new(value: float, is_radians: bool) -> Self { Self(value, is_radians) } - /// Creates a new `Angle` from the given `value` in radians. + /// Creates a new `Angle2D` from the given `value` in radians. #[inline] #[must_use] - pub const fn from_radians(value: Float) -> Self { + pub const fn from_radians(value: float) -> Self { Self::new(value, true) } - /// Creates a new `Angle` from the given `value` in degrees. + /// Creates a new `Angle2D` from the given `value` in degrees. #[inline] #[must_use] - pub const fn from_degrees(value: Float) -> Self { + pub const fn from_degrees(value: float) -> Self { Self::new(value, false) } + /// Creates a new `Angle2D` with a value of `0.0` radians. + #[inline] + #[must_use] + pub const fn zero() -> Self { + Self::new(0.0, true) + } + /// Creates a new `Angle2D` with a value of `0.0` degrees. + #[inline] + #[must_use] + pub const fn zero_deg() -> Self { + Self::new(0.0, false) + } /// Returns the value of the angle in radians. #[inline] #[must_use] - pub fn to_radians(&self) -> Float { + pub fn to_radians(&self) -> float { if self.1 { self.0 } else { @@ -39,7 +51,7 @@ impl Angle { /// Returns the value of the angle in degrees. #[inline] #[must_use] - pub fn to_degrees(&self) -> Float { + pub fn to_degrees(&self) -> float { if self.1 { self.0.to_degrees() } else { @@ -48,8 +60,237 @@ impl Angle { } } -impl std::fmt::Display for Angle { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @ORM Angle2D +)] +impl core::ops::Add for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() + rhs.to_radians()) + } else { + Angle2D::from_degrees(self.to_degrees() + rhs.to_degrees()) + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR float +)] +impl core::ops::Add for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() + rhs) + } else { + Angle2D::from_degrees(self.to_degrees() + rhs) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @ORM Angle2D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() + rhs.to_radians(); + } else { + self.0 = self.to_degrees() + rhs.to_degrees(); + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR float +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() + rhs; + } else { + self.0 = self.to_degrees() + rhs; + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @ORM Angle2D +)] +impl core::ops::Sub for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() - rhs.to_radians()) + } else { + Angle2D::from_degrees(self.to_degrees() - rhs.to_degrees()) + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR float +)] +impl core::ops::Sub for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() - rhs) + } else { + Angle2D::from_degrees(self.to_degrees() - rhs) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Angle2D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() - rhs.to_radians(); + } else { + self.0 = self.to_degrees() - rhs.to_degrees(); + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR float +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() - rhs; + } else { + self.0 = self.to_degrees() - rhs; + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR float +)] +impl core::ops::Mul for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn mul(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() * rhs) + } else { + Angle2D::from_degrees(self.to_degrees() * rhs) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR float +)] +impl core::ops::MulAssign for THIS { + #[inline] + fn mul_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() * rhs; + } else { + self.0 = self.to_degrees() * rhs; + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR float +)] +impl core::ops::Div for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn div(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() / rhs) + } else { + Angle2D::from_degrees(self.to_degrees() / rhs) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR float +)] +impl core::ops::DivAssign for THIS { + #[inline] + fn div_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() / rhs; + } else { + self.0 = self.to_degrees() / rhs; + } + } +} + +#[macros::mass_impl($THIS = @ORM Angle2D)] +impl core::ops::Neg for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn neg(self) -> Self::Output { + if self.1 { + Angle2D::from_radians(-self.to_radians()) + } else { + Angle2D::from_degrees(-self.to_degrees()) + } + } +} + +impl Default for Angle2D { + #[inline] + #[must_use] + fn default() -> Self { + Self::zero() + } +} + +impl core::fmt::Display for Angle2D { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if self.1 { + return write!(f, "{}rad", self.to_radians()); + } write!(f, "{}°", self.to_degrees()) } } + +impl> From<(F, bool)> for Angle2D { + #[inline] + #[must_use] + fn from((f, r): (F, bool)) -> Self { + if r { + Self::from_radians(f.into()) + } else { + Self::from_degrees(f.into()) + } + } +} diff --git a/libtrig/coords/coord2d.rs b/libtrig/coords/coord2d.rs new file mode 100644 index 0000000..4b8c482 --- /dev/null +++ b/libtrig/coords/coord2d.rs @@ -0,0 +1,292 @@ +use crate::traits::Float; +use crate::*; + +/// A wrapper around a `float` value that represents a 2D coordinate. +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +pub struct Coord2D { + /// The x coordinate. + pub x: float, + /// The y coordinate. + pub y: float, +} + +impl Coord2D { + /// Creates a new `Vec2D` from the given `x` and `y` values. + #[inline] + #[must_use] + pub const fn new(x: float, y: float) -> Self { + Self { x, y } + } + /// Creates a new `Vec2D` located at the origin. + #[inline] + #[must_use] + pub const fn origin() -> Self { + Self::new(0.0, 0.0) + } + /// Rotates the vector by the given angle in radians. + #[must_use] + pub fn rotate_by(&self, angle: Angle2D) -> Self { + let angle = angle.to_radians(); + let (sin, cos) = angle.sin_cos(); + Self::new( + self.x * cos - self.y * sin, + self.x * sin + self.y * cos, + ) + } + /// Returns the angle of the vector in radians. + #[inline] + #[must_use] + pub fn angle(&self) -> Angle2D { + Angle2D::from_radians(self.y.atan2(self.x)) + } + /// Returns the inverted position. + /// + /// Same as rotating the position by 180 degrees. + #[inline] + #[must_use] + pub fn inverse(&self) -> Self { + -self + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::Add for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x + rhs.x(), self.y + rhs.y()) + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::Add for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x + rhs.x, self.y + rhs.y) + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + self.x += rhs.x(); + self.y += rhs.y(); + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + self.x += rhs.x; + self.y += rhs.y; + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::Sub for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x - rhs.x(), self.y - rhs.y()) + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::Sub for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x - rhs.x, self.y - rhs.y) + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + self.x -= rhs.x(); + self.y -= rhs.y(); + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + self.x -= rhs.x; + self.y -= rhs.y; + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @OR float +)] +impl core::ops::Mul for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn mul(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x * rhs, self.y * rhs) + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @OR Vec2D +)] +impl core::ops::Mul for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn mul(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x * rhs.x(), self.y * rhs.y()) + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @OR float +)] +impl core::ops::MulAssign for THIS { + #[inline] + fn mul_assign(&mut self, rhs: OTHER) { + self.x *= rhs; + self.y *= rhs; + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @OR Vec2D +)] +impl core::ops::MulAssign for THIS { + #[inline] + fn mul_assign(&mut self, rhs: OTHER) { + self.x *= rhs.x(); + self.y *= rhs.y(); + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @OR float +)] +impl core::ops::Div for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn div(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x / rhs, self.y / rhs) + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @OR Vec2D +)] +impl core::ops::Div for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn div(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x / rhs.x(), self.y / rhs.y()) + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @OR float +)] +impl core::ops::DivAssign for THIS { + #[inline] + fn div_assign(&mut self, rhs: OTHER) { + self.x /= rhs; + self.y /= rhs; + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @OR Vec2D +)] +impl core::ops::DivAssign for THIS { + #[inline] + fn div_assign(&mut self, rhs: OTHER) { + self.x /= rhs.x(); + self.y /= rhs.y(); + } +} + +#[macros::mass_impl($THIS = @ORM Coord2D)] +impl core::ops::Neg for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn neg(self) -> Self::Output { + Coord2D::new(-self.x, -self.y) + } +} + +impl core::fmt::Display for Coord2D { + #[inline] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "[{}, {}]", self.x, self.y) + } +} + +impl Default for Coord2D { + #[inline] + #[must_use] + fn default() -> Self { + Self::origin() + } +} + +impl> From<(F, F)> for Coord2D { + #[inline] + #[must_use] + fn from((x, y): (F, F)) -> Self { + Self::new(x.into(), y.into()) + } +} + +impl From for (float, float) { + #[inline] + #[must_use] + fn from(Coord2D {x, y}: Coord2D) -> Self { + (x, y) + } +} diff --git a/libtrig/coords/coord3d.rs b/libtrig/coords/coord3d.rs new file mode 100644 index 0000000..983f41c --- /dev/null +++ b/libtrig/coords/coord3d.rs @@ -0,0 +1,9 @@ +use crate::*; + +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +pub struct Coord3D { + pub x: Float, + pub y: Float, + pub z: Float, +} \ No newline at end of file diff --git a/libtrig/coords/mod.rs b/libtrig/coords/mod.rs new file mode 100644 index 0000000..aad37f6 --- /dev/null +++ b/libtrig/coords/mod.rs @@ -0,0 +1,5 @@ +mod coord2d; +// mod coord3d; + +pub use coord2d::Coord2D; +// pub use coord3d::Coord3D; \ No newline at end of file diff --git a/libtrig/main.rs b/libtrig/main.rs index e4ceb3f..79761a3 100644 --- a/libtrig/main.rs +++ b/libtrig/main.rs @@ -1,8 +1,23 @@ +#![feature(const_mut_refs)] + +#![no_std] + +#![warn(missing_docs, unused, clippy::all)] +#![doc = include_str!("./README.md")] + pub(crate) mod vectors; +pub(crate) mod traits; +pub(crate) mod coords; pub(crate) mod angle; +pub(crate) mod types; +pub mod odo; + +pub mod prelude { + //! Re-exports all the traits. + pub use super::traits::*; +} pub use vectors::*; +pub use coords::*; pub use angle::*; - -pub type Float = f64; -pub type Int = i32; +pub use types::*; diff --git a/libtrig/odo/FORMULA.md b/libtrig/odo/FORMULA.md new file mode 100644 index 0000000..afcb42d --- /dev/null +++ b/libtrig/odo/FORMULA.md @@ -0,0 +1,64 @@ +In a 3-wheel odometry setup, +where two deadwheels are parallel and the third wheel intersects the two parallel wheels, +we can use this configuration to estimate the robot's position and orientation as it moves on the field. + +Basic Robot Encoder Setup + + +Input: + +- `FLCount` - Encoder count for the front-left dead wheel. (yes we are using encoder) +- `FRCount` - Encoder count for the front-right dead wheel. +- `ICount` - Encoder count for the intersecting dead wheel. +- `DCLateral` - Distance calibration factor for lateral movement (strafe). + This factor relates encoder counts to lateral distance traveled for each wheel. +- `DCForward` - Distance calibration factor for forward/backward movement. + This factor relates encoder counts to forward/backward distance traveled for each wheel. +- `DCAngle` - Angle calibration factor. This factor relates encoder counts to the angle of rotation for the robot. +- `x` - Robot's x-coordinate on the field (lateral position). +- `y` - Robot's y-coordinate on the field (forward position). +- `θ` - Robot's orientation with respect to a reference direction (usually the starting orientation) + +Update Loop: +The robot continuously reads encoder counts from the odometry wheels at regular intervals, +typically every few milliseconds. For each loop iteration, +the robot updates its position and orientation on the field. + +Lateral Movement Update: +The change in lateral position (Δx) +can be calculated using the average encoder counts from the +front-left, front-right, and intersecting dead wheels: + +```rust,ignore,no_run + Δx = (FLCount + FRCount + ICount) * DCLateral / 3 +``` + +Forward Movement Update: The change in forward position (Δy) +can be calculated using the average encoder counts from the two parallel dead wheels: + +```rust,ignore,no_run + Δy = (FLCount + FRCount + ICount) * DCForward / 2 +``` + +Updating Orientation: The change in orientation (Δθ) +can be calculated using the difference in encoder counts between the front-left and front-right dead wheels. +The distance between these wheels is known as the "track width" (W): + +```rust,ignore,no_run + Δθ = (FLCount - FRCount + ICount) * DCAngle / 2 +``` + +Combining Updates: +Using the `Δx`, `Δy`, and `Δtheta` calculated in the previous steps, +the robot can update its position and orientation as follows: + +```rust,ignore,no_run + xₙ = xₒ + Δy * cos(θ) - Δx * sin(θ) + yₙ = yₒ + Δy * sin(θ) + Δx * cos(θ) + θₙ = θₒ + Δθ +``` diff --git a/libtrig/odo/config.rs b/libtrig/odo/config.rs new file mode 100644 index 0000000..0925b71 --- /dev/null +++ b/libtrig/odo/config.rs @@ -0,0 +1,79 @@ +use crate::*; + +use core::f64::consts::PI; + +/// The configuration for odometry calculations. +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct OdometryConfig { + /// The distance between encoder 1 and encoder 2 in centimeters. + pub lateral_wheel_distance: float, + /// The distance between the midpoint of encoder 1 and 2 and encoder 3 in centimeters. + pub longitudinal_wheel_distance: float, + /// The radius of the wheels in centimeters. + pub wheel_radius: float, + /// The number of ticks per revolution of the encoders. + pub ticks_per_revolution: float, +} + +impl OdometryConfig { + /// Creates a new `OdometryConfig` with all fields set to `0.0`. + pub const fn new() -> OdometryConfig { + OdometryConfig { + lateral_wheel_distance: 0.0, + longitudinal_wheel_distance: 0.0, + wheel_radius: 0.0, + ticks_per_revolution: 0.0, + } + } + + /// Modifies `lateral_wheel_distance` and returns `self`. + pub const fn set_lateral_wheel_distance(mut self, lateral_wheel_distance: float) -> Self { + self.lateral_wheel_distance = lateral_wheel_distance; + self + } + + /// Modifies `longitudinal_wheel_distance` and returns `self`. + pub const fn set_longitudinal_wheel_distance(mut self, longitudinal_wheel_distance: float) -> Self { + self.longitudinal_wheel_distance = longitudinal_wheel_distance; + self + } + + /// Modifies `wheel_radius` and returns `self`. + pub const fn set_wheel_radius(mut self, wheel_radius: float) -> Self { + self.wheel_radius = wheel_radius; + self + } + + /// Modifies `ticks_per_revolution` and returns `self`. + pub const fn set_ticks_per_revolution(mut self, ticks_per_revolution: float) -> Self { + self.ticks_per_revolution = ticks_per_revolution; + self + } +} + +/// The configuration for odometry formulae. +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub(crate) struct OdometryFormulaeConfig { + /// The distance between encoder 1 and encoder 2 in centimeters. + pub lateral_wheel_distance: float, + /// The distance between the midpoint of encoder 1 and 2 and encoder 3 in centimeters. + pub longitudinal_wheel_distance: float, + /// The number of centimeters per tick. + pub cm_per_tick: float, +} + +impl OdometryFormulaeConfig { + fn cm_per_tick_calc(wheel_radius: float, ticks_per_revolution: float) -> float { + wheel_radius * 2.0 * PI / ticks_per_revolution + } +} + +impl From for OdometryFormulaeConfig { + fn from(config: OdometryConfig) -> Self { + Self { + lateral_wheel_distance: config.lateral_wheel_distance, + longitudinal_wheel_distance: config.longitudinal_wheel_distance, + cm_per_tick: Self::cm_per_tick_calc(config.wheel_radius, config.ticks_per_revolution), + } + } +} diff --git a/libtrig/odo/mod.rs b/libtrig/odo/mod.rs new file mode 100644 index 0000000..1c655df --- /dev/null +++ b/libtrig/odo/mod.rs @@ -0,0 +1,11 @@ +//! Odometry calculations. + +mod movement_calc; +mod config; +mod pos; + +pub(crate) use config::OdometryFormulaeConfig; +pub use config::OdometryConfig; + +pub use movement_calc::Odometry; +pub use pos::Pos2D; diff --git a/libtrig/odo/movement_calc.rs b/libtrig/odo/movement_calc.rs new file mode 100644 index 0000000..2088258 --- /dev/null +++ b/libtrig/odo/movement_calc.rs @@ -0,0 +1,69 @@ +use crate::*; + +/// Odometry calculations. +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct Odometry { + config: odo::OdometryFormulaeConfig, + current_position: odo::Pos2D, + encoder_values: Vec3D, +} + +impl Odometry { + /// Creates a new `Odometry` with the given `config`. + #[must_use] + pub fn new(config: odo::OdometryConfig) -> Self { + Self { + config: config.into(), + current_position: odo::Pos2D::origin(), + encoder_values: Vec3D::origin() + } + } + + /// Forces the current position to be set to the given `coords`. + #[inline] + #[allow(non_snake_case)] + pub fn setCurrentPosition(&mut self, coords: impl Into) { + self.current_position = coords.into(); + } + + /// Forces the current position to be set to the origin. (0, 0, 0) + #[inline] + #[allow(non_snake_case)] + pub fn setCurrentPositionToOrigin(&mut self) { + self.current_position = odo::Pos2D::origin(); + } + + /// Updates the current position, with the provided 3D vector + /// + #[doc = include_str!("./FORMULA.md")] + pub fn update(&mut self, movement: Vec3D) { + let old_encoder_values = self.encoder_values; + + self.encoder_values += movement; + + let dn1 = self.encoder_values.x() - old_encoder_values.x(); + let dn2 = self.encoder_values.y() - old_encoder_values.y(); + let dn3 = self.encoder_values.z() - old_encoder_values.z(); + + let dtheta = self.config.cm_per_tick * ((dn1 - dn2) / self.config.lateral_wheel_distance); + let dx = self.config.cm_per_tick * ((dn1 + dn2) / 2.0); + let dy = self.config.cm_per_tick * (dn3 + ( (dn2 - dn1) / 2.0 )); + + // pos.h += dtheta / 2; + // pos.x += dx * Math.cos(pos.h) - dy * Math.sin(pos.h); + // pos.y += dx * Math.sin(pos.h) + dy * Math.cos(pos.h); + // pos.h += dtheta / 2; + // pos.h = normDiff(pos.h); + // let new_angle = self.current_position.angle() + (dtheta / 2.0); + // self.current_position.setAngle(new_angle); + // let new_x = dx * new_angle.cos() - dy * new_angle.sin(); + // self.current_position.setX(new_x); + } + + /// Returns the current position. + #[inline] + #[must_use] + pub fn current_position(&self) -> odo::Pos2D { + self.current_position + } +} diff --git a/libtrig/odo/pos/mod.rs b/libtrig/odo/pos/mod.rs new file mode 100644 index 0000000..2c7bc84 --- /dev/null +++ b/libtrig/odo/pos/mod.rs @@ -0,0 +1,3 @@ +mod pos2d; + +pub use pos2d::Pos2D; \ No newline at end of file diff --git a/libtrig/odo/pos/pos2d.rs b/libtrig/odo/pos/pos2d.rs new file mode 100644 index 0000000..ad51136 --- /dev/null +++ b/libtrig/odo/pos/pos2d.rs @@ -0,0 +1,321 @@ +use crate::*; + +/// A 2D position. +/// +/// Contains a `Coord2D` and an `Angle2D`. +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +pub struct Pos2D(Coord2D, Angle2D); + +impl Pos2D { + /// Creates a new `Pos2D` from the given `coords` and `angle`. + #[inline] + #[must_use] + pub const fn new(coords: Coord2D, angle: Angle2D) -> Self { + Self(coords, angle) + } + /// Creates a new `Pos2D` at the origin, with an angle of `0.0` radians. + #[inline] + #[must_use] + pub const fn origin() -> Self { + Self(Coord2D::origin(), Angle2D::zero()) + } + /// Returns the x coordinate of the position. + #[inline] + #[must_use] + pub const fn x(&self) -> float { + self.0.x + } + /// Sets the x coordinate of the position. + #[inline] + #[must_use] + #[allow(non_snake_case)] + pub const fn setX(&mut self, x: float) { + self.0.x = x; + } + /// Returns the y coordinate of the position. + #[inline] + #[must_use] + pub const fn y(&self) -> float { + self.0.y + } + /// Sets the y coordinate of the position. + #[inline] + #[must_use] + #[allow(non_snake_case)] + pub const fn setY(&mut self, y: float) { + self.0.y = y; + } + /// Rotates the position by the given angle in radians. + #[must_use] + pub fn rotate_by(&self, angle: Angle2D) -> Self { + Self(self.0.rotate_by(angle), self.1 + angle) + } + /// Returns the facing angle. + #[inline] + #[must_use] + pub fn angle(&self) -> Angle2D { + self.1 + } + /// Sets the facing angle. + #[inline] + #[must_use] + #[allow(non_snake_case)] + pub const fn setAngle(&mut self, angle: Angle2D) { + self.1 = angle; + } + /// Returns the inverted Position. + /// + /// Same as rotating the position by 180 degrees. + #[inline] + #[must_use] + pub fn inverse(&self) -> Self { + -self + } +} + +#[macros::mass_impl( + $THIS = @ORM Pos2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::Add for THIS { + type Output = Pos2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + Pos2D::new(Coord2D::new(self.0.x + rhs.x(), self.0.y + rhs.y()), self.1) + } +} + +#[macros::mass_impl( + $THIS = @ORM Pos2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::Add for THIS { + type Output = Pos2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + Pos2D::new(Coord2D::new(self.0.x + rhs.x, self.0.y + rhs.y), self.1) + } +} + +#[macros::mass_impl( + $THIS = @ORM Pos2D, + $OTHER = @ORM Pos2D +)] +impl core::ops::Add for THIS { + type Output = Pos2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + Pos2D::new(Coord2D::new(self.0.x + rhs.0.x, self.0.y + rhs.0.y), self.1 + rhs.1) + } +} + +#[macros::mass_impl( + $THIS = @ORM Pos2D, + $OTHER = @ORM Angle2D +)] +impl core::ops::Add for THIS { + type Output = Pos2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + Pos2D::new(self.0, self.1 + rhs) + } +} + +#[macros::mass_impl( + $THIS = @OM Pos2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + self.0 += rhs; + } +} + +#[macros::mass_impl( + $THIS = @OM Pos2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + self.0 += rhs; + } +} + +#[macros::mass_impl( + $THIS = @OM Pos2D, + $OTHER = @ORM Pos2D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + self.0 += rhs.0; + self.1 += rhs.1; + } +} + +#[macros::mass_impl( + $THIS = @OM Pos2D, + $OTHER = @ORM Angle2D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + self.1 += rhs; + } +} + +#[macros::mass_impl( + $THIS = @ORM Pos2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::Sub for THIS { + type Output = Pos2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + Pos2D::new(Coord2D::new(self.0.x - rhs.x(), self.0.y - rhs.y()), self.1) + } +} + +#[macros::mass_impl( + $THIS = @ORM Pos2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::Sub for THIS { + type Output = Pos2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + Pos2D::new(Coord2D::new(self.0.x - rhs.x, self.0.y - rhs.y), self.1) + } +} + +#[macros::mass_impl( + $THIS = @ORM Pos2D, + $OTHER = @ORM Pos2D +)] +impl core::ops::Sub for THIS { + type Output = Pos2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + Pos2D::new(Coord2D::new(self.0.x - rhs.0.x, self.0.y - rhs.0.y), self.1 - rhs.1) + } +} + +#[macros::mass_impl( + $THIS = @ORM Pos2D, + $OTHER = @ORM Angle2D +)] +impl core::ops::Sub for THIS { + type Output = Pos2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + Pos2D::new(self.0, self.1 - rhs) + } +} + +#[macros::mass_impl( + $THIS = @OM Pos2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + self.0 -= rhs; + } +} + +#[macros::mass_impl( + $THIS = @OM Pos2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + self.0 -= rhs; + } +} + +#[macros::mass_impl( + $THIS = @OM Pos2D, + $OTHER = @ORM Pos2D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + self.0 -= rhs.0; + self.1 -= rhs.1; + } +} + +#[macros::mass_impl( + $THIS = @OM Pos2D, + $OTHER = @OR Angle2D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + self.1 -= rhs; + } +} + +#[macros::mass_impl($THIS = @ORM Pos2D)] +impl core::ops::Neg for THIS { + type Output = Pos2D; + #[inline] + #[must_use] + fn neg(self) -> Self::Output { + Pos2D::new(-self.0, -self.1) + } +} + +impl core::fmt::Display for Pos2D { + #[inline] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}; {}", self.0, self.1) + } +} + +impl Default for Pos2D { + #[inline] + #[must_use] + fn default() -> Self { + Self::origin() + } +} + +impl, A: Into> From<(C, A)> for Pos2D { + #[inline] + #[must_use] + fn from((c, a): (C, A)) -> Self { + Self::new(c.into(), a.into()) + } +} + +impl> From<(F, F, F, bool)> for Pos2D { + #[inline] + #[must_use] + fn from(i: (F, F, F, bool)) -> Self { + Self::new( + Coord2D::from((i.0, i.1)), + Angle2D::from((i.2, i.3)) + ) + } +} + +impl> From<(F, F, F)> for Pos2D { + #[inline] + #[must_use] + fn from(i: (F, F, F)) -> Self { + Self::from((i.0, i.1, i.2, false)) + } +} diff --git a/libtrig/traits/float.rs b/libtrig/traits/float.rs new file mode 100644 index 0000000..dad8b6a --- /dev/null +++ b/libtrig/traits/float.rs @@ -0,0 +1,651 @@ +use super::Number; +use crate::int; + +/// A trait for floating point numbers. +pub trait Float: Number { + /// Returns the largest integer less than or equal to `self`. + /// + /// # Examples + /// + /// ``` + /// let f = 3.7_f64; + /// let g = 3.0_f64; + /// let h = -3.7_f64; + /// + /// assert_eq!(f.floor(), 3.0); + /// assert_eq!(g.floor(), 3.0); + /// assert_eq!(h.floor(), -4.0); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn floor(&self) -> Self; + + /// Returns the smallest integer greater than or equal to `self`. + /// + /// # Examples + /// + /// ``` + /// let f = 3.01_f64; + /// let g = 4.0_f64; + /// + /// assert_eq!(f.ceil(), 4.0); + /// assert_eq!(g.ceil(), 4.0); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn ceil(&self) -> Self; + + /// Returns the nearest integer to `self`. If a value is half-way between two + /// integers, round away from `0.0`. + /// + /// # Examples + /// + /// ``` + /// let f = 3.3_f64; + /// let g = -3.3_f64; + /// let h = -3.7_f64; + /// let i = 3.5_f64; + /// let j = 4.5_f64; + /// + /// assert_eq!(f.round(), 3.0); + /// assert_eq!(g.round(), -3.0); + /// assert_eq!(h.round(), -4.0); + /// assert_eq!(i.round(), 4.0); + /// assert_eq!(j.round(), 5.0); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn round(&self) -> Self; + + /// Returns the integer part of `self`. + /// This means that non-integer numbers are always truncated towards zero. + /// + /// # Examples + /// + /// ``` + /// let f = 3.7_f64; + /// let g = 3.0_f64; + /// let h = -3.7_f64; + /// + /// assert_eq!(f.trunc(), 3.0); + /// assert_eq!(g.trunc(), 3.0); + /// assert_eq!(h.trunc(), -3.0); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn trunc(&self) -> Self; + + /// Returns the fractional part of `self`. + /// + /// # Examples + /// + /// ``` + /// let x = 3.6_f64; + /// let y = -3.6_f64; + /// let abs_difference_x = (x.fract() - 0.6).abs(); + /// let abs_difference_y = (y.fract() - (-0.6)).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// ``` + #[inline] + #[must_use = "method returns a new number and does not mutate the original value"] + fn fract(&self) -> Self { + *self - self.trunc() + } + + /// Computes the absolute value of `self`. + /// + /// # Examples + /// + /// ``` + /// let x = 3.5_f64; + /// let y = -3.5_f64; + /// + /// let abs_difference_x = (x.abs() - x).abs(); + /// let abs_difference_y = (y.abs() - (-y)).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// + /// assert!(f64::NAN.abs().is_nan()); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn abs(&self) -> Self; + + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - NaN if the number is NaN + /// + /// # Examples + /// + /// ``` + /// let f = 3.5_f64; + /// + /// assert_eq!(f.signum(), 1.0); + /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0); + /// + /// assert!(f64::NAN.signum().is_nan()); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn signum(&self) -> Self; + + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. However, + /// this is not always true, and will be heavily dependant on designing + /// algorithms with specific target hardware in mind. + /// + /// # Examples + /// + /// ``` + /// let m = 10.0_f64; + /// let x = 4.0_f64; + /// let b = 60.0_f64; + /// + /// // 100.0 + /// let abs_difference = (m.mul_add(x, b) - ((m * x) + b)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn mul_add(&self, a: Self, b: Self) -> Self; + + /// Calculates Euclidean division, the matching method for `rem_euclid`. + /// + /// This computes the integer `n` such that + /// `self = n * rhs + self.rem_euclid(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer `n` + /// such that `self >= n * rhs`. + /// + /// # Examples + /// + /// ``` + /// let a: f64 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn div_euclid(&self, rhs: Self) -> Self; + + /// Calculates the least nonnegative remainder of `self (mod rhs)`. + /// + /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in + /// most cases. However, due to a floating point round-off error it can + /// result in `r == rhs.abs()`, violating the mathematical definition, if + /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. + /// This result is not an element of the function's codomain, but it is the + /// closest floating point number in the real numbers and thus fulfills the + /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` + /// approximately. + /// + /// # Examples + /// + /// ``` + /// let a: f64 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.rem_euclid(b), 3.0); + /// assert_eq!((-a).rem_euclid(b), 1.0); + /// assert_eq!(a.rem_euclid(-b), 3.0); + /// assert_eq!((-a).rem_euclid(-b), 1.0); + /// // limitation due to round-off error + /// assert!((-f64::EPSILON).rem_euclid(3.0) != 0.0); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn rem_euclid(&self, rhs: Self) -> Self; + + /// Raises a number to an integer power. + /// + /// Using this function is generally faster than using `powf`. + /// It might have a different sequence of rounding operations than `powf`, + /// so the results are not guaranteed to agree. + /// + /// # Examples + /// + /// ``` + /// let x = 2.0_f64; + /// let abs_difference = (x.powi(2) - (x * x)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn powi(&self, n: int) -> Self; + + /// Raises a number to a floating point power. + /// + /// # Examples + /// + /// ``` + /// let x = 2.0_f64; + /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn powf(&self, n: Self) -> Self; + + /// Returns the square root of a number. + /// + /// Returns NaN if `self` is a negative number other than `-0.0`. + /// + /// # Examples + /// + /// ``` + /// let positive = 4.0_f64; + /// let negative = -4.0_f64; + /// let negative_zero = -0.0_f64; + /// + /// let abs_difference = (positive.sqrt() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// assert!(negative.sqrt().is_nan()); + /// assert!(negative_zero.sqrt() == negative_zero); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn sqrt(&self) -> Self; + + /// Returns `e^(self)`, (the exponential function). + /// + /// # Examples + /// + /// ``` + /// let one = 1.0_f64; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn exp(&self) -> Self; + + /// Returns `2^(self)`. + /// + /// # Examples + /// + /// ``` + /// let f = 2.0_f64; + /// + /// // 2^2 - 4 == 0 + /// let abs_difference = (f.exp2() - 4.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn exp2(&self) -> Self; + + /// Returns the natural logarithm of the number. + /// + /// # Examples + /// + /// ``` + /// let one = 1.0_f64; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn ln(&self) -> Self; + + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// The result might not be correctly rounded owing to implementation details; + /// `self.log2()` can produce more accurate results for base 2, and + /// `self.log10()` can produce more accurate results for base 10. + /// + /// # Examples + /// + /// ``` + /// let twenty_five = 25.0_f64; + /// + /// // log5(25) - 2 == 0 + /// let abs_difference = (twenty_five.log(5.0) - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn log(&self, base: Self) -> Self; + + /// Returns the base 2 logarithm of the number. + /// + /// # Examples + /// + /// ``` + /// let four = 4.0_f64; + /// + /// // log2(4) - 2 == 0 + /// let abs_difference = (four.log2() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn log2(&self) -> Self; + + /// Returns the base 10 logarithm of the number. + /// + /// # Examples + /// + /// ``` + /// let hundred = 100.0_f64; + /// + /// // log10(100) - 2 == 0 + /// let abs_difference = (hundred.log10() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn log10(&self) -> Self; + + /// Returns the cube root of a number. + /// + /// # Examples + /// + /// ``` + /// let x = 8.0_f64; + /// + /// // x^(1/3) - 2 == 0 + /// let abs_difference = (x.cbrt() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn cbrt(&self) -> Self; + + /// Compute the distance between the origin and a point (`x`, `y`) on the + /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a + /// right-angle triangle with other sides having length `x.abs()` and + /// `y.abs()`. + /// + /// # Examples + /// + /// ``` + /// let x = 2.0_f64; + /// let y = 3.0_f64; + /// + /// // sqrt(x^2 + y^2) + /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn hypot(&self, other: Self) -> Self; + + /// Computes the sine of a number (in radians). + /// + /// # Examples + /// + /// ``` + /// let x = std::f64::consts::FRAC_PI_2; + /// + /// let abs_difference = (x.sin() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn sin(&self) -> Self; + + /// Computes the cosine of a number (in radians). + /// + /// # Examples + /// + /// ``` + /// let x = 2.0 * std::f64::consts::PI; + /// + /// let abs_difference = (x.cos() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn cos(&self) -> Self; + + /// Computes the tangent of a number (in radians). + /// + /// # Examples + /// + /// ``` + /// let x = std::f64::consts::FRAC_PI_4; + /// let abs_difference = (x.tan() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-14); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn tan(&self) -> Self; + + /// Computes the arcsine of a number. Return value is in radians in + /// the range [-pi/2, pi/2] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// # Examples + /// + /// ``` + /// let f = std::f64::consts::FRAC_PI_2; + /// + /// // asin(sin(pi/2)) + /// let abs_difference = (f.sin().asin() - std::f64::consts::FRAC_PI_2).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn asin(&self) -> Self; + + /// Computes the arccosine of a number. Return value is in radians in + /// the range [0, pi] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// # Examples + /// + /// ``` + /// let f = std::f64::consts::FRAC_PI_4; + /// + /// // acos(cos(pi/4)) + /// let abs_difference = (f.cos().acos() - std::f64::consts::FRAC_PI_4).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn acos(&self) -> Self; + + /// Computes the arctangent of a number. Return value is in radians in the + /// range [-pi/2, pi/2]; + /// + /// # Examples + /// + /// ``` + /// let f = 1.0_f64; + /// + /// // atan(tan(1)) + /// let abs_difference = (f.tan().atan() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn atan(&self) -> Self; + + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. + /// + /// * `x = 0`, `y = 0`: `0` + /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` + /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` + /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + /// + /// # Examples + /// + /// ``` + /// // Positive angles measured counter-clockwise + /// // from positive x axis + /// // -pi/4 radians (45 deg clockwise) + /// let x1 = 3.0_f64; + /// let y1 = -3.0_f64; + /// + /// // 3pi/4 radians (135 deg counter-clockwise) + /// let x2 = -3.0_f64; + /// let y2 = 3.0_f64; + /// + /// let abs_difference_1 = (y1.atan2(x1) - (-std::f64::consts::FRAC_PI_4)).abs(); + /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * std::f64::consts::FRAC_PI_4)).abs(); + /// + /// assert!(abs_difference_1 < 1e-10); + /// assert!(abs_difference_2 < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn atan2(&self, other: Self) -> Self; + + /// Simultaneously computes the sine and cosine of the number, `x`. Returns + /// `(sin(x), cos(x))`. + /// + /// # Examples + /// + /// ``` + /// let x = std::f64::consts::FRAC_PI_4; + /// let f = x.sin_cos(); + /// + /// let abs_difference_0 = (f.0 - x.sin()).abs(); + /// let abs_difference_1 = (f.1 - x.cos()).abs(); + /// + /// assert!(abs_difference_0 < 1e-10); + /// assert!(abs_difference_1 < 1e-10); + /// ``` + fn sin_cos(&self) -> (Self, Self); + + /// Returns `e^(self) - 1` in a way that is accurate even if the + /// number is close to zero. + /// + /// # Examples + /// + /// ``` + /// let x = 1e-16_f64; + /// + /// // for very small x, e^x is approximately 1 + x + x^2 / 2 + /// let approx = x + x * x / 2.0; + /// let abs_difference = (x.exp_m1() - approx).abs(); + /// + /// assert!(abs_difference < 1e-20); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn exp_m1(&self) -> Self; + + /// Returns `ln(1+n)` (natural logarithm) more accurately than if + /// the operations were performed separately. + /// + /// # Examples + /// + /// ``` + /// let x = 1e-16_f64; + /// + /// // for very small x, ln(1 + x) is approximately x - x^2 / 2 + /// let approx = x - x * x / 2.0; + /// let abs_difference = (x.ln_1p() - approx).abs(); + /// + /// assert!(abs_difference < 1e-20); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn ln_1p(&self) -> Self; + + /// Hyperbolic sine function. + /// + /// # Examples + /// + /// ``` + /// let e = std::f64::consts::E; + /// let x = 1.0_f64; + /// + /// let f = x.sinh(); + /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` + /// let g = ((e * e) - 1.0) / (2.0 * e); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn sinh(&self) -> Self; + + /// Hyperbolic cosine function. + /// + /// # Examples + /// + /// ``` + /// let e = std::f64::consts::E; + /// let x = 1.0_f64; + /// let f = x.cosh(); + /// // Solving cosh() at 1 gives this result + /// let g = ((e * e) + 1.0) / (2.0 * e); + /// let abs_difference = (f - g).abs(); + /// + /// // Same result + /// assert!(abs_difference < 1.0e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn cosh(&self) -> Self; + + /// Hyperbolic tangent function. + /// + /// # Examples + /// + /// ``` + /// let e = std::f64::consts::E; + /// let x = 1.0_f64; + /// + /// let f = x.tanh(); + /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` + /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2)); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn tanh(&self) -> Self; + + /// Inverse hyperbolic sine function. + /// + /// # Examples + /// + /// ``` + /// let x = 1.0_f64; + /// let f = x.sinh().asinh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn asinh(&self) -> Self; + + /// Inverse hyperbolic cosine function. + /// + /// # Examples + /// + /// ``` + /// let x = 1.0_f64; + /// let f = x.cosh().acosh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn acosh(&self) -> Self; + + /// Inverse hyperbolic tangent function. + /// + /// # Examples + /// + /// ``` + /// let e = std::f64::consts::E; + /// let f = e.tanh().atanh(); + /// + /// let abs_difference = (f - e).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + fn atanh(&self) -> Self; +} diff --git a/libtrig/traits/mod.rs b/libtrig/traits/mod.rs new file mode 100644 index 0000000..8ac1551 --- /dev/null +++ b/libtrig/traits/mod.rs @@ -0,0 +1,137 @@ +use crate::*; + +mod number; +mod float; + +pub use number::Number; +pub use float::Float; + +macro_rules! simpl { + ($n:ident => $m:ident $($o:tt)*) => ( + #[inline] + #[must_use] + fn $n(&self) -> Self { + math::$m(*self) + } + simpl!($($o)*); + ); + ($n:ident $($o:tt)*) => ( + simpl!($n => $n $($o)*); + ); + () => (); +} + +impl Float for crate::float { + fn signum(&self) -> Self { + todo!() + } + + fn mul_add(&self, a: Self, b: Self) -> Self { + todo!() + } + + fn div_euclid(&self, rhs: Self) -> Self { + todo!() + } + + fn rem_euclid(&self, rhs: Self) -> Self { + todo!() + } + + fn powi(&self, n: int) -> Self { + todo!() + } + + fn powf(&self, n: Self) -> Self { + todo!() + } + simpl!(floor ceil round trunc abs => fabs sqrt exp exp2); + + fn ln(&self) -> Self { + todo!() + } + + fn log(&self, base: Self) -> Self { + todo!() + } + + fn log2(&self) -> Self { + todo!() + } + + fn log10(&self) -> Self { + todo!() + } + + fn cbrt(&self) -> Self { + todo!() + } + + fn hypot(&self, other: Self) -> Self { + todo!() + } + + fn sin(&self) -> Self { + todo!() + } + + fn cos(&self) -> Self { + todo!() + } + + fn tan(&self) -> Self { + todo!() + } + + fn asin(&self) -> Self { + todo!() + } + + fn acos(&self) -> Self { + todo!() + } + + fn atan(&self) -> Self { + todo!() + } + + fn atan2(&self, other: Self) -> Self { + todo!() + } + + fn sin_cos(&self) -> (Self, Self) { + todo!() + } + + fn exp_m1(&self) -> Self { + todo!() + } + + fn ln_1p(&self) -> Self { + todo!() + } + + fn sinh(&self) -> Self { + todo!() + } + + fn cosh(&self) -> Self { + todo!() + } + + fn tanh(&self) -> Self { + todo!() + } + + fn asinh(&self) -> Self { + todo!() + } + + fn acosh(&self) -> Self { + todo!() + } + + fn atanh(&self) -> Self { + todo!() + } +} \ No newline at end of file diff --git a/libtrig/traits/number.rs b/libtrig/traits/number.rs new file mode 100644 index 0000000..4c3775d --- /dev/null +++ b/libtrig/traits/number.rs @@ -0,0 +1,14 @@ +use core::ops; + +/// A trait for types that can be used as numbers. +pub trait Number: + core::fmt::Debug + Copy + Clone + PartialEq + + ops::Add + ops::AddAssign + + ops::Sub + ops::SubAssign + + ops::Mul + ops::MulAssign + + ops::Div + ops::DivAssign + + ops::Rem + ops::RemAssign + +{ } + +impl Number for crate::int { } +impl Number for crate::float { } diff --git a/libtrig/types.rs b/libtrig/types.rs new file mode 100644 index 0000000..e3c78fb --- /dev/null +++ b/libtrig/types.rs @@ -0,0 +1,10 @@ +#![allow(non_camel_case_types)] + +type __float = f64; +type __int = i32; + +/// A floating point number. +pub type float = __float; + +/// An integer. +pub type int = __int; diff --git a/libtrig/vectors/mod.rs b/libtrig/vectors/mod.rs new file mode 100644 index 0000000..0078ddd --- /dev/null +++ b/libtrig/vectors/mod.rs @@ -0,0 +1,5 @@ +mod vec2d; +mod vec3d; + +pub use vec2d::Vec2D; +pub use vec3d::Vec3D; diff --git a/libtrig/vectors.rs b/libtrig/vectors/vec2d.rs similarity index 69% rename from libtrig/vectors.rs rename to libtrig/vectors/vec2d.rs index 2e7dbee..90b95da 100644 --- a/libtrig/vectors.rs +++ b/libtrig/vectors/vec2d.rs @@ -1,17 +1,19 @@ -use crate::{Angle, Float}; +use crate::traits::Float; +use crate::*; +/// A 2D vector. #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Vec2D(Float, Float); +pub struct Vec2D(float, float); impl Vec2D { /// Creates a new `Vec2D` from the given `x` and `y` values. #[inline] #[must_use] - pub const fn new(x: Float, y: Float) -> Self { + pub const fn new(x: float, y: float) -> Self { Self(x, y) } - /// Creates a new `Vec2D` from the given `x` and `y` values. + /// Creates a new `Vec2D` located at the origin. #[inline] #[must_use] pub const fn origin() -> Self { @@ -20,18 +22,18 @@ impl Vec2D { /// Returns the x component of the vector. #[inline] #[must_use] - pub const fn x(&self) -> Float { + pub const fn x(&self) -> float { self.0 } /// Returns the y component of the vector. #[inline] #[must_use] - pub const fn y(&self) -> Float { + pub const fn y(&self) -> float { self.1 } /// Rotates the vector by the given angle in radians. #[must_use] - pub fn rotate_by(&self, angle: Angle) -> Self { + pub fn rotate_by(&self, angle: Angle2D) -> Self { let angle = angle.to_radians(); let (sin, cos) = angle.sin_cos(); Self( @@ -42,8 +44,8 @@ impl Vec2D { /// Returns the angle of the vector in radians. #[inline] #[must_use] - pub fn angle(&self) -> Angle { - Angle::from_radians(self.y().atan2(self.x())) + pub fn angle(&self) -> Angle2D { + Angle2D::from_radians(self.y().atan2(self.x())) } /// Returns the inverted vector. /// @@ -51,26 +53,27 @@ impl Vec2D { #[inline] #[must_use] pub fn inverse(&self) -> Self { - -*self + -self } /// Returns the dot product of the vector and the given vector. #[inline] #[must_use] - pub fn dot(&self, other: Self) -> Float { + pub fn dot(&self, other: Self) -> float { self.x() * other.x() + self.y() * other.y() } /// Returns the magnitude of the vector. #[inline] #[must_use] - pub fn magnitude(&self) -> Float { + pub fn magnitude(&self) -> float { self.dot(*self).sqrt() } - /// Returns the normalized vector. + /// Normalizes this vector. #[inline] #[must_use] pub fn normalize(&mut self) { - // let magnitude = self.magnitude(); - // self /= magnitude; + let magnitude = self.magnitude(); + self.0 /= magnitude; + self.1 /= magnitude; } } @@ -78,7 +81,7 @@ impl Vec2D { $THIS = @ORM Vec2D, $OTHER = @ORM Vec2D )] -impl std::ops::Add for THIS { +impl core::ops::Add for THIS { type Output = Vec2D; #[inline] #[must_use] @@ -91,7 +94,7 @@ impl std::ops::Add for THIS { $THIS = @OM Vec2D, $OTHER = @ORM Vec2D )] -impl std::ops::AddAssign for THIS { +impl core::ops::AddAssign for THIS { #[inline] fn add_assign(&mut self, rhs: OTHER) { self.0 += rhs.x(); @@ -103,7 +106,7 @@ impl std::ops::AddAssign for THIS { $THIS = @ORM Vec2D, $OTHER = @ORM Vec2D )] -impl std::ops::Sub for THIS { +impl core::ops::Sub for THIS { type Output = Vec2D; #[inline] #[must_use] @@ -116,7 +119,7 @@ impl std::ops::Sub for THIS { $THIS = @OM Vec2D, $OTHER = @ORM Vec2D )] -impl std::ops::SubAssign for THIS { +impl core::ops::SubAssign for THIS { #[inline] fn sub_assign(&mut self, rhs: OTHER) { self.0 -= rhs.x(); @@ -126,9 +129,9 @@ impl std::ops::SubAssign for THIS { #[macros::mass_impl( $THIS = @ORM Vec2D, - $OTHER = @OR Float + $OTHER = @OR float )] -impl std::ops::Mul for THIS { +impl core::ops::Mul for THIS { type Output = Vec2D; #[inline] #[must_use] @@ -139,9 +142,9 @@ impl std::ops::Mul for THIS { #[macros::mass_impl( $THIS = @OM Vec2D, - $OTHER = @OR Float + $OTHER = @OR float )] -impl std::ops::MulAssign for THIS { +impl core::ops::MulAssign for THIS { #[inline] fn mul_assign(&mut self, rhs: OTHER) { self.0 *= rhs; @@ -151,9 +154,9 @@ impl std::ops::MulAssign for THIS { #[macros::mass_impl( $THIS = @ORM Vec2D, - $OTHER = @OR Float + $OTHER = @OR float )] -impl std::ops::Div for THIS { +impl core::ops::Div for THIS { type Output = Vec2D; #[inline] #[must_use] @@ -164,9 +167,9 @@ impl std::ops::Div for THIS { #[macros::mass_impl( $THIS = @OM Vec2D, - $OTHER = @OR Float + $OTHER = @OR float )] -impl std::ops::DivAssign for THIS { +impl core::ops::DivAssign for THIS { #[inline] fn div_assign(&mut self, rhs: OTHER) { self.0 /= rhs; @@ -175,7 +178,7 @@ impl std::ops::DivAssign for THIS { } #[macros::mass_impl($THIS = @ORM Vec2D)] -impl std::ops::Neg for THIS { +impl core::ops::Neg for THIS { type Output = Vec2D; #[inline] #[must_use] @@ -184,9 +187,9 @@ impl std::ops::Neg for THIS { } } -impl std::fmt::Display for Vec2D { +impl core::fmt::Display for Vec2D { #[inline] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "[{}, {}]", self.x(), self.y()) } } @@ -199,15 +202,15 @@ impl Default for Vec2D { } } -impl From<(Float, Float)> for Vec2D { +impl From<(float, float)> for Vec2D { #[inline] #[must_use] - fn from((x, y): (Float, Float)) -> Self { + fn from((x, y): (float, float)) -> Self { Self::new(x, y) } } -impl From for (Float, Float) { +impl From for (float, float) { #[inline] #[must_use] fn from(Vec2D(x, y): Vec2D) -> Self { diff --git a/libtrig/vectors/vec3d.rs b/libtrig/vectors/vec3d.rs new file mode 100644 index 0000000..101dcc1 --- /dev/null +++ b/libtrig/vectors/vec3d.rs @@ -0,0 +1,224 @@ +use crate::traits::Float; +use crate::*; + +/// A 3D vector. +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +pub struct Vec3D(float, float, float); + +impl Vec3D { + /// Creates a new `Vec3D` from the given `x`, `y` and `z` values. + #[inline] + #[must_use] + pub const fn new(x: float, y: float, z: float) -> Self { + Self(x, y, z) + } + /// Creates a new `Vec3D` located at the origin. + #[inline] + #[must_use] + pub const fn origin() -> Self { + Self(0.0, 0.0, 0.0) + } + /// Returns the x component of the vector. + #[inline] + #[must_use] + pub const fn x(&self) -> float { + self.0 + } + /// Returns the y component of the vector. + #[inline] + #[must_use] + pub const fn y(&self) -> float { + self.1 + } + /// Returns the z component of the vector. + #[inline] + #[must_use] + pub const fn z(&self) -> float { + self.2 + } + /// Returns the inverted vector. + #[inline] + #[must_use] + pub fn inverse(&self) -> Self { + -self + } + /// Returns the dot product of the vector and the given vector. + #[inline] + #[must_use] + pub fn dot(&self, other: Self) -> float { + self.x() * other.x() + self.y() * other.y() + self.z() * other.z() + } + /// Returns the magnitude of the vector. + #[inline] + #[must_use] + pub fn magnitude(&self) -> float { + self.dot(*self).sqrt() + } + /// Normalizes this vector. + #[inline] + pub fn normalize(&mut self) { + let magnitude = self.magnitude(); + self.0 /= magnitude; + self.1 /= magnitude; + self.2 /= magnitude; + } +} + +#[macros::mass_impl( + $THIS = @ORM Vec3D, + $OTHER = @ORM Vec3D +)] +impl core::ops::Add for THIS { + type Output = Vec3D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + Vec3D(self.x() + rhs.x(), self.y() + rhs.y(), self.z() + rhs.z()) + } +} + +#[macros::mass_impl( + $THIS = @ORM Vec3D, + $OTHER = @ORM Vec2D +)] +impl core::ops::Add for THIS { + type Output = Vec3D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + Vec3D(self.x() + rhs.x(), self.y() + rhs.y(), self.z()) + } +} + +#[macros::mass_impl( + $THIS = @OM Vec3D, + $OTHER = @ORM Vec3D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + self.0 += rhs.x(); + self.1 += rhs.y(); + self.2 += rhs.z(); + } +} + +#[macros::mass_impl( + $THIS = @ORM Vec3D, + $OTHER = @ORM Vec3D +)] +impl core::ops::Sub for THIS { + type Output = Vec3D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + Vec3D(self.x() - rhs.x(), self.y() - rhs.y(), self.z() - rhs.z()) + } +} + +#[macros::mass_impl( + $THIS = @OM Vec3D, + $OTHER = @ORM Vec3D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + self.0 -= rhs.x(); + self.1 -= rhs.y(); + self.2 -= rhs.z(); + } +} + +#[macros::mass_impl( + $THIS = @ORM Vec3D, + $OTHER = @OR float +)] +impl core::ops::Mul for THIS { + type Output = Vec3D; + #[inline] + #[must_use] + fn mul(self, rhs: OTHER) -> Self::Output { + Vec3D(self.x() * rhs, self.y() * rhs, self.z() * rhs) + } +} + +#[macros::mass_impl( + $THIS = @OM Vec3D, + $OTHER = @OR float +)] +impl core::ops::MulAssign for THIS { + #[inline] + fn mul_assign(&mut self, rhs: OTHER) { + self.0 *= rhs; + self.1 *= rhs; + self.2 *= rhs; + } +} + +#[macros::mass_impl( + $THIS = @ORM Vec3D, + $OTHER = @OR float +)] +impl core::ops::Div for THIS { + type Output = Vec3D; + #[inline] + #[must_use] + fn div(self, rhs: OTHER) -> Self::Output { + Vec3D(self.x() / rhs, self.y() / rhs, self.z() / rhs) + } +} + +#[macros::mass_impl( + $THIS = @OM Vec3D, + $OTHER = @OR float +)] +impl core::ops::DivAssign for THIS { + #[inline] + fn div_assign(&mut self, rhs: OTHER) { + self.0 /= rhs; + self.1 /= rhs; + self.2 /= rhs; + } +} + +#[macros::mass_impl($THIS = @ORM Vec3D)] +impl core::ops::Neg for THIS { + type Output = Vec3D; + #[inline] + #[must_use] + fn neg(self) -> Self::Output { + Vec3D(-self.x(), -self.y(), -self.z()) + } +} + +impl core::fmt::Display for Vec3D { + #[inline] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "[{}, {}, {}]", self.x(), self.y(), self.z()) + } +} + +impl Default for Vec3D { + #[inline] + #[must_use] + fn default() -> Self { + Self::origin() + } +} + +impl From<(float, float, float)> for Vec3D { + #[inline] + #[must_use] + fn from((x, y, z): (float, float, float)) -> Self { + Self::new(x, y, z) + } +} + +impl From for (float, float, float) { + #[inline] + #[must_use] + fn from(Vec3D(x, y, z): Vec3D) -> Self { + (x, y, z) + } +} diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 0000000..07ade69 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +nightly \ No newline at end of file From 173dabfdf63702a9068a5d152ce286700fdea37a Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sat, 4 Nov 2023 18:56:05 -0700 Subject: [PATCH 03/93] LLM improvement --- core/llm/README.md | 4 +- core/llm/lib.rs | 4 +- core/llm/math.rs | 22 ++-- core/llm/math/acos.rs | 57 ++++----- core/llm/math/acosf.rs | 40 ++++--- core/llm/math/acosh.rs | 8 +- core/llm/math/acoshf.rs | 8 +- core/llm/math/asin.rs | 53 ++++---- core/llm/math/asinf.rs | 36 +++--- core/llm/math/asinh.rs | 12 +- core/llm/math/asinhf.rs | 12 +- core/llm/math/atan.rs | 46 +++---- core/llm/math/atan2.rs | 19 +-- core/llm/math/atan2f.rs | 20 ++-- core/llm/math/atanf.rs | 26 ++-- core/llm/math/atanh.rs | 10 +- core/llm/math/atanhf.rs | 10 +- core/llm/math/cbrt.rs | 39 +++--- core/llm/math/cbrtf.rs | 35 +++--- core/llm/math/ceil.rs | 17 +-- core/llm/math/ceilf.rs | 16 +-- core/llm/math/copysign.rs | 8 +- core/llm/math/copysignf.rs | 8 +- core/llm/math/cos.rs | 95 ++++++++------- core/llm/math/cosf.rs | 32 +++-- core/llm/math/cosh.rs | 10 +- core/llm/math/coshf.rs | 10 +- core/llm/math/erf.rs | 190 +++++++++++++++-------------- core/llm/math/erff.rs | 176 +++++++++++++-------------- core/llm/math/exp.rs | 53 ++++---- core/llm/math/exp10.rs | 11 +- core/llm/math/exp10f.rs | 15 ++- core/llm/math/exp2.rs | 38 +++--- core/llm/math/exp2f.rs | 43 +++---- core/llm/math/expf.rs | 38 +++--- core/llm/math/expm1.rs | 48 ++++---- core/llm/math/expm1f.rs | 42 +++---- core/llm/math/expo2.rs | 12 +- core/llm/math/fabs.rs | 13 +- core/llm/math/fabsf.rs | 13 +- core/llm/math/fdim.rs | 6 +- core/llm/math/fdimf.rs | 6 +- core/llm/math/floor.rs | 15 +-- core/llm/math/floorf.rs | 16 +-- core/llm/math/fma.rs | 32 ++--- core/llm/math/fmaf.rs | 51 ++++---- core/llm/math/fmax.rs | 5 +- core/llm/math/fmaxf.rs | 5 +- core/llm/math/fmin.rs | 5 +- core/llm/math/fminf.rs | 5 +- core/llm/math/fmod.rs | 11 +- core/llm/math/fmodf.rs | 12 +- core/llm/math/frexp.rs | 14 ++- core/llm/math/frexpf.rs | 14 ++- core/llm/math/hypot.rs | 25 ++-- core/llm/math/hypotf.rs | 17 +-- core/llm/math/ilogb.rs | 5 +- core/llm/math/ilogbf.rs | 5 +- core/llm/math/j0.rs | 141 ++++++++++++---------- core/llm/math/j0f.rs | 144 +++++++++++----------- core/llm/math/j1.rs | 127 +++++++++++--------- core/llm/math/j1f.rs | 149 ++++++++++++----------- core/llm/math/jn.rs | 68 ++++++----- core/llm/math/jnf.rs | 147 ++++++++++++----------- core/llm/math/k_cos.rs | 16 +-- core/llm/math/k_cosf.rs | 26 ++-- core/llm/math/k_expo2.rs | 8 +- core/llm/math/k_expo2f.rs | 8 +- core/llm/math/k_sin.rs | 16 +-- core/llm/math/k_sinf.rs | 26 ++-- core/llm/math/k_tan.rs | 18 +-- core/llm/math/k_tanf.rs | 12 +- core/llm/math/ldexp.rs | 5 +- core/llm/math/ldexpf.rs | 5 +- core/llm/math/lgamma.rs | 7 +- core/llm/math/lgamma_r.rs | 169 +++++++++++++------------- core/llm/math/lgammaf.rs | 7 +- core/llm/math/lgammaf_r.rs | 172 +++++++++++++------------- core/llm/math/ln.rs | 9 ++ core/llm/math/lnf.rs | 9 ++ core/llm/math/log.rs | 54 +++++---- core/llm/math/log10.rs | 71 +++++------ core/llm/math/log10f.rs | 59 ++++----- core/llm/math/log1p.rs | 64 +++++----- core/llm/math/log1pf.rs | 51 ++++---- core/llm/math/log2.rs | 63 +++++----- core/llm/math/log2f.rs | 53 ++++---- core/llm/math/logf.rs | 33 ++--- core/llm/math/modf.rs | 15 ++- core/llm/math/modff.rs | 15 ++- core/llm/math/nextafter.rs | 7 +- core/llm/math/nextafterf.rs | 7 +- core/llm/math/pow.rs | 206 ++++++++++++++++---------------- core/llm/math/powf.rs | 135 +++++++++++---------- core/llm/math/rem_pio2.rs | 53 ++++---- core/llm/math/rem_pio2_large.rs | 41 +++---- core/llm/math/rem_pio2f.rs | 34 +++--- core/llm/math/remainder.rs | 9 +- core/llm/math/remainderf.rs | 9 +- core/llm/math/remquo.rs | 13 +- core/llm/math/remquof.rs | 7 +- core/llm/math/rint.rs | 7 +- core/llm/math/rintf.rs | 7 +- core/llm/math/round.rs | 8 +- core/llm/math/roundf.rs | 8 +- core/llm/math/scalbn.rs | 13 +- core/llm/math/scalbnf.rs | 13 +- core/llm/math/sin.rs | 73 +++++------ core/llm/math/sincos.rs | 23 ++-- core/llm/math/sincosf.rs | 75 ++++++------ core/llm/math/sinf.rs | 29 +++-- core/llm/math/sinh.rs | 18 +-- core/llm/math/sinhf.rs | 7 +- core/llm/math/sqrt.rs | 26 ++-- core/llm/math/sqrtf.rs | 27 +++-- core/llm/math/tan.rs | 71 ++++++----- core/llm/math/tanf.rs | 29 +++-- core/llm/math/tanh.rs | 23 ++-- core/llm/math/tanhf.rs | 7 +- core/llm/math/tgamma.rs | 45 +++---- core/llm/math/tgammaf.rs | 7 +- core/llm/math/trunc.rs | 12 +- core/llm/math/truncf.rs | 12 +- core/llm/types.rs | 15 +-- 124 files changed, 2407 insertions(+), 2034 deletions(-) create mode 100644 core/llm/math/ln.rs create mode 100644 core/llm/math/lnf.rs diff --git a/core/llm/README.md b/core/llm/README.md index e066f00..4f5506b 100644 --- a/core/llm/README.md +++ b/core/llm/README.md @@ -1 +1,3 @@ -libm in pure Rust \ No newline at end of file +# **L**ow **L**evel **M**ath + +

A port of MUSL's Math library to Rust for no_std environments.

diff --git a/core/llm/lib.rs b/core/llm/lib.rs index a38b134..f31d77c 100644 --- a/core/llm/lib.rs +++ b/core/llm/lib.rs @@ -17,7 +17,7 @@ mod types; mod math; pub use self::math::*; -pub use types::*; +pub use self::types::*; /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] @@ -38,7 +38,7 @@ pub fn _eqf(a: Float32, b: Float32) -> Result<(), u32> { #[doc(hidden)] #[inline] -pub fn _eq(a: Float, b: Float) -> Result<(), u64> { +pub fn _eq(a: Float64, b: Float64) -> Result<(), u64> { if a.is_nan() && b.is_nan() { Ok(()) } else { diff --git a/core/llm/math.rs b/core/llm/math.rs index d0a004a..34ac60b 100644 --- a/core/llm/math.rs +++ b/core/llm/math.rs @@ -152,6 +152,8 @@ mod lgamma; mod lgamma_r; mod lgammaf; mod lgammaf_r; +mod ln; +mod lnf; mod log; mod log10; mod log10f; @@ -268,6 +270,8 @@ pub use self::lgamma::lgamma; pub use self::lgamma_r::lgamma_r; pub use self::lgammaf::lgammaf; pub use self::lgammaf_r::lgammaf_r; +pub use self::ln::ln; +pub use self::lnf::lnf; pub use self::log::log; pub use self::log10::log10; pub use self::log10f::log10f; @@ -338,33 +342,35 @@ use self::rem_pio2::rem_pio2; use self::rem_pio2_large::rem_pio2_large; use self::rem_pio2f::rem_pio2f; +use crate::Float64; + #[inline] -fn get_high_word(x: f64) -> u32 { +fn get_high_word(x: Float64) -> u32 { (x.to_bits() >> 32) as u32 } #[inline] -fn get_low_word(x: f64) -> u32 { +fn get_low_word(x: Float64) -> u32 { x.to_bits() as u32 } #[inline] -fn with_set_high_word(f: f64, hi: u32) -> f64 { +fn with_set_high_word(f: Float64, hi: u32) -> Float64 { let mut tmp = f.to_bits(); tmp &= 0x00000000_ffffffff; tmp |= (hi as u64) << 32; - f64::from_bits(tmp) + Float64::from_bits(tmp) } #[inline] -fn with_set_low_word(f: f64, lo: u32) -> f64 { +fn with_set_low_word(f: Float64, lo: u32) -> Float64 { let mut tmp = f.to_bits(); tmp &= 0xffffffff_00000000; tmp |= lo as u64; - f64::from_bits(tmp) + Float64::from_bits(tmp) } #[inline] -fn combine_words(hi: u32, lo: u32) -> f64 { - f64::from_bits((hi as u64) << 32 | lo as u64) +fn combine_words(hi: u32, lo: u32) -> Float64 { + Float64::from_bits((hi as u64) << 32 | lo as u64) } diff --git a/core/llm/math/acos.rs b/core/llm/math/acos.rs index 23b1325..d4a1360 100644 --- a/core/llm/math/acos.rs +++ b/core/llm/math/acos.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -9,7 +9,8 @@ * is preserved. * ==================================================== */ -/* acos(x) +/** + * acos(x) * Method : * acos(x) = pi/2 - asin(x) * acos(-x) = pi/2 + asin(x) @@ -31,42 +32,44 @@ * if |x|>1, return NaN with invalid signal. * * Function needed: sqrt - */ +*/ + +use crate::{Float64, Radian64}; use super::sqrt; -const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ -const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ -const PS0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ -const PS1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ -const PS2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ -const PS3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ -const PS4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ -const PS5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ -const QS1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ -const QS2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ -const QS3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ -const QS4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ +const PIO2_HI: Float64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +const PIO2_LO: Float64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +const PS0: Float64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ +const PS1: Float64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ +const PS2: Float64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ +const PS3: Float64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ +const PS4: Float64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ +const PS5: Float64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ +const QS1: Float64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ +const QS2: Float64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ +const QS3: Float64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ +const QS4: Float64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ -fn r(z: f64) -> f64 { - let p: f64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); - let q: f64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); +fn r(z: Float64) -> Float64 { + let p: Float64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); + let q: Float64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); p / q } -/// Arccosine (f64) +/// Arccosine /// /// Computes the inverse cosine (arc cosine) of the input value. /// Arguments must be in the range -1 to 1. /// Returns values in radians, in the range of 0 to pi. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn acos(x: f64) -> f64 { - let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 - let z: f64; - let w: f64; - let s: f64; - let c: f64; - let df: f64; +pub fn acos(x: Float64) -> Radian64 { + let x1p_120f = Float64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 + let z: Float64; + let w: Float64; + let s: Float64; + let c: Float64; + let df: Float64; let hx: u32; let ix: u32; @@ -104,7 +107,7 @@ pub fn acos(x: f64) -> f64 { z = (1.0 - x) * 0.5; s = sqrt(z); // Set the low 4 bytes to zero - df = f64::from_bits(s.to_bits() & 0xff_ff_ff_ff_00_00_00_00); + df = Float64::from_bits(s.to_bits() & 0xff_ff_ff_ff_00_00_00_00); c = (z - df * df) / (s + df); w = r(z) * s + c; diff --git a/core/llm/math/acosf.rs b/core/llm/math/acosf.rs index 1a60479..a5d9176 100644 --- a/core/llm/math/acosf.rs +++ b/core/llm/math/acosf.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,35 +8,40 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::{Float32, Radian32}; use super::sqrtf::sqrtf; -const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */ -const PIO2_LO: f32 = 7.5497894159e-08; /* 0x33a22168 */ -const P_S0: f32 = 1.6666586697e-01; -const P_S1: f32 = -4.2743422091e-02; -const P_S2: f32 = -8.6563630030e-03; -const Q_S1: f32 = -7.0662963390e-01; +const PIO2_HI: Float32 = 1.5707962513e+00; /* 0x3fc90fda */ +const PIO2_LO: Float32 = 7.5497894159e-08; /* 0x33a22168 */ +const P_S0: Float32 = 1.6666586697e-01; +const P_S1: Float32 = -4.2743422091e-02; +const P_S2: Float32 = -8.6563630030e-03; +const Q_S1: Float32 = -7.0662963390e-01; -fn r(z: f32) -> f32 { +fn r(z: Float32) -> Float32 { let p = z * (P_S0 + z * (P_S1 + z * P_S2)); let q = 1. + z * Q_S1; p / q } -/// Arccosine (f32) +/// Arccosine /// /// Computes the inverse cosine (arc cosine) of the input value. /// Arguments must be in the range -1 to 1. /// Returns values in radians, in the range of 0 to pi. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn acosf(x: f32) -> f32 { - let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) +pub fn acosf(x: Float32) -> Radian32 { + let x1p_120 = Float32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) - let z: f32; - let w: f32; - let s: f32; + let z: Float32; + let w: Float32; + let s: Float32; let mut hx = x.to_bits(); let ix = hx & 0x7fffffff; @@ -72,7 +74,7 @@ pub fn acosf(x: f32) -> f32 { z = (1. - x) * 0.5; s = sqrtf(z); hx = s.to_bits(); - let df = f32::from_bits(hx & 0xfffff000); + let df = Float32::from_bits(hx & 0xfffff000); let c = (z - df * df) / (s + df); w = r(z) * s + c; 2. * (df + w) diff --git a/core/llm/math/acosh.rs b/core/llm/math/acosh.rs index d1f5b9f..b722cdf 100644 --- a/core/llm/math/acosh.rs +++ b/core/llm/math/acosh.rs @@ -1,14 +1,16 @@ +use crate::{Float64, Radian64}; + use super::{log, log1p, sqrt}; -const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ +const LN2: Float64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ -/// Inverse hyperbolic cosine (f64) +/// Inverse hyperbolic cosine /// /// Calculates the inverse hyperbolic cosine of `x`. /// Is defined as `log(x + sqrt(x*x-1))`. /// `x` must be a number greater than or equal to 1. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn acosh(x: f64) -> f64 { +pub fn acosh(x: Float64) -> Radian64 { let u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/core/llm/math/acoshf.rs b/core/llm/math/acoshf.rs index ad3455f..617178a 100644 --- a/core/llm/math/acoshf.rs +++ b/core/llm/math/acoshf.rs @@ -1,14 +1,16 @@ +use crate::{Float32, Radian32}; + use super::{log1pf, logf, sqrtf}; -const LN2: f32 = 0.693147180559945309417232121458176568; +const LN2: Float32 = 0.693147180559945309417232121458176568; -/// Inverse hyperbolic cosine (f32) +/// Inverse hyperbolic cosine /// /// Calculates the inverse hyperbolic cosine of `x`. /// Is defined as `log(x + sqrt(x*x-1))`. /// `x` must be a number greater than or equal to 1. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn acoshf(x: f32) -> f32 { +pub fn acoshf(x: Float32) -> Radian32 { let u = x.to_bits(); let a = u & 0x7fffffff; diff --git a/core/llm/math/asin.rs b/core/llm/math/asin.rs index 3e4b7c5..a44c490 100644 --- a/core/llm/math/asin.rs +++ b/core/llm/math/asin.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -8,8 +8,9 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ -/* asin(x) +*/ +/** + * asin(x) * Method : * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... * we approximate asin(x) on [0,0.5] by @@ -37,40 +38,42 @@ * if x is NaN, return x itself; * if |x|>1, return NaN with invalid signal. * - */ +*/ + +use crate::{Float64, Radian64}; use super::{fabs, get_high_word, get_low_word, sqrt, with_set_low_word}; -const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ -const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +const PIO2_HI: Float64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +const PIO2_LO: Float64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ /* coefficients for R(x^2) */ -const P_S0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ -const P_S1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ -const P_S2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ -const P_S3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ -const P_S4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ -const P_S5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ -const Q_S1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ -const Q_S2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ -const Q_S3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ -const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ +const P_S0: Float64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ +const P_S1: Float64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ +const P_S2: Float64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ +const P_S3: Float64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ +const P_S4: Float64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ +const P_S5: Float64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ +const Q_S1: Float64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ +const Q_S2: Float64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ +const Q_S3: Float64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ +const Q_S4: Float64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ -fn comp_r(z: f64) -> f64 { +fn comp_r(z: Float64) -> Float64 { let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); p / q } -/// Arcsine (f64) +/// Arcsine /// /// Computes the inverse sine (arc sine) of the argument `x`. /// Arguments to asin must be in the range -1 to 1. /// Returns values in radians, in the range of -pi/2 to pi/2. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn asin(mut x: f64) -> f64 { - let z: f64; - let r: f64; - let s: f64; +pub fn asin(mut x: Float64) -> Radian64 { + let z: Float64; + let r: Float64; + let s: Float64; let hx: u32; let ix: u32; @@ -82,7 +85,7 @@ pub fn asin(mut x: f64) -> f64 { lx = get_low_word(x); if ((ix - 0x3ff00000) | lx) == 0 { /* asin(1) = +-pi/2 with inexact */ - return x * PIO2_HI + f64::from_bits(0x3870000000000000); + return x * PIO2_HI + Float64::from_bits(0x3870000000000000); } else { return 0.0 / (x - x); } @@ -104,8 +107,8 @@ pub fn asin(mut x: f64) -> f64 { /* if |x| > 0.975 */ x = PIO2_HI - (2. * (s + s * r) - PIO2_LO); } else { - let f: f64; - let c: f64; + let f: Float64; + let c: Float64; /* f+c = sqrt(z) */ f = with_set_low_word(s, 0); c = (z - f * f) / (s + f); diff --git a/core/llm/math/asinf.rs b/core/llm/math/asinf.rs index 6ec61b6..dcd4b3a 100644 --- a/core/llm/math/asinf.rs +++ b/core/llm/math/asinf.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,33 +8,38 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::{Float64, Float32, Radian32}; use super::fabsf::fabsf; use super::sqrt::sqrt; -const PIO2: f64 = 1.570796326794896558e+00; +const PIO2: Float64 = 1.570796326794896558e+00; /* coefficients for R(x^2) */ -const P_S0: f32 = 1.6666586697e-01; -const P_S1: f32 = -4.2743422091e-02; -const P_S2: f32 = -8.6563630030e-03; -const Q_S1: f32 = -7.0662963390e-01; +const P_S0: Float32 = 1.6666586697e-01; +const P_S1: Float32 = -4.2743422091e-02; +const P_S2: Float32 = -8.6563630030e-03; +const Q_S1: Float32 = -7.0662963390e-01; -fn r(z: f32) -> f32 { +fn r(z: Float32) -> Float32 { let p = z * (P_S0 + z * (P_S1 + z * P_S2)); let q = 1. + z * Q_S1; p / q } -/// Arcsine (f32) +/// Arcsine /// /// Computes the inverse sine (arc sine) of the argument `x`. /// Arguments to asin must be in the range -1 to 1. /// Returns values in radians, in the range of -pi/2 to pi/2. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn asinf(mut x: f32) -> f32 { - let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) +pub fn asinf(mut x: Float32) -> Radian32 { + let x1p_120 = Float64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) let hx = x.to_bits(); let ix = hx & 0x7fffffff; @@ -46,7 +48,7 @@ pub fn asinf(mut x: f32) -> f32 { /* |x| >= 1 */ if ix == 0x3f800000 { /* |x| == 1 */ - return ((x as f64) * PIO2 + x1p_120) as f32; /* asin(+-1) = +-pi/2 with inexact */ + return ((x as Float64) * PIO2 + x1p_120) as Float32; /* asin(+-1) = +-pi/2 with inexact */ } return 0. / (x - x); /* asin(|x|>1) is NaN */ } @@ -62,8 +64,8 @@ pub fn asinf(mut x: f32) -> f32 { /* 1 > |x| >= 0.5 */ let z = (1. - fabsf(x)) * 0.5; - let s = sqrt(z as f64); - x = (PIO2 - 2. * (s + s * (r(z) as f64))) as f32; + let s = sqrt(z as Float64); + x = (PIO2 - 2. * (s + s * (r(z) as Float64))) as Float32; if (hx >> 31) != 0 { -x } else { diff --git a/core/llm/math/asinh.rs b/core/llm/math/asinh.rs index 0abd80c..4ac7d17 100644 --- a/core/llm/math/asinh.rs +++ b/core/llm/math/asinh.rs @@ -1,21 +1,23 @@ +use crate::{Float64, Radian64}; + use super::{log, log1p, sqrt}; -const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ +const LN2: Float64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ /* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ -/// Inverse hyperbolic sine (f64) +/// Inverse hyperbolic sine /// /// Calculates the inverse hyperbolic sine of `x`. /// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn asinh(mut x: f64) -> f64 { +pub fn asinh(mut x: Float64) -> Radian64 { let mut u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; let sign = (u >> 63) != 0; /* |x| */ u &= (!0) >> 1; - x = f64::from_bits(u); + x = Float64::from_bits(u); if e >= 0x3ff + 26 { /* |x| >= 0x1p26 or inf or nan */ @@ -28,7 +30,7 @@ pub fn asinh(mut x: f64) -> f64 { x = log1p(x + x * x / (sqrt(x * x + 1.0) + 1.0)); } else { /* |x| < 0x1p-26, raise inexact if x != 0 */ - let x1p120 = f64::from_bits(0x4770000000000000); + let x1p120 = Float64::from_bits(0x4770000000000000); force_eval!(x + x1p120); } diff --git a/core/llm/math/asinhf.rs b/core/llm/math/asinhf.rs index 09c7782..5a56fd7 100644 --- a/core/llm/math/asinhf.rs +++ b/core/llm/math/asinhf.rs @@ -1,20 +1,22 @@ +use crate::{Float32, Radian32}; + use super::{log1pf, logf, sqrtf}; -const LN2: f32 = 0.693147180559945309417232121458176568; +const LN2: Float32 = 0.693147180559945309417232121458176568; /* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ -/// Inverse hyperbolic sine (f32) +/// Inverse hyperbolic sine /// /// Calculates the inverse hyperbolic sine of `x`. /// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn asinhf(mut x: f32) -> f32 { +pub fn asinhf(mut x: Float32) -> Radian32 { let u = x.to_bits(); let i = u & 0x7fffffff; let sign = (u >> 31) != 0; /* |x| */ - x = f32::from_bits(i); + x = Float32::from_bits(i); if i >= 0x3f800000 + (12 << 23) { /* |x| >= 0x1p12 or inf or nan */ @@ -27,7 +29,7 @@ pub fn asinhf(mut x: f32) -> f32 { x = log1pf(x + x * x / (sqrtf(x * x + 1.0) + 1.0)); } else { /* |x| < 0x1p-12, raise inexact if x!=0 */ - let x1p120 = f32::from_bits(0x7b800000); + let x1p120 = Float32::from_bits(0x7b800000); force_eval!(x + x1p120); } diff --git a/core/llm/math/atan.rs b/core/llm/math/atan.rs index 4259dc7..c0ce6a5 100644 --- a/core/llm/math/atan.rs +++ b/core/llm/math/atan.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -8,8 +8,9 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ -/* atan(x) +*/ +/** + * atan(x) * Method * 1. Reduce x to positive by atan(x) = -atan(-x). * 2. According to the integer k=4t+0.25 chopped, t=x, the argument @@ -27,26 +28,27 @@ * constants. The decimal values may be used, provided that the * compiler will convert from decimal to binary accurately enough * to produce the hexadecimal values shown. - */ +*/ + +use crate::{Float64, Float32, Radian64}; use super::fabs; -use core::f64; -const ATANHI: [f64; 4] = [ +const ATANHI: [Float64; 4] = [ 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ ]; -const ATANLO: [f64; 4] = [ +const ATANLO: [Float64; 4] = [ 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ ]; -const AT: [f64; 11] = [ +const AT: [Float64; 11] = [ 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ @@ -60,12 +62,12 @@ const AT: [f64; 11] = [ 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ ]; -/// Arctangent (f64) +/// Arctangent /// /// Computes the inverse tangent (arc tangent) of the input value. /// Returns a value in radians, in the range of -pi/2 to pi/2. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atan(x: f64) -> f64 { +pub fn atan(x: Float64) -> Radian64 { let mut x = x; let mut ix = (x.to_bits() >> 32) as u32; let sign = ix >> 31; @@ -75,7 +77,7 @@ pub fn atan(x: f64) -> f64 { return x; } - let z = ATANHI[3] + f64::from_bits(0x0380_0000); // 0x1p-120f + let z = ATANHI[3] + Float64::from_bits(0x0380_0000); // 0x1p-120f return if sign != 0 { -z } else { z }; } @@ -85,7 +87,7 @@ pub fn atan(x: f64) -> f64 { /* |x| < 2^-27 */ if ix < 0x0010_0000 { /* raise underflow for subnormal x */ - force_eval!(x as f32); + force_eval!(x as Float32); } return x; @@ -138,17 +140,17 @@ pub fn atan(x: f64) -> f64 { #[cfg(test)] mod tests { use super::atan; - use core::f64; + use core::Float64; #[test] fn sanity_check() { for (input, answer) in [ - (3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6), - (1.0, f64::consts::FRAC_PI_4), - (3.0_f64.sqrt(), f64::consts::FRAC_PI_3), - (-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6), - (-1.0, -f64::consts::FRAC_PI_4), - (-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3), + (3.0_f64.sqrt() / 3.0, Float64::consts::FRAC_PI_6), + (1.0, Float64::consts::FRAC_PI_4), + (3.0_f64.sqrt(), Float64::consts::FRAC_PI_3), + (-3.0_f64.sqrt() / 3.0, -Float64::consts::FRAC_PI_6), + (-1.0, -Float64::consts::FRAC_PI_4), + (-3.0_f64.sqrt(), -Float64::consts::FRAC_PI_3), ] .iter() { @@ -169,16 +171,16 @@ mod tests { #[test] fn infinity() { - assert_eq!(atan(f64::INFINITY), f64::consts::FRAC_PI_2); + assert_eq!(atan(Float64::INFINITY), Float64::consts::FRAC_PI_2); } #[test] fn minus_infinity() { - assert_eq!(atan(f64::NEG_INFINITY), -f64::consts::FRAC_PI_2); + assert_eq!(atan(Float64::NEG_INFINITY), -Float64::consts::FRAC_PI_2); } #[test] fn nan() { - assert!(atan(f64::NAN).is_nan()); + assert!(atan(Float64::NAN).is_nan()); } } diff --git a/core/llm/math/atan2.rs b/core/llm/math/atan2.rs index fb2ea4e..4479dc5 100644 --- a/core/llm/math/atan2.rs +++ b/core/llm/math/atan2.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -9,8 +9,9 @@ * is preserved. * ==================================================== * - */ -/* atan2(y,x) +*/ +/** + * atan2(y,x) * Method : * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). * 2. Reduce x to positive by (if x and y are unexceptional): @@ -35,21 +36,23 @@ * constants. The decimal values may be used, provided that the * compiler will convert from decimal to binary accurately enough * to produce the hexadecimal values shown. - */ +*/ + +use crate::{Float64, Radian64}; use super::atan; use super::fabs; -const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ -const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ +const PI: Float64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ +const PI_LO: Float64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ -/// Arctangent of y/x (f64) +/// Arctangent of y/x /// /// Computes the inverse tangent (arc tangent) of `y/x`. /// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). /// Returns a value in radians, in the range of -pi to pi. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atan2(y: f64, x: f64) -> f64 { +pub fn atan2(y: Float64, x: Float64) -> Radian64 { if x.is_nan() || y.is_nan() { return x + y; } diff --git a/core/llm/math/atan2f.rs b/core/llm/math/atan2f.rs index eae3b00..f711504 100644 --- a/core/llm/math/atan2f.rs +++ b/core/llm/math/atan2f.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,21 +8,26 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::{Float32, Radian32}; use super::atanf; use super::fabsf; -const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ -const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ +const PI: Float32 = 3.1415927410e+00; /* 0x40490fdb */ +const PI_LO: Float32 = -8.7422776573e-08; /* 0xb3bbbd2e */ -/// Arctangent of y/x (f32) +/// Arctangent of y/x /// /// Computes the inverse tangent (arc tangent) of `y/x`. /// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). /// Returns a value in radians, in the range of -pi to pi. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atan2f(y: f32, x: f32) -> f32 { +pub fn atan2f(y: Float32, x: Float32) -> Radian32 { if x.is_nan() || y.is_nan() { return x + y; } diff --git a/core/llm/math/atanf.rs b/core/llm/math/atanf.rs index d042b3b..f283fbe 100644 --- a/core/llm/math/atanf.rs +++ b/core/llm/math/atanf.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,25 +8,30 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::{Float32, Radian32}; use super::fabsf; -const ATAN_HI: [f32; 4] = [ +const ATAN_HI: [Float32; 4] = [ 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ ]; -const ATAN_LO: [f32; 4] = [ +const ATAN_LO: [Float32; 4] = [ 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ ]; -const A_T: [f32; 5] = [ +const A_T: [Float32; 5] = [ 3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, @@ -37,15 +39,15 @@ const A_T: [f32; 5] = [ 6.1687607318e-02, ]; -/// Arctangent (f32) +/// Arctangent /// /// Computes the inverse tangent (arc tangent) of the input value. /// Returns a value in radians, in the range of -pi/2 to pi/2. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atanf(mut x: f32) -> f32 { - let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) +pub fn atanf(mut x: Float32) -> Radian32 { + let x1p_120 = Float32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) - let z: f32; + let z: Float32; let mut ix = x.to_bits(); let sign = (ix >> 31) != 0; diff --git a/core/llm/math/atanh.rs b/core/llm/math/atanh.rs index b984c4a..5520b85 100644 --- a/core/llm/math/atanh.rs +++ b/core/llm/math/atanh.rs @@ -1,24 +1,26 @@ +use crate::{Float64, Float32, Radian64}; + use super::log1p; /* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ -/// Inverse hyperbolic tangent (f64) +/// Inverse hyperbolic tangent /// /// Calculates the inverse hyperbolic tangent of `x`. /// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atanh(x: f64) -> f64 { +pub fn atanh(x: Float64) -> Radian64 { let u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; let sign = (u >> 63) != 0; /* |x| */ - let mut y = f64::from_bits(u & 0x7fff_ffff_ffff_ffff); + let mut y = Float64::from_bits(u & 0x7fff_ffff_ffff_ffff); if e < 0x3ff - 1 { if e < 0x3ff - 32 { /* handle underflow */ if e == 0 { - force_eval!(y as f32); + force_eval!(y as Float32); } } else { /* |x| < 0.5, up to 1.7ulp error */ diff --git a/core/llm/math/atanhf.rs b/core/llm/math/atanhf.rs index a1aa314..9dcc5eb 100644 --- a/core/llm/math/atanhf.rs +++ b/core/llm/math/atanhf.rs @@ -1,24 +1,26 @@ +use crate::{Float32, Radian32}; + use super::log1pf; /* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ -/// Inverse hyperbolic tangent (f32) +/// Inverse hyperbolic tangent /// /// Calculates the inverse hyperbolic tangent of `x`. /// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn atanhf(mut x: f32) -> f32 { +pub fn atanhf(mut x: Float32) -> Radian32 { let mut u = x.to_bits(); let sign = (u >> 31) != 0; /* |x| */ u &= 0x7fffffff; - x = f32::from_bits(u); + x = Float32::from_bits(u); if u < 0x3f800000 - (1 << 23) { if u < 0x3f800000 - (32 << 23) { /* handle underflow */ if u < (1 << 23) { - force_eval!((x * x) as f32); + force_eval!((x * x) as Float32); } } else { /* |x| < 0.5, up to 1.7ulp error */ diff --git a/core/llm/math/cbrt.rs b/core/llm/math/cbrt.rs index b4e77ea..4dc3cd1 100644 --- a/core/llm/math/cbrt.rs +++ b/core/llm/math/cbrt.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_cbrt.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -10,35 +10,36 @@ * ==================================================== * * Optimized by Bruce D. Evans. - */ -/* cbrt(x) +*/ +/** + * cbrt(x) * Return cube root of x - */ +*/ -use core::f64; +use crate::Float64; const B1: u32 = 715094163; /* B1 = (1023-1023/3-0.03306235651)*2**20 */ const B2: u32 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */ /* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */ -const P0: f64 = 1.87595182427177009643; /* 0x3ffe03e6, 0x0f61e692 */ -const P1: f64 = -1.88497979543377169875; /* 0xbffe28e0, 0x92f02420 */ -const P2: f64 = 1.621429720105354466140; /* 0x3ff9f160, 0x4a49d6c2 */ -const P3: f64 = -0.758397934778766047437; /* 0xbfe844cb, 0xbee751d9 */ -const P4: f64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ +const P0: Float64 = 1.87595182427177009643; /* 0x3ffe03e6, 0x0f61e692 */ +const P1: Float64 = -1.88497979543377169875; /* 0xbffe28e0, 0x92f02420 */ +const P2: Float64 = 1.621429720105354466140; /* 0x3ff9f160, 0x4a49d6c2 */ +const P3: Float64 = -0.758397934778766047437; /* 0xbfe844cb, 0xbee751d9 */ +const P4: Float64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ -// Cube root (f64) +// Cube root /// /// Computes the cube root of the argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cbrt(x: f64) -> f64 { - let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 +pub fn cbrt(x: Float64) -> Float64 { + let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 let mut ui: u64 = x.to_bits(); - let mut r: f64; - let s: f64; - let mut t: f64; - let w: f64; + let mut r: Float64; + let s: Float64; + let mut t: Float64; + let w: Float64; let mut hx: u32 = (ui >> 32) as u32 & 0x7fffffff; if hx >= 0x7ff00000 { @@ -74,7 +75,7 @@ pub fn cbrt(x: f64) -> f64 { } ui &= 1 << 63; ui |= (hx as u64) << 32; - t = f64::from_bits(ui); + t = Float64::from_bits(ui); /* * New cbrt to 23 bits: @@ -101,7 +102,7 @@ pub fn cbrt(x: f64) -> f64 { */ ui = t.to_bits(); ui = (ui + 0x80000000) & 0xffffffffc0000000; - t = f64::from_bits(ui); + t = Float64::from_bits(ui); /* one step Newton iteration to 53 bits with error < 0.667 ulps */ s = t * t; /* t*t is exact */ diff --git a/core/llm/math/cbrtf.rs b/core/llm/math/cbrtf.rs index 9d70305..34a78f6 100644 --- a/core/llm/math/cbrtf.rs +++ b/core/llm/math/cbrtf.rs @@ -1,9 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Debugged and optimized by Bruce D. Evans. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -13,24 +9,29 @@ * is preserved. * ==================================================== */ -/* cbrtf(x) +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. +*/ +/** + * cbrtf(x) * Return cube root of x - */ +*/ -use core::f32; +use crate::{Float64, Float32}; const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ -/// Cube root (f32) +/// Cube root /// /// Computes the cube root of the argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cbrtf(x: f32) -> f32 { - let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 +pub fn cbrtf(x: Float32) -> Float32 { + let x1p24 = Float32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 - let mut r: f64; - let mut t: f64; + let mut r: Float64; + let mut t: Float64; let mut ui: u32 = x.to_bits(); let mut hx: u32 = ui & 0x7fffffff; @@ -59,17 +60,17 @@ pub fn cbrtf(x: f32) -> f32 { * double precision so that its terms can be arranged for efficiency * without causing overflow or underflow. */ - t = f32::from_bits(ui) as f64; + t = Float32::from_bits(ui) as Float64; r = t * t * t; - t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); + t = t * (x as Float64 + x as Float64 + r) / (x as Float64 + r + r); /* * Second step Newton iteration to 47 bits. In double precision for * efficiency and accuracy. */ r = t * t * t; - t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); + t = t * (x as Float64 + x as Float64 + r) / (x as Float64 + r + r); /* rounding to 24 bits is perfect in round-to-nearest mode */ - t as f32 + t as Float32 } diff --git a/core/llm/math/ceil.rs b/core/llm/math/ceil.rs index 22d8929..8860e43 100644 --- a/core/llm/math/ceil.rs +++ b/core/llm/math/ceil.rs @@ -1,15 +1,16 @@ #![allow(unreachable_code)] -use core::f64; -const TOINT: f64 = 1. / f64::EPSILON; +use crate::Float64; -/// Ceil (f64) +const TOINT: Float64 = 1. / Float64::EPSILON; + +/// Ceil /// /// Finds the nearest integer greater than or equal to `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceil(x: f64) -> f64 { +pub fn ceil(x: Float64) -> Float64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.ceil` native instruction, so we can leverage this for both code size + // `Float64.ceil` native instruction, so we can leverage this for both code size // and speed. llvm_intrinsically_optimized! { #[cfg(target_arch = "wasm32")] { @@ -24,7 +25,7 @@ pub fn ceil(x: f64) -> f64 { //basic implementation taken from https://github.com/rust-lang/libm/issues/219 use super::fabs; if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as f64; + let truncated = x as i64 as Float64; if truncated < x { return truncated + 1.0; } else { @@ -36,7 +37,7 @@ pub fn ceil(x: f64) -> f64 { } let u: u64 = x.to_bits(); let e: i64 = (u >> 52 & 0x7ff) as i64; - let y: f64; + let y: Float64; if e >= 0x3ff + 52 || x == 0. { return x; @@ -62,7 +63,7 @@ pub fn ceil(x: f64) -> f64 { #[cfg(test)] mod tests { use super::*; - use core::f64::*; + use core::Float64::*; #[test] fn sanity_check() { diff --git a/core/llm/math/ceilf.rs b/core/llm/math/ceilf.rs index 7bcc647..677ccf9 100644 --- a/core/llm/math/ceilf.rs +++ b/core/llm/math/ceilf.rs @@ -1,12 +1,12 @@ -use core::f32; +use crate::Float32; -/// Ceil (f32) +/// Ceil /// /// Finds the nearest integer greater than or equal to `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceilf(x: f32) -> f32 { +pub fn ceilf(x: Float32) -> Float32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.ceil` native instruction, so we can leverage this for both code size + // `Float32.ceil` native instruction, so we can leverage this for both code size // and speed. llvm_intrinsically_optimized! { #[cfg(target_arch = "wasm32")] { @@ -24,20 +24,20 @@ pub fn ceilf(x: f32) -> f32 { if (ui & m) == 0 { return x; } - force_eval!(x + f32::from_bits(0x7b800000)); + force_eval!(x + Float32::from_bits(0x7b800000)); if ui >> 31 == 0 { ui += m; } ui &= !m; } else { - force_eval!(x + f32::from_bits(0x7b800000)); + force_eval!(x + Float32::from_bits(0x7b800000)); if ui >> 31 != 0 { return -0.0; } else if ui << 1 != 0 { return 1.0; } } - f32::from_bits(ui) + Float32::from_bits(ui) } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 @@ -45,7 +45,7 @@ pub fn ceilf(x: f32) -> f32 { #[cfg(test)] mod tests { use super::*; - use core::f32::*; + use core::Float32::*; #[test] fn sanity_check() { diff --git a/core/llm/math/copysign.rs b/core/llm/math/copysign.rs index 1f4a35a..37d6f66 100644 --- a/core/llm/math/copysign.rs +++ b/core/llm/math/copysign.rs @@ -1,12 +1,14 @@ -/// Sign of Y, magnitude of X (f64) +use crate::Float64; + +/// Sign of Y, magnitude of X /// /// Constructs a number with the magnitude (absolute value) of its /// first argument, `x`, and the sign of its second argument, `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysign(x: f64, y: f64) -> f64 { +pub fn copysign(x: Float64, y: Float64) -> Float64 { let mut ux = x.to_bits(); let uy = y.to_bits(); ux &= (!0) >> 1; ux |= uy & (1 << 63); - f64::from_bits(ux) + Float64::from_bits(ux) } diff --git a/core/llm/math/copysignf.rs b/core/llm/math/copysignf.rs index 6c346e3..8791ff2 100644 --- a/core/llm/math/copysignf.rs +++ b/core/llm/math/copysignf.rs @@ -1,12 +1,14 @@ -/// Sign of Y, magnitude of X (f32) +use crate::Float32; + +/// Sign of Y, magnitude of X /// /// Constructs a number with the magnitude (absolute value) of its /// first argument, `x`, and the sign of its second argument, `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf(x: f32, y: f32) -> f32 { +pub fn copysignf(x: Float32, y: Float32) -> Float32 { let mut ux = x.to_bits(); let uy = y.to_bits(); ux &= 0x7fffffff; ux |= uy & 0x80000000; - f32::from_bits(ux) + Float32::from_bits(ux) } diff --git a/core/llm/math/cos.rs b/core/llm/math/cos.rs index db8bc49..2563b2f 100644 --- a/core/llm/math/cos.rs +++ b/core/llm/math/cos.rs @@ -1,49 +1,60 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */ -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunPro, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ +/** + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ +/** + * cos(x) + * Return cosine function of x. + * + * kernel function: + * k_sin ... sine function on [-pi/4,pi/4] + * k_cos ... cosine function on [-pi/4,pi/4] + * rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded +*/ + +use crate::{Float64, Radian64}; use super::{k_cos, k_sin, rem_pio2}; -// cos(x) -// Return cosine function of x. -// -// kernel function: -// k_sin ... sine function on [-pi/4,pi/4] -// k_cos ... cosine function on [-pi/4,pi/4] -// rem_pio2 ... argument reduction routine -// -// Method. -// Let S,C and T denote the sin, cos and tan respectively on -// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 -// in [-pi/4 , +pi/4], and let n = k mod 4. -// We have -// -// n sin(x) cos(x) tan(x) -// ---------------------------------------------------------- -// 0 S C T -// 1 C -S -1/T -// 2 -S -C T -// 3 -C S -1/T -// ---------------------------------------------------------- -// -// Special cases: -// Let trig be any of sin, cos, or tan. -// trig(+-INF) is NaN, with signals; -// trig(NaN) is that NaN; -// -// Accuracy: -// TRIG(x) returns trig(x) nearly rounded -// +/// Cosine +/// +/// Computes the cosine of a number (in radians). +/// Returns a number between -1 and 1. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cos(x: f64) -> f64 { - let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; +pub fn cos(x: Radian64) -> Float64 { + let ix = (Float64::to_bits(x) >> 32) as u32 & 0x7fffffff; /* |x| ~< pi/4 */ if ix <= 0x3fe921fb { diff --git a/core/llm/math/cosf.rs b/core/llm/math/cosf.rs index 424fa42..738acc3 100644 --- a/core/llm/math/cosf.rs +++ b/core/llm/math/cosf.rs @@ -1,9 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -12,23 +8,33 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. +*/ + +use crate::{Float64, Float32}; use super::{k_cosf, k_sinf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; /* Small multiples of pi/2 rounded to double precision. */ -const C1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +const C1_PIO2: Float64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const C2_PIO2: Float64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const C3_PIO2: Float64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const C4_PIO2: Float64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +/// Cosine +/// +/// Computes the cosine of a number (in radians). +/// Returns a number between -1 and 1. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cosf(x: f32) -> f32 { - let x64 = x as f64; +pub fn cosf(x: Float32) -> Float32 { + let x64 = x as Float64; - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 let mut ix = x.to_bits(); let sign = (ix >> 31) != 0; diff --git a/core/llm/math/cosh.rs b/core/llm/math/cosh.rs index 2fb568a..4676b66 100644 --- a/core/llm/math/cosh.rs +++ b/core/llm/math/cosh.rs @@ -1,24 +1,26 @@ +use crate::{Float64, Radian64}; + use super::exp; use super::expm1; use super::k_expo2; -/// Hyperbolic cosine (f64) +/// Hyperbolic cosine /// /// Computes the hyperbolic cosine of the argument x. /// Is defined as `(exp(x) + exp(-x))/2` /// Angles are specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn cosh(mut x: f64) -> f64 { +pub fn cosh(mut x: Radian64) -> Float64 { /* |x| */ let mut ix = x.to_bits(); ix &= 0x7fffffffffffffff; - x = f64::from_bits(ix); + x = Float64::from_bits(ix); let w = ix >> 32; /* |x| < log(2) */ if w < 0x3fe62e42 { if w < 0x3ff00000 - (26 << 20) { - let x1p120 = f64::from_bits(0x4770000000000000); + let x1p120 = Float64::from_bits(0x4770000000000000); force_eval!(x + x1p120); return 1.; } diff --git a/core/llm/math/coshf.rs b/core/llm/math/coshf.rs index e7b6845..052f334 100644 --- a/core/llm/math/coshf.rs +++ b/core/llm/math/coshf.rs @@ -1,20 +1,22 @@ +use crate::{Float32, Radian32}; + use super::expf; use super::expm1f; use super::k_expo2f; -/// Hyperbolic cosine (f64) +/// Hyperbolic cosine /// /// Computes the hyperbolic cosine of the argument x. /// Is defined as `(exp(x) + exp(-x))/2` /// Angles are specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn coshf(mut x: f32) -> f32 { - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 +pub fn coshf(mut x: Radian32) -> Float32 { + let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 /* |x| */ let mut ix = x.to_bits(); ix &= 0x7fffffff; - x = f32::from_bits(ix); + x = Float32::from_bits(ix); let w = ix; /* |x| < log(2) */ diff --git a/core/llm/math/erf.rs b/core/llm/math/erf.rs index 55569af..0eb0253 100644 --- a/core/llm/math/erf.rs +++ b/core/llm/math/erf.rs @@ -1,6 +1,5 @@ -use super::{exp, fabs, get_high_word, with_set_low_word}; /* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -9,8 +8,9 @@ use super::{exp, fabs, get_high_word, with_set_low_word}; * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ -/* double erf(double x) +*/ +/** + * double erf(double x) * double erfc(double x) * x * 2 |\ @@ -102,80 +102,84 @@ use super::{exp, fabs, get_high_word, with_set_low_word}; * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, * erfc/erf(NaN) is NaN - */ +*/ + +use crate::Float64; + +use super::{exp, fabs, get_high_word, with_set_low_word}; -const ERX: f64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ -/* +const ERX: Float64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ +/** * Coefficients for approximation to erf on [0,0.84375] - */ -const EFX8: f64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ -const PP0: f64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ -const PP1: f64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ -const PP2: f64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ -const PP3: f64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ -const PP4: f64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ -const QQ1: f64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ -const QQ2: f64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ -const QQ3: f64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ -const QQ4: f64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ -const QQ5: f64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ -/* +*/ +const EFX8: Float64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ +const PP0: Float64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ +const PP1: Float64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ +const PP2: Float64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ +const PP3: Float64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ +const PP4: Float64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ +const QQ1: Float64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ +const QQ2: Float64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ +const QQ3: Float64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ +const QQ4: Float64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ +const QQ5: Float64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ +/** * Coefficients for approximation to erf in [0.84375,1.25] - */ -const PA0: f64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ -const PA1: f64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ -const PA2: f64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ -const PA3: f64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ -const PA4: f64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ -const PA5: f64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ -const PA6: f64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ -const QA1: f64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ -const QA2: f64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ -const QA3: f64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ -const QA4: f64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ -const QA5: f64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ -const QA6: f64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ -/* +*/ +const PA0: Float64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ +const PA1: Float64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ +const PA2: Float64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ +const PA3: Float64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ +const PA4: Float64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ +const PA5: Float64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ +const PA6: Float64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ +const QA1: Float64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ +const QA2: Float64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ +const QA3: Float64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ +const QA4: Float64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ +const QA5: Float64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ +const QA6: Float64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ +/** * Coefficients for approximation to erfc in [1.25,1/0.35] - */ -const RA0: f64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ -const RA1: f64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ -const RA2: f64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ -const RA3: f64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ -const RA4: f64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ -const RA5: f64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ -const RA6: f64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ -const RA7: f64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ -const SA1: f64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ -const SA2: f64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ -const SA3: f64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ -const SA4: f64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ -const SA5: f64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ -const SA6: f64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ -const SA7: f64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ -const SA8: f64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ -/* +*/ +const RA0: Float64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ +const RA1: Float64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ +const RA2: Float64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ +const RA3: Float64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ +const RA4: Float64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ +const RA5: Float64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ +const RA6: Float64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ +const RA7: Float64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ +const SA1: Float64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ +const SA2: Float64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ +const SA3: Float64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ +const SA4: Float64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ +const SA5: Float64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ +const SA6: Float64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ +const SA7: Float64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ +const SA8: Float64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ +/** * Coefficients for approximation to erfc in [1/.35,28] - */ -const RB0: f64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ -const RB1: f64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ -const RB2: f64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ -const RB3: f64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ -const RB4: f64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ -const RB5: f64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ -const RB6: f64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ -const SB1: f64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ -const SB2: f64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ -const SB3: f64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ -const SB4: f64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ -const SB5: f64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ -const SB6: f64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ -const SB7: f64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ +*/ +const RB0: Float64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ +const RB1: Float64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ +const RB2: Float64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ +const RB3: Float64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ +const RB4: Float64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ +const RB5: Float64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ +const RB6: Float64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ +const SB1: Float64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ +const SB2: Float64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ +const SB3: Float64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ +const SB4: Float64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ +const SB5: Float64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ +const SB6: Float64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ +const SB7: Float64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ -fn erfc1(x: f64) -> f64 { - let s: f64; - let p: f64; - let q: f64; +fn erfc1(x: Float64) -> Float64 { + let s: Float64; + let p: Float64; + let q: Float64; s = fabs(x) - 1.0; p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); @@ -184,11 +188,11 @@ fn erfc1(x: f64) -> f64 { 1.0 - ERX - p / q } -fn erfc2(ix: u32, mut x: f64) -> f64 { - let s: f64; - let r: f64; - let big_s: f64; - let z: f64; +fn erfc2(ix: u32, mut x: Float64) -> Float64 { + let s: Float64; + let r: Float64; + let big_s: Float64; + let z: Float64; if ix < 0x3ff40000 { /* |x| < 1.25 */ @@ -214,17 +218,17 @@ fn erfc2(ix: u32, mut x: f64) -> f64 { exp(-z * z - 0.5625) * exp((z - x) * (z + x) + r / big_s) / x } -/// Error function (f64) +/// Error function /// /// Calculates an approximation to the “error function”, which estimates /// the probability that an observation will fall within x standard /// deviations of the mean (assuming a normal distribution). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn erf(x: f64) -> f64 { - let r: f64; - let s: f64; - let z: f64; - let y: f64; +pub fn erf(x: Float64) -> Float64 { + let r: Float64; + let s: Float64; + let z: Float64; + let y: Float64; let mut ix: u32; let sign: usize; @@ -233,7 +237,7 @@ pub fn erf(x: f64) -> f64 { ix &= 0x7fffffff; if ix >= 0x7ff00000 { /* erf(nan)=nan, erf(+-inf)=+-1 */ - return 1.0 - 2.0 * (sign as f64) + 1.0 / x; + return 1.0 - 2.0 * (sign as Float64) + 1.0 / x; } if ix < 0x3feb0000 { /* |x| < 0.84375 */ @@ -252,7 +256,7 @@ pub fn erf(x: f64) -> f64 { /* 0.84375 <= |x| < 6 */ y = 1.0 - erfc2(ix, x); } else { - let x1p_1022 = f64::from_bits(0x0010000000000000); + let x1p_1022 = Float64::from_bits(0x0010000000000000); y = 1.0 - x1p_1022; } @@ -263,17 +267,17 @@ pub fn erf(x: f64) -> f64 { } } -/// Complementary error function (f64) +/// Complementary error function /// /// Calculates the complementary probability. /// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid /// the loss of precision that would result from subtracting /// large probabilities (on large `x`) from 1. -pub fn erfc(x: f64) -> f64 { - let r: f64; - let s: f64; - let z: f64; - let y: f64; +pub fn erfc(x: Float64) -> Float64 { + let r: Float64; + let s: Float64; + let z: Float64; + let y: Float64; let mut ix: u32; let sign: usize; @@ -282,7 +286,7 @@ pub fn erfc(x: f64) -> f64 { ix &= 0x7fffffff; if ix >= 0x7ff00000 { /* erfc(nan)=nan, erfc(+-inf)=0,2 */ - return 2.0 * (sign as f64) + 1.0 / x; + return 2.0 * (sign as Float64) + 1.0 / x; } if ix < 0x3feb0000 { /* |x| < 0.84375 */ @@ -309,7 +313,7 @@ pub fn erfc(x: f64) -> f64 { } } - let x1p_1022 = f64::from_bits(0x0010000000000000); + let x1p_1022 = Float64::from_bits(0x0010000000000000); if sign != 0 { 2.0 - x1p_1022 } else { diff --git a/core/llm/math/erff.rs b/core/llm/math/erff.rs index 7b25474..b25d595 100644 --- a/core/llm/math/erff.rs +++ b/core/llm/math/erff.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,82 +8,87 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::Float32; use super::{expf, fabsf}; -const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */ +const ERX: Float32 = 8.4506291151e-01; /* 0x3f58560b */ /* * Coefficients for approximation to erf on [0,0.84375] */ -const EFX8: f32 = 1.0270333290e+00; /* 0x3f8375d4 */ -const PP0: f32 = 1.2837916613e-01; /* 0x3e0375d4 */ -const PP1: f32 = -3.2504209876e-01; /* 0xbea66beb */ -const PP2: f32 = -2.8481749818e-02; /* 0xbce9528f */ -const PP3: f32 = -5.7702702470e-03; /* 0xbbbd1489 */ -const PP4: f32 = -2.3763017452e-05; /* 0xb7c756b1 */ -const QQ1: f32 = 3.9791721106e-01; /* 0x3ecbbbce */ -const QQ2: f32 = 6.5022252500e-02; /* 0x3d852a63 */ -const QQ3: f32 = 5.0813062117e-03; /* 0x3ba68116 */ -const QQ4: f32 = 1.3249473704e-04; /* 0x390aee49 */ -const QQ5: f32 = -3.9602282413e-06; /* 0xb684e21a */ +const EFX8: Float32 = 1.0270333290e+00; /* 0x3f8375d4 */ +const PP0: Float32 = 1.2837916613e-01; /* 0x3e0375d4 */ +const PP1: Float32 = -3.2504209876e-01; /* 0xbea66beb */ +const PP2: Float32 = -2.8481749818e-02; /* 0xbce9528f */ +const PP3: Float32 = -5.7702702470e-03; /* 0xbbbd1489 */ +const PP4: Float32 = -2.3763017452e-05; /* 0xb7c756b1 */ +const QQ1: Float32 = 3.9791721106e-01; /* 0x3ecbbbce */ +const QQ2: Float32 = 6.5022252500e-02; /* 0x3d852a63 */ +const QQ3: Float32 = 5.0813062117e-03; /* 0x3ba68116 */ +const QQ4: Float32 = 1.3249473704e-04; /* 0x390aee49 */ +const QQ5: Float32 = -3.9602282413e-06; /* 0xb684e21a */ /* * Coefficients for approximation to erf in [0.84375,1.25] */ -const PA0: f32 = -2.3621185683e-03; /* 0xbb1acdc6 */ -const PA1: f32 = 4.1485610604e-01; /* 0x3ed46805 */ -const PA2: f32 = -3.7220788002e-01; /* 0xbebe9208 */ -const PA3: f32 = 3.1834661961e-01; /* 0x3ea2fe54 */ -const PA4: f32 = -1.1089469492e-01; /* 0xbde31cc2 */ -const PA5: f32 = 3.5478305072e-02; /* 0x3d1151b3 */ -const PA6: f32 = -2.1663755178e-03; /* 0xbb0df9c0 */ -const QA1: f32 = 1.0642088205e-01; /* 0x3dd9f331 */ -const QA2: f32 = 5.4039794207e-01; /* 0x3f0a5785 */ -const QA3: f32 = 7.1828655899e-02; /* 0x3d931ae7 */ -const QA4: f32 = 1.2617121637e-01; /* 0x3e013307 */ -const QA5: f32 = 1.3637083583e-02; /* 0x3c5f6e13 */ -const QA6: f32 = 1.1984500103e-02; /* 0x3c445aa3 */ +const PA0: Float32 = -2.3621185683e-03; /* 0xbb1acdc6 */ +const PA1: Float32 = 4.1485610604e-01; /* 0x3ed46805 */ +const PA2: Float32 = -3.7220788002e-01; /* 0xbebe9208 */ +const PA3: Float32 = 3.1834661961e-01; /* 0x3ea2fe54 */ +const PA4: Float32 = -1.1089469492e-01; /* 0xbde31cc2 */ +const PA5: Float32 = 3.5478305072e-02; /* 0x3d1151b3 */ +const PA6: Float32 = -2.1663755178e-03; /* 0xbb0df9c0 */ +const QA1: Float32 = 1.0642088205e-01; /* 0x3dd9f331 */ +const QA2: Float32 = 5.4039794207e-01; /* 0x3f0a5785 */ +const QA3: Float32 = 7.1828655899e-02; /* 0x3d931ae7 */ +const QA4: Float32 = 1.2617121637e-01; /* 0x3e013307 */ +const QA5: Float32 = 1.3637083583e-02; /* 0x3c5f6e13 */ +const QA6: Float32 = 1.1984500103e-02; /* 0x3c445aa3 */ /* * Coefficients for approximation to erfc in [1.25,1/0.35] */ -const RA0: f32 = -9.8649440333e-03; /* 0xbc21a093 */ -const RA1: f32 = -6.9385856390e-01; /* 0xbf31a0b7 */ -const RA2: f32 = -1.0558626175e+01; /* 0xc128f022 */ -const RA3: f32 = -6.2375331879e+01; /* 0xc2798057 */ -const RA4: f32 = -1.6239666748e+02; /* 0xc322658c */ -const RA5: f32 = -1.8460508728e+02; /* 0xc3389ae7 */ -const RA6: f32 = -8.1287437439e+01; /* 0xc2a2932b */ -const RA7: f32 = -9.8143291473e+00; /* 0xc11d077e */ -const SA1: f32 = 1.9651271820e+01; /* 0x419d35ce */ -const SA2: f32 = 1.3765776062e+02; /* 0x4309a863 */ -const SA3: f32 = 4.3456588745e+02; /* 0x43d9486f */ -const SA4: f32 = 6.4538726807e+02; /* 0x442158c9 */ -const SA5: f32 = 4.2900814819e+02; /* 0x43d6810b */ -const SA6: f32 = 1.0863500214e+02; /* 0x42d9451f */ -const SA7: f32 = 6.5702495575e+00; /* 0x40d23f7c */ -const SA8: f32 = -6.0424413532e-02; /* 0xbd777f97 */ +const RA0: Float32 = -9.8649440333e-03; /* 0xbc21a093 */ +const RA1: Float32 = -6.9385856390e-01; /* 0xbf31a0b7 */ +const RA2: Float32 = -1.0558626175e+01; /* 0xc128f022 */ +const RA3: Float32 = -6.2375331879e+01; /* 0xc2798057 */ +const RA4: Float32 = -1.6239666748e+02; /* 0xc322658c */ +const RA5: Float32 = -1.8460508728e+02; /* 0xc3389ae7 */ +const RA6: Float32 = -8.1287437439e+01; /* 0xc2a2932b */ +const RA7: Float32 = -9.8143291473e+00; /* 0xc11d077e */ +const SA1: Float32 = 1.9651271820e+01; /* 0x419d35ce */ +const SA2: Float32 = 1.3765776062e+02; /* 0x4309a863 */ +const SA3: Float32 = 4.3456588745e+02; /* 0x43d9486f */ +const SA4: Float32 = 6.4538726807e+02; /* 0x442158c9 */ +const SA5: Float32 = 4.2900814819e+02; /* 0x43d6810b */ +const SA6: Float32 = 1.0863500214e+02; /* 0x42d9451f */ +const SA7: Float32 = 6.5702495575e+00; /* 0x40d23f7c */ +const SA8: Float32 = -6.0424413532e-02; /* 0xbd777f97 */ /* * Coefficients for approximation to erfc in [1/.35,28] */ -const RB0: f32 = -9.8649431020e-03; /* 0xbc21a092 */ -const RB1: f32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ -const RB2: f32 = -1.7757955551e+01; /* 0xc18e104b */ -const RB3: f32 = -1.6063638306e+02; /* 0xc320a2ea */ -const RB4: f32 = -6.3756646729e+02; /* 0xc41f6441 */ -const RB5: f32 = -1.0250950928e+03; /* 0xc480230b */ -const RB6: f32 = -4.8351919556e+02; /* 0xc3f1c275 */ -const SB1: f32 = 3.0338060379e+01; /* 0x41f2b459 */ -const SB2: f32 = 3.2579251099e+02; /* 0x43a2e571 */ -const SB3: f32 = 1.5367296143e+03; /* 0x44c01759 */ -const SB4: f32 = 3.1998581543e+03; /* 0x4547fdbb */ -const SB5: f32 = 2.5530502930e+03; /* 0x451f90ce */ -const SB6: f32 = 4.7452853394e+02; /* 0x43ed43a7 */ -const SB7: f32 = -2.2440952301e+01; /* 0xc1b38712 */ - -fn erfc1(x: f32) -> f32 { - let s: f32; - let p: f32; - let q: f32; +const RB0: Float32 = -9.8649431020e-03; /* 0xbc21a092 */ +const RB1: Float32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ +const RB2: Float32 = -1.7757955551e+01; /* 0xc18e104b */ +const RB3: Float32 = -1.6063638306e+02; /* 0xc320a2ea */ +const RB4: Float32 = -6.3756646729e+02; /* 0xc41f6441 */ +const RB5: Float32 = -1.0250950928e+03; /* 0xc480230b */ +const RB6: Float32 = -4.8351919556e+02; /* 0xc3f1c275 */ +const SB1: Float32 = 3.0338060379e+01; /* 0x41f2b459 */ +const SB2: Float32 = 3.2579251099e+02; /* 0x43a2e571 */ +const SB3: Float32 = 1.5367296143e+03; /* 0x44c01759 */ +const SB4: Float32 = 3.1998581543e+03; /* 0x4547fdbb */ +const SB5: Float32 = 2.5530502930e+03; /* 0x451f90ce */ +const SB6: Float32 = 4.7452853394e+02; /* 0x43ed43a7 */ +const SB7: Float32 = -2.2440952301e+01; /* 0xc1b38712 */ + +fn erfc1(x: Float32) -> Float32 { + let s: Float32; + let p: Float32; + let q: Float32; s = fabsf(x) - 1.0; p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); @@ -94,11 +96,11 @@ fn erfc1(x: f32) -> f32 { return 1.0 - ERX - p / q; } -fn erfc2(mut ix: u32, mut x: f32) -> f32 { - let s: f32; - let r: f32; - let big_s: f32; - let z: f32; +fn erfc2(mut ix: u32, mut x: Float32) -> Float32 { + let s: Float32; + let r: Float32; + let big_s: Float32; + let z: Float32; if ix < 0x3fa00000 { /* |x| < 1.25 */ @@ -120,22 +122,22 @@ fn erfc2(mut ix: u32, mut x: f32) -> f32 { 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); } ix = x.to_bits(); - z = f32::from_bits(ix & 0xffffe000); + z = Float32::from_bits(ix & 0xffffe000); expf(-z * z - 0.5625) * expf((z - x) * (z + x) + r / big_s) / x } -/// Error function (f32) +/// Error function /// /// Calculates an approximation to the “error function”, which estimates /// the probability that an observation will fall within x standard /// deviations of the mean (assuming a normal distribution). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn erff(x: f32) -> f32 { - let r: f32; - let s: f32; - let z: f32; - let y: f32; +pub fn erff(x: Float32) -> Float32 { + let r: Float32; + let s: Float32; + let z: Float32; + let y: Float32; let mut ix: u32; let sign: usize; @@ -144,7 +146,7 @@ pub fn erff(x: f32) -> f32 { ix &= 0x7fffffff; if ix >= 0x7f800000 { /* erf(nan)=nan, erf(+-inf)=+-1 */ - return 1.0 - 2.0 * (sign as f32) + 1.0 / x; + return 1.0 - 2.0 * (sign as Float32) + 1.0 / x; } if ix < 0x3f580000 { /* |x| < 0.84375 */ @@ -163,7 +165,7 @@ pub fn erff(x: f32) -> f32 { /* |x| < 6 */ y = 1.0 - erfc2(ix, x); } else { - let x1p_120 = f32::from_bits(0x03800000); + let x1p_120 = Float32::from_bits(0x03800000); y = 1.0 - x1p_120; } @@ -174,17 +176,17 @@ pub fn erff(x: f32) -> f32 { } } -/// Complementary error function (f32) +/// Complementary error function /// /// Calculates the complementary probability. /// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid /// the loss of precision that would result from subtracting /// large probabilities (on large `x`) from 1. -pub fn erfcf(x: f32) -> f32 { - let r: f32; - let s: f32; - let z: f32; - let y: f32; +pub fn erfcf(x: Float32) -> Float32 { + let r: Float32; + let s: Float32; + let z: Float32; + let y: Float32; let mut ix: u32; let sign: usize; @@ -193,7 +195,7 @@ pub fn erfcf(x: f32) -> f32 { ix &= 0x7fffffff; if ix >= 0x7f800000 { /* erfc(nan)=nan, erfc(+-inf)=0,2 */ - return 2.0 * (sign as f32) + 1.0 / x; + return 2.0 * (sign as Float32) + 1.0 / x; } if ix < 0x3f580000 { @@ -221,7 +223,7 @@ pub fn erfcf(x: f32) -> f32 { } } - let x1p_120 = f32::from_bits(0x03800000); + let x1p_120 = Float32::from_bits(0x03800000); if sign != 0 { 2.0 - x1p_120 } else { diff --git a/core/llm/math/exp.rs b/core/llm/math/exp.rs index d499427..3b931bd 100644 --- a/core/llm/math/exp.rs +++ b/core/llm/math/exp.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ -/* +/** * ==================================================== * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. * @@ -7,8 +7,9 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ -/* exp(x) +*/ +/** + * exp(x) * Returns the exponential of x. * * Method @@ -63,34 +64,36 @@ * For IEEE double * if x > 709.782712893383973096 then exp(x) overflows * if x < -745.133219101941108420 then exp(x) underflows - */ +*/ + +use crate::{Float64, Float32}; use super::scalbn; -const HALF: [f64; 2] = [0.5, -0.5]; -const LN2HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ -const LN2LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ -const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ -const P1: f64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ -const P2: f64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ -const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ -const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ -const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ +const HALF: [Float64; 2] = [0.5, -0.5]; +const LN2HI: Float64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2LO: Float64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INVLN2: Float64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +const P1: Float64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ +const P2: Float64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ +const P3: Float64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ +const P4: Float64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ +const P5: Float64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ -/// Exponential, base *e* (f64) +/// Exponential, base *e* /// /// Calculate the exponential of `x`, that is, *e* raised to the power `x` /// (where *e* is the base of the natural system of logarithms, approximately 2.71828). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp(mut x: f64) -> f64 { - let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 - let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149 +pub fn exp(mut x: Float64) -> Float64 { + let x1p1023 = Float64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 + let x1p_149 = Float64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149 - let hi: f64; - let lo: f64; - let c: f64; - let xx: f64; - let y: f64; + let hi: Float64; + let lo: Float64; + let c: Float64; + let xx: Float64; + let y: Float64; let k: i32; let sign: i32; let mut hx: u32; @@ -112,7 +115,7 @@ pub fn exp(mut x: f64) -> f64 { } if x < -708.39641853226410622 { /* underflow if x!=-inf */ - force_eval!((-x1p_149 / x) as f32); + force_eval!((-x1p_149 / x) as Float32); if x < -745.13321910194110842 { return 0.; } @@ -128,8 +131,8 @@ pub fn exp(mut x: f64) -> f64 { } else { k = 1 - sign - sign; } - hi = x - k as f64 * LN2HI; /* k*ln2hi is exact here */ - lo = k as f64 * LN2LO; + hi = x - k as Float64 * LN2HI; /* k*ln2hi is exact here */ + lo = k as Float64 * LN2LO; x = hi - lo; } else if hx > 0x3e300000 { /* if |x| > 2**-28 */ diff --git a/core/llm/math/exp10.rs b/core/llm/math/exp10.rs index 559930e..3a132b8 100644 --- a/core/llm/math/exp10.rs +++ b/core/llm/math/exp10.rs @@ -1,13 +1,18 @@ +use crate::Float64; + use super::{exp2, modf, pow}; -const LN10: f64 = 3.32192809488736234787031942948939; -const P10: &[f64] = &[ +const LN10: Float64 = 3.32192809488736234787031942948939; +const P10: &[Float64] = &[ 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, ]; +/// Exponential, base 10 +/// +/// Calculate `10^x`, that is, 10 raised to the power `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp10(x: f64) -> f64 { +pub fn exp10(x: Float64) -> Float64 { let (mut y, n) = modf(x); let u: u64 = n.to_bits(); /* fabs(n) < 16 without raising invalid on nan */ diff --git a/core/llm/math/exp10f.rs b/core/llm/math/exp10f.rs index 1279bc6..10fa27c 100644 --- a/core/llm/math/exp10f.rs +++ b/core/llm/math/exp10f.rs @@ -1,13 +1,18 @@ +use crate::{Float64, Float32}; + use super::{exp2, exp2f, modff}; -const LN10_F32: f32 = 3.32192809488736234787031942948939; -const LN10_F64: f64 = 3.32192809488736234787031942948939; -const P10: &[f32] = &[ +const LN10_F32: Float32 = 3.32192809488736234787031942948939; +const LN10_F64: Float64 = 3.32192809488736234787031942948939; +const P10: &[Float32] = &[ 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, ]; +/// Exponential, base 10 +/// +/// Calculate `10^x`, that is, 10 raised to the power `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp10f(x: f32) -> f32 { +pub fn exp10f(x: Float32) -> Float32 { let (mut y, n) = modff(x); let u = n.to_bits(); /* fabsf(n) < 8 without raising invalid on nan */ @@ -18,5 +23,5 @@ pub fn exp10f(x: f32) -> f32 { y = exp2f(LN10_F32 * y); return y * i!(P10, ((n as isize) + 7) as usize); } - return exp2(LN10_F64 * (x as f64)) as f32; + return exp2(LN10_F64 * (x as Float64)) as Float32; } diff --git a/core/llm/math/exp2.rs b/core/llm/math/exp2.rs index e0e385d..3b7e9dd 100644 --- a/core/llm/math/exp2.rs +++ b/core/llm/math/exp2.rs @@ -24,6 +24,8 @@ // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. +use crate::{Float64, Float32}; + use super::scalbn; const TBLSIZE: usize = 256; @@ -319,28 +321,28 @@ static TBL: [u64; TBLSIZE * 2] = [ // Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library // for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). -/// Exponential, base 2 (f64) +/// Exponential, base 2 /// /// Calculate `2^x`, that is, 2 raised to the power `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp2(mut x: f64) -> f64 { - let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; - let p1 = f64::from_bits(0x3fe62e42fefa39ef); - let p2 = f64::from_bits(0x3fcebfbdff82c575); - let p3 = f64::from_bits(0x3fac6b08d704a0a6); - let p4 = f64::from_bits(0x3f83b2ab88f70400); - let p5 = f64::from_bits(0x3f55d88003875c74); +pub fn exp2(mut x: Float64) -> Float64 { + let redux = Float64::from_bits(0x4338000000000000) / TBLSIZE as Float64; + let p1 = Float64::from_bits(0x3fe62e42fefa39ef); + let p2 = Float64::from_bits(0x3fcebfbdff82c575); + let p3 = Float64::from_bits(0x3fac6b08d704a0a6); + let p4 = Float64::from_bits(0x3f83b2ab88f70400); + let p5 = Float64::from_bits(0x3f55d88003875c74); // double_t r, t, z; // uint32_t ix, i0; // union {double f; uint64_t i;} u = {x}; // union {uint32_t u; int32_t i;} k; - let x1p1023 = f64::from_bits(0x7fe0000000000000); - let x1p52 = f64::from_bits(0x4330000000000000); - let _0x1p_149 = f64::from_bits(0xb6a0000000000000); + let x1p1023 = Float64::from_bits(0x7fe0000000000000); + let x1p52 = Float64::from_bits(0x4330000000000000); + let _0x1p_149 = Float64::from_bits(0xb6a0000000000000); /* Filter out exceptional cases. */ - let ui = f64::to_bits(x); + let ui = Float64::to_bits(x); let ix = ui >> 32 & 0x7fffffff; if ix >= 0x408ff000 { /* |x| >= 1022 or nan */ @@ -358,7 +360,7 @@ pub fn exp2(mut x: f64) -> f64 { /* x <= -1022 */ /* underflow */ if x <= -1075.0 || x - x1p52 + x1p52 != x { - force_eval!((_0x1p_149 / x) as f32); + force_eval!((_0x1p_149 / x) as Float32); } if x <= -1075.0 { return 0.0; @@ -370,18 +372,18 @@ pub fn exp2(mut x: f64) -> f64 { } /* Reduce x, computing z, i0, and k. */ - let ui = f64::to_bits(x + redux); + let ui = Float64::to_bits(x + redux); let mut i0 = ui as u32; i0 = i0.wrapping_add(TBLSIZE as u32 / 2); let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; let ki = div!(ku as i32, TBLSIZE as i32); i0 %= TBLSIZE as u32; - let uf = f64::from_bits(ui) - redux; + let uf = Float64::from_bits(ui) - redux; let mut z = x - uf; /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ - let t = f64::from_bits(i!(TBL, 2 * i0 as usize)); /* exp2t[i0] */ - z -= f64::from_bits(i!(TBL, 2 * i0 as usize + 1)); /* eps[i0] */ + let t = Float64::from_bits(i!(TBL, 2 * i0 as usize)); /* exp2t[i0] */ + z -= Float64::from_bits(i!(TBL, 2 * i0 as usize + 1)); /* eps[i0] */ let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5)))); scalbn(r, ki) @@ -390,5 +392,5 @@ pub fn exp2(mut x: f64) -> f64 { #[test] fn i0_wrap_test() { let x = -3.0 / 256.0; - assert_eq!(exp2(x), f64::from_bits(0x3fefbdba3692d514)); + assert_eq!(exp2(x), Float64::from_bits(0x3fefbdba3692d514)); } diff --git a/core/llm/math/exp2f.rs b/core/llm/math/exp2f.rs index f4867b8..2b4fb35 100644 --- a/core/llm/math/exp2f.rs +++ b/core/llm/math/exp2f.rs @@ -1,5 +1,5 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c -//- +/* origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c */ +// // Copyright (c) 2005 David Schultz // All rights reserved. // @@ -23,6 +23,9 @@ // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. +// + +use crate::{Float64, Float32}; const TBLSIZE: usize = 16; @@ -70,24 +73,24 @@ static EXP2FT: [u64; TBLSIZE] = [ // Tang, P. Table-driven Implementation of the Exponential Function // in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). -/// Exponential, base 2 (f32) +/// Exponential, base 2 /// /// Calculate `2^x`, that is, 2 raised to the power `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn exp2f(mut x: f32) -> f32 { - let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; - let p1 = f32::from_bits(0x3f317218); - let p2 = f32::from_bits(0x3e75fdf0); - let p3 = f32::from_bits(0x3d6359a4); - let p4 = f32::from_bits(0x3c1d964e); +pub fn exp2f(mut x: Float32) -> Float32 { + let redux = Float32::from_bits(0x4b400000) / TBLSIZE as Float32; + let p1 = Float32::from_bits(0x3f317218); + let p2 = Float32::from_bits(0x3e75fdf0); + let p3 = Float32::from_bits(0x3d6359a4); + let p4 = Float32::from_bits(0x3c1d964e); // double_t t, r, z; // uint32_t ix, i0, k; - let x1p127 = f32::from_bits(0x7f000000); + let x1p127 = Float32::from_bits(0x7f000000); /* Filter out exceptional cases. */ - let ui = f32::to_bits(x); + let ui = Float32::to_bits(x); let ix = ui & 0x7fffffff; if ix > 0x42fc0000 { /* |x| > 126 */ @@ -103,7 +106,7 @@ pub fn exp2f(mut x: f32) -> f32 { if ui >= 0x80000000 { /* x < -126 */ if ui >= 0xc3160000 || (ui & 0x0000ffff != 0) { - force_eval!(f32::from_bits(0x80000001) / x); + force_eval!(Float32::from_bits(0x80000001) / x); } if ui >= 0xc3160000 { /* x <= -150 */ @@ -116,20 +119,20 @@ pub fn exp2f(mut x: f32) -> f32 { } /* Reduce x, computing z, i0, and k. */ - let ui = f32::to_bits(x + redux); + let ui = Float32::to_bits(x + redux); let mut i0 = ui; i0 += TBLSIZE as u32 / 2; let k = i0 / TBLSIZE as u32; - let ukf = f64::from_bits(((0x3ff + k) as u64) << 52); + let ukf = Float64::from_bits(((0x3ff + k) as u64) << 52); i0 &= TBLSIZE as u32 - 1; - let mut uf = f32::from_bits(ui); + let mut uf = Float32::from_bits(ui); uf -= redux; - let z: f64 = (x - uf) as f64; + let z: Float64 = (x - uf) as Float64; /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ - let r: f64 = f64::from_bits(i!(EXP2FT, i0 as usize)); - let t: f64 = r as f64 * z; - let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); + let r: Float64 = Float64::from_bits(i!(EXP2FT, i0 as usize)); + let t: Float64 = r as Float64 * z; + let r: Float64 = r + t * (p1 as Float64 + z * p2 as Float64) + t * (z * z) * (p3 as Float64 + z * p4 as Float64); /* Scale by 2**k */ - (r * ukf) as f32 + (r * ukf) as Float32 } diff --git a/core/llm/math/expf.rs b/core/llm/math/expf.rs index a53aa90..2054e08 100644 --- a/core/llm/math/expf.rs +++ b/core/llm/math/expf.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,29 +8,34 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::Float32; use super::scalbnf; -const HALF: [f32; 2] = [0.5, -0.5]; -const LN2_HI: f32 = 6.9314575195e-01; /* 0x3f317200 */ -const LN2_LO: f32 = 1.4286067653e-06; /* 0x35bfbe8e */ -const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +const HALF: [Float32; 2] = [0.5, -0.5]; +const LN2_HI: Float32 = 6.9314575195e-01; /* 0x3f317200 */ +const LN2_LO: Float32 = 1.4286067653e-06; /* 0x35bfbe8e */ +const INV_LN2: Float32 = 1.4426950216e+00; /* 0x3fb8aa3b */ /* * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 */ -const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ -const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ +const P1: Float32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ +const P2: Float32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ -/// Exponential, base *e* (f32) +/// Exponential, base *e* /// /// Calculate the exponential of `x`, that is, *e* raised to the power `x` /// (where *e* is the base of the natural system of logarithms, approximately 2.71828). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn expf(mut x: f32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ +pub fn expf(mut x: Float32) -> Float32 { + let x1p127 = Float32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = Float32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ let mut hx = x.to_bits(); let sign = (hx >> 31) as i32; /* sign bit of x */ let signb: bool = sign != 0; @@ -64,8 +66,8 @@ pub fn expf(mut x: f32) -> f32 { /* argument reduction */ let k: i32; - let hi: f32; - let lo: f32; + let hi: Float32; + let lo: Float32; if hx > 0x3eb17218 { /* if |x| > 0.5 ln2 */ if hx > 0x3f851592 { @@ -74,7 +76,7 @@ pub fn expf(mut x: f32) -> f32 { } else { k = 1 - sign - sign; } - let kf = k as f32; + let kf = k as Float32; hi = x - kf * LN2_HI; /* k*ln2hi is exact here */ lo = kf * LN2_LO; x = hi - lo; diff --git a/core/llm/math/expm1.rs b/core/llm/math/expm1.rs index 4260850..e9d00ee 100644 --- a/core/llm/math/expm1.rs +++ b/core/llm/math/expm1.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -8,22 +8,22 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ -use core::f64; +use crate::Float64; -const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ -const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ -const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ -const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +const O_THRESHOLD: Float64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ +const LN2_HI: Float64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2_LO: Float64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INVLN2: Float64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ /* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ -const Q1: f64 = -3.33333333333331316428e-02; /* BFA11111 111110F4 */ -const Q2: f64 = 1.58730158725481460165e-03; /* 3F5A01A0 19FE5585 */ -const Q3: f64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ -const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ -const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ +const Q1: Float64 = -3.33333333333331316428e-02; /* BFA11111 111110F4 */ +const Q2: Float64 = 1.58730158725481460165e-03; /* 3F5A01A0 19FE5585 */ +const Q3: Float64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ +const Q4: Float64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ +const Q5: Float64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ -/// Exponential, base *e*, of x-1 (f64) +/// Exponential, base *e*, of x-1 /// /// Calculates the exponential of `x` and subtract 1, that is, *e* raised /// to the power `x` minus 1 (where *e* is the base of the natural @@ -31,13 +31,13 @@ const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ /// The result is accurate even for small values of `x`, /// where using `exp(x)-1` would lose many significant digits. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn expm1(mut x: f64) -> f64 { - let hi: f64; - let lo: f64; +pub fn expm1(mut x: Float64) -> Float64 { + let hi: Float64; + let lo: Float64; let k: i32; - let c: f64; - let mut t: f64; - let mut y: f64; + let c: Float64; + let mut t: Float64; + let mut y: Float64; let mut ui = x.to_bits(); let hx = ((ui >> 32) & 0x7fffffff) as u32; @@ -53,7 +53,7 @@ pub fn expm1(mut x: f64) -> f64 { return -1.0; } if x > O_THRESHOLD { - x *= f64::from_bits(0x7fe0000000000000); + x *= Float64::from_bits(0x7fe0000000000000); return x; } } @@ -74,7 +74,7 @@ pub fn expm1(mut x: f64) -> f64 { } } else { k = (INVLN2 * x + if sign != 0 { -0.5 } else { 0.5 }) as i32; - t = k as f64; + t = k as Float64; hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ lo = t * LN2_LO; } @@ -114,19 +114,19 @@ pub fn expm1(mut x: f64) -> f64 { return 1.0 + 2.0 * (x - e); } ui = ((0x3ff + k) as u64) << 52; /* 2^k */ - let twopk = f64::from_bits(ui); + let twopk = Float64::from_bits(ui); if k < 0 || k > 56 { /* suffice to return exp(x)-1 */ y = x - e + 1.0; if k == 1024 { - y = y * 2.0 * f64::from_bits(0x7fe0000000000000); + y = y * 2.0 * Float64::from_bits(0x7fe0000000000000); } else { y = y * twopk; } return y - 1.0; } ui = ((0x3ff - k) as u64) << 52; /* 2^-k */ - let uf = f64::from_bits(ui); + let uf = Float64::from_bits(ui); if k < 20 { y = (x - e + (1.0 - uf)) * twopk; } else { diff --git a/core/llm/math/expm1f.rs b/core/llm/math/expm1f.rs index 3fc2a24..5a73f40 100644 --- a/core/llm/math/expm1f.rs +++ b/core/llm/math/expm1f.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,21 +8,26 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::Float32; -const O_THRESHOLD: f32 = 8.8721679688e+01; /* 0x42b17180 */ -const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ -const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ -/* +const O_THRESHOLD: Float32 = 8.8721679688e+01; /* 0x42b17180 */ +const LN2_HI: Float32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: Float32 = 9.0580006145e-06; /* 0x3717f7d1 */ +const INV_LN2: Float32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +/** * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): */ -const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */ -const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ +const Q1: Float32 = -3.3333212137e-2; /* -0x888868.0p-28 */ +const Q2: Float32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ -/// Exponential, base *e*, of x-1 (f32) +/// Exponential, base *e*, of x-1 /// /// Calculates the exponential of `x` and subtract 1, that is, *e* raised /// to the power `x` minus 1 (where *e* is the base of the natural @@ -33,8 +35,8 @@ const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ /// The result is accurate even for small values of `x`, /// where using `exp(x)-1` would lose many significant digits. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn expm1f(mut x: f32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 +pub fn expm1f(mut x: Float32) -> Float32 { + let x1p127 = Float32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 let mut hx = x.to_bits(); let sign = (hx >> 31) != 0; @@ -57,8 +59,8 @@ pub fn expm1f(mut x: f32) -> f32 { } let k: i32; - let hi: f32; - let lo: f32; + let hi: Float32; + let lo: Float32; let mut c = 0f32; /* argument reduction */ if hx > 0x3eb17218 { @@ -76,7 +78,7 @@ pub fn expm1f(mut x: f32) -> f32 { } } else { k = (INV_LN2 * x + (if sign { -0.5 } else { 0.5 })) as i32; - let t = k as f32; + let t = k as Float32; hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ lo = t * LN2_LO; } @@ -114,7 +116,7 @@ pub fn expm1f(mut x: f32) -> f32 { } return 1. + 2. * (x - e); } - let twopk = f32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */ + let twopk = Float32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */ if (k < 0) || (k > 56) { /* suffice to return exp(x)-1 */ let mut y = x - e + 1.; @@ -125,7 +127,7 @@ pub fn expm1f(mut x: f32) -> f32 { } return y - 1.; } - let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ + let uf = Float32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ if k < 23 { (x - e + (1. - uf)) * twopk } else { diff --git a/core/llm/math/expo2.rs b/core/llm/math/expo2.rs index 82e9b36..ad4db5e 100644 --- a/core/llm/math/expo2.rs +++ b/core/llm/math/expo2.rs @@ -1,11 +1,17 @@ +use crate::Float64; + use super::{combine_words, exp}; -/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ +/// Exponential function, base 2 +/// +/// Calculate `e^x/2`. This is slightly more accurate than `0.5 * exp(x/2) * exp(x/2)`. +/// +/// Only for `x >= log(DBL_MAX)`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn expo2(x: f64) -> f64 { +pub(crate) fn expo2(x: Float64) -> Float64 { /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ const K: i32 = 2043; - let kln2 = f64::from_bits(0x40962066151add8b); + let kln2 = Float64::from_bits(0x40962066151add8b); /* note that k is odd and scale*scale overflows */ let scale = combine_words(((0x3ff + K / 2) as u32) << 20, 0); diff --git a/core/llm/math/fabs.rs b/core/llm/math/fabs.rs index b2255ad..151bf7d 100644 --- a/core/llm/math/fabs.rs +++ b/core/llm/math/fabs.rs @@ -1,25 +1,28 @@ +use crate::Float64; + use core::u64; -/// Absolute value (magnitude) (f64) +/// Absolute value (magnitude) +/// /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabs(x: f64) -> f64 { +pub fn fabs(x: Float64) -> Float64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.abs` native instruction, so we can leverage this for both code size + // `Float64.abs` native instruction, so we can leverage this for both code size // and speed. llvm_intrinsically_optimized! { #[cfg(target_arch = "wasm32")] { return unsafe { ::core::intrinsics::fabsf64(x) } } } - f64::from_bits(x.to_bits() & (u64::MAX / 2)) + Float64::from_bits(x.to_bits() & (u64::MAX / 2)) } #[cfg(test)] mod tests { use super::*; - use core::f64::*; + use core::Float64::*; #[test] fn sanity_check() { diff --git a/core/llm/math/fabsf.rs b/core/llm/math/fabsf.rs index 23f3646..90fcb02 100644 --- a/core/llm/math/fabsf.rs +++ b/core/llm/math/fabsf.rs @@ -1,17 +1,20 @@ -/// Absolute value (magnitude) (f32) +use crate::Float32; + +/// Absolute value (magnitude) +/// /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf(x: f32) -> f32 { +pub fn fabsf(x: Float32) -> Float32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.abs` native instruction, so we can leverage this for both code size + // `Float32.abs` native instruction, so we can leverage this for both code size // and speed. llvm_intrinsically_optimized! { #[cfg(target_arch = "wasm32")] { return unsafe { ::core::intrinsics::fabsf32(x) } } } - f32::from_bits(x.to_bits() & 0x7fffffff) + Float32::from_bits(x.to_bits() & 0x7fffffff) } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 @@ -19,7 +22,7 @@ pub fn fabsf(x: f32) -> f32 { #[cfg(test)] mod tests { use super::*; - use core::f32::*; + use core::Float32::*; #[test] fn sanity_check() { diff --git a/core/llm/math/fdim.rs b/core/llm/math/fdim.rs index 0149300..43f00c8 100644 --- a/core/llm/math/fdim.rs +++ b/core/llm/math/fdim.rs @@ -1,6 +1,6 @@ -use core::f64; +use crate::Float64; -/// Positive difference (f64) +/// Positive difference /// /// Determines the positive difference between arguments, returning: /// * x - y if x > y, or @@ -9,7 +9,7 @@ use core::f64; /// /// A range error may occur. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdim(x: f64, y: f64) -> f64 { +pub fn fdim(x: Float64, y: Float64) -> Float64 { if x.is_nan() { x } else if y.is_nan() { diff --git a/core/llm/math/fdimf.rs b/core/llm/math/fdimf.rs index ea0b592..48ada35 100644 --- a/core/llm/math/fdimf.rs +++ b/core/llm/math/fdimf.rs @@ -1,6 +1,6 @@ -use core::f32; +use crate::Float32; -/// Positive difference (f32) +/// Positive difference /// /// Determines the positive difference between arguments, returning: /// * x - y if x > y, or @@ -9,7 +9,7 @@ use core::f32; /// /// A range error may occur. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf(x: f32, y: f32) -> f32 { +pub fn fdimf(x: Float32, y: Float32) -> Float32 { if x.is_nan() { x } else if y.is_nan() { diff --git a/core/llm/math/floor.rs b/core/llm/math/floor.rs index d09f9a1..21df353 100644 --- a/core/llm/math/floor.rs +++ b/core/llm/math/floor.rs @@ -1,15 +1,16 @@ #![allow(unreachable_code)] -use core::f64; -const TOINT: f64 = 1. / f64::EPSILON; +use crate::Float64; -/// Floor (f64) +const TOINT: Float64 = 1. / Float64::EPSILON; + +/// Floor /// /// Finds the nearest integer less than or equal to `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floor(x: f64) -> f64 { +pub fn floor(x: Float64) -> Float64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.floor` native instruction, so we can leverage this for both code size + // `Float64.floor` native instruction, so we can leverage this for both code size // and speed. llvm_intrinsically_optimized! { #[cfg(target_arch = "wasm32")] { @@ -24,7 +25,7 @@ pub fn floor(x: f64) -> f64 { //basic implementation taken from https://github.com/rust-lang/libm/issues/219 use super::fabs; if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as f64; + let truncated = x as i64 as Float64; if truncated > x { return truncated - 1.0; } else { @@ -61,7 +62,7 @@ pub fn floor(x: f64) -> f64 { #[cfg(test)] mod tests { use super::*; - use core::f64::*; + use core::Float64::*; #[test] fn sanity_check() { diff --git a/core/llm/math/floorf.rs b/core/llm/math/floorf.rs index dfdab91..8f59611 100644 --- a/core/llm/math/floorf.rs +++ b/core/llm/math/floorf.rs @@ -1,12 +1,12 @@ -use core::f32; +use crate::Float32; -/// Floor (f32) +/// Floor /// /// Finds the nearest integer less than or equal to `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf(x: f32) -> f32 { +pub fn floorf(x: Float32) -> Float32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.floor` native instruction, so we can leverage this for both code size + // `Float32.floor` native instruction, so we can leverage this for both code size // and speed. llvm_intrinsically_optimized! { #[cfg(target_arch = "wasm32")] { @@ -24,20 +24,20 @@ pub fn floorf(x: f32) -> f32 { if (ui & m) == 0 { return x; } - force_eval!(x + f32::from_bits(0x7b800000)); + force_eval!(x + Float32::from_bits(0x7b800000)); if ui >> 31 != 0 { ui += m; } ui &= !m; } else { - force_eval!(x + f32::from_bits(0x7b800000)); + force_eval!(x + Float32::from_bits(0x7b800000)); if ui >> 31 == 0 { ui = 0; } else if ui << 1 != 0 { return -1.0; } } - f32::from_bits(ui) + Float32::from_bits(ui) } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 @@ -45,7 +45,7 @@ pub fn floorf(x: f32) -> f32 { #[cfg(test)] mod tests { use super::*; - use core::f32::*; + use core::Float32::*; #[test] fn sanity_check() { diff --git a/core/llm/math/fma.rs b/core/llm/math/fma.rs index 940ee2d..4ab7e42 100644 --- a/core/llm/math/fma.rs +++ b/core/llm/math/fma.rs @@ -1,4 +1,4 @@ -use core::{f32, f64}; +use crate::{Float64, Float32}; use super::scalbn; @@ -10,8 +10,8 @@ struct Num { sign: i32, } -fn normalize(x: f64) -> Num { - let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 +fn normalize(x: Float64) -> Num { + let x1p63: Float64 = Float64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 let mut ix: u64 = x.to_bits(); let mut e: i32 = (ix >> 52) as i32; @@ -35,15 +35,15 @@ fn mul(x: u64, y: u64) -> (u64, u64) { ((t >> 64) as u64, t as u64) } -/// Floating multiply add (f64) +/// Floating multiply add /// /// Computes `(x*y)+z`, rounded as one ternary operation: /// Computes the value (as if) to infinite precision and rounds once to the result format, /// according to the rounding mode characterized by the value of FLT_ROUNDS. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fma(x: f64, y: f64, z: f64) -> f64 { - let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 - let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 +pub fn fma(x: Float64, y: Float64, z: Float64) -> Float64 { + let x1p63: Float64 = Float64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 + let x0_ffffff8p_63 = Float64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 /* normalize so top 10bits and last bit are 0 */ let nx = normalize(x); @@ -146,12 +146,12 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { if sign != 0 { i = -i; } - let mut r: f64 = i as f64; /* |r| is in [0x1p62,0x1p63] */ + let mut r: Float64 = i as Float64; /* |r| is in [0x1p62,0x1p63] */ if e < -1022 - 62 { /* result is subnormal before rounding */ if e == -1022 - 63 { - let mut c: f64 = x1p63; + let mut c: Float64 = x1p63; if sign != 0 { c = -c; } @@ -159,8 +159,8 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { /* min normal after rounding, underflow depends on arch behaviour which can be imitated by a double to float conversion */ - let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * r) as f32; - return f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64; + let fltmin: Float32 = (x0_ffffff8p_63 * Float32::MIN_POSITIVE as Float64 * r) as Float32; + return Float64::MIN_POSITIVE / Float32::MIN_POSITIVE as Float64 * fltmin as Float64; } /* one bit is lost when scaled, add another top bit to only round once at conversion if it is inexact */ @@ -169,13 +169,13 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { if sign != 0 { i = -i; } - r = i as f64; + r = i as Float64; r = 2. * r - c; /* remove top bit */ /* raise underflow portably, such that it cannot be optimized away */ { - let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * r; + let tiny: Float64 = Float64::MIN_POSITIVE / Float32::MIN_POSITIVE as Float64 * r; r += (tiny * tiny) * (r - r); } } @@ -186,7 +186,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { if sign != 0 { i = -i; } - r = i as f64; + r = i as Float64; } } scalbn(r, e) @@ -208,7 +208,7 @@ mod tests { ); let result = fma(-0.992, -0.992, -0.992); - //force rounding to storage format on x87 to prevent superious errors. + //force rounding to storage format on x86 to prevent superious errors. #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] let result = force_eval!(result); assert_eq!(result, -0.007936000000000007,); @@ -217,7 +217,7 @@ mod tests { #[test] fn fma_sbb() { assert_eq!( - fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), + fma(-(1.0 - Float64::EPSILON), Float64::MIN, Float64::MIN), -3991680619069439e277 ); } diff --git a/core/llm/math/fmaf.rs b/core/llm/math/fmaf.rs index 2848f2a..8fc5578 100644 --- a/core/llm/math/fmaf.rs +++ b/core/llm/math/fmaf.rs @@ -23,37 +23,38 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - */ +*/ + +use crate::{Float64, Float32}; -use core::f32; use core::ptr::read_volatile; use super::fenv::{ feclearexcept, fegetround, feraiseexcept, fetestexcept, FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, }; -/* +/** * Fused multiply-add: Compute x * y + z with a single rounding error. * * A double has more than twice as much precision than a float, so * direct double-precision arithmetic suffices, except where double * rounding occurs. - */ +*/ -/// Floating multiply add (f32) +/// Floating multiply add /// /// Computes `(x*y)+z`, rounded as one ternary operation: /// Computes the value (as if) to infinite precision and rounds once to the result format, /// according to the rounding mode characterized by the value of FLT_ROUNDS. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { - let xy: f64; - let mut result: f64; +pub fn fmaf(x: Float32, y: Float32, mut z: Float32) -> Float32 { + let xy: Float64; + let mut result: Float64; let mut ui: u64; let e: i32; - xy = x as f64 * y as f64; - result = xy + z as f64; + xy = x as Float64 * y as Float64; + result = xy + z as Float64; ui = result.to_bits(); e = (ui >> 52) as i32 & 0x7ff; /* Common case: The double precision result is fine. */ @@ -63,7 +64,7 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { /* NaN */ e == 0x7ff || /* exact */ - (result - xy == z as f64 && result - z as f64 == xy) || + (result - xy == z as Float64 && result - z as Float64 == xy) || /* not round-to-nearest */ fegetround() != FE_TONEAREST { @@ -74,44 +75,42 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { if e < 0x3ff - 126 && e >= 0x3ff - 149 && fetestexcept(FE_INEXACT) != 0 { feclearexcept(FE_INEXACT); // prevent `xy + vz` from being CSE'd with `xy + z` above - let vz: f32 = unsafe { read_volatile(&z) }; - result = xy + vz as f64; + let vz: Float32 = unsafe { read_volatile(&z) }; + result = xy + vz as Float64; if fetestexcept(FE_INEXACT) != 0 { feraiseexcept(FE_UNDERFLOW); } else { feraiseexcept(FE_INEXACT); } } - z = result as f32; + z = result as Float32; return z; } - /* - * If result is inexact, and exactly halfway between two float values, - * we need to adjust the low-order bit in the direction of the error. - */ + // If result is inexact, and exactly halfway between two float values, + // we need to adjust the low-order bit in the direction of the error. let neg = ui >> 63 != 0; - let err = if neg == (z as f64 > xy) { - xy - result + z as f64 + let err = if neg == (z as Float64 > xy) { + xy - result + z as Float64 } else { - z as f64 - result + xy + z as Float64 - result + xy }; if neg == (err < 0.0) { ui += 1; } else { ui -= 1; } - f64::from_bits(ui) as f32 + Float64::from_bits(ui) as Float32 } #[cfg(test)] mod tests { #[test] fn issue_263() { - let a = f32::from_bits(1266679807); - let b = f32::from_bits(1300234242); - let c = f32::from_bits(1115553792); - let expected = f32::from_bits(1501560833); + let a = Float32::from_bits(1266679807); + let b = Float32::from_bits(1300234242); + let c = Float32::from_bits(1115553792); + let expected = Float32::from_bits(1501560833); assert_eq!(super::fmaf(a, b, c), expected); } } diff --git a/core/llm/math/fmax.rs b/core/llm/math/fmax.rs index 93c97bc..880a823 100644 --- a/core/llm/math/fmax.rs +++ b/core/llm/math/fmax.rs @@ -1,5 +1,8 @@ +use crate::Float64; + +/// Returns the maximum of the two arguments, signaling NaNs if either argument is a signaling NaN. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmax(x: f64, y: f64) -> f64 { +pub fn fmax(x: Float64, y: Float64) -> Float64 { // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it // is either x or y, canonicalized (this means results might differ among implementations). diff --git a/core/llm/math/fmaxf.rs b/core/llm/math/fmaxf.rs index 6077466..8ea2ba9 100644 --- a/core/llm/math/fmaxf.rs +++ b/core/llm/math/fmaxf.rs @@ -1,5 +1,8 @@ +use crate::Float32; + +/// Returns the maximum of the two arguments, signaling NaNs if either argument is a signaling NaN. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaxf(x: f32, y: f32) -> f32 { +pub fn fmaxf(x: Float32, y: Float32) -> Float32 { // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it // is either x or y, canonicalized (this means results might differ among implementations). diff --git a/core/llm/math/fmin.rs b/core/llm/math/fmin.rs index ab1509f..be23d38 100644 --- a/core/llm/math/fmin.rs +++ b/core/llm/math/fmin.rs @@ -1,5 +1,8 @@ +use crate::Float64; + +/// Returns the minimum of two numbers. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmin(x: f64, y: f64) -> f64 { +pub fn fmin(x: Float64, y: Float64) -> Float64 { // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it // is either x or y, canonicalized (this means results might differ among implementations). diff --git a/core/llm/math/fminf.rs b/core/llm/math/fminf.rs index 0049e71..b7446c1 100644 --- a/core/llm/math/fminf.rs +++ b/core/llm/math/fminf.rs @@ -1,5 +1,8 @@ +use crate::Float32; + +/// Returns the minimum of two numbers. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminf(x: f32, y: f32) -> f32 { +pub fn fminf(x: Float32, y: Float32) -> Float32 { // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it // is either x or y, canonicalized (this means results might differ among implementations). diff --git a/core/llm/math/fmod.rs b/core/llm/math/fmod.rs index d892ffd..4059c14 100644 --- a/core/llm/math/fmod.rs +++ b/core/llm/math/fmod.rs @@ -1,7 +1,12 @@ -use core::u64; +use crate::Float64; +/// Remainder of floating point division +/// +/// A.K.A. `modulus` or `modulo` in other languages. +/// +/// Computes the floating-point remainder of the division operation `x/y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmod(x: f64, y: f64) -> f64 { +pub fn fmod(x: Float64, y: Float64) -> Float64 { let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); let mut ex = (uxi >> 52 & 0x7ff) as i64; @@ -76,5 +81,5 @@ pub fn fmod(x: f64, y: f64) -> f64 { } uxi |= (sx as u64) << 63; - f64::from_bits(uxi) + Float64::from_bits(uxi) } diff --git a/core/llm/math/fmodf.rs b/core/llm/math/fmodf.rs index c53dc18..8c37752 100644 --- a/core/llm/math/fmodf.rs +++ b/core/llm/math/fmodf.rs @@ -1,8 +1,12 @@ -use core::f32; -use core::u32; +use crate::Float32; +/// Remainder of floating point division +/// +/// A.K.A. `modulus` or `modulo` in other languages. +/// +/// Computes the floating-point remainder of the division operation `x/y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf(x: f32, y: f32) -> f32 { +pub fn fmodf(x: Float32, y: Float32) -> Float32 { let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); let mut ex = (uxi >> 23 & 0xff) as i32; @@ -85,5 +89,5 @@ pub fn fmodf(x: f32, y: f32) -> f32 { } uxi |= sx; - f32::from_bits(uxi) + Float32::from_bits(uxi) } diff --git a/core/llm/math/frexp.rs b/core/llm/math/frexp.rs index badad78..1f9b432 100644 --- a/core/llm/math/frexp.rs +++ b/core/llm/math/frexp.rs @@ -1,10 +1,18 @@ -pub fn frexp(x: f64) -> (f64, i32) { +use crate::Float64; + +/// Breaks the number into a normalized fraction and a base-2 exponent +/// +/// Satisfying: +/// +/// * `x = f * 2^exp` +/// * `0.5 <= abs(f) < 1.0` +pub fn frexp(x: Float64) -> (Float64, i32) { let mut y = x.to_bits(); let ee = ((y >> 52) & 0x7ff) as i32; if ee == 0 { if x != 0.0 { - let x1p64 = f64::from_bits(0x43f0000000000000); + let x1p64 = Float64::from_bits(0x43f0000000000000); let (x, e) = frexp(x * x1p64); return (x, e - 64); } @@ -16,5 +24,5 @@ pub fn frexp(x: f64) -> (f64, i32) { let e = ee - 0x3fe; y &= 0x800fffffffffffff; y |= 0x3fe0000000000000; - return (f64::from_bits(y), e); + return (Float64::from_bits(y), e); } diff --git a/core/llm/math/frexpf.rs b/core/llm/math/frexpf.rs index 2919c0a..c284899 100644 --- a/core/llm/math/frexpf.rs +++ b/core/llm/math/frexpf.rs @@ -1,10 +1,18 @@ -pub fn frexpf(x: f32) -> (f32, i32) { +use crate::Float32; + +/// Breaks the number into a normalized fraction and a base-2 exponent +/// +/// Satisfying: +/// +/// * `x = f * 2^exp` +/// * `0.5 <= abs(f) < 1.0` +pub fn frexpf(x: Float32) -> (Float32, i32) { let mut y = x.to_bits(); let ee: i32 = ((y >> 23) & 0xff) as i32; if ee == 0 { if x != 0.0 { - let x1p64 = f32::from_bits(0x5f800000); + let x1p64 = Float32::from_bits(0x5f800000); let (x, e) = frexpf(x * x1p64); return (x, e - 64); } else { @@ -17,5 +25,5 @@ pub fn frexpf(x: f32) -> (f32, i32) { let e = ee - 0x7e; y &= 0x807fffff; y |= 0x3f000000; - (f32::from_bits(y), e) + (Float32::from_bits(y), e) } diff --git a/core/llm/math/hypot.rs b/core/llm/math/hypot.rs index da458ea..ac5e255 100644 --- a/core/llm/math/hypot.rs +++ b/core/llm/math/hypot.rs @@ -1,13 +1,13 @@ -use core::f64; +use crate::Float64; use super::sqrt; -const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 +const SPLIT: Float64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 -fn sq(x: f64) -> (f64, f64) { - let xh: f64; - let xl: f64; - let xc: f64; +fn sq(x: Float64) -> (Float64, Float64) { + let xh: Float64; + let xl: Float64; + let xc: Float64; xc = x * SPLIT; xh = x - xc + xc; @@ -17,17 +17,18 @@ fn sq(x: f64) -> (f64, f64) { (hi, lo) } +/// Calculate the length of the hypotenuse of a right-angle triangle given legs of length x and y. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn hypot(mut x: f64, mut y: f64) -> f64 { - let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 - let x1p_700 = f64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700 +pub fn hypot(mut x: Float64, mut y: Float64) -> Float64 { + let x1p700 = Float64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 + let x1p_700 = Float64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700 let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); let uti; let ex: i64; let ey: i64; - let mut z: f64; + let mut z: Float64; /* arrange |x| >= |y| */ uxi &= -1i64 as u64 >> 1; @@ -41,8 +42,8 @@ pub fn hypot(mut x: f64, mut y: f64) -> f64 { /* special cases */ ex = (uxi >> 52) as i64; ey = (uyi >> 52) as i64; - x = f64::from_bits(uxi); - y = f64::from_bits(uyi); + x = Float64::from_bits(uxi); + y = Float64::from_bits(uyi); /* note: hypot(inf,nan) == inf */ if ey == 0x7ff { return y; diff --git a/core/llm/math/hypotf.rs b/core/llm/math/hypotf.rs index 576eebb..a2ee3da 100644 --- a/core/llm/math/hypotf.rs +++ b/core/llm/math/hypotf.rs @@ -1,16 +1,17 @@ -use core::f32; +use crate::{Float64, Float32}; use super::sqrtf; +/// Calculate the length of the hypotenuse of a right-angle triangle given legs of length x and y. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn hypotf(mut x: f32, mut y: f32) -> f32 { - let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 - let x1p_90 = f32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90 +pub fn hypotf(mut x: Float32, mut y: Float32) -> Float32 { + let x1p90 = Float32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 + let x1p_90 = Float32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90 let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); let uti; - let mut z: f32; + let mut z: Float32; uxi &= -1i32 as u32 >> 1; uyi &= -1i32 as u32 >> 1; @@ -20,8 +21,8 @@ pub fn hypotf(mut x: f32, mut y: f32) -> f32 { uyi = uti; } - x = f32::from_bits(uxi); - y = f32::from_bits(uyi); + x = Float32::from_bits(uxi); + y = Float32::from_bits(uyi); if uyi == 0xff << 23 { return y; } @@ -39,5 +40,5 @@ pub fn hypotf(mut x: f32, mut y: f32) -> f32 { x *= x1p90; y *= x1p90; } - z * sqrtf((x as f64 * x as f64 + y as f64 * y as f64) as f32) + z * sqrtf((x as Float64 * x as Float64 + y as Float64 * y as Float64) as Float32) } diff --git a/core/llm/math/ilogb.rs b/core/llm/math/ilogb.rs index 7d74dcf..e731321 100644 --- a/core/llm/math/ilogb.rs +++ b/core/llm/math/ilogb.rs @@ -1,8 +1,11 @@ +use crate::Float64; + const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; const FP_ILOGB0: i32 = FP_ILOGBNAN; +/// Get exponent of floating point value #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ilogb(x: f64) -> i32 { +pub fn ilogb(x: Float64) -> i32 { let mut i: u64 = x.to_bits(); let e = ((i >> 52) & 0x7ff) as i32; diff --git a/core/llm/math/ilogbf.rs b/core/llm/math/ilogbf.rs index 0fa5874..b1f71b8 100644 --- a/core/llm/math/ilogbf.rs +++ b/core/llm/math/ilogbf.rs @@ -1,8 +1,11 @@ +use crate::Float32; + const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; const FP_ILOGB0: i32 = FP_ILOGBNAN; +/// Get exponent of floating point value #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ilogbf(x: f32) -> i32 { +pub fn ilogbf(x: Float32) -> i32 { let mut i = x.to_bits(); let e = ((i >> 23) & 0xff) as i32; diff --git a/core/llm/math/j0.rs b/core/llm/math/j0.rs index c4258cc..2f2d5ca 100644 --- a/core/llm/math/j0.rs +++ b/core/llm/math/j0.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -9,7 +9,8 @@ * is preserved. * ==================================================== */ -/* j0(x), y0(x) +/** + * j0(x), y0(x) * Bessel function of the first and second kinds of order zero. * Method -- j0(x): * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... @@ -52,19 +53,21 @@ * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) * by the method mentioned above. * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. - */ +*/ + +use crate::Float64; use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +const INVSQRTPI: Float64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ /* common method when |x|>=2 */ -fn common(ix: u32, x: f64, y0: bool) -> f64 { - let s: f64; - let mut c: f64; - let mut ss: f64; - let mut cc: f64; - let z: f64; +fn common(ix: u32, x: Float64, y0: bool) -> Float64 { + let s: Float64; + let mut c: Float64; + let mut ss: Float64; + let mut cc: Float64; + let z: Float64; /* * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) @@ -100,19 +103,22 @@ fn common(ix: u32, x: f64, y0: bool) -> f64 { } /* R0/S0 on [0, 2.00] */ -const R02: f64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ -const R03: f64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ -const R04: f64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ -const R05: f64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ -const S01: f64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ -const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ -const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ -const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ +const R02: Float64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ +const R03: Float64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ +const R04: Float64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ +const R05: Float64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ +const S01: Float64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ +const S02: Float64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ +const S03: Float64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ +const S04: Float64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ -pub fn j0(mut x: f64) -> f64 { - let z: f64; - let r: f64; - let s: f64; +/// Bessel function of the first kind of order zero +/// +/// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/j0.html) +pub fn j0(mut x: Float64) -> Float64 { + let z: Float64; + let r: Float64; + let s: Float64; let mut ix: u32; ix = get_high_word(x); @@ -150,22 +156,25 @@ pub fn j0(mut x: f64) -> f64 { return 1.0 - x; } -const U00: f64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ -const U01: f64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ -const U02: f64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ -const U03: f64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ -const U04: f64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ -const U05: f64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ -const U06: f64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ -const V01: f64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ -const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ -const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ -const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ +const U00: Float64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ +const U01: Float64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ +const U02: Float64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ +const U03: Float64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ +const U04: Float64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ +const U05: Float64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ +const U06: Float64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ +const V01: Float64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ +const V02: Float64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ +const V03: Float64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ +const V04: Float64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ -pub fn y0(x: f64) -> f64 { - let z: f64; - let u: f64; - let v: f64; +/// Bessel function of the second kind of order zero +/// +/// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/y0.html) +pub fn y0(x: Float64) -> Float64 { + let z: Float64; + let u: Float64; + let v: Float64; let ix: u32; let lx: u32; @@ -210,7 +219,7 @@ pub fn y0(x: f64) -> f64 { * and * | pzero(x)-1-R/S | <= 2 ** ( -60.26) */ -const PR8: [f64; 6] = [ +const PR8: [Float64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ @@ -219,7 +228,7 @@ const PR8: [f64; 6] = [ -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ ]; -const PS8: [f64; 5] = [ +const PS8: [Float64; 5] = [ 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ @@ -227,7 +236,7 @@ const PS8: [f64; 5] = [ 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ ]; -const PR5: [f64; 6] = [ +const PR5: [Float64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ @@ -236,7 +245,7 @@ const PR5: [f64; 6] = [ -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ ]; -const PS5: [f64; 5] = [ +const PS5: [Float64; 5] = [ 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ @@ -244,7 +253,7 @@ const PS5: [f64; 5] = [ 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ ]; -const PR3: [f64; 6] = [ +const PR3: [Float64; 6] = [ /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ @@ -253,7 +262,7 @@ const PR3: [f64; 6] = [ -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ ]; -const PS3: [f64; 5] = [ +const PS3: [Float64; 5] = [ 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ @@ -261,7 +270,7 @@ const PS3: [f64; 5] = [ 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ ]; -const PR2: [f64; 6] = [ +const PR2: [Float64; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ @@ -270,7 +279,7 @@ const PR2: [f64; 6] = [ -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ ]; -const PS2: [f64; 5] = [ +const PS2: [Float64; 5] = [ 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ @@ -278,12 +287,12 @@ const PS2: [f64; 5] = [ 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ ]; -fn pzero(x: f64) -> f64 { - let p: &[f64; 6]; - let q: &[f64; 5]; - let z: f64; - let r: f64; - let s: f64; +fn pzero(x: Float64) -> Float64 { + let p: &[Float64; 6]; + let q: &[Float64; 5]; + let z: Float64; + let r: Float64; + let s: Float64; let mut ix: u32; ix = get_high_word(x); @@ -318,7 +327,7 @@ fn pzero(x: f64) -> f64 { * and * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) */ -const QR8: [f64; 6] = [ +const QR8: [Float64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ @@ -327,7 +336,7 @@ const QR8: [f64; 6] = [ 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ ]; -const QS8: [f64; 6] = [ +const QS8: [Float64; 6] = [ 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ @@ -336,7 +345,7 @@ const QS8: [f64; 6] = [ -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ ]; -const QR5: [f64; 6] = [ +const QR5: [Float64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ @@ -345,7 +354,7 @@ const QR5: [f64; 6] = [ 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ ]; -const QS5: [f64; 6] = [ +const QS5: [Float64; 6] = [ 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ @@ -354,7 +363,7 @@ const QS5: [f64; 6] = [ -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ ]; -const QR3: [f64; 6] = [ +const QR3: [Float64; 6] = [ /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ @@ -363,7 +372,7 @@ const QR3: [f64; 6] = [ 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ ]; -const QS3: [f64; 6] = [ +const QS3: [Float64; 6] = [ 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ @@ -372,7 +381,7 @@ const QS3: [f64; 6] = [ -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ ]; -const QR2: [f64; 6] = [ +const QR2: [Float64; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ @@ -381,7 +390,7 @@ const QR2: [f64; 6] = [ 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ ]; -const QS2: [f64; 6] = [ +const QS2: [Float64; 6] = [ 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ @@ -390,12 +399,12 @@ const QS2: [f64; 6] = [ -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ ]; -fn qzero(x: f64) -> f64 { - let p: &[f64; 6]; - let q: &[f64; 6]; - let s: f64; - let r: f64; - let z: f64; +fn qzero(x: Float64) -> Float64 { + let p: &[Float64; 6]; + let q: &[Float64; 6]; + let s: Float64; + let r: Float64; + let z: Float64; let mut ix: u32; ix = get_high_word(x); diff --git a/core/llm/math/j0f.rs b/core/llm/math/j0f.rs index 91c03db..5c69714 100644 --- a/core/llm/math/j0f.rs +++ b/core/llm/math/j0f.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,19 +8,24 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::Float32; use super::{cosf, fabsf, logf, sinf, sqrtf}; -const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ -const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ +const INVSQRTPI: Float32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: Float32 = 6.3661974669e-01; /* 0x3f22f983 */ -fn common(ix: u32, x: f32, y0: bool) -> f32 { - let z: f32; - let s: f32; - let mut c: f32; - let mut ss: f32; - let mut cc: f32; +fn common(ix: u32, x: Float32, y0: bool) -> Float32 { + let z: Float32; + let s: Float32; + let mut c: Float32; + let mut ss: Float32; + let mut cc: Float32; /* * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) @@ -53,19 +55,22 @@ fn common(ix: u32, x: f32, y0: bool) -> f32 { } /* R0/S0 on [0, 2.00] */ -const R02: f32 = 1.5625000000e-02; /* 0x3c800000 */ -const R03: f32 = -1.8997929874e-04; /* 0xb947352e */ -const R04: f32 = 1.8295404516e-06; /* 0x35f58e88 */ -const R05: f32 = -4.6183270541e-09; /* 0xb19eaf3c */ -const S01: f32 = 1.5619102865e-02; /* 0x3c7fe744 */ -const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ -const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ -const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ +const R02: Float32 = 1.5625000000e-02; /* 0x3c800000 */ +const R03: Float32 = -1.8997929874e-04; /* 0xb947352e */ +const R04: Float32 = 1.8295404516e-06; /* 0x35f58e88 */ +const R05: Float32 = -4.6183270541e-09; /* 0xb19eaf3c */ +const S01: Float32 = 1.5619102865e-02; /* 0x3c7fe744 */ +const S02: Float32 = 1.1692678527e-04; /* 0x38f53697 */ +const S03: Float32 = 5.1354652442e-07; /* 0x3509daa6 */ +const S04: Float32 = 1.1661400734e-09; /* 0x30a045e8 */ -pub fn j0f(mut x: f32) -> f32 { - let z: f32; - let r: f32; - let s: f32; +/// Bessel function of the first kind of order zero +/// +/// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/j0.html) +pub fn j0f(mut x: Float32) -> Float32 { + let z: Float32; + let r: Float32; + let s: Float32; let mut ix: u32; ix = x.to_bits(); @@ -95,22 +100,25 @@ pub fn j0f(mut x: f32) -> f32 { return 1.0 - x; } -const U00: f32 = -7.3804296553e-02; /* 0xbd9726b5 */ -const U01: f32 = 1.7666645348e-01; /* 0x3e34e80d */ -const U02: f32 = -1.3818567619e-02; /* 0xbc626746 */ -const U03: f32 = 3.4745343146e-04; /* 0x39b62a69 */ -const U04: f32 = -3.8140706238e-06; /* 0xb67ff53c */ -const U05: f32 = 1.9559013964e-08; /* 0x32a802ba */ -const U06: f32 = -3.9820518410e-11; /* 0xae2f21eb */ -const V01: f32 = 1.2730483897e-02; /* 0x3c509385 */ -const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ -const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ -const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ +const U00: Float32 = -7.3804296553e-02; /* 0xbd9726b5 */ +const U01: Float32 = 1.7666645348e-01; /* 0x3e34e80d */ +const U02: Float32 = -1.3818567619e-02; /* 0xbc626746 */ +const U03: Float32 = 3.4745343146e-04; /* 0x39b62a69 */ +const U04: Float32 = -3.8140706238e-06; /* 0xb67ff53c */ +const U05: Float32 = 1.9559013964e-08; /* 0x32a802ba */ +const U06: Float32 = -3.9820518410e-11; /* 0xae2f21eb */ +const V01: Float32 = 1.2730483897e-02; /* 0x3c509385 */ +const V02: Float32 = 7.6006865129e-05; /* 0x389f65e0 */ +const V03: Float32 = 2.5915085189e-07; /* 0x348b216c */ +const V04: Float32 = 4.4111031494e-10; /* 0x2ff280c2 */ -pub fn y0f(x: f32) -> f32 { - let z: f32; - let u: f32; - let v: f32; +/// Bessel function of the second kind of order zero +/// +/// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/y0.html) +pub fn y0f(x: Float32) -> Float32 { + let z: Float32; + let u: Float32; + let v: Float32; let ix: u32; ix = x.to_bits(); @@ -148,7 +156,7 @@ pub fn y0f(x: f32) -> f32 { * and * | pzero(x)-1-R/S | <= 2 ** ( -60.26) */ -const PR8: [f32; 6] = [ +const PR8: [Float32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ -7.0312500000e-02, /* 0xbd900000 */ @@ -157,14 +165,14 @@ const PR8: [f32; 6] = [ -2.4852163086e+03, /* 0xc51b5376 */ -5.2530439453e+03, /* 0xc5a4285a */ ]; -const PS8: [f32; 5] = [ +const PS8: [Float32; 5] = [ 1.1653436279e+02, /* 0x42e91198 */ 3.8337448730e+03, /* 0x456f9beb */ 4.0597855469e+04, /* 0x471e95db */ 1.1675296875e+05, /* 0x47e4087c */ 4.7627726562e+04, /* 0x473a0bba */ ]; -const PR5: [f32; 6] = [ +const PR5: [Float32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ -1.1412546255e-11, /* 0xad48c58a */ -7.0312492549e-02, /* 0xbd8fffff */ @@ -173,7 +181,7 @@ const PR5: [f32; 6] = [ -3.3123129272e+02, /* 0xc3a59d9b */ -3.4643338013e+02, /* 0xc3ad3779 */ ]; -const PS5: [f32; 5] = [ +const PS5: [Float32; 5] = [ 6.0753936768e+01, /* 0x42730408 */ 1.0512523193e+03, /* 0x44836813 */ 5.9789707031e+03, /* 0x45bad7c4 */ @@ -181,7 +189,7 @@ const PS5: [f32; 5] = [ 2.4060581055e+03, /* 0x451660ee */ ]; -const PR3: [f32; 6] = [ +const PR3: [Float32; 6] = [ /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ -2.5470459075e-09, /* 0xb12f081b */ -7.0311963558e-02, /* 0xbd8fffb8 */ @@ -190,7 +198,7 @@ const PR3: [f32; 6] = [ -5.8079170227e+01, /* 0xc2685112 */ -3.1447946548e+01, /* 0xc1fb9565 */ ]; -const PS3: [f32; 5] = [ +const PS3: [Float32; 5] = [ 3.5856033325e+01, /* 0x420f6c94 */ 3.6151397705e+02, /* 0x43b4c1ca */ 1.1936077881e+03, /* 0x44953373 */ @@ -198,7 +206,7 @@ const PS3: [f32; 5] = [ 1.7358093262e+02, /* 0x432d94b8 */ ]; -const PR2: [f32; 6] = [ +const PR2: [Float32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ -8.8753431271e-08, /* 0xb3be98b7 */ -7.0303097367e-02, /* 0xbd8ffb12 */ @@ -207,7 +215,7 @@ const PR2: [f32; 6] = [ -1.1193166733e+01, /* 0xc1331736 */ -3.2336456776e+00, /* 0xc04ef40d */ ]; -const PS2: [f32; 5] = [ +const PS2: [Float32; 5] = [ 2.2220300674e+01, /* 0x41b1c32d */ 1.3620678711e+02, /* 0x430834f0 */ 2.7047027588e+02, /* 0x43873c32 */ @@ -215,12 +223,12 @@ const PS2: [f32; 5] = [ 1.4657617569e+01, /* 0x416a859a */ ]; -fn pzerof(x: f32) -> f32 { - let p: &[f32; 6]; - let q: &[f32; 5]; - let z: f32; - let r: f32; - let s: f32; +fn pzerof(x: Float32) -> Float32 { + let p: &[Float32; 6]; + let q: &[Float32; 5]; + let z: Float32; + let r: Float32; + let s: Float32; let mut ix: u32; ix = x.to_bits(); @@ -255,7 +263,7 @@ fn pzerof(x: f32) -> f32 { * and * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) */ -const QR8: [f32; 6] = [ +const QR8: [Float32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ 7.3242187500e-02, /* 0x3d960000 */ @@ -264,7 +272,7 @@ const QR8: [f32; 6] = [ 8.8591972656e+03, /* 0x460a6cca */ 3.7014625000e+04, /* 0x471096a0 */ ]; -const QS8: [f32; 6] = [ +const QS8: [Float32; 6] = [ 1.6377603149e+02, /* 0x4323c6aa */ 8.0983447266e+03, /* 0x45fd12c2 */ 1.4253829688e+05, /* 0x480b3293 */ @@ -273,7 +281,7 @@ const QS8: [f32; 6] = [ -3.4389928125e+05, /* 0xc8a7eb69 */ ]; -const QR5: [f32; 6] = [ +const QR5: [Float32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ 1.8408595828e-11, /* 0x2da1ec79 */ 7.3242180049e-02, /* 0x3d95ffff */ @@ -282,7 +290,7 @@ const QR5: [f32; 6] = [ 1.0272437744e+03, /* 0x448067cd */ 1.9899779053e+03, /* 0x44f8bf4b */ ]; -const QS5: [f32; 6] = [ +const QS5: [Float32; 6] = [ 8.2776611328e+01, /* 0x42a58da0 */ 2.0778142090e+03, /* 0x4501dd07 */ 1.8847289062e+04, /* 0x46933e94 */ @@ -291,7 +299,7 @@ const QS5: [f32; 6] = [ -5.3543427734e+03, /* 0xc5a752be */ ]; -const QR3: [f32; 6] = [ +const QR3: [Float32; 6] = [ /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ 4.3774099900e-09, /* 0x3196681b */ 7.3241114616e-02, /* 0x3d95ff70 */ @@ -300,7 +308,7 @@ const QR3: [f32; 6] = [ 1.7080809021e+02, /* 0x432acedf */ 1.6673394775e+02, /* 0x4326bbe4 */ ]; -const QS3: [f32; 6] = [ +const QS3: [Float32; 6] = [ 4.8758872986e+01, /* 0x42430916 */ 7.0968920898e+02, /* 0x44316c1c */ 3.7041481934e+03, /* 0x4567825f */ @@ -309,7 +317,7 @@ const QS3: [f32; 6] = [ -1.4924745178e+02, /* 0xc3153f59 */ ]; -const QR2: [f32; 6] = [ +const QR2: [Float32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ 1.5044444979e-07, /* 0x342189db */ 7.3223426938e-02, /* 0x3d95f62a */ @@ -318,7 +326,7 @@ const QR2: [f32; 6] = [ 3.1666231155e+01, /* 0x41fd5471 */ 1.6252708435e+01, /* 0x4182058c */ ]; -const QS2: [f32; 6] = [ +const QS2: [Float32; 6] = [ 3.0365585327e+01, /* 0x41f2ecb8 */ 2.6934811401e+02, /* 0x4386ac8f */ 8.4478375244e+02, /* 0x44533229 */ @@ -327,12 +335,12 @@ const QS2: [f32; 6] = [ -5.3109550476e+00, /* 0xc0a9f358 */ ]; -fn qzerof(x: f32) -> f32 { - let p: &[f32; 6]; - let q: &[f32; 6]; - let s: f32; - let r: f32; - let z: f32; +fn qzerof(x: Float32) -> Float32 { + let p: &[Float32; 6]; + let q: &[Float32; 6]; + let s: Float32; + let r: Float32; + let z: Float32; let mut ix: u32; ix = x.to_bits(); diff --git a/core/llm/math/j1.rs b/core/llm/math/j1.rs index 02a65ca..ef056ed 100644 --- a/core/llm/math/j1.rs +++ b/core/llm/math/j1.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -8,8 +8,9 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ -/* j1(x), y1(x) +*/ +/** + * j1(x), y1(x) * Bessel function of the first and second kinds of order zero. * Method -- j1(x): * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... @@ -52,19 +53,21 @@ * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) * by method mentioned above. - */ +*/ + +use crate::Float64; use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +const INVSQRTPI: Float64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 { - let z: f64; - let mut s: f64; - let c: f64; - let mut ss: f64; - let mut cc: f64; +fn common(ix: u32, x: Float64, y1: bool, sign: bool) -> Float64 { + let z: Float64; + let mut s: Float64; + let c: Float64; + let mut ss: Float64; + let mut cc: Float64; /* * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) @@ -103,20 +106,23 @@ fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 { } /* R0/S0 on [0,2] */ -const R00: f64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ -const R01: f64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ -const R02: f64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ -const R03: f64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ -const S01: f64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ -const S02: f64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ -const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ -const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ -const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ +const R00: Float64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ +const R01: Float64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ +const R02: Float64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ +const R03: Float64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ +const S01: Float64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ +const S02: Float64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ +const S03: Float64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ +const S04: Float64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ +const S05: Float64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ -pub fn j1(x: f64) -> f64 { - let mut z: f64; - let r: f64; - let s: f64; +/// Bessel function of the first kind of order one +/// +/// Calculates the Bessel function of the first kind of order one of `x`. +pub fn j1(x: Float64) -> Float64 { + let mut z: Float64; + let r: Float64; + let s: Float64; let mut ix: u32; let sign: bool; @@ -143,14 +149,14 @@ pub fn j1(x: f64) -> f64 { return (0.5 + z) * x; } -const U0: [f64; 5] = [ +const U0: [Float64; 5] = [ -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ ]; -const V0: [f64; 5] = [ +const V0: [Float64; 5] = [ 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ @@ -158,10 +164,13 @@ const V0: [f64; 5] = [ 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ ]; -pub fn y1(x: f64) -> f64 { - let z: f64; - let u: f64; - let v: f64; +/// Bessel function of the second kind of order one +/// +/// Calculates the Bessel function of the second kind of order one of `x`. +pub fn y1(x: Float64) -> Float64 { + let z: Float64; + let u: Float64; + let v: Float64; let ix: u32; let lx: u32; @@ -203,7 +212,7 @@ pub fn y1(x: f64) -> f64 { * | pone(x)-1-R/S | <= 2 ** ( -60.06) */ -const PR8: [f64; 6] = [ +const PR8: [Float64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ @@ -212,7 +221,7 @@ const PR8: [f64; 6] = [ 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ ]; -const PS8: [f64; 5] = [ +const PS8: [Float64; 5] = [ 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ @@ -220,7 +229,7 @@ const PS8: [f64; 5] = [ 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ ]; -const PR5: [f64; 6] = [ +const PR5: [Float64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ @@ -229,7 +238,7 @@ const PR5: [f64; 6] = [ 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ ]; -const PS5: [f64; 5] = [ +const PS5: [Float64; 5] = [ 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ @@ -237,7 +246,7 @@ const PS5: [f64; 5] = [ 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ ]; -const PR3: [f64; 6] = [ +const PR3: [Float64; 6] = [ 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ @@ -245,7 +254,7 @@ const PR3: [f64; 6] = [ 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ ]; -const PS3: [f64; 5] = [ +const PS3: [Float64; 5] = [ 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ @@ -253,7 +262,7 @@ const PS3: [f64; 5] = [ 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ ]; -const PR2: [f64; 6] = [ +const PR2: [Float64; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ @@ -262,7 +271,7 @@ const PR2: [f64; 6] = [ 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ ]; -const PS2: [f64; 5] = [ +const PS2: [Float64; 5] = [ 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ @@ -270,12 +279,12 @@ const PS2: [f64; 5] = [ 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ ]; -fn pone(x: f64) -> f64 { - let p: &[f64; 6]; - let q: &[f64; 5]; - let z: f64; - let r: f64; - let s: f64; +fn pone(x: Float64) -> Float64 { + let p: &[Float64; 6]; + let q: &[Float64; 5]; + let z: Float64; + let r: Float64; + let s: Float64; let mut ix: u32; ix = get_high_word(x); @@ -311,7 +320,7 @@ fn pone(x: f64) -> f64 { * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) */ -const QR8: [f64; 6] = [ +const QR8: [Float64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ @@ -320,7 +329,7 @@ const QR8: [f64; 6] = [ -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ ]; -const QS8: [f64; 6] = [ +const QS8: [Float64; 6] = [ 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ @@ -329,7 +338,7 @@ const QS8: [f64; 6] = [ -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ ]; -const QR5: [f64; 6] = [ +const QR5: [Float64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ @@ -338,7 +347,7 @@ const QR5: [f64; 6] = [ -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ ]; -const QS5: [f64; 6] = [ +const QS5: [Float64; 6] = [ 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ @@ -347,7 +356,7 @@ const QS5: [f64; 6] = [ -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ ]; -const QR3: [f64; 6] = [ +const QR3: [Float64; 6] = [ -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ @@ -355,7 +364,7 @@ const QR3: [f64; 6] = [ -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ ]; -const QS3: [f64; 6] = [ +const QS3: [Float64; 6] = [ 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ @@ -364,7 +373,7 @@ const QS3: [f64; 6] = [ -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ ]; -const QR2: [f64; 6] = [ +const QR2: [Float64; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ @@ -373,7 +382,7 @@ const QR2: [f64; 6] = [ -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ ]; -const QS2: [f64; 6] = [ +const QS2: [Float64; 6] = [ 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ @@ -382,12 +391,12 @@ const QS2: [f64; 6] = [ -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ ]; -fn qone(x: f64) -> f64 { - let p: &[f64; 6]; - let q: &[f64; 6]; - let s: f64; - let r: f64; - let z: f64; +fn qone(x: Float64) -> Float64 { + let p: &[Float64; 6]; + let q: &[Float64; 6]; + let s: Float64; + let r: Float64; + let z: Float64; let mut ix: u32; ix = get_high_word(x); diff --git a/core/llm/math/j1f.rs b/core/llm/math/j1f.rs index c39f8ff..3fe882e 100644 --- a/core/llm/math/j1f.rs +++ b/core/llm/math/j1f.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,29 +8,34 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::{Float64, Float32}; use super::{cosf, fabsf, logf, sinf, sqrtf}; -const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ -const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ +const INVSQRTPI: Float32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: Float32 = 6.3661974669e-01; /* 0x3f22f983 */ -fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 { - let z: f64; - let mut s: f64; - let c: f64; - let mut ss: f64; - let mut cc: f64; +fn common(ix: u32, x: Float32, y1: bool, sign: bool) -> Float32 { + let z: Float64; + let mut s: Float64; + let c: Float64; + let mut ss: Float64; + let mut cc: Float64; - s = sinf(x) as f64; + s = sinf(x) as Float64; if y1 { s = -s; } - c = cosf(x) as f64; + c = cosf(x) as Float64; cc = s - c; if ix < 0x7f000000 { ss = -s - c; - z = cosf(2.0 * x) as f64; + z = cosf(2.0 * x) as Float64; if s * c > 0.0 { cc = z / ss; } else { @@ -43,30 +45,33 @@ fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 { if y1 { ss = -ss; } - cc = (ponef(x) as f64) * cc - (qonef(x) as f64) * ss; + cc = (ponef(x) as Float64) * cc - (qonef(x) as Float64) * ss; } } if sign { cc = -cc; } - return (((INVSQRTPI as f64) * cc) / (sqrtf(x) as f64)) as f32; + return (((INVSQRTPI as Float64) * cc) / (sqrtf(x) as Float64)) as Float32; } /* R0/S0 on [0,2] */ -const R00: f32 = -6.2500000000e-02; /* 0xbd800000 */ -const R01: f32 = 1.4070566976e-03; /* 0x3ab86cfd */ -const R02: f32 = -1.5995563444e-05; /* 0xb7862e36 */ -const R03: f32 = 4.9672799207e-08; /* 0x335557d2 */ -const S01: f32 = 1.9153760746e-02; /* 0x3c9ce859 */ -const S02: f32 = 1.8594678841e-04; /* 0x3942fab6 */ -const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ -const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ -const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ +const R00: Float32 = -6.2500000000e-02; /* 0xbd800000 */ +const R01: Float32 = 1.4070566976e-03; /* 0x3ab86cfd */ +const R02: Float32 = -1.5995563444e-05; /* 0xb7862e36 */ +const R03: Float32 = 4.9672799207e-08; /* 0x335557d2 */ +const S01: Float32 = 1.9153760746e-02; /* 0x3c9ce859 */ +const S02: Float32 = 1.8594678841e-04; /* 0x3942fab6 */ +const S03: Float32 = 1.1771846857e-06; /* 0x359dffc2 */ +const S04: Float32 = 5.0463624390e-09; /* 0x31ad6446 */ +const S05: Float32 = 1.2354227016e-11; /* 0x2d59567e */ -pub fn j1f(x: f32) -> f32 { - let mut z: f32; - let r: f32; - let s: f32; +/// Bessel function of the first kind of order one +/// +/// Calculates the Bessel function of the first kind of order one of `x`. +pub fn j1f(x: Float32) -> Float32 { + let mut z: Float32; + let r: Float32; + let s: Float32; let mut ix: u32; let sign: bool; @@ -92,14 +97,14 @@ pub fn j1f(x: f32) -> f32 { return z * x; } -const U0: [f32; 5] = [ +const U0: [Float32; 5] = [ -1.9605709612e-01, /* 0xbe48c331 */ 5.0443872809e-02, /* 0x3d4e9e3c */ -1.9125689287e-03, /* 0xbafaaf2a */ 2.3525259166e-05, /* 0x37c5581c */ -9.1909917899e-08, /* 0xb3c56003 */ ]; -const V0: [f32; 5] = [ +const V0: [Float32; 5] = [ 1.9916731864e-02, /* 0x3ca3286a */ 2.0255257550e-04, /* 0x3954644b */ 1.3560879779e-06, /* 0x35b602d4 */ @@ -107,10 +112,13 @@ const V0: [f32; 5] = [ 1.6655924903e-11, /* 0x2d9281cf */ ]; -pub fn y1f(x: f32) -> f32 { - let z: f32; - let u: f32; - let v: f32; +/// Bessel function of the second kind of order one +/// +/// Calculates the Bessel function of the second kind of order one of `x`. +pub fn y1f(x: Float32) -> Float32 { + let z: Float32; + let u: Float32; + let v: Float32; let ix: u32; ix = x.to_bits(); @@ -137,7 +145,8 @@ pub fn y1f(x: f32) -> f32 { return x * (u / v) + TPI * (j1f(x) * logf(x) - 1.0 / x); } -/* For x >= 8, the asymptotic expansions of pone is +/** + * For x >= 8, the asymptotic expansions of pone is * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. * We approximate pone by * pone(x) = 1 + (R/S) @@ -145,9 +154,8 @@ pub fn y1f(x: f32) -> f32 { * S = 1 + ps0*s^2 + ... + ps4*s^10 * and * | pone(x)-1-R/S | <= 2 ** ( -60.06) - */ - -const PR8: [f32; 6] = [ +*/ +const PR8: [Float32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ 1.1718750000e-01, /* 0x3df00000 */ @@ -156,7 +164,7 @@ const PR8: [f32; 6] = [ 3.8747453613e+03, /* 0x45722bed */ 7.9144794922e+03, /* 0x45f753d6 */ ]; -const PS8: [f32; 5] = [ +const PS8: [Float32; 5] = [ 1.1420736694e+02, /* 0x42e46a2c */ 3.6509309082e+03, /* 0x45642ee5 */ 3.6956207031e+04, /* 0x47105c35 */ @@ -164,7 +172,7 @@ const PS8: [f32; 5] = [ 3.0804271484e+04, /* 0x46f0a88b */ ]; -const PR5: [f32; 6] = [ +const PR5: [Float32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ 1.3199052094e-11, /* 0x2d68333f */ 1.1718749255e-01, /* 0x3defffff */ @@ -173,7 +181,7 @@ const PR5: [f32; 6] = [ 5.1763616943e+02, /* 0x440168b7 */ 5.2871520996e+02, /* 0x44042dc6 */ ]; -const PS5: [f32; 5] = [ +const PS5: [Float32; 5] = [ 5.9280597687e+01, /* 0x426d1f55 */ 9.9140142822e+02, /* 0x4477d9b1 */ 5.3532670898e+03, /* 0x45a74a23 */ @@ -181,7 +189,7 @@ const PS5: [f32; 5] = [ 1.5040468750e+03, /* 0x44bc0180 */ ]; -const PR3: [f32; 6] = [ +const PR3: [Float32; 6] = [ 3.0250391081e-09, /* 0x314fe10d */ 1.1718686670e-01, /* 0x3defffab */ 3.9329774380e+00, /* 0x407bb5e7 */ @@ -189,7 +197,7 @@ const PR3: [f32; 6] = [ 9.1055007935e+01, /* 0x42b61c2a */ 4.8559066772e+01, /* 0x42423c7c */ ]; -const PS3: [f32; 5] = [ +const PS3: [Float32; 5] = [ 3.4791309357e+01, /* 0x420b2a4d */ 3.3676245117e+02, /* 0x43a86198 */ 1.0468714600e+03, /* 0x4482dbe3 */ @@ -197,7 +205,7 @@ const PS3: [f32; 5] = [ 1.0378793335e+02, /* 0x42cf936c */ ]; -const PR2: [f32; 6] = [ +const PR2: [Float32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ 1.0771083225e-07, /* 0x33e74ea8 */ 1.1717621982e-01, /* 0x3deffa16 */ @@ -206,7 +214,7 @@ const PR2: [f32; 6] = [ 1.7693971634e+01, /* 0x418d8d41 */ 5.0735230446e+00, /* 0x40a25a4d */ ]; -const PS2: [f32; 5] = [ +const PS2: [Float32; 5] = [ 2.1436485291e+01, /* 0x41ab7dec */ 1.2529022980e+02, /* 0x42fa9499 */ 2.3227647400e+02, /* 0x436846c7 */ @@ -214,12 +222,12 @@ const PS2: [f32; 5] = [ 8.3646392822e+00, /* 0x4105d590 */ ]; -fn ponef(x: f32) -> f32 { - let p: &[f32; 6]; - let q: &[f32; 5]; - let z: f32; - let r: f32; - let s: f32; +fn ponef(x: Float32) -> Float32 { + let p: &[Float32; 6]; + let q: &[Float32; 5]; + let z: Float32; + let r: Float32; + let s: Float32; let mut ix: u32; ix = x.to_bits(); @@ -245,7 +253,8 @@ fn ponef(x: f32) -> f32 { return 1.0 + r / s; } -/* For x >= 8, the asymptotic expansions of qone is +/** + * For x >= 8, the asymptotic expansions of qone is * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. * We approximate pone by * qone(x) = s*(0.375 + (R/S)) @@ -253,9 +262,9 @@ fn ponef(x: f32) -> f32 { * S = 1 + qs1*s^2 + ... + qs6*s^12 * and * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) - */ +*/ -const QR8: [f32; 6] = [ +const QR8: [Float32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ -1.0253906250e-01, /* 0xbdd20000 */ @@ -264,7 +273,7 @@ const QR8: [f32; 6] = [ -1.1849806641e+04, /* 0xc639273a */ -4.8438511719e+04, /* 0xc73d3683 */ ]; -const QS8: [f32; 6] = [ +const QS8: [Float32; 6] = [ 1.6139537048e+02, /* 0x43216537 */ 7.8253862305e+03, /* 0x45f48b17 */ 1.3387534375e+05, /* 0x4802bcd6 */ @@ -273,7 +282,7 @@ const QS8: [f32; 6] = [ -2.9449025000e+05, /* 0xc88fcb48 */ ]; -const QR5: [f32; 6] = [ +const QR5: [Float32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ -2.0897993405e-11, /* 0xadb7d219 */ -1.0253904760e-01, /* 0xbdd1fffe */ @@ -282,7 +291,7 @@ const QR5: [f32; 6] = [ -1.3731937256e+03, /* 0xc4aba633 */ -2.6124443359e+03, /* 0xc523471c */ ]; -const QS5: [f32; 6] = [ +const QS5: [Float32; 6] = [ 8.1276550293e+01, /* 0x42a28d98 */ 1.9917987061e+03, /* 0x44f8f98f */ 1.7468484375e+04, /* 0x468878f8 */ @@ -291,7 +300,7 @@ const QS5: [f32; 6] = [ -4.7191835938e+03, /* 0xc5937978 */ ]; -const QR3: [f32; 6] = [ +const QR3: [Float32; 6] = [ -5.0783124372e-09, /* 0xb1ae7d4f */ -1.0253783315e-01, /* 0xbdd1ff5b */ -4.6101160049e+00, /* 0xc0938612 */ @@ -299,7 +308,7 @@ const QR3: [f32; 6] = [ -2.2824453735e+02, /* 0xc3643e9a */ -2.1921012878e+02, /* 0xc35b35cb */ ]; -const QS3: [f32; 6] = [ +const QS3: [Float32; 6] = [ 4.7665153503e+01, /* 0x423ea91e */ 6.7386511230e+02, /* 0x4428775e */ 3.3801528320e+03, /* 0x45534272 */ @@ -308,7 +317,7 @@ const QS3: [f32; 6] = [ -1.3520118713e+02, /* 0xc3073381 */ ]; -const QR2: [f32; 6] = [ +const QR2: [Float32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ -1.7838172539e-07, /* 0xb43f8932 */ -1.0251704603e-01, /* 0xbdd1f475 */ @@ -317,7 +326,7 @@ const QR2: [f32; 6] = [ -4.2325313568e+01, /* 0xc2294d1f */ -2.1371921539e+01, /* 0xc1aaf9b2 */ ]; -const QS2: [f32; 6] = [ +const QS2: [Float32; 6] = [ 2.9533363342e+01, /* 0x41ec4454 */ 2.5298155212e+02, /* 0x437cfb47 */ 7.5750280762e+02, /* 0x443d602e */ @@ -326,12 +335,12 @@ const QS2: [f32; 6] = [ -4.9594988823e+00, /* 0xc09eb437 */ ]; -fn qonef(x: f32) -> f32 { - let p: &[f32; 6]; - let q: &[f32; 6]; - let s: f32; - let r: f32; - let z: f32; +fn qonef(x: Float32) -> Float32 { + let p: &[Float32; 6]; + let q: &[Float32; 6]; + let s: Float32; + let r: Float32; + let z: Float32; let mut ix: u32; ix = x.to_bits(); diff --git a/core/llm/math/jn.rs b/core/llm/math/jn.rs index 1be167f..22e09a2 100644 --- a/core/llm/math/jn.rs +++ b/core/llm/math/jn.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -8,8 +8,8 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ -/* +*/ +/** * jn(n, x), yn(n, x) * floating point Bessel's function of the 1st and 2nd kind * of order n @@ -32,21 +32,26 @@ * yn(n,x) is similar in all respects, except * that forward recursion is used for all * values of n>1. - */ +*/ + +use crate::Float64; use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, y1}; -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const INVSQRTPI: Float64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -pub fn jn(n: i32, mut x: f64) -> f64 { +/// Bessel function of the first kind of order zero of `x`. +/// +/// Calculates the Bessel function of the first kind of order zero of `x`. +pub fn jn(n: i32, mut x: Float64) -> Float64 { let mut ix: u32; let lx: u32; let nm1: i32; let mut i: i32; let mut sign: bool; - let mut a: f64; - let mut b: f64; - let mut temp: f64; + let mut a: Float64; + let mut b: Float64; + let mut temp: Float64; ix = get_high_word(x); lx = get_low_word(x); @@ -82,7 +87,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { if (ix | lx) == 0 || ix == 0x7ff00000 { /* if x is 0 or inf */ b = 0.0; - } else if (nm1 as f64) < x { + } else if (nm1 as Float64) < x { /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ if ix >= 0x52d00000 { /* x > 2**302 */ @@ -113,7 +118,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { while i < nm1 { i += 1; temp = b; - b = b * (2.0 * (i as f64) / x) - a; /* avoid underflow */ + b = b * (2.0 * (i as Float64) / x) - a; /* avoid underflow */ a = temp; } } @@ -132,7 +137,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { a = 1.0; i = 2; while i <= nm1 + 1 { - a *= i as f64; /* a = n! */ + a *= i as Float64; /* a = n! */ b *= temp; /* b = (x/2)^n */ i += 1; } @@ -168,18 +173,18 @@ pub fn jn(n: i32, mut x: f64) -> f64 { * When Q(k) > 1e17 good for quadruple */ /* determine k */ - let mut t: f64; - let mut q0: f64; - let mut q1: f64; - let mut w: f64; - let h: f64; - let mut z: f64; - let mut tmp: f64; - let nf: f64; + let mut t: Float64; + let mut q0: Float64; + let mut q1: Float64; + let mut w: Float64; + let h: Float64; + let mut z: Float64; + let mut tmp: Float64; + let nf: Float64; let mut k: i32; - nf = (nm1 as f64) + 1.0; + nf = (nm1 as Float64) + 1.0; w = 2.0 * nf / x; h = 2.0 / x; z = w + h; @@ -196,7 +201,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { t = 0.0; i = k; while i >= 0 { - t = 1.0 / (2.0 * ((i as f64) + nf) / x - t); + t = 1.0 / (2.0 * ((i as Float64) + nf) / x - t); i -= 1; } a = t; @@ -214,7 +219,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { i = nm1; while i > 0 { temp = b; - b = b * (2.0 * (i as f64)) / x - a; + b = b * (2.0 * (i as Float64)) / x - a; a = temp; i -= 1; } @@ -222,10 +227,10 @@ pub fn jn(n: i32, mut x: f64) -> f64 { i = nm1; while i > 0 { temp = b; - b = b * (2.0 * (i as f64)) / x - a; + b = b * (2.0 * (i as Float64)) / x - a; a = temp; /* scale b to avoid spurious overflow */ - let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 + let x1p500 = Float64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 if b > x1p500 { a /= b; t /= b; @@ -251,16 +256,19 @@ pub fn jn(n: i32, mut x: f64) -> f64 { } } -pub fn yn(n: i32, x: f64) -> f64 { +/// Bessel function of the second kind of order zero of `x`. +/// +/// Calculates the Bessel function of the second kind of order zero of `x`. +pub fn yn(n: i32, x: Float64) -> Float64 { let mut ix: u32; let lx: u32; let mut ib: u32; let nm1: i32; let mut sign: bool; let mut i: i32; - let mut a: f64; - let mut b: f64; - let mut temp: f64; + let mut a: Float64; + let mut b: Float64; + let mut temp: Float64; ix = get_high_word(x); lx = get_low_word(x); @@ -329,7 +337,7 @@ pub fn yn(n: i32, x: f64) -> f64 { while i < nm1 && ib != 0xfff00000 { i += 1; temp = b; - b = (2.0 * (i as f64) / x) * b - a; + b = (2.0 * (i as Float64) / x) * b - a; ib = get_high_word(b); a = temp; } diff --git a/core/llm/math/jnf.rs b/core/llm/math/jnf.rs index 360f62e..35bb33a 100644 --- a/core/llm/math/jnf.rs +++ b/core/llm/math/jnf.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,18 +8,26 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::Float32; use super::{fabsf, j0f, j1f, logf, y0f, y1f}; -pub fn jnf(n: i32, mut x: f32) -> f32 { +/// Bessel function of the first kind of order zero +/// +/// Calculates the Bessel function of the first kind of order zero of `x`. +pub fn jnf(n: i32, mut x: Float32) -> Float32 { let mut ix: u32; let mut nm1: i32; let mut sign: bool; let mut i: i32; - let mut a: f32; - let mut b: f32; - let mut temp: f32; + let mut a: Float32; + let mut b: Float32; + let mut temp: Float32; ix = x.to_bits(); sign = (ix >> 31) != 0; @@ -52,7 +57,7 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { if ix == 0 || ix == 0x7f800000 { /* if x is 0 or inf */ b = 0.0; - } else if (nm1 as f32) < x { + } else if (nm1 as Float32) < x { /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ a = j0f(x); b = j1f(x); @@ -60,15 +65,14 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { while i < nm1 { i += 1; temp = b; - b = b * (2.0 * (i as f32) / x) - a; + b = b * (2.0 * (i as Float32) / x) - a; a = temp; } } else { if ix < 0x35800000 { - /* x < 2**-20 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ + // x < 2**-20 + //x is tiny, return the first Taylor expansion of J(n,x) + // J(n,x) = 1/n!*(x/2)^n - ... if nm1 > 8 { /* underflow */ nm1 = 8; @@ -78,53 +82,52 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { a = 1.0; i = 2; while i <= nm1 + 1 { - a *= i as f32; /* a = n! */ + a *= i as Float32; /* a = n! */ b *= temp; /* b = (x/2)^n */ i += 1; } b = b / a; } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ + // use backward recurrence + // x x^2 x^2 + // J(n,x)/J(n-1,x) = ---- ------ ------ ..... + // 2n - 2(n+1) - 2(n+2) + // + // 1 1 1 + // (for large x) = ---- ------ ------ ..... + // 2n 2(n+1) 2(n+2) + // -- - ------ - ------ - + // x x x + // + // Let w = 2n/x and h=2/x, then the above quotient + // is equal to the continued fraction: + // 1 + // = ----------------------- + // 1 + // w - ----------------- + // 1 + // w+h - --------- + // w+2h - ... + // + // To determine how many terms needed, let + // Q(0) = w, Q(1) = w(w+h) - 1, + // Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + // When Q(k) > 1e4 good for single + // When Q(k) > 1e9 good for double + // When Q(k) > 1e17 good for quadruple /* determine k */ - let mut t: f32; - let mut q0: f32; - let mut q1: f32; - let mut w: f32; - let h: f32; - let mut z: f32; - let mut tmp: f32; - let nf: f32; + let mut t: Float32; + let mut q0: Float32; + let mut q1: Float32; + let mut w: Float32; + let h: Float32; + let mut z: Float32; + let mut tmp: Float32; + let nf: Float32; let mut k: i32; - nf = (nm1 as f32) + 1.0; - w = 2.0 * (nf as f32) / x; + nf = (nm1 as Float32) + 1.0; + w = 2.0 * (nf as Float32) / x; h = 2.0 / x; z = w + h; q0 = w; @@ -140,25 +143,24 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { t = 0.0; i = k; while i >= 0 { - t = 1.0 / (2.0 * ((i as f32) + nf) / x - t); + t = 1.0 / (2.0 * ((i as Float32) + nf) / x - t); i -= 1; } a = t; b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ + // estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + // Hence, if n*(log(2n/x)) > ... + // single 8.8722839355e+01 + // double 7.09782712893383973096e+02 + // long double 1.1356523406294143949491931077970765006170e+04 + // then recurrent value may overflow and the result is + // likely underflow to zero tmp = nf * logf(fabsf(w)); if tmp < 88.721679688 { i = nm1; while i > 0 { temp = b; - b = 2.0 * (i as f32) * b / x - a; + b = 2.0 * (i as Float32) * b / x - a; a = temp; i -= 1; } @@ -166,10 +168,10 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { i = nm1; while i > 0 { temp = b; - b = 2.0 * (i as f32) * b / x - a; + b = 2.0 * (i as Float32) * b / x - a; a = temp; /* scale b to avoid spurious overflow */ - let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 + let x1p60 = Float32::from_bits(0x5d800000); // 0x1p60 == 2^60 if b > x1p60 { a /= b; t /= b; @@ -195,15 +197,18 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { } } -pub fn ynf(n: i32, x: f32) -> f32 { +/// Bessel function of the second kind of order zero +/// +/// Calculates the Bessel function of the second kind of order zero of `x`. +pub fn ynf(n: i32, x: Float32) -> Float32 { let mut ix: u32; let mut ib: u32; let nm1: i32; let mut sign: bool; let mut i: i32; - let mut a: f32; - let mut b: f32; - let mut temp: f32; + let mut a: Float32; + let mut b: Float32; + let mut temp: Float32; ix = x.to_bits(); sign = (ix >> 31) != 0; @@ -246,7 +251,7 @@ pub fn ynf(n: i32, x: f32) -> f32 { while i < nm1 && ib != 0xff800000 { i += 1; temp = b; - b = (2.0 * (i as f32) / x) * b - a; + b = (2.0 * (i as Float32) / x) * b - a; ib = b.to_bits(); a = temp; } diff --git a/core/llm/math/k_cos.rs b/core/llm/math/k_cos.rs index 49b2fc6..5ef6334 100644 --- a/core/llm/math/k_cos.rs +++ b/core/llm/math/k_cos.rs @@ -9,12 +9,14 @@ // is preserved. // ==================================================== -const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ -const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ -const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ -const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ -const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ -const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ +use crate::Float64; + +const C1: Float64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ +const C2: Float64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ +const C3: Float64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ +const C4: Float64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ +const C5: Float64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ +const C6: Float64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ // kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 // Input x is assumed to be bounded by ~pi/4 in magnitude. @@ -52,7 +54,7 @@ const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ // under FreeBSD, so don't pessimize things by forcibly clipping // any extra precision in w. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_cos(x: f64, y: f64) -> f64 { +pub(crate) fn k_cos(x: Float64, y: Float64) -> Float64 { let z = x * x; let w = z * z; let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); diff --git a/core/llm/math/k_cosf.rs b/core/llm/math/k_cosf.rs index e99f234..c2cc739 100644 --- a/core/llm/math/k_cosf.rs +++ b/core/llm/math/k_cosf.rs @@ -1,9 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Debugged and optimized by Bruce D. Evans. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -12,18 +8,24 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. +*/ + +use crate::{Float64, Float32}; /* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ -const C0: f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ -const C1: f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ -const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ -const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ +const C0: Float64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ +const C1: Float64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ +const C2: Float64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ +const C3: Float64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_cosf(x: f64) -> f32 { +pub(crate) fn k_cosf(x: Float64) -> Float32 { let z = x * x; let w = z * z; let r = C2 + z * C3; - (((1.0 + z * C0) + w * C1) + (w * z) * r) as f32 + (((1.0 + z * C0) + w * C1) + (w * z) * r) as Float32 } diff --git a/core/llm/math/k_expo2.rs b/core/llm/math/k_expo2.rs index 7345075..9afd31d 100644 --- a/core/llm/math/k_expo2.rs +++ b/core/llm/math/k_expo2.rs @@ -1,3 +1,5 @@ +use crate::Float64; + use super::exp; /* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ @@ -5,10 +7,10 @@ const K: i32 = 2043; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_expo2(x: f64) -> f64 { - let k_ln2 = f64::from_bits(0x40962066151add8b); +pub(crate) fn k_expo2(x: Float64) -> Float64 { + let k_ln2 = Float64::from_bits(0x40962066151add8b); /* note that k is odd and scale*scale overflows */ - let scale = f64::from_bits(((((0x3ff + K / 2) as u32) << 20) as u64) << 32); + let scale = Float64::from_bits(((((0x3ff + K / 2) as u32) << 20) as u64) << 32); /* exp(x - k ln2) * 2**(k-1) */ exp(x - k_ln2) * scale * scale } diff --git a/core/llm/math/k_expo2f.rs b/core/llm/math/k_expo2f.rs index fbd7b27..bbaa982 100644 --- a/core/llm/math/k_expo2f.rs +++ b/core/llm/math/k_expo2f.rs @@ -1,3 +1,5 @@ +use crate::Float32; + use super::expf; /* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ @@ -5,10 +7,10 @@ const K: i32 = 235; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_expo2f(x: f32) -> f32 { - let k_ln2 = f32::from_bits(0x4322e3bc); +pub(crate) fn k_expo2f(x: Float32) -> Float32 { + let k_ln2 = Float32::from_bits(0x4322e3bc); /* note that k is odd and scale*scale overflows */ - let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); + let scale = Float32::from_bits(((0x7f + K / 2) as u32) << 23); /* exp(x - k ln2) * 2**(k-1) */ expf(x - k_ln2) * scale * scale } diff --git a/core/llm/math/k_sin.rs b/core/llm/math/k_sin.rs index 9dd96c9..900b59c 100644 --- a/core/llm/math/k_sin.rs +++ b/core/llm/math/k_sin.rs @@ -9,12 +9,14 @@ // is preserved. // ==================================================== -const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ -const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ -const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ -const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ -const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ -const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ +use crate::Float64; + +const S1: Float64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ +const S2: Float64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ +const S3: Float64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ +const S4: Float64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ +const S5: Float64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ +const S6: Float64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ // kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 // Input x is assumed to be bounded by ~pi/4 in magnitude. @@ -44,7 +46,7 @@ const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ // then 3 2 // sin(x) = x + (S1*x + (x *(r-y/2)+y)) #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { +pub(crate) fn k_sin(x: Float64, y: Float64, iy: i32) -> Float64 { let z = x * x; let w = z * z; let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); diff --git a/core/llm/math/k_sinf.rs b/core/llm/math/k_sinf.rs index 88d10ca..80aa6f8 100644 --- a/core/llm/math/k_sinf.rs +++ b/core/llm/math/k_sinf.rs @@ -1,9 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -12,19 +8,25 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. +*/ + +use crate::{Float64, Float32}; /* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ -const S1: f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ -const S2: f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ -const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ -const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ +const S1: Float64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ +const S2: Float64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ +const S3: Float64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ +const S4: Float64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_sinf(x: f64) -> f32 { +pub(crate) fn k_sinf(x: Float64) -> Float32 { let z = x * x; let w = z * z; let r = S3 + z * S4; let s = z * x; - ((x + s * (S1 + z * S2)) + s * w * r) as f32 + ((x + s * (S1 + z * S2)) + s * w * r) as Float32 } diff --git a/core/llm/math/k_tan.rs b/core/llm/math/k_tan.rs index d177010..6c7c12b 100644 --- a/core/llm/math/k_tan.rs +++ b/core/llm/math/k_tan.rs @@ -8,6 +8,8 @@ // is preserved. // ==================================================== +use crate::Float64; + // kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 // Input x is assumed to be bounded by ~pi/4 in magnitude. // Input y is the tail of x. @@ -40,7 +42,7 @@ // 4. For x in [0.67434,pi/4], let y = pi/4 - x, then // tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) // = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) -static T: [f64; 13] = [ +static T: [Float64; 13] = [ 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ @@ -55,12 +57,12 @@ static T: [f64; 13] = [ -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ ]; -const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ -const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ +const PIO4: Float64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ +const PIO4_LO: Float64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { - let hx = (f64::to_bits(x) >> 32) as u32; +pub(crate) fn k_tan(mut x: Float64, mut y: Float64, odd: i32) -> Float64 { + let hx = (Float64::to_bits(x) >> 32) as u32; let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ if big { let sign = hx >> 31; @@ -85,7 +87,7 @@ pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { let w = x + r; if big { let sign = hx >> 31; - let s = 1.0 - 2.0 * odd as f64; + let s = 1.0 - 2.0 * odd as Float64; let v = s - 2.0 * (x + (r - w * w / (w + s))); return if sign != 0 { -v } else { v }; } @@ -100,6 +102,6 @@ pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { a0 + a * (1.0 + a0 * w0 + a0 * v) } -fn zero_low_word(x: f64) -> f64 { - f64::from_bits(f64::to_bits(x) & 0xFFFF_FFFF_0000_0000) +fn zero_low_word(x: Float64) -> Float64 { + Float64::from_bits(Float64::to_bits(x) & 0xFFFF_FFFF_0000_0000) } diff --git a/core/llm/math/k_tanf.rs b/core/llm/math/k_tanf.rs index af8db53..cba17d7 100644 --- a/core/llm/math/k_tanf.rs +++ b/core/llm/math/k_tanf.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ -/* +/** * ==================================================== * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. * @@ -7,10 +7,12 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ + +use crate::{Float64, Float32}; /* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ -const T: [f64; 6] = [ +const T: [Float64; 6] = [ 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ 0.133392002712976742718, /* 0x1112fd38999f72.0p-55 */ 0.0533812378445670393523, /* 0x1b54c91d865afe.0p-57 */ @@ -20,7 +22,7 @@ const T: [f64; 6] = [ ]; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { +pub(crate) fn k_tanf(x: Float64, odd: bool) -> Float32 { let z = x * x; /* * Split up the polynomial into small independent terms to give @@ -42,5 +44,5 @@ pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { let s = z * x; let u = T[0] + z * T[1]; r = (x + s * u) + (s * w) * (t + w * r); - (if odd { -1. / r } else { r }) as f32 + (if odd { -1. / r } else { r }) as Float32 } diff --git a/core/llm/math/ldexp.rs b/core/llm/math/ldexp.rs index e46242e..21aac07 100644 --- a/core/llm/math/ldexp.rs +++ b/core/llm/math/ldexp.rs @@ -1,4 +1,7 @@ +use crate::Float64; + +/// Returns `x` * 2`n`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexp(x: f64, n: i32) -> f64 { +pub fn ldexp(x: Float64, n: i32) -> Float64 { super::scalbn(x, n) } diff --git a/core/llm/math/ldexpf.rs b/core/llm/math/ldexpf.rs index 95b27fc..ba30776 100644 --- a/core/llm/math/ldexpf.rs +++ b/core/llm/math/ldexpf.rs @@ -1,4 +1,7 @@ +use crate::Float32; + +/// Returns `x` * 2`n`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf(x: f32, n: i32) -> f32 { +pub fn ldexpf(x: Float32, n: i32) -> Float32 { super::scalbnf(x, n) } diff --git a/core/llm/math/lgamma.rs b/core/llm/math/lgamma.rs index a08bc5b..f04503f 100644 --- a/core/llm/math/lgamma.rs +++ b/core/llm/math/lgamma.rs @@ -1,6 +1,11 @@ +use crate::Float64; + use super::lgamma_r; +/// Natural logarithm of gamma function +/// +/// Returns the natural logarithm of the absolute value of the gamma function of x. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgamma(x: f64) -> f64 { +pub fn lgamma(x: Float64) -> Float64 { lgamma_r(x).0 } diff --git a/core/llm/math/lgamma_r.rs b/core/llm/math/lgamma_r.rs index b26177e..ca48670 100644 --- a/core/llm/math/lgamma_r.rs +++ b/core/llm/math/lgamma_r.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -9,8 +9,9 @@ * is preserved. * ==================================================== * - */ -/* lgamma_r(x, signgamp) +*/ +/** + * lgamma_r(x, signgamp) * Reentrant version of the logarithm of the Gamma function * with user provide pointer for the sign of Gamma(x). * @@ -76,76 +77,78 @@ * lgamma(inf) = inf * lgamma(-inf) = inf (bug for bug compatible with C99!?) * - */ +*/ + +use crate::Float64; use super::{floor, k_cos, k_sin, log}; -const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ -const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ -const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ -const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ -const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ -const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ -const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ -const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ -const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ -const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ -const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ -const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ -const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ -const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ -const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ +const PI: Float64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ +const A0: Float64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ +const A1: Float64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ +const A2: Float64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ +const A3: Float64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ +const A4: Float64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ +const A5: Float64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ +const A6: Float64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ +const A7: Float64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ +const A8: Float64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ +const A9: Float64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ +const A10: Float64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ +const A11: Float64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ +const TC: Float64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ +const TF: Float64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ /* tt = -(tail of TF) */ -const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ -const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ -const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ -const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ -const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ -const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ -const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ -const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ -const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ -const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ -const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ -const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ -const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ -const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ -const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ -const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ -const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ -const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ -const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ -const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ -const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ -const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ -const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ -const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ -const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ -const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ -const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ -const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ -const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ -const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ -const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ -const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ -const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ -const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ -const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ -const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ -const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ -const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ -const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ -const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ -const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ -const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ -const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ -const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ -const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ +const TT: Float64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ +const T0: Float64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ +const T1: Float64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ +const T2: Float64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ +const T3: Float64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ +const T4: Float64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ +const T5: Float64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ +const T6: Float64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ +const T7: Float64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ +const T8: Float64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ +const T9: Float64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ +const T10: Float64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ +const T11: Float64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ +const T12: Float64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ +const T13: Float64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ +const T14: Float64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ +const U0: Float64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const U1: Float64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ +const U2: Float64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ +const U3: Float64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ +const U4: Float64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ +const U5: Float64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ +const V1: Float64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ +const V2: Float64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ +const V3: Float64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ +const V4: Float64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ +const V5: Float64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ +const S0: Float64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const S1: Float64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ +const S2: Float64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ +const S3: Float64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ +const S4: Float64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ +const S5: Float64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ +const S6: Float64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ +const R1: Float64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ +const R2: Float64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ +const R3: Float64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ +const R4: Float64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ +const R5: Float64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ +const R6: Float64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ +const W0: Float64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ +const W1: Float64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ +const W2: Float64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ +const W3: Float64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ +const W4: Float64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ +const W5: Float64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ +const W6: Float64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ /* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f64) -> f64 { +fn sin_pi(mut x: Float64) -> Float64 { let mut n: i32; /* spurious inexact if odd int */ @@ -153,7 +156,7 @@ fn sin_pi(mut x: f64) -> f64 { n = (x * 4.0) as i32; n = div!(n + 1, 2); - x -= (n as f64) * 0.5; + x -= (n as Float64) * 0.5; x *= PI; match n { @@ -164,20 +167,24 @@ fn sin_pi(mut x: f64) -> f64 { } } +/// Natural logarithm of gamma function +/// +/// Returns the natural logarithm of the absolute value of the gamma function of x, +/// and the sign of the gamma function of x #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgamma_r(mut x: f64) -> (f64, i32) { +pub fn lgamma_r(mut x: Float64) -> (Float64, i32) { let u: u64 = x.to_bits(); - let mut t: f64; - let y: f64; - let mut z: f64; - let nadj: f64; - let p: f64; - let p1: f64; - let p2: f64; - let p3: f64; - let q: f64; - let mut r: f64; - let w: f64; + let mut t: Float64; + let y: Float64; + let mut z: Float64; + let nadj: Float64; + let p: Float64; + let p1: Float64; + let p2: Float64; + let p3: Float64; + let q: Float64; + let mut r: Float64; + let w: Float64; let ix: u32; let sign: bool; let i: i32; @@ -279,7 +286,7 @@ pub fn lgamma_r(mut x: f64) -> (f64, i32) { } else if ix < 0x40200000 { /* x < 8.0 */ i = x as i32; - y = x - (i as f64); + y = x - (i as Float64); p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); r = 0.5 * y + p / q; diff --git a/core/llm/math/lgammaf.rs b/core/llm/math/lgammaf.rs index a9c2da7..a6f1eee 100644 --- a/core/llm/math/lgammaf.rs +++ b/core/llm/math/lgammaf.rs @@ -1,6 +1,11 @@ +use crate::Float32; + use super::lgammaf_r; +/// Natural logarithm of gamma function +/// +/// Returns the natural logarithm of the absolute value of the gamma function of x. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgammaf(x: f32) -> f32 { +pub fn lgammaf(x: Float32) -> Float32 { lgammaf_r(x).0 } diff --git a/core/llm/math/lgammaf_r.rs b/core/llm/math/lgammaf_r.rs index 723c90d..1b8f994 100644 --- a/core/llm/math/lgammaf_r.rs +++ b/core/llm/math/lgammaf_r.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,77 +8,82 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::{Float64, Float32}; use super::{floorf, k_cosf, k_sinf, logf}; -const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ -const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ -const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ -const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ -const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ -const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ -const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ -const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ -const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ -const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ -const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ -const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ -const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ -const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ -const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ +const PI: Float32 = 3.1415927410e+00; /* 0x40490fdb */ +const A0: Float32 = 7.7215664089e-02; /* 0x3d9e233f */ +const A1: Float32 = 3.2246702909e-01; /* 0x3ea51a66 */ +const A2: Float32 = 6.7352302372e-02; /* 0x3d89f001 */ +const A3: Float32 = 2.0580807701e-02; /* 0x3ca89915 */ +const A4: Float32 = 7.3855509982e-03; /* 0x3bf2027e */ +const A5: Float32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ +const A6: Float32 = 1.1927076848e-03; /* 0x3a9c54a1 */ +const A7: Float32 = 5.1006977446e-04; /* 0x3a05b634 */ +const A8: Float32 = 2.2086278477e-04; /* 0x39679767 */ +const A9: Float32 = 1.0801156895e-04; /* 0x38e28445 */ +const A10: Float32 = 2.5214456400e-05; /* 0x37d383a2 */ +const A11: Float32 = 4.4864096708e-05; /* 0x383c2c75 */ +const TC: Float32 = 1.4616321325e+00; /* 0x3fbb16c3 */ +const TF: Float32 = -1.2148628384e-01; /* 0xbdf8cdcd */ /* TT = -(tail of TF) */ -const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ -const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ -const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ -const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ -const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ -const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ -const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ -const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ -const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ -const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ -const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ -const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ -const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ -const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ -const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ -const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ -const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ -const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ -const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ -const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ -const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ -const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ -const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ -const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ -const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ -const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ -const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ -const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ -const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ -const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ -const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ -const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ -const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ -const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ -const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ -const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ -const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ -const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ -const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ -const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ -const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ -const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ -const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ -const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ -const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ +const TT: Float32 = 6.6971006518e-09; /* 0x31e61c52 */ +const T0: Float32 = 4.8383611441e-01; /* 0x3ef7b95e */ +const T1: Float32 = -1.4758771658e-01; /* 0xbe17213c */ +const T2: Float32 = 6.4624942839e-02; /* 0x3d845a15 */ +const T3: Float32 = -3.2788541168e-02; /* 0xbd064d47 */ +const T4: Float32 = 1.7970675603e-02; /* 0x3c93373d */ +const T5: Float32 = -1.0314224288e-02; /* 0xbc28fcfe */ +const T6: Float32 = 6.1005386524e-03; /* 0x3bc7e707 */ +const T7: Float32 = -3.6845202558e-03; /* 0xbb7177fe */ +const T8: Float32 = 2.2596477065e-03; /* 0x3b141699 */ +const T9: Float32 = -1.4034647029e-03; /* 0xbab7f476 */ +const T10: Float32 = 8.8108185446e-04; /* 0x3a66f867 */ +const T11: Float32 = -5.3859531181e-04; /* 0xba0d3085 */ +const T12: Float32 = 3.1563205994e-04; /* 0x39a57b6b */ +const T13: Float32 = -3.1275415677e-04; /* 0xb9a3f927 */ +const T14: Float32 = 3.3552918467e-04; /* 0x39afe9f7 */ +const U0: Float32 = -7.7215664089e-02; /* 0xbd9e233f */ +const U1: Float32 = 6.3282704353e-01; /* 0x3f2200f4 */ +const U2: Float32 = 1.4549225569e+00; /* 0x3fba3ae7 */ +const U3: Float32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ +const U4: Float32 = 2.2896373272e-01; /* 0x3e6a7578 */ +const U5: Float32 = 1.3381091878e-02; /* 0x3c5b3c5e */ +const V1: Float32 = 2.4559779167e+00; /* 0x401d2ebe */ +const V2: Float32 = 2.1284897327e+00; /* 0x4008392d */ +const V3: Float32 = 7.6928514242e-01; /* 0x3f44efdf */ +const V4: Float32 = 1.0422264785e-01; /* 0x3dd572af */ +const V5: Float32 = 3.2170924824e-03; /* 0x3b52d5db */ +const S0: Float32 = -7.7215664089e-02; /* 0xbd9e233f */ +const S1: Float32 = 2.1498242021e-01; /* 0x3e5c245a */ +const S2: Float32 = 3.2577878237e-01; /* 0x3ea6cc7a */ +const S3: Float32 = 1.4635047317e-01; /* 0x3e15dce6 */ +const S4: Float32 = 2.6642270386e-02; /* 0x3cda40e4 */ +const S5: Float32 = 1.8402845599e-03; /* 0x3af135b4 */ +const S6: Float32 = 3.1947532989e-05; /* 0x3805ff67 */ +const R1: Float32 = 1.3920053244e+00; /* 0x3fb22d3b */ +const R2: Float32 = 7.2193557024e-01; /* 0x3f38d0c5 */ +const R3: Float32 = 1.7193385959e-01; /* 0x3e300f6e */ +const R4: Float32 = 1.8645919859e-02; /* 0x3c98bf54 */ +const R5: Float32 = 7.7794247773e-04; /* 0x3a4beed6 */ +const R6: Float32 = 7.3266842264e-06; /* 0x36f5d7bd */ +const W0: Float32 = 4.1893854737e-01; /* 0x3ed67f1d */ +const W1: Float32 = 8.3333335817e-02; /* 0x3daaaaab */ +const W2: Float32 = -2.7777778450e-03; /* 0xbb360b61 */ +const W3: Float32 = 7.9365057172e-04; /* 0x3a500cfd */ +const W4: Float32 = -5.9518753551e-04; /* 0xba1c065c */ +const W5: Float32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ +const W6: Float32 = -1.6309292987e-03; /* 0xbad5c4e8 */ /* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f32) -> f32 { - let mut y: f64; +fn sin_pi(mut x: Float32) -> Float32 { + let mut y: Float64; let mut n: isize; /* spurious inexact if odd int */ @@ -89,7 +91,7 @@ fn sin_pi(mut x: f32) -> f32 { n = (x * 4.0) as isize; n = div!(n + 1, 2); - y = (x as f64) - (n as f64) * 0.5; + y = (x as Float64) - (n as Float64) * 0.5; y *= 3.14159265358979323846; match n { 1 => k_cosf(y), @@ -99,20 +101,24 @@ fn sin_pi(mut x: f32) -> f32 { } } +/// Natural logarithm of gamma function +/// +/// Returns the natural logarithm of the absolute value of the gamma function of x, +/// and the sign of the gamma function of x #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgammaf_r(mut x: f32) -> (f32, i32) { +pub fn lgammaf_r(mut x: Float32) -> (Float32, i32) { let u = x.to_bits(); - let mut t: f32; - let y: f32; - let mut z: f32; - let nadj: f32; - let p: f32; - let p1: f32; - let p2: f32; - let p3: f32; - let q: f32; - let mut r: f32; - let w: f32; + let mut t: Float32; + let y: Float32; + let mut z: Float32; + let nadj: Float32; + let p: Float32; + let p1: Float32; + let p2: Float32; + let p3: Float32; + let q: Float32; + let mut r: Float32; + let w: Float32; let ix: u32; let i: i32; let sign: bool; @@ -214,7 +220,7 @@ pub fn lgammaf_r(mut x: f32) -> (f32, i32) { } else if ix < 0x41000000 { /* x < 8.0 */ i = x as i32; - y = x - (i as f32); + y = x - (i as Float32); p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); r = 0.5 * y + p / q; diff --git a/core/llm/math/ln.rs b/core/llm/math/ln.rs new file mode 100644 index 0000000..1b53c5f --- /dev/null +++ b/core/llm/math/ln.rs @@ -0,0 +1,9 @@ +use crate::Float64; + +use super::log1p; + +/// Return the natural logarithm of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ln(x: Float64) -> Float64 { + log1p(x - 1.) +} diff --git a/core/llm/math/lnf.rs b/core/llm/math/lnf.rs new file mode 100644 index 0000000..46d703d --- /dev/null +++ b/core/llm/math/lnf.rs @@ -0,0 +1,9 @@ +use crate::Float32; + +use super::log1pf; + +/// Return the natural logarithm of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn lnf(x: Float32) -> Float32 { + log1pf(x - 1.) +} diff --git a/core/llm/math/log.rs b/core/llm/math/log.rs index 27a26da..6ff860c 100644 --- a/core/llm/math/log.rs +++ b/core/llm/math/log.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -8,8 +8,9 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ -/* log(x) +*/ +/** + * log(x) * Return the logarithm of x * * Method : @@ -58,21 +59,24 @@ * constants. The decimal values may be used, provided that the * compiler will convert from decimal to binary accurately enough * to produce the hexadecimal values shown. - */ +*/ -const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ -const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ -const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +use crate::Float64; +const LN2_HI: Float64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ +const LN2_LO: Float64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ +const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +/// Returns the logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log(mut x: f64) -> f64 { - let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 +pub fn log(mut x: Float64) -> Float64 { + let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 let mut ui = x.to_bits(); let mut hx: u32 = (ui >> 32) as u32; @@ -102,16 +106,16 @@ pub fn log(mut x: f64) -> f64 { k += ((hx >> 20) as i32) - 0x3ff; hx = (hx & 0x000fffff) + 0x3fe6a09e; ui = ((hx as u64) << 32) | (ui & 0xffffffff); - x = f64::from_bits(ui); + x = Float64::from_bits(ui); - let f: f64 = x - 1.0; - let hfsq: f64 = 0.5 * f * f; - let s: f64 = f / (2.0 + f); - let z: f64 = s * s; - let w: f64 = z * z; - let t1: f64 = w * (LG2 + w * (LG4 + w * LG6)); - let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - let r: f64 = t2 + t1; - let dk: f64 = k as f64; + let f: Float64 = x - 1.0; + let hfsq: Float64 = 0.5 * f * f; + let s: Float64 = f / (2.0 + f); + let z: Float64 = s * s; + let w: Float64 = z * z; + let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); + let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + let r: Float64 = t2 + t1; + let dk: Float64 = k as Float64; s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI } diff --git a/core/llm/math/log10.rs b/core/llm/math/log10.rs index 40dacf2..c128eab 100644 --- a/core/llm/math/log10.rs +++ b/core/llm/math/log10.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -8,48 +8,49 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ -/* +*/ +/** * Return the base 10 logarithm of x. See log.c for most comments. * * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 * as in log.c, then combine and scale in extra precision: * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) - */ +*/ -use core::f64; +use crate::Float64; -const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ -const IVLN10LO: f64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ -const LOG10_2HI: f64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ -const LOG10_2LO: f64 = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ -const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +const IVLN10HI: Float64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ +const IVLN10LO: Float64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ +const LOG10_2HI: Float64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ +const LOG10_2LO: Float64 = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ +const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +/// Returns the base 10 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log10(mut x: f64) -> f64 { - let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 +pub fn log10(mut x: Float64) -> Float64 { + let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 let mut ui: u64 = x.to_bits(); - let hfsq: f64; - let f: f64; - let s: f64; - let z: f64; - let r: f64; - let mut w: f64; - let t1: f64; - let t2: f64; - let dk: f64; - let y: f64; - let mut hi: f64; - let lo: f64; - let mut val_hi: f64; - let mut val_lo: f64; + let hfsq: Float64; + let f: Float64; + let s: Float64; + let z: Float64; + let r: Float64; + let mut w: Float64; + let t1: Float64; + let t2: Float64; + let dk: Float64; + let y: Float64; + let mut hi: Float64; + let lo: Float64; + let mut val_hi: Float64; + let mut val_lo: Float64; let mut hx: u32; let mut k: i32; @@ -78,7 +79,7 @@ pub fn log10(mut x: f64) -> f64 { k += (hx >> 20) as i32 - 0x3ff; hx = (hx & 0x000fffff) + 0x3fe6a09e; ui = (hx as u64) << 32 | (ui & 0xffffffff); - x = f64::from_bits(ui); + x = Float64::from_bits(ui); f = x - 1.0; hfsq = 0.5 * f * f; @@ -94,12 +95,12 @@ pub fn log10(mut x: f64) -> f64 { hi = f - hfsq; ui = hi.to_bits(); ui &= (-1i64 as u64) << 32; - hi = f64::from_bits(ui); + hi = Float64::from_bits(ui); lo = f - hi - hfsq + s * (hfsq + r); /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ val_hi = hi * IVLN10HI; - dk = k as f64; + dk = k as Float64; y = dk * LOG10_2HI; val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI; diff --git a/core/llm/math/log10f.rs b/core/llm/math/log10f.rs index 108dfa8..45d5c32 100644 --- a/core/llm/math/log10f.rs +++ b/core/llm/math/log10f.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -8,39 +8,40 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ -/* +*/ +/** * See comments in log10.c. - */ +*/ -use core::f32; +use crate::Float32; -const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */ -const IVLN10LO: f32 = -3.1689971365e-05; /* 0xb804ead9 */ -const LOG10_2HI: f32 = 3.0102920532e-01; /* 0x3e9a2080 */ -const LOG10_2LO: f32 = 7.9034151668e-07; /* 0x355427db */ +const IVLN10HI: Float32 = 4.3432617188e-01; /* 0x3ede6000 */ +const IVLN10LO: Float32 = -3.1689971365e-05; /* 0xb804ead9 */ +const LOG10_2HI: Float32 = 3.0102920532e-01; /* 0x3e9a2080 */ +const LOG10_2LO: Float32 = 7.9034151668e-07; /* 0x355427db */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ +/// Returns the base 10 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log10f(mut x: f32) -> f32 { - let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 +pub fn log10f(mut x: Float32) -> Float32 { + let x1p25f = Float32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ui: u32 = x.to_bits(); - let hfsq: f32; - let f: f32; - let s: f32; - let z: f32; - let r: f32; - let w: f32; - let t1: f32; - let t2: f32; - let dk: f32; - let mut hi: f32; - let lo: f32; + let hfsq: Float32; + let f: Float32; + let s: Float32; + let z: Float32; + let r: Float32; + let w: Float32; + let t1: Float32; + let t2: Float32; + let dk: Float32; + let mut hi: Float32; + let lo: Float32; let mut ix: u32; let mut k: i32; @@ -70,7 +71,7 @@ pub fn log10f(mut x: f32) -> f32 { k += (ix >> 23) as i32 - 0x7f; ix = (ix & 0x007fffff) + 0x3f3504f3; ui = ix; - x = f32::from_bits(ui); + x = Float32::from_bits(ui); f = x - 1.0; s = f / (2.0 + f); @@ -84,8 +85,8 @@ pub fn log10f(mut x: f32) -> f32 { hi = f - hfsq; ui = hi.to_bits(); ui &= 0xfffff000; - hi = f32::from_bits(ui); + hi = Float32::from_bits(ui); lo = f - hi - hfsq + s * (hfsq + r); - dk = k as f32; + dk = k as Float32; dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI } diff --git a/core/llm/math/log1p.rs b/core/llm/math/log1p.rs index 4fd1c73..dab5e19 100644 --- a/core/llm/math/log1p.rs +++ b/core/llm/math/log1p.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -8,8 +8,9 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ -/* double log1p(double x) +*/ +/** + * double log1p(double x) * Return the natural logarithm of 1+x. * * Method : @@ -51,33 +52,34 @@ * return log(u)*(x/(u-1.0)); * * See HP-15C Advanced Functions Handbook, p.193. - */ +*/ -use core::f64; +use crate::{Float64, Float32}; -const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ -const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ -const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +const LN2_HI: Float64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ +const LN2_LO: Float64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ +const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +/// Return the natural logarithm of `1+x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log1p(x: f64) -> f64 { +pub fn log1p(x: Float64) -> Float64 { let mut ui: u64 = x.to_bits(); - let hfsq: f64; - let mut f: f64 = 0.; - let mut c: f64 = 0.; - let s: f64; - let z: f64; - let r: f64; - let w: f64; - let t1: f64; - let t2: f64; - let dk: f64; + let hfsq: Float64; + let mut f: Float64 = 0.; + let mut c: Float64 = 0.; + let s: Float64; + let z: Float64; + let r: Float64; + let w: Float64; + let t1: Float64; + let t2: Float64; + let dk: Float64; let hx: u32; let mut hu: u32; let mut k: i32; @@ -97,7 +99,7 @@ pub fn log1p(x: f64) -> f64 { /* |x| < 2**-53 */ /* underflow if subnormal */ if (hx & 0x7ff00000) == 0 { - force_eval!(x as f32); + force_eval!(x as Float32); } return x; } @@ -118,18 +120,18 @@ pub fn log1p(x: f64) -> f64 { /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ if k < 54 { c = if k >= 2 { - 1. - (f64::from_bits(ui) - x) + 1. - (Float64::from_bits(ui) - x) } else { - x - (f64::from_bits(ui) - 1.) + x - (Float64::from_bits(ui) - 1.) }; - c /= f64::from_bits(ui); + c /= Float64::from_bits(ui); } else { c = 0.; } /* reduce u into [sqrt(2)/2, sqrt(2)] */ hu = (hu & 0x000fffff) + 0x3fe6a09e; ui = (hu as u64) << 32 | (ui & 0xffffffff); - f = f64::from_bits(ui) - 1.; + f = Float64::from_bits(ui) - 1.; } hfsq = 0.5 * f * f; s = f / (2.0 + f); @@ -138,6 +140,6 @@ pub fn log1p(x: f64) -> f64 { t1 = w * (LG2 + w * (LG4 + w * LG6)); t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); r = t2 + t1; - dk = k as f64; + dk = k as Float64; s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } diff --git a/core/llm/math/log1pf.rs b/core/llm/math/log1pf.rs index 500e8ee..0b8cffa 100644 --- a/core/llm/math/log1pf.rs +++ b/core/llm/math/log1pf.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -8,31 +8,32 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ -use core::f32; +use crate::Float32; -const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +const LN2_HI: Float32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: Float32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ +/// Return the natural logarithm of `1+x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log1pf(x: f32) -> f32 { +pub fn log1pf(x: Float32) -> Float32 { let mut ui: u32 = x.to_bits(); - let hfsq: f32; - let mut f: f32 = 0.; - let mut c: f32 = 0.; - let s: f32; - let z: f32; - let r: f32; - let w: f32; - let t1: f32; - let t2: f32; - let dk: f32; + let hfsq: Float32; + let mut f: Float32 = 0.; + let mut c: Float32 = 0.; + let s: Float32; + let z: Float32; + let r: Float32; + let w: Float32; + let t1: Float32; + let t2: Float32; + let dk: Float32; let ix: u32; let mut iu: u32; let mut k: i32; @@ -73,18 +74,18 @@ pub fn log1pf(x: f32) -> f32 { /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ if k < 25 { c = if k >= 2 { - 1. - (f32::from_bits(ui) - x) + 1. - (Float32::from_bits(ui) - x) } else { - x - (f32::from_bits(ui) - 1.) + x - (Float32::from_bits(ui) - 1.) }; - c /= f32::from_bits(ui); + c /= Float32::from_bits(ui); } else { c = 0.; } /* reduce u into [sqrt(2)/2, sqrt(2)] */ iu = (iu & 0x007fffff) + 0x3f3504f3; ui = iu; - f = f32::from_bits(ui) - 1.; + f = Float32::from_bits(ui) - 1.; } s = f / (2.0 + f); z = s * s; @@ -93,6 +94,6 @@ pub fn log1pf(x: f32) -> f32 { t2 = z * (LG1 + w * LG3); r = t2 + t1; hfsq = 0.5 * f * f; - dk = k as f32; + dk = k as Float32; s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } diff --git a/core/llm/math/log2.rs b/core/llm/math/log2.rs index 83da3a1..02f6957 100644 --- a/core/llm/math/log2.rs +++ b/core/llm/math/log2.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -8,45 +8,46 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ -/* +*/ +/** * Return the base 2 logarithm of x. See log.c for most comments. * * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 * as in log.c, then combine and scale in extra precision: * log2(x) = (f - f*f/2 + r)/log(2) + k - */ +*/ -use core::f64; +use crate::Float64; -const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ -const IVLN2LO: f64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ -const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +const IVLN2HI: Float64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ +const IVLN2LO: Float64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ +const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +/// Returns the base 2 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log2(mut x: f64) -> f64 { - let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 +pub fn log2(mut x: Float64) -> Float64 { + let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 let mut ui: u64 = x.to_bits(); - let hfsq: f64; - let f: f64; - let s: f64; - let z: f64; - let r: f64; - let mut w: f64; - let t1: f64; - let t2: f64; - let y: f64; - let mut hi: f64; - let lo: f64; - let mut val_hi: f64; - let mut val_lo: f64; + let hfsq: Float64; + let f: Float64; + let s: Float64; + let z: Float64; + let r: Float64; + let mut w: Float64; + let t1: Float64; + let t2: Float64; + let y: Float64; + let mut hi: Float64; + let lo: Float64; + let mut val_hi: Float64; + let mut val_lo: Float64; let mut hx: u32; let mut k: i32; @@ -75,7 +76,7 @@ pub fn log2(mut x: f64) -> f64 { k += (hx >> 20) as i32 - 0x3ff; hx = (hx & 0x000fffff) + 0x3fe6a09e; ui = (hx as u64) << 32 | (ui & 0xffffffff); - x = f64::from_bits(ui); + x = Float64::from_bits(ui); f = x - 1.0; hfsq = 0.5 * f * f; @@ -90,7 +91,7 @@ pub fn log2(mut x: f64) -> f64 { hi = f - hfsq; ui = hi.to_bits(); ui &= (-1i64 as u64) << 32; - hi = f64::from_bits(ui); + hi = Float64::from_bits(ui); lo = f - hi - hfsq + s * (hfsq + r); val_hi = hi * IVLN2HI; diff --git a/core/llm/math/log2f.rs b/core/llm/math/log2f.rs index 3a20fb1..afa3c17 100644 --- a/core/llm/math/log2f.rs +++ b/core/llm/math/log2f.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -8,36 +8,37 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ -/* +*/ +/** * See comments in log2.c. - */ +*/ -use core::f32; +use crate::Float32; -const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */ -const IVLN2LO: f32 = -1.7605285393e-04; /* 0xb9389ad4 */ +const IVLN2HI: Float32 = 1.4428710938e+00; /* 0x3fb8b000 */ +const IVLN2LO: Float32 = -1.7605285393e-04; /* 0xb9389ad4 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ +/// Returns the base 2 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log2f(mut x: f32) -> f32 { - let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 +pub fn log2f(mut x: Float32) -> Float32 { + let x1p25f = Float32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ui: u32 = x.to_bits(); - let hfsq: f32; - let f: f32; - let s: f32; - let z: f32; - let r: f32; - let w: f32; - let t1: f32; - let t2: f32; - let mut hi: f32; - let lo: f32; + let hfsq: Float32; + let f: Float32; + let s: Float32; + let z: Float32; + let r: Float32; + let w: Float32; + let t1: Float32; + let t2: Float32; + let mut hi: Float32; + let lo: Float32; let mut ix: u32; let mut k: i32; @@ -67,7 +68,7 @@ pub fn log2f(mut x: f32) -> f32 { k += (ix >> 23) as i32 - 0x7f; ix = (ix & 0x007fffff) + 0x3f3504f3; ui = ix; - x = f32::from_bits(ui); + x = Float32::from_bits(ui); f = x - 1.0; s = f / (2.0 + f); @@ -81,7 +82,7 @@ pub fn log2f(mut x: f32) -> f32 { hi = f - hfsq; ui = hi.to_bits(); ui &= 0xfffff000; - hi = f32::from_bits(ui); + hi = Float32::from_bits(ui); lo = f - hi - hfsq + s * (hfsq + r); - (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as f32 + (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as Float32 } diff --git a/core/llm/math/logf.rs b/core/llm/math/logf.rs index 2b57b93..57cfdab 100644 --- a/core/llm/math/logf.rs +++ b/core/llm/math/logf.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,19 +8,25 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::Float32; -const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +const LN2_HI: Float32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: Float32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ -const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ +const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ +/// Returns the logarithm of `x` #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn logf(mut x: f32) -> f32 { - let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 +pub fn logf(mut x: Float32) -> Float32 { + let x1p25 = Float32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ix = x.to_bits(); let mut k = 0i32; @@ -50,7 +53,7 @@ pub fn logf(mut x: f32) -> f32 { ix += 0x3f800000 - 0x3f3504f3; k += ((ix >> 23) as i32) - 0x7f; ix = (ix & 0x007fffff) + 0x3f3504f3; - x = f32::from_bits(ix); + x = Float32::from_bits(ix); let f = x - 1.; let s = f / (2. + f); @@ -60,6 +63,6 @@ pub fn logf(mut x: f32) -> f32 { let t2 = z * (LG1 + w * LG3); let r = t2 + t1; let hfsq = 0.5 * f * f; - let dk = k as f32; + let dk = k as Float32; s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI } diff --git a/core/llm/math/modf.rs b/core/llm/math/modf.rs index bcab33a..4d64cc4 100644 --- a/core/llm/math/modf.rs +++ b/core/llm/math/modf.rs @@ -1,5 +1,8 @@ -pub fn modf(x: f64) -> (f64, f64) { - let rv2: f64; +use crate::Float64; + +/// Breaks the given number into an integral and a fractional part. +pub fn modf(x: Float64) -> (Float64, Float64) { + let rv2: Float64; let mut u = x.to_bits(); let mask: u64; let e = ((u >> 52 & 0x7ff) as i32) - 0x3ff; @@ -12,13 +15,13 @@ pub fn modf(x: f64) -> (f64, f64) { return (x, rv2); } u &= 1 << 63; - return (f64::from_bits(u), rv2); + return (Float64::from_bits(u), rv2); } /* no integral part*/ if e < 0 { u &= 1 << 63; - rv2 = f64::from_bits(u); + rv2 = Float64::from_bits(u); return (x, rv2); } @@ -26,9 +29,9 @@ pub fn modf(x: f64) -> (f64, f64) { if (u & mask) == 0 { rv2 = x; u &= 1 << 63; - return (f64::from_bits(u), rv2); + return (Float64::from_bits(u), rv2); } u &= !mask; - rv2 = f64::from_bits(u); + rv2 = Float64::from_bits(u); return (x - rv2, rv2); } diff --git a/core/llm/math/modff.rs b/core/llm/math/modff.rs index 56ece12..1bbaf1c 100644 --- a/core/llm/math/modff.rs +++ b/core/llm/math/modff.rs @@ -1,5 +1,8 @@ -pub fn modff(x: f32) -> (f32, f32) { - let rv2: f32; +use crate::Float32; + +/// Breaks the given number into an integral and a fractional part. +pub fn modff(x: Float32) -> (Float32, Float32) { + let rv2: Float32; let mut u: u32 = x.to_bits(); let mask: u32; let e = ((u >> 23 & 0xff) as i32) - 0x7f; @@ -12,12 +15,12 @@ pub fn modff(x: f32) -> (f32, f32) { return (x, rv2); } u &= 0x80000000; - return (f32::from_bits(u), rv2); + return (Float32::from_bits(u), rv2); } /* no integral part */ if e < 0 { u &= 0x80000000; - rv2 = f32::from_bits(u); + rv2 = Float32::from_bits(u); return (x, rv2); } @@ -25,9 +28,9 @@ pub fn modff(x: f32) -> (f32, f32) { if (u & mask) == 0 { rv2 = x; u &= 0x80000000; - return (f32::from_bits(u), rv2); + return (Float32::from_bits(u), rv2); } u &= !mask; - rv2 = f32::from_bits(u); + rv2 = Float32::from_bits(u); return (x - rv2, rv2); } diff --git a/core/llm/math/nextafter.rs b/core/llm/math/nextafter.rs index 0576261..9d30ea2 100644 --- a/core/llm/math/nextafter.rs +++ b/core/llm/math/nextafter.rs @@ -1,5 +1,8 @@ +use crate::Float64; + +/// Returns the next representable floating-point value following `x` in the direction of `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn nextafter(x: f64, y: f64) -> f64 { +pub fn nextafter(x: Float64, y: Float64) -> Float64 { if x.is_nan() || y.is_nan() { return x + y; } @@ -28,7 +31,7 @@ pub fn nextafter(x: f64, y: f64) -> f64 { if e == 0x7ff { force_eval!(x + x); } - let ux_f = f64::from_bits(ux_i); + let ux_f = Float64::from_bits(ux_i); // raise underflow if ux.f is subnormal or zero if e == 0 { force_eval!(x * x + ux_f * ux_f); diff --git a/core/llm/math/nextafterf.rs b/core/llm/math/nextafterf.rs index 8ba3833..f5a8ccc 100644 --- a/core/llm/math/nextafterf.rs +++ b/core/llm/math/nextafterf.rs @@ -1,5 +1,8 @@ +use crate::Float32; + +/// Returns the next representable floating-point value following `x` in the direction of `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn nextafterf(x: f32, y: f32) -> f32 { +pub fn nextafterf(x: Float32, y: Float32) -> Float32 { if x.is_nan() || y.is_nan() { return x + y; } @@ -28,7 +31,7 @@ pub fn nextafterf(x: f32, y: f32) -> f32 { if e == 0x7f80_0000_u32 { force_eval!(x + x); } - let ux_f = f32::from_bits(ux_i); + let ux_f = Float32::from_bits(ux_i); // raise underflow if ux_f is subnormal or zero if e == 0 { force_eval!(x * x + ux_f * ux_f); diff --git a/core/llm/math/pow.rs b/core/llm/math/pow.rs index 6a19ae6..a4267cd 100644 --- a/core/llm/math/pow.rs +++ b/core/llm/math/pow.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ -/* +/** * ==================================================== * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. * @@ -7,7 +7,7 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ // pow(x,y) return x**y // @@ -57,42 +57,46 @@ // compiler will convert from decimal to binary accurately enough // to produce the hexadecimal values shown. // + +use crate::Float64; + use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; -const BP: [f64; 2] = [1.0, 1.5]; -const DP_H: [f64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ -const DP_L: [f64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ -const TWO53: f64 = 9007199254740992.0; /* 0x43400000_00000000 */ -const HUGE: f64 = 1.0e300; -const TINY: f64 = 1.0e-300; +const BP: [Float64; 2] = [1.0, 1.5]; +const DP_H: [Float64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ +const DP_L: [Float64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ +const TWO53: Float64 = 9007199254740992.0; /* 0x43400000_00000000 */ +const HUGE: Float64 = 1.0e300; +const TINY: Float64 = 1.0e-300; // poly coefs for (3/2)*(log(x)-2s-2/3*s**3: -const L1: f64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ -const L2: f64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ -const L3: f64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ -const L4: f64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ -const L5: f64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ -const L6: f64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ -const P1: f64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ -const P2: f64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ -const P3: f64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ -const P4: f64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ -const P5: f64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ -const LG2: f64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ -const LG2_H: f64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ -const LG2_L: f64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ -const OVT: f64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ -const CP: f64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ -const CP_H: f64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ -const CP_L: f64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ -const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ -const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ -const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ - +const L1: Float64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ +const L2: Float64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ +const L3: Float64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ +const L4: Float64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ +const L5: Float64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ +const L6: Float64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ +const P1: Float64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ +const P2: Float64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ +const P3: Float64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ +const P4: Float64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ +const P5: Float64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ +const LG2: Float64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ +const LG2_H: Float64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ +const LG2_L: Float64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ +const OVT: Float64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ +const CP: Float64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ +const CP_H: Float64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ +const CP_L: Float64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ +const IVLN2: Float64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ +const IVLN2_H: Float64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ +const IVLN2_L: Float64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ + +/// Returns `x` raised to the power `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn pow(x: f64, y: f64) -> f64 { - let t1: f64; - let t2: f64; +pub fn pow(x: Float64, y: Float64) -> Float64 { + let t1: Float64; + let t2: Float64; let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); @@ -193,12 +197,12 @@ pub fn pow(x: f64, y: f64) -> f64 { } } - let mut ax: f64 = fabs(x); + let mut ax: Float64 = fabs(x); if lx == 0 { /* special value of x */ if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { /* x is +-0,+-inf,+-1 */ - let mut z: f64 = ax; + let mut z: Float64 = ax; if hy < 0 { /* z = (1/|x|) */ @@ -217,7 +221,7 @@ pub fn pow(x: f64, y: f64) -> f64 { } } - let mut s: f64 = 1.0; /* sign of result */ + let mut s: Float64 = 1.0; /* sign of result */ if hx < 0 { if yisint == 0 { /* (x<0)**(non-int) is NaN */ @@ -262,10 +266,10 @@ pub fn pow(x: f64, y: f64) -> f64 { /* now |1-x| is TINY <= 2**-20, suffice to compute log(x) by x-x^2/2+x^3/3-x^4/4 */ - let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ - let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); - let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ - let v: f64 = t * IVLN2_L - w * IVLN2; + let t: Float64 = ax - 1.0; /* t has 20 trailing zeros */ + let w: Float64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); + let u: Float64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ + let v: Float64 = t * IVLN2_L - w * IVLN2; t1 = with_set_low_word(u + v, 0); t2 = v - (t1 - u); } else { @@ -299,48 +303,48 @@ pub fn pow(x: f64, y: f64) -> f64 { ax = with_set_high_word(ax, ix as u32); /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ - let u: f64 = ax - i!(BP, k as usize); /* bp[0]=1.0, bp[1]=1.5 */ - let v: f64 = 1.0 / (ax + i!(BP, k as usize)); - let ss: f64 = u * v; + let u: Float64 = ax - i!(BP, k as usize); /* bp[0]=1.0, bp[1]=1.5 */ + let v: Float64 = 1.0 / (ax + i!(BP, k as usize)); + let ss: Float64 = u * v; let s_h = with_set_low_word(ss, 0); /* t_h=ax+bp[k] High */ - let t_h: f64 = with_set_high_word( + let t_h: Float64 = with_set_high_word( 0.0, ((ix as u32 >> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18), ); - let t_l: f64 = ax - (t_h - i!(BP, k as usize)); - let s_l: f64 = v * ((u - s_h * t_h) - s_h * t_l); + let t_l: Float64 = ax - (t_h - i!(BP, k as usize)); + let s_l: Float64 = v * ((u - s_h * t_h) - s_h * t_l); /* compute log(ax) */ - let s2: f64 = ss * ss; - let mut r: f64 = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); + let s2: Float64 = ss * ss; + let mut r: Float64 = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); r += s_l * (s_h + ss); - let s2: f64 = s_h * s_h; - let t_h: f64 = with_set_low_word(3.0 + s2 + r, 0); - let t_l: f64 = r - ((t_h - 3.0) - s2); + let s2: Float64 = s_h * s_h; + let t_h: Float64 = with_set_low_word(3.0 + s2 + r, 0); + let t_l: Float64 = r - ((t_h - 3.0) - s2); /* u+v = ss*(1+...) */ - let u: f64 = s_h * t_h; - let v: f64 = s_l * t_h + t_l * ss; + let u: Float64 = s_h * t_h; + let v: Float64 = s_l * t_h + t_l * ss; /* 2/(3log2)*(ss+...) */ - let p_h: f64 = with_set_low_word(u + v, 0); + let p_h: Float64 = with_set_low_word(u + v, 0); let p_l = v - (p_h - u); - let z_h: f64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ - let z_l: f64 = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); + let z_h: Float64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ + let z_l: Float64 = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ - let t: f64 = n as f64; + let t: Float64 = n as Float64; t1 = with_set_low_word(((z_h + z_l) + i!(DP_H, k as usize)) + t, 0); t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); } /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ - let y1: f64 = with_set_low_word(y, 0); - let p_l: f64 = (y - y1) * t1 + y * t2; - let mut p_h: f64 = y1 * t1; - let z: f64 = p_l + p_h; + let y1: Float64 = with_set_low_word(y, 0); + let p_l: Float64 = (y - y1) * t1 + y * t2; + let mut p_h: Float64 = y1 * t1; + let z: Float64 = p_l + p_h; let mut j: i32 = (z.to_bits() >> 32) as i32; let i: i32 = z.to_bits() as i32; // let (j, i): (i32, i32) = ((z.to_bits() >> 32) as i32, z.to_bits() as i32); @@ -378,7 +382,7 @@ pub fn pow(x: f64, y: f64) -> f64 { /* if |z| > 0.5, set n = [z+0.5] */ n = j + (0x00100000 >> (k + 1)); k = ((n & 0x7fffffff) >> 20) - 0x3ff; /* new k for n */ - let t: f64 = with_set_high_word(0.0, (n & !(0x000fffff >> k)) as u32); + let t: Float64 = with_set_high_word(0.0, (n & !(0x000fffff >> k)) as u32); n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); if j < 0 { n = -n; @@ -386,14 +390,14 @@ pub fn pow(x: f64, y: f64) -> f64 { p_h -= t; } - let t: f64 = with_set_low_word(p_l + p_h, 0); - let u: f64 = t * LG2_H; - let v: f64 = (p_l - (t - p_h)) * LG2 + t * LG2_L; - let mut z: f64 = u + v; - let w: f64 = v - (z - u); - let t: f64 = z * z; - let t1: f64 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); - let r: f64 = (z * t1) / (t1 - 2.0) - (w + z * w); + let t: Float64 = with_set_low_word(p_l + p_h, 0); + let u: Float64 = t * LG2_H; + let v: Float64 = (p_l - (t - p_h)) * LG2 + t * LG2_L; + let mut z: Float64 = u + v; + let w: Float64 = v - (z - u); + let t: Float64 = z * z; + let t1: Float64 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + let r: Float64 = (z * t1) / (t1 - 2.0) - (w + z * w); z = 1.0 - (r - z); j = get_high_word(z) as i32; j += n << 20; @@ -412,27 +416,27 @@ pub fn pow(x: f64, y: f64) -> f64 { mod tests { extern crate core; - use self::core::f64::consts::{E, PI}; - use self::core::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; + use self::core::Float64::consts::{E, PI}; + use self::core::Float64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; use super::pow; - const POS_ZERO: &[f64] = &[0.0]; - const NEG_ZERO: &[f64] = &[-0.0]; - const POS_ONE: &[f64] = &[1.0]; - const NEG_ONE: &[f64] = &[-1.0]; - const POS_FLOATS: &[f64] = &[99.0 / 70.0, E, PI]; - const NEG_FLOATS: &[f64] = &[-99.0 / 70.0, -E, -PI]; - const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), MIN_POSITIVE, EPSILON]; - const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -MIN_POSITIVE, -EPSILON]; - const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, MAX]; - const NEG_EVENS: &[f64] = &[MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; - const POS_ODDS: &[f64] = &[3.0, 7.0]; - const NEG_ODDS: &[f64] = &[-7.0, -3.0]; - const NANS: &[f64] = &[NAN]; - const POS_INF: &[f64] = &[INFINITY]; - const NEG_INF: &[f64] = &[NEG_INFINITY]; - - const ALL: &[&[f64]] = &[ + const POS_ZERO: &[Float64] = &[0.0]; + const NEG_ZERO: &[Float64] = &[-0.0]; + const POS_ONE: &[Float64] = &[1.0]; + const NEG_ONE: &[Float64] = &[-1.0]; + const POS_FLOATS: &[Float64] = &[99.0 / 70.0, E, PI]; + const NEG_FLOATS: &[Float64] = &[-99.0 / 70.0, -E, -PI]; + const POS_SMALL_FLOATS: &[Float64] = &[(1.0 / 2.0), MIN_POSITIVE, EPSILON]; + const NEG_SMALL_FLOATS: &[Float64] = &[-(1.0 / 2.0), -MIN_POSITIVE, -EPSILON]; + const POS_EVENS: &[Float64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, MAX]; + const NEG_EVENS: &[Float64] = &[MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; + const POS_ODDS: &[Float64] = &[3.0, 7.0]; + const NEG_ODDS: &[Float64] = &[-7.0, -3.0]; + const NANS: &[Float64] = &[NAN]; + const POS_INF: &[Float64] = &[INFINITY]; + const NEG_INF: &[Float64] = &[NEG_INFINITY]; + + const ALL: &[&[Float64]] = &[ POS_ZERO, NEG_ZERO, NANS, @@ -449,10 +453,10 @@ mod tests { NEG_ONE, POS_ONE, ]; - const POS: &[&[f64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; - const NEG: &[&[f64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; + const POS: &[&[Float64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; + const NEG: &[&[Float64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; - fn pow_test(base: f64, exponent: f64, expected: f64) { + fn pow_test(base: Float64, exponent: Float64, expected: Float64) { let res = pow(base, exponent); assert!( if expected.is_nan() { @@ -468,17 +472,17 @@ mod tests { ); } - fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { + fn test_sets_as_base(sets: &[&[Float64]], exponent: Float64, expected: Float64) { sets.iter() .for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); } - fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { + fn test_sets_as_exponent(base: Float64, sets: &[&[Float64]], expected: Float64) { sets.iter() .for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); } - fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { + fn test_sets(sets: &[&[Float64]], computed: &dyn Fn(Float64) -> Float64, expected: &dyn Fn(Float64) -> Float64) { sets.iter().for_each(|s| { s.iter().for_each(|val| { let exp = expected(*val); @@ -541,7 +545,7 @@ mod tests { // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) // We can lump in pos/neg odd ints here because they don't seem to // cause panics (div by zero) in release mode (I think). - test_sets(ALL, &|v: f64| pow(NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); + test_sets(ALL, &|v: Float64| pow(NEG_INFINITY, v), &|v: Float64| pow(-0.0, -v)); } #[test] @@ -600,11 +604,11 @@ mod tests { fn special_cases() { // One as the exponent: // (anything ^ 1 should be anything - i.e. the base) - test_sets(ALL, &|v: f64| pow(v, 1.0), &|v: f64| v); + test_sets(ALL, &|v: Float64| pow(v, 1.0), &|v: Float64| v); // Negative One as the exponent: // (anything ^ -1 should be 1/anything) - test_sets(ALL, &|v: f64| pow(v, -1.0), &|v: f64| 1.0 / v); + test_sets(ALL, &|v: Float64| pow(v, -1.0), &|v: Float64| 1.0 / v); // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) @@ -612,7 +616,7 @@ mod tests { .iter() .for_each(|int_set| { int_set.iter().for_each(|int| { - test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| { + test_sets(ALL, &|v: Float64| pow(-v, *int), &|v: Float64| { pow(-1.0, *int) * pow(v, *int) }); }) @@ -622,14 +626,14 @@ mod tests { // (-anything except 0 and Infinity ^ non-integer should be NAN) (&NEG[1..(NEG.len() - 1)]).iter().for_each(|set| { set.iter().for_each(|val| { - test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| NAN); + test_sets(&ALL[3..7], &|v: Float64| pow(*val, v), &|_| NAN); }) }); } #[test] fn normal_cases() { - assert_eq!(pow(2.0, 20.0), (1 << 20) as f64); + assert_eq!(pow(2.0, 20.0), (1 << 20) as Float64); assert_eq!(pow(-1.0, 9.0), -1.0); assert!(pow(-1.0, 2.2).is_nan()); assert!(pow(-1.0, -1.14).is_nan()); diff --git a/core/llm/math/powf.rs b/core/llm/math/powf.rs index 68d2083..1cae7c3 100644 --- a/core/llm/math/powf.rs +++ b/core/llm/math/powf.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,56 +8,62 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::Float32; use super::{fabsf, scalbnf, sqrtf}; -const BP: [f32; 2] = [1.0, 1.5]; -const DP_H: [f32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ -const DP_L: [f32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ -const TWO24: f32 = 16777216.0; /* 0x4b800000 */ -const HUGE: f32 = 1.0e30; -const TINY: f32 = 1.0e-30; -const L1: f32 = 6.0000002384e-01; /* 0x3f19999a */ -const L2: f32 = 4.2857143283e-01; /* 0x3edb6db7 */ -const L3: f32 = 3.3333334327e-01; /* 0x3eaaaaab */ -const L4: f32 = 2.7272811532e-01; /* 0x3e8ba305 */ -const L5: f32 = 2.3066075146e-01; /* 0x3e6c3255 */ -const L6: f32 = 2.0697501302e-01; /* 0x3e53f142 */ -const P1: f32 = 1.6666667163e-01; /* 0x3e2aaaab */ -const P2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ -const P3: f32 = 6.6137559770e-05; /* 0x388ab355 */ -const P4: f32 = -1.6533901999e-06; /* 0xb5ddea0e */ -const P5: f32 = 4.1381369442e-08; /* 0x3331bb4c */ -const LG2: f32 = 6.9314718246e-01; /* 0x3f317218 */ -const LG2_H: f32 = 6.93145752e-01; /* 0x3f317200 */ -const LG2_L: f32 = 1.42860654e-06; /* 0x35bfbe8c */ -const OVT: f32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ -const CP: f32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ -const CP_H: f32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ -const CP_L: f32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ -const IVLN2: f32 = 1.4426950216e+00; -const IVLN2_H: f32 = 1.4426879883e+00; -const IVLN2_L: f32 = 7.0526075433e-06; +const BP: [Float32; 2] = [1.0, 1.5]; +const DP_H: [Float32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ +const DP_L: [Float32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ +const TWO24: Float32 = 16777216.0; /* 0x4b800000 */ +const HUGE: Float32 = 1.0e30; +const TINY: Float32 = 1.0e-30; +const L1: Float32 = 6.0000002384e-01; /* 0x3f19999a */ +const L2: Float32 = 4.2857143283e-01; /* 0x3edb6db7 */ +const L3: Float32 = 3.3333334327e-01; /* 0x3eaaaaab */ +const L4: Float32 = 2.7272811532e-01; /* 0x3e8ba305 */ +const L5: Float32 = 2.3066075146e-01; /* 0x3e6c3255 */ +const L6: Float32 = 2.0697501302e-01; /* 0x3e53f142 */ +const P1: Float32 = 1.6666667163e-01; /* 0x3e2aaaab */ +const P2: Float32 = -2.7777778450e-03; /* 0xbb360b61 */ +const P3: Float32 = 6.6137559770e-05; /* 0x388ab355 */ +const P4: Float32 = -1.6533901999e-06; /* 0xb5ddea0e */ +const P5: Float32 = 4.1381369442e-08; /* 0x3331bb4c */ +const LG2: Float32 = 6.9314718246e-01; /* 0x3f317218 */ +const LG2_H: Float32 = 6.93145752e-01; /* 0x3f317200 */ +const LG2_L: Float32 = 1.42860654e-06; /* 0x35bfbe8c */ +const OVT: Float32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ +const CP: Float32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ +const CP_H: Float32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ +const CP_L: Float32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ +const IVLN2: Float32 = 1.4426950216e+00; +const IVLN2_H: Float32 = 1.4426879883e+00; +const IVLN2_L: Float32 = 7.0526075433e-06; +/// Returns `x` raised to the power `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn powf(x: f32, y: f32) -> f32 { - let mut z: f32; - let mut ax: f32; - let z_h: f32; - let z_l: f32; - let mut p_h: f32; - let mut p_l: f32; - let y1: f32; - let mut t1: f32; - let t2: f32; - let mut r: f32; - let s: f32; - let mut sn: f32; - let mut t: f32; - let mut u: f32; - let mut v: f32; - let mut w: f32; +pub fn powf(x: Float32, y: Float32) -> Float32 { + let mut z: Float32; + let mut ax: Float32; + let z_h: Float32; + let z_l: Float32; + let mut p_h: Float32; + let mut p_l: Float32; + let y1: Float32; + let mut t1: Float32; + let t2: Float32; + let mut r: Float32; + let s: Float32; + let mut sn: Float32; + let mut t: Float32; + let mut u: Float32; + let mut v: Float32; + let mut w: Float32; let i: i32; let mut j: i32; let mut k: i32; @@ -204,14 +207,14 @@ pub fn powf(x: f32, y: f32) -> f32 { v = t * IVLN2_L - w * IVLN2; t1 = u + v; is = t1.to_bits() as i32; - t1 = f32::from_bits(is as u32 & 0xfffff000); + t1 = Float32::from_bits(is as u32 & 0xfffff000); t2 = v - (t1 - u); } else { - let mut s2: f32; - let mut s_h: f32; - let s_l: f32; - let mut t_h: f32; - let mut t_l: f32; + let mut s2: Float32; + let mut s_h: Float32; + let s_l: Float32; + let mut t_h: Float32; + let mut t_l: Float32; n = 0; /* take care subnormal number */ @@ -235,7 +238,7 @@ pub fn powf(x: f32, y: f32) -> f32 { n += 1; ix -= 0x00800000; } - ax = f32::from_bits(ix as u32); + ax = Float32::from_bits(ix as u32); /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ u = ax - i!(BP, k as usize); /* bp[0]=1.0, bp[1]=1.5 */ @@ -243,10 +246,10 @@ pub fn powf(x: f32, y: f32) -> f32 { s = u * v; s_h = s; is = s_h.to_bits() as i32; - s_h = f32::from_bits(is as u32 & 0xfffff000); + s_h = Float32::from_bits(is as u32 & 0xfffff000); /* t_h=ax+bp[k] High */ is = (((ix as u32 >> 1) & 0xfffff000) | 0x20000000) as i32; - t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); + t_h = Float32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); t_l = ax - (t_h - i!(BP, k as usize)); s_l = v * ((u - s_h * t_h) - s_h * t_l); /* compute log(ax) */ @@ -256,7 +259,7 @@ pub fn powf(x: f32, y: f32) -> f32 { s2 = s_h * s_h; t_h = 3.0 + s2 + r; is = t_h.to_bits() as i32; - t_h = f32::from_bits(is as u32 & 0xfffff000); + t_h = Float32::from_bits(is as u32 & 0xfffff000); t_l = r - ((t_h - 3.0) - s2); /* u+v = s*(1+...) */ u = s_h * t_h; @@ -264,21 +267,21 @@ pub fn powf(x: f32, y: f32) -> f32 { /* 2/(3log2)*(s+...) */ p_h = u + v; is = p_h.to_bits() as i32; - p_h = f32::from_bits(is as u32 & 0xfffff000); + p_h = Float32::from_bits(is as u32 & 0xfffff000); p_l = v - (p_h - u); z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ z_l = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ - t = n as f32; + t = n as Float32; t1 = ((z_h + z_l) + i!(DP_H, k as usize)) + t; is = t1.to_bits() as i32; - t1 = f32::from_bits(is as u32 & 0xfffff000); + t1 = Float32::from_bits(is as u32 & 0xfffff000); t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); }; /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ is = y.to_bits() as i32; - y1 = f32::from_bits(is as u32 & 0xfffff000); + y1 = Float32::from_bits(is as u32 & 0xfffff000); p_l = (y - y1) * t1 + y * t2; p_h = y1 * t1; z = p_l + p_h; @@ -312,7 +315,7 @@ pub fn powf(x: f32, y: f32) -> f32 { /* if |z| > 0.5, set n = [z+0.5] */ n = j + (0x00800000 >> (k + 1)); k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */ - t = f32::from_bits(n as u32 & !(0x007fffff >> k)); + t = Float32::from_bits(n as u32 & !(0x007fffff >> k)); n = ((n & 0x007fffff) | 0x00800000) >> (23 - k); if j < 0 { n = -n; @@ -321,7 +324,7 @@ pub fn powf(x: f32, y: f32) -> f32 { } t = p_l + p_h; is = t.to_bits() as i32; - t = f32::from_bits(is as u32 & 0xffff8000); + t = Float32::from_bits(is as u32 & 0xffff8000); u = t * LG2_H; v = (p_l - (t - p_h)) * LG2 + t * LG2_L; z = u + v; @@ -336,7 +339,7 @@ pub fn powf(x: f32, y: f32) -> f32 { /* subnormal output */ z = scalbnf(z, n); } else { - z = f32::from_bits(j as u32); + z = Float32::from_bits(j as u32); } sn * z } diff --git a/core/llm/math/rem_pio2.rs b/core/llm/math/rem_pio2.rs index 644616f..04b2701 100644 --- a/core/llm/math/rem_pio2.rs +++ b/core/llm/math/rem_pio2.rs @@ -9,48 +9,51 @@ // is preserved. // ==================================================== // -// Optimized by Bruce D. Evans. */ +// Optimized by Bruce D. Evans. + +use crate::Float64; + use super::rem_pio2_large; // #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 // #define EPS DBL_EPSILON -const EPS: f64 = 2.2204460492503131e-16; +const EPS: Float64 = 2.2204460492503131e-16; // #elif FLT_EVAL_METHOD==2 // #define EPS LDBL_EPSILON // #endif // TODO: Support FLT_EVAL_METHOD? -const TO_INT: f64 = 1.5 / EPS; +const TO_INT: Float64 = 1.5 / EPS; /// 53 bits of 2/pi -const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +const INV_PIO2: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ /// first 33 bits of pi/2 -const PIO2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ +const PIO2_1: Float64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ /// pi/2 - PIO2_1 -const PIO2_1T: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ +const PIO2_1T: Float64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ /// second 33 bits of pi/2 -const PIO2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ +const PIO2_2: Float64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ /// pi/2 - (PIO2_1+PIO2_2) -const PIO2_2T: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ +const PIO2_2T: Float64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ /// third 33 bits of pi/2 -const PIO2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ +const PIO2_3: Float64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ /// pi/2 - (PIO2_1+PIO2_2+PIO2_3) -const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ +const PIO2_3T: Float64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ -// return the remainder of x rem pi/2 in y[0]+y[1] -// use rem_pio2_large() for large x -// -// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +/// return the remainder of x rem pi/2 in y[0]+y[1] +/// use rem_pio2_large() for large x +/// +/// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { - let x1p24 = f64::from_bits(0x4170000000000000); +pub(crate) fn rem_pio2(x: Float64) -> (i32, Float64, Float64) { + let x1p24 = Float64::from_bits(0x4170000000000000); - let sign = (f64::to_bits(x) >> 63) as i32; - let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + let sign = (Float64::to_bits(x) >> 63) as i32; + let ix = (Float64::to_bits(x) >> 32) as u32 & 0x7fffffff; - fn medium(x: f64, ix: u32) -> (i32, f64, f64) { + fn medium(x: Float64, ix: u32) -> (i32, Float64, Float64) { /* rint(x/(pi/2)), Assume round-to-nearest. */ - let tmp = x as f64 * INV_PIO2 + TO_INT; + let tmp = x as Float64 * INV_PIO2 + TO_INT; // force rounding of tmp to it's storage format on x87 to avoid // excess precision issues. #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] @@ -60,7 +63,7 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { let mut r = x - f_n * PIO2_1; let mut w = f_n * PIO2_1T; /* 1st round, good to 85 bits */ let mut y0 = r - w; - let ui = f64::to_bits(y0); + let ui = Float64::to_bits(y0); let ey = (ui >> 52) as i32 & 0x7ff; let ex = (ix >> 20) as i32; if ex - ey > 16 { @@ -70,7 +73,7 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { r = t - w; w = f_n * PIO2_2T - ((t - r) - w); y0 = r - w; - let ey = (f64::to_bits(y0) >> 52) as i32 & 0x7ff; + let ey = (Float64::to_bits(y0) >> 52) as i32 & 0x7ff; if ex - ey > 49 { /* 3rd round, good to 151 bits, covers all cases */ let t = r; @@ -166,13 +169,13 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { return (0, y0, y1); } /* set z = scalbn(|x|,-ilogb(x)+23) */ - let mut ui = f64::to_bits(x); + let mut ui = Float64::to_bits(x); ui &= (!1) >> 12; ui |= (0x3ff + 23) << 52; - let mut z = f64::from_bits(ui); + let mut z = Float64::from_bits(ui); let mut tx = [0.0; 3]; for i in 0..2 { - i!(tx,i, =, z as i32 as f64); + i!(tx,i, =, z as i32 as Float64); z = (z - i!(tx, i)) * x1p24; } i!(tx,2, =, z); diff --git a/core/llm/math/rem_pio2_large.rs b/core/llm/math/rem_pio2_large.rs index db97a39..6aa68ef 100644 --- a/core/llm/math/rem_pio2_large.rs +++ b/core/llm/math/rem_pio2_large.rs @@ -1,6 +1,5 @@ -#![allow(unused_unsafe)] /* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -9,7 +8,9 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ + +use crate::Float64; use super::floor; use super::scalbn; @@ -120,7 +121,7 @@ const IPIO2: [i32; 690] = [ 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, ]; -const PIO2: [f64; 8] = [ +const PIO2: [Float64; 8] = [ 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ @@ -131,7 +132,7 @@ const PIO2: [f64; 8] = [ 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ ]; -// fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 +// fn rem_pio2_large(x : &[Float64], y : &mut [Float64], e0 : i32, prec : usize) -> i32 // // Input parameters: // x[] The input value (must be positive) is broken into nx @@ -223,22 +224,22 @@ const PIO2: [f64; 8] = [ /// more accurately, = 0 mod 8 ). Thus the number of operations are /// independent of the exponent of the input. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { - let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 - let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) +pub(crate) fn rem_pio2_large(x: &[Float64], y: &mut [Float64], e0: i32, prec: usize) -> i32 { + let x1p24 = Float64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 + let x1p_24 = Float64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) #[cfg(all(target_pointer_width = "64", feature = "checked"))] assert!(e0 <= 16360); let nx = x.len(); - let mut fw: f64; + let mut fw: Float64; let mut n: i32; let mut ih: i32; - let mut z: f64; - let mut f: [f64; 20] = [0.; 20]; - let mut fq: [f64; 20] = [0.; 20]; - let mut q: [f64; 20] = [0.; 20]; + let mut z: Float64; + let mut f: [Float64; 20] = [0.; 20]; + let mut fq: [Float64; 20] = [0.; 20]; + let mut q: [Float64; 20] = [0.; 20]; let mut iq: [i32; 20] = [0; 20]; /* initialize jk*/ @@ -261,7 +262,7 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i!(f, i, =, if j < 0 { 0. } else { - i!(IPIO2, j as usize) as f64 + i!(IPIO2, j as usize) as Float64 }); j += 1; } @@ -282,7 +283,7 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> let mut i = 0i32; z = i!(q, jz); for j in (1..=jz).rev() { - fw = (x1p_24 * z) as i32 as f64; + fw = (x1p_24 * z) as i32 as Float64; i!(iq, i as usize, =, (z - x1p24 * fw) as i32); z = i!(q, j - 1) + fw; i += 1; @@ -292,7 +293,7 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> z = scalbn(z, q0); /* actual value of z */ z -= 8.0 * floor(z * 0.125); /* trim off integer >= 8 */ n = z as i32; - z -= n as f64; + z -= n as Float64; ih = 0; if q0 > 0 { /* need iq[jz-1] to determine n */ @@ -357,7 +358,7 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> for i in (jz + 1)..=(jz + k) { /* add q[jz+1] to q[jz+k] */ - i!(f, jx + i, =, i!(IPIO2, jv + i) as f64); + i!(f, jx + i, =, i!(IPIO2, jv + i) as Float64); fw = 0f64; for j in 0..=jx { fw += i!(x, j) * i!(f, jx + i - j); @@ -384,7 +385,7 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> /* break z into 24-bit if necessary */ z = scalbn(z, -q0); if z >= x1p24 { - fw = (x1p_24 * z) as i32 as f64; + fw = (x1p_24 * z) as i32 as Float64; i!(iq, jz, =, (z - x1p24 * fw) as i32); jz += 1; q0 += 24; @@ -397,7 +398,7 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> /* convert integer "bit" chunk to floating-point value */ fw = scalbn(1., q0); for i in (0..=jz).rev() { - i!(q, i, =, fw * (i!(iq, i) as f64)); + i!(q, i, =, fw * (i!(iq, i) as Float64)); fw *= x1p_24; } @@ -427,7 +428,7 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> fw += i!(fq, i); } // TODO: drop excess precision here once double_t is used - fw = fw as f64; + fw = fw as Float64; i!(y, 0, =, if ih == 0 { fw } else { -fw }); fw = i!(fq, 0) - fw; for i in 1..=jz { diff --git a/core/llm/math/rem_pio2f.rs b/core/llm/math/rem_pio2f.rs index 775f5d7..1a803cd 100644 --- a/core/llm/math/rem_pio2f.rs +++ b/core/llm/math/rem_pio2f.rs @@ -1,9 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Debugged and optimized by Bruce D. Evans. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -12,31 +8,35 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. +*/ -use super::rem_pio2_large; +use crate::{Float64, Float32}; -use core::f64; +use super::rem_pio2_large; -const TOINT: f64 = 1.5 / f64::EPSILON; +const TOINT: Float64 = 1.5 / Float64::EPSILON; /// 53 bits of 2/pi -const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +const INV_PIO2: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ /// first 25 bits of pi/2 -const PIO2_1: f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ +const PIO2_1: Float64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ /// pi/2 - pio2_1 -const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ +const PIO2_1T: Float64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ /// Return the remainder of x rem pi/2 in *y /// /// use double precision for everything except passing x /// use __rem_pio2_large() for large x #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { - let x64 = x as f64; +pub(crate) fn rem_pio2f(x: Float32) -> (i32, Float64) { + let x64 = x as Float64; - let mut tx: [f64; 1] = [0.]; - let mut ty: [f64; 1] = [0.]; + let mut tx: [Float64; 1] = [0.]; + let mut ty: [Float64; 1] = [0.]; let ix = x.to_bits() & 0x7fffffff; /* 25+53 bit pi is good enough for medium size */ @@ -58,7 +58,7 @@ pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { /* scale x into [2^23, 2^24-1] */ let sign = (x.to_bits() >> 31) != 0; let e0 = ((ix >> 23) - (0x7f + 23)) as i32; /* e0 = ilogb(|x|)-23, positive */ - tx[0] = f32::from_bits(ix - (e0 << 23) as u32) as f64; + tx[0] = Float32::from_bits(ix - (e0 << 23) as u32) as Float64; let n = rem_pio2_large(&tx, &mut ty, e0, 0); if sign { return (-n, -ty[0]); diff --git a/core/llm/math/remainder.rs b/core/llm/math/remainder.rs index 9e966c9..3f6f54a 100644 --- a/core/llm/math/remainder.rs +++ b/core/llm/math/remainder.rs @@ -1,5 +1,8 @@ +use crate::Float64; + +/// Returns the remainder of `x/y`. +#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remainder(x: f64, y: f64) -> f64 { - let (result, _) = super::remquo(x, y); - result +pub fn remainder(x: Float64, y: Float64) -> Float64 { + super::remquo(x, y).0 } diff --git a/core/llm/math/remainderf.rs b/core/llm/math/remainderf.rs index b1407cf..8b24f1e 100644 --- a/core/llm/math/remainderf.rs +++ b/core/llm/math/remainderf.rs @@ -1,5 +1,8 @@ +use crate::Float32; + +/// Returns the remainder of `x/y`. +#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remainderf(x: f32, y: f32) -> f32 { - let (result, _) = super::remquof(x, y); - result +pub fn remainderf(x: Float32, y: Float32) -> Float32 { + super::remquof(x, y).0 } diff --git a/core/llm/math/remquo.rs b/core/llm/math/remquo.rs index 0afd1f7..0a95602 100644 --- a/core/llm/math/remquo.rs +++ b/core/llm/math/remquo.rs @@ -1,5 +1,8 @@ +use crate::Float64; + +/// Return the remainder and part of the quotient of `x` and `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { +pub fn remquo(mut x: Float64, mut y: Float64) -> (Float64, i32) { let ux: u64 = x.to_bits(); let mut uy: u64 = y.to_bits(); let mut ex = ((ux >> 52) & 0x7ff) as i32; @@ -80,7 +83,7 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { } else { uxi >>= -ex + 1; } - x = f64::from_bits(uxi); + x = Float64::from_bits(uxi); if sy { y = -y; } @@ -91,11 +94,7 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { } q &= 0x7fffffff; let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; - if sx { - (-x, quo) - } else { - (x, quo) - } + (if sx { -x } else { x }, quo) } #[cfg(test)] diff --git a/core/llm/math/remquof.rs b/core/llm/math/remquof.rs index d71bd38..2c85326 100644 --- a/core/llm/math/remquof.rs +++ b/core/llm/math/remquof.rs @@ -1,5 +1,8 @@ +use crate::Float32; + +/// Return the remainder and part of the quotient of `x` and `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { +pub fn remquof(mut x: Float32, mut y: Float32) -> (Float32, i32) { let ux: u32 = x.to_bits(); let mut uy: u32 = y.to_bits(); let mut ex = ((ux >> 23) & 0xff) as i32; @@ -79,7 +82,7 @@ pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { } else { uxi >>= -ex + 1; } - x = f32::from_bits(uxi); + x = Float32::from_bits(uxi); if sy { y = -y; } diff --git a/core/llm/math/rint.rs b/core/llm/math/rint.rs index 8edbe34..35a897c 100644 --- a/core/llm/math/rint.rs +++ b/core/llm/math/rint.rs @@ -1,6 +1,9 @@ +use crate::Float64; + +/// Round to nearest integer, rounding halfway cases away from zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rint(x: f64) -> f64 { - let one_over_e = 1.0 / f64::EPSILON; +pub fn rint(x: Float64) -> Float64 { + let one_over_e = 1.0 / Float64::EPSILON; let as_u64: u64 = x.to_bits(); let exponent: u64 = as_u64 >> 52 & 0x7ff; let is_positive = (as_u64 >> 63) == 0; diff --git a/core/llm/math/rintf.rs b/core/llm/math/rintf.rs index 7a7da61..9ffe4f2 100644 --- a/core/llm/math/rintf.rs +++ b/core/llm/math/rintf.rs @@ -1,6 +1,9 @@ +use crate::Float32; + +/// Round to nearest integer, rounding halfway cases away from zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rintf(x: f32) -> f32 { - let one_over_e = 1.0 / f32::EPSILON; +pub fn rintf(x: Float32) -> Float32 { + let one_over_e = 1.0 / Float32::EPSILON; let as_u32: u32 = x.to_bits(); let exponent: u32 = as_u32 >> 23 & 0xff; let is_positive = (as_u32 >> 31) == 0; diff --git a/core/llm/math/round.rs b/core/llm/math/round.rs index 46fabc9..8c0f13f 100644 --- a/core/llm/math/round.rs +++ b/core/llm/math/round.rs @@ -1,10 +1,12 @@ +use crate::Float64; + use super::copysign; use super::trunc; -use core::f64; +/// Rounds `x` to the nearest integer in the direction of the current rounding mode. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn round(x: f64) -> f64 { - trunc(x + copysign(0.5 - 0.25 * f64::EPSILON, x)) +pub fn round(x: Float64) -> Float64 { + trunc(x + copysign(0.5 - 0.25 * Float64::EPSILON, x)) } #[cfg(test)] diff --git a/core/llm/math/roundf.rs b/core/llm/math/roundf.rs index becdb56..c67ab5c 100644 --- a/core/llm/math/roundf.rs +++ b/core/llm/math/roundf.rs @@ -1,10 +1,12 @@ +use crate::Float32; + use super::copysignf; use super::truncf; -use core::f32; +/// Rounds `x` to the nearest integer in the direction of the current rounding mode. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf(x: f32) -> f32 { - truncf(x + copysignf(0.5 - 0.25 * f32::EPSILON, x)) +pub fn roundf(x: Float32) -> Float32 { + truncf(x + copysignf(0.5 - 0.25 * Float32::EPSILON, x)) } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 diff --git a/core/llm/math/scalbn.rs b/core/llm/math/scalbn.rs index 00c455a..b18b270 100644 --- a/core/llm/math/scalbn.rs +++ b/core/llm/math/scalbn.rs @@ -1,8 +1,11 @@ +use crate::Float64; + +/// Returns `x * 2^n` #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbn(x: f64, mut n: i32) -> f64 { - let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 - let x1p53 = f64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 - let x1p_1022 = f64::from_bits(0x0010000000000000); // 0x1p-1022 === 2 ^ (-1022) +pub fn scalbn(x: Float64, mut n: i32) -> Float64 { + let x1p1023 = Float64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 + let x1p53 = Float64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 + let x1p_1022 = Float64::from_bits(0x0010000000000000); // 0x1p-1022 === 2 ^ (-1022) let mut y = x; @@ -29,5 +32,5 @@ pub fn scalbn(x: f64, mut n: i32) -> f64 { } } } - y * f64::from_bits(((0x3ff + n) as u64) << 52) + y * Float64::from_bits(((0x3ff + n) as u64) << 52) } diff --git a/core/llm/math/scalbnf.rs b/core/llm/math/scalbnf.rs index 73f4bb5..71f5e60 100644 --- a/core/llm/math/scalbnf.rs +++ b/core/llm/math/scalbnf.rs @@ -1,8 +1,11 @@ +use crate::Float32; + +/// Returns `x * 2^n` #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 - let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 +pub fn scalbnf(mut x: Float32, mut n: i32) -> Float32 { + let x1p127 = Float32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = Float32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 + let x1p24 = Float32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 if n > 127 { x *= x1p127; @@ -25,5 +28,5 @@ pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { } } } - x * f32::from_bits(((0x7f + n) as u32) << 23) + x * Float32::from_bits(((0x7f + n) as u32) << 23) } diff --git a/core/llm/math/sin.rs b/core/llm/math/sin.rs index a53843d..f7f2874 100644 --- a/core/llm/math/sin.rs +++ b/core/llm/math/sin.rs @@ -9,43 +9,48 @@ // is preserved. // ==================================================== +use crate::{Float64, Radian64}; + use super::{k_cos, k_sin, rem_pio2}; -// sin(x) -// Return sine function of x. -// -// kernel function: -// k_sin ... sine function on [-pi/4,pi/4] -// k_cos ... cose function on [-pi/4,pi/4] -// rem_pio2 ... argument reduction routine -// -// Method. -// Let S,C and T denote the sin, cos and tan respectively on -// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 -// in [-pi/4 , +pi/4], and let n = k mod 4. -// We have -// -// n sin(x) cos(x) tan(x) -// ---------------------------------------------------------- -// 0 S C T -// 1 C -S -1/T -// 2 -S -C T -// 3 -C S -1/T -// ---------------------------------------------------------- -// -// Special cases: -// Let trig be any of sin, cos, or tan. -// trig(+-INF) is NaN, with signals; -// trig(NaN) is that NaN; -// -// Accuracy: -// TRIG(x) returns trig(x) nearly rounded +/// Returns the sine function of x. +/// +/// ### Info: +/// +/// ```text +/// kernel function: +/// k_sin ... sine function on [-pi/4,pi/4] +/// k_cos ... cose function on [-pi/4,pi/4] +/// rem_pio2 ... argument reduction routine +/// +/// Method. +/// Let S,C and T denote the sin, cos and tan respectively on +/// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +/// in [-pi/4 , +pi/4], and let n = k mod 4. +/// We have +/// +/// n sin(x) cos(x) tan(x) +/// ---------------------------------------------------------- +/// 0 S C T +/// 1 C -S -1/T +/// 2 -S -C T +/// 3 -C S -1/T +/// ---------------------------------------------------------- +/// +/// Special cases: +/// Let trig be any of sin, cos, or tan. +/// trig(+-INF) is NaN, with signals; +/// trig(NaN) is that NaN; +/// +/// Accuracy: +/// TRIG(x) returns trig(x) nearly rounded +/// ``` #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sin(x: f64) -> f64 { - let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 +pub fn sin(x: Radian64) -> Float64 { + let x1p120 = Float64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 /* High word of x. */ - let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + let ix = (Float64::to_bits(x) >> 32) as u32 & 0x7fffffff; /* |x| ~< pi/4 */ if ix <= 0x3fe921fb { @@ -79,8 +84,8 @@ pub fn sin(x: f64) -> f64 { #[test] fn test_near_pi() { - let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 - let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 + let x = Float64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 + let sx = Float64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 let result = sin(x); #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] let result = force_eval!(result); diff --git a/core/llm/math/sincos.rs b/core/llm/math/sincos.rs index ff5d87a..75bfe63 100644 --- a/core/llm/math/sincos.rs +++ b/core/llm/math/sincos.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -8,14 +8,17 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ + +use crate::{Float64, Radian64}; use super::{get_high_word, k_cos, k_sin, rem_pio2}; +/// Simultaneously computes the sine and cosine of the argument x. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sincos(x: f64) -> (f64, f64) { - let s: f64; - let c: f64; +pub fn sincos(x: Radian64) -> (Float64, Float64) { + let s: Float64; + let c: Float64; let mut ix: u32; ix = get_high_word(x); @@ -26,7 +29,7 @@ pub fn sincos(x: f64) -> (f64, f64) { /* if |x| < 2**-27 * sqrt(2) */ if ix < 0x3e46a09e { /* raise inexact if x!=0 and underflow if subnormal */ - let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 + let x1p120 = Float64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 if ix < 0x00100000 { force_eval!(x / x1p120); } else { @@ -64,11 +67,11 @@ pub fn sincos(x: f64) -> (f64, f64) { mod tests { use super::sincos; - const TOLERANCE: f64 = 1e-6; + const TOLERANCE: Float64 = 1e-6; #[test] fn with_pi() { - let (s, c) = sincos(core::f64::consts::PI); + let (s, c) = sincos(core::Float64::consts::PI); assert!( (s - 0.0).abs() < TOLERANCE, "|{} - {}| = {} >= {}", @@ -89,10 +92,10 @@ mod tests { #[test] fn rotational_symmetry() { - use core::f64::consts::PI; + use core::Float64::consts::PI; const N: usize = 24; for n in 0..N { - let theta = 2. * PI * (n as f64) / (N as f64); + let theta = 2. * PI * (n as Float64) / (N as Float64); let (s, c) = sincos(theta); let (s_plus, c_plus) = sincos(theta + 2. * PI); let (s_minus, c_minus) = sincos(theta - 2. * PI); diff --git a/core/llm/math/sincosf.rs b/core/llm/math/sincosf.rs index 9a4c361..3bf3719 100644 --- a/core/llm/math/sincosf.rs +++ b/core/llm/math/sincosf.rs @@ -1,9 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -12,21 +8,28 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. +*/ + +use crate::{Float64, Float32, Radian32}; use super::{k_cosf, k_sinf, rem_pio2f}; /* Small multiples of pi/2 rounded to double precision. */ -const PI_2: f32 = 0.5 * 3.1415926535897931160E+00; -const S1PIO2: f32 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ -const S2PIO2: f32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ -const S3PIO2: f32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const S4PIO2: f32 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ +const PI_2: Float32 = 0.5 * 3.1415926535897931160E+00; +const S1PIO2: Float32 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2PIO2: Float32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ +const S3PIO2: Float32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4PIO2: Float32 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ +/// Simultaneously computes the sine and cosine of the argument x. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sincosf(x: f32) -> (f32, f32) { - let s: f32; - let c: f32; +pub fn sincosf(x: Radian32) -> (Float32, Float32) { + let s: Float32; + let c: Float32; let mut ix: u32; let sign: bool; @@ -40,7 +43,7 @@ pub fn sincosf(x: f32) -> (f32, f32) { if ix < 0x39800000 { /* raise inexact if x!=0 and underflow if subnormal */ - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120 == 2^120 + let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120 == 2^120 if ix < 0x00100000 { force_eval!(x / x1p120); } else { @@ -48,7 +51,7 @@ pub fn sincosf(x: f32) -> (f32, f32) { } return (x, 1.0); } - return (k_sinf(x as f64), k_cosf(x as f64)); + return (k_sinf(x as Float64), k_cosf(x as Float64)); } /* |x| ~<= 5*pi/4 */ @@ -56,21 +59,21 @@ pub fn sincosf(x: f32) -> (f32, f32) { if ix <= 0x4016cbe3 { /* |x| ~<= 3pi/4 */ if sign { - s = -k_cosf((x + S1PIO2) as f64); - c = k_sinf((x + S1PIO2) as f64); + s = -k_cosf((x + S1PIO2) as Float64); + c = k_sinf((x + S1PIO2) as Float64); } else { - s = k_cosf((S1PIO2 - x) as f64); - c = k_sinf((S1PIO2 - x) as f64); + s = k_cosf((S1PIO2 - x) as Float64); + c = k_sinf((S1PIO2 - x) as Float64); } } /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ else { if sign { - s = -k_sinf((x + S2PIO2) as f64); - c = -k_cosf((x + S2PIO2) as f64); + s = -k_sinf((x + S2PIO2) as Float64); + c = -k_cosf((x + S2PIO2) as Float64); } else { - s = -k_sinf((x - S2PIO2) as f64); - c = -k_cosf((x - S2PIO2) as f64); + s = -k_sinf((x - S2PIO2) as Float64); + c = -k_cosf((x - S2PIO2) as Float64); } } @@ -82,19 +85,19 @@ pub fn sincosf(x: f32) -> (f32, f32) { if ix <= 0x40afeddf { /* |x| ~<= 7*pi/4 */ if sign { - s = k_cosf((x + S3PIO2) as f64); - c = -k_sinf((x + S3PIO2) as f64); + s = k_cosf((x + S3PIO2) as Float64); + c = -k_sinf((x + S3PIO2) as Float64); } else { - s = -k_cosf((x - S3PIO2) as f64); - c = k_sinf((x - S3PIO2) as f64); + s = -k_cosf((x - S3PIO2) as Float64); + c = k_sinf((x - S3PIO2) as Float64); } } else { if sign { - s = k_sinf((x + S4PIO2) as f64); - c = k_cosf((x + S4PIO2) as f64); + s = k_sinf((x + S4PIO2) as Float64); + c = k_cosf((x + S4PIO2) as Float64); } else { - s = k_sinf((x - S4PIO2) as f64); - c = k_cosf((x - S4PIO2) as f64); + s = k_sinf((x - S4PIO2) as Float64); + c = k_cosf((x - S4PIO2) as Float64); } } @@ -132,22 +135,22 @@ mod tests { #[test] fn with_pi() { - let (s, c) = sincosf(core::f32::consts::PI); + let (s, c) = sincosf(core::Float32::consts::PI); _eqf(s.abs(), 0.0).unwrap(); _eqf(c, -1.0).unwrap(); } #[test] fn rotational_symmetry() { - use core::f32::consts::PI; + use core::Float32::consts::PI; const N: usize = 24; for n in 0..N { - let theta = 2. * PI * (n as f32) / (N as f32); + let theta = 2. * PI * (n as Float32) / (N as Float32); let (s, c) = sincosf(theta); let (s_plus, c_plus) = sincosf(theta + 2. * PI); let (s_minus, c_minus) = sincosf(theta - 2. * PI); - const TOLERANCE: f32 = 1e-6; + const TOLERANCE: Float32 = 1e-6; assert!( (s - s_plus).abs() < TOLERANCE, "|{} - {}| = {} >= {}", diff --git a/core/llm/math/sinf.rs b/core/llm/math/sinf.rs index 6e20be2..b01181c 100644 --- a/core/llm/math/sinf.rs +++ b/core/llm/math/sinf.rs @@ -1,9 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -12,23 +8,30 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. +*/ + +use crate::{Float64, Float32, Radian32}; use super::{k_cosf, k_sinf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; /* Small multiples of pi/2 rounded to double precision. */ -const S1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +const S1_PIO2: Float64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2_PIO2: Float64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const S3_PIO2: Float64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4_PIO2: Float64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +/// Returns the sine of the argument x. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sinf(x: f32) -> f32 { - let x64 = x as f64; +pub fn sinf(x: Radian32) -> Float32 { + let x64 = x as Float64; - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 let mut ix = x.to_bits(); let sign = (ix >> 31) != 0; diff --git a/core/llm/math/sinh.rs b/core/llm/math/sinh.rs index fd24fd2..e6ea30c 100644 --- a/core/llm/math/sinh.rs +++ b/core/llm/math/sinh.rs @@ -1,21 +1,25 @@ +use crate::{Float64, Radian64}; + use super::{expm1, expo2}; // sinh(x) = (exp(x) - 1/exp(x))/2 // = (exp(x)-1 + (exp(x)-1)/exp(x))/2 // = x + x^3/6 + o(x^5) // + +/// Returns the hyperbolic sine of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sinh(x: f64) -> f64 { +pub fn sinh(x: Radian64) -> Float64 { // union {double f; uint64_t i;} u = {.f = x}; // uint32_t w; // double t, h, absx; - let mut uf: f64 = x; - let mut ui: u64 = f64::to_bits(uf); + let mut uf: Float64 = x; + let mut ui: u64 = Float64::to_bits(uf); let w: u32; - let t: f64; - let mut h: f64; - let absx: f64; + let t: Float64; + let mut h: Float64; + let absx: Float64; h = 0.5; if ui >> 63 != 0 { @@ -23,7 +27,7 @@ pub fn sinh(x: f64) -> f64 { } /* |x| */ ui &= !1 / 2; - uf = f64::from_bits(ui); + uf = Float64::from_bits(ui); absx = uf; w = (ui >> 32) as u32; diff --git a/core/llm/math/sinhf.rs b/core/llm/math/sinhf.rs index 24f863c..d727209 100644 --- a/core/llm/math/sinhf.rs +++ b/core/llm/math/sinhf.rs @@ -1,8 +1,11 @@ +use crate::{Float32, Radian32}; + use super::expm1f; use super::k_expo2f; +/// Returns the hyperbolic sine of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sinhf(x: f32) -> f32 { +pub fn sinhf(x: Radian32) -> Float32 { let mut h = 0.5f32; let mut ix = x.to_bits(); if (ix >> 31) != 0 { @@ -10,7 +13,7 @@ pub fn sinhf(x: f32) -> f32 { } /* |x| */ ix &= 0x7fffffff; - let absx = f32::from_bits(ix); + let absx = Float32::from_bits(ix); let w = ix; /* |x| < log(FLT_MAX) */ diff --git a/core/llm/math/sqrt.rs b/core/llm/math/sqrt.rs index 3733ba0..7473c50 100644 --- a/core/llm/math/sqrt.rs +++ b/core/llm/math/sqrt.rs @@ -1,5 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -9,7 +9,8 @@ * is preserved. * ==================================================== */ -/* sqrt(x) +/** + * sqrt(x) * Return correctly rounded sqrt. * ------------------------------------------ * | Use the hardware sqrt if you have one | @@ -74,19 +75,20 @@ * sqrt(inf) = inf * sqrt(-ve) = NaN ... with invalid signal * sqrt(NaN) = NaN ... with invalid signal for signaling NaN - */ +*/ -use core::f64; +use crate::Float64; +/// Returns the square root of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrt(x: f64) -> f64 { +pub fn sqrt(x: Float64) -> Float64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.sqrt` native instruction, so we can leverage this for both code size + // `Float64.sqrt` native instruction, so we can leverage this for both code size // and speed. llvm_intrinsically_optimized! { #[cfg(target_arch = "wasm32")] { return if x < 0.0 { - f64::NAN + ::core::f64::NAN } else { unsafe { ::core::intrinsics::sqrtf64(x) } } @@ -111,9 +113,9 @@ pub fn sqrt(x: f64) -> f64 { { use core::num::Wrapping; - const TINY: f64 = 1.0e-300; + const TINY: Float64 = 1.0e-300; - let mut z: f64; + let mut z: Float64; let sign: Wrapping = Wrapping(0x80000000); let mut ix0: i32; let mut s0: i32; @@ -236,7 +238,7 @@ pub fn sqrt(x: f64) -> f64 { ix1 |= sign; } ix0 += m << 20; - f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) + Float64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } } @@ -264,7 +266,7 @@ mod tests { #[test] fn conformance_tests() { - let values = [3.14159265359, 10000.0, f64::from_bits(0x0000000f), INFINITY]; + let values = [3.14159265359, 10000.0, Float64::from_bits(0x0000000f), INFINITY]; let results = [ 4610661241675116657u64, 4636737291354636288u64, @@ -273,7 +275,7 @@ mod tests { ]; for i in 0..values.len() { - let bits = f64::to_bits(sqrt(values[i])); + let bits = Float64::to_bits(sqrt(values[i])); assert_eq!(results[i], bits); } } diff --git a/core/llm/math/sqrtf.rs b/core/llm/math/sqrtf.rs index 8ec72fb..9c2c427 100644 --- a/core/llm/math/sqrtf.rs +++ b/core/llm/math/sqrtf.rs @@ -1,8 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_sqrtf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -11,12 +8,18 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::Float32; +/// Returns the square root of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf(x: f32) -> f32 { +pub fn sqrtf(x: Float32) -> Float32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.sqrt` native instruction, so we can leverage this for both code size + // `Float32.sqrt` native instruction, so we can leverage this for both code size // and speed. llvm_intrinsically_optimized! { #[cfg(target_arch = "wasm32")] { @@ -44,9 +47,9 @@ pub fn sqrtf(x: f32) -> f32 { } #[cfg(not(target_feature = "sse"))] { - const TINY: f32 = 1.0e-30; + const TINY: Float32 = 1.0e-30; - let mut z: f32; + let mut z: Float32; let sign: i32 = 0x80000000u32 as i32; let mut ix: i32; let mut s: i32; @@ -124,7 +127,7 @@ pub fn sqrtf(x: f32) -> f32 { ix = (q >> 1) + 0x3f000000; ix += m << 23; - f32::from_bits(ix as u32) + Float32::from_bits(ix as u32) } } @@ -157,13 +160,13 @@ mod tests { let values = [ 3.14159265359f32, 10000.0f32, - f32::from_bits(0x0000000f), + Float32::from_bits(0x0000000f), INFINITY, ]; let results = [1071833029u32, 1120403456u32, 456082799u32, 2139095040u32]; for i in 0..values.len() { - let bits = f32::to_bits(sqrtf(values[i])); + let bits = Float32::to_bits(sqrtf(values[i])); assert_eq!(results[i], bits); } } diff --git a/core/llm/math/tan.rs b/core/llm/math/tan.rs index 5a72f68..16567f7 100644 --- a/core/llm/math/tan.rs +++ b/core/llm/math/tan.rs @@ -9,50 +9,55 @@ // is preserved. // ==================================================== +use crate::{Float64, Float32, Radian64}; + use super::{k_tan, rem_pio2}; -// tan(x) -// Return tangent function of x. -// -// kernel function: -// k_tan ... tangent function on [-pi/4,pi/4] -// rem_pio2 ... argument reduction routine -// -// Method. -// Let S,C and T denote the sin, cos and tan respectively on -// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 -// in [-pi/4 , +pi/4], and let n = k mod 4. -// We have -// -// n sin(x) cos(x) tan(x) -// ---------------------------------------------------------- -// 0 S C T -// 1 C -S -1/T -// 2 -S -C T -// 3 -C S -1/T -// ---------------------------------------------------------- -// -// Special cases: -// Let trig be any of sin, cos, or tan. -// trig(+-INF) is NaN, with signals; -// trig(NaN) is that NaN; -// -// Accuracy: -// TRIG(x) returns trig(x) nearly rounded +/// Returns tangent of `x`. +/// +/// ### Info: +/// +/// ```text +/// kernel function: +/// k_tan ... tangent function on [-pi/4,pi/4] +/// rem_pio2 ... argument reduction routine +/// +/// Method. +/// Let S,C and T denote the sin, cos and tan respectively on +/// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +/// in [-pi/4 , +pi/4], and let n = k mod 4. +/// We have +/// +/// n sin(x) cos(x) tan(x) +/// ---------------------------------------------------------- +/// 0 S C T +/// 1 C -S -1/T +/// 2 -S -C T +/// 3 -C S -1/T +/// ---------------------------------------------------------- +/// +/// Special cases: +/// Let trig be any of sin, cos, or tan. +/// trig(+-INF) is NaN, with signals; +/// trig(NaN) is that NaN; +/// +/// Accuracy: +/// TRIG(x) returns trig(x) nearly rounded +/// ``` #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tan(x: f64) -> f64 { - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 +pub fn tan(x: Radian64) -> Float64 { + let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + let ix = (Float64::to_bits(x) >> 32) as u32 & 0x7fffffff; /* |x| ~< pi/4 */ if ix <= 0x3fe921fb { if ix < 0x3e400000 { /* |x| < 2**-27 */ /* raise inexact if x!=0 and underflow if subnormal */ force_eval!(if ix < 0x00100000 { - x / x1p120 as f64 + x / x1p120 as Float64 } else { - x + x1p120 as f64 + x + x1p120 as Float64 }); return x; } diff --git a/core/llm/math/tanf.rs b/core/llm/math/tanf.rs index 10de59c..e3681e6 100644 --- a/core/llm/math/tanf.rs +++ b/core/llm/math/tanf.rs @@ -1,9 +1,5 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* +/** * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * @@ -12,23 +8,30 @@ * software is freely granted, provided that this notice * is preserved. * ==================================================== - */ +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. +*/ + +use crate::{Float64, Float32, Radian32}; use super::{k_tanf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; /* Small multiples of pi/2 rounded to double precision. */ -const T1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +const T1_PIO2: Float64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const T2_PIO2: Float64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const T3_PIO2: Float64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const T4_PIO2: Float64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +/// Returns tangent of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tanf(x: f32) -> f32 { - let x64 = x as f64; +pub fn tanf(x: Radian32) -> Float32 { + let x64 = x as Float64; - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 let mut ix = x.to_bits(); let sign = (ix >> 31) != 0; diff --git a/core/llm/math/tanh.rs b/core/llm/math/tanh.rs index 980c685..51df661 100644 --- a/core/llm/math/tanh.rs +++ b/core/llm/math/tanh.rs @@ -1,22 +1,27 @@ -use super::expm1; +use crate::{Float64, Float32, Radian64}; -/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) +/** + * tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) - */ +*/ + +use super::expm1; + +/// Returns the hyperbolic tangent of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tanh(mut x: f64) -> f64 { - let mut uf: f64 = x; - let mut ui: u64 = f64::to_bits(uf); +pub fn tanh(mut x: Radian64) -> Float64 { + let mut uf: Float64 = x; + let mut ui: u64 = Float64::to_bits(uf); let w: u32; let sign: bool; - let mut t: f64; + let mut t: Float64; /* x = |x| */ sign = ui >> 63 != 0; ui &= !1 / 2; - uf = f64::from_bits(ui); + uf = Float64::from_bits(ui); x = uf; w = (ui >> 32) as u32; @@ -41,7 +46,7 @@ pub fn tanh(mut x: f64) -> f64 { } else { /* |x| is subnormal */ /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ - force_eval!(x as f32); + force_eval!(x as Float32); t = x; } diff --git a/core/llm/math/tanhf.rs b/core/llm/math/tanhf.rs index fc94e3d..1a5bd6a 100644 --- a/core/llm/math/tanhf.rs +++ b/core/llm/math/tanhf.rs @@ -1,12 +1,15 @@ +use crate::{Float32, Radian32}; + use super::expm1f; +/// Returns the hyperbolic tangent of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tanhf(mut x: f32) -> f32 { +pub fn tanhf(mut x: Radian32) -> Float32 { /* x = |x| */ let mut ix = x.to_bits(); let sign = (ix >> 31) != 0; ix &= 0x7fffffff; - x = f32::from_bits(ix); + x = Float32::from_bits(ix); let w = ix; let tt = if w > 0x3f0c9f54 { diff --git a/core/llm/math/tgamma.rs b/core/llm/math/tgamma.rs index e64eff6..8cc6e54 100644 --- a/core/llm/math/tgamma.rs +++ b/core/llm/math/tgamma.rs @@ -22,13 +22,15 @@ Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) most ideas and constants are from boost and python */ -extern crate core; + +use crate::{Float64, Float32}; + use super::{exp, floor, k_cos, k_sin, pow}; -const PI: f64 = 3.141592653589793238462643383279502884; +const PI: Float64 = 3.141592653589793238462643383279502884; /* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ -fn sinpi(mut x: f64) -> f64 { +fn sinpi(mut x: Float64) -> Float64 { let mut n: isize; /* argument reduction: x = |x| mod 2 */ @@ -39,7 +41,7 @@ fn sinpi(mut x: f64) -> f64 { /* reduce x into [-.25,.25] */ n = (4.0 * x) as isize; n = div!(n + 1, 2); - x -= (n as f64) * 0.5; + x -= (n as Float64) * 0.5; x *= PI; match n { @@ -52,8 +54,8 @@ fn sinpi(mut x: f64) -> f64 { const N: usize = 12; //static const double g = 6.024680040776729583740234375; -const GMHALF: f64 = 5.524680040776729583740234375; -const SNUM: [f64; N + 1] = [ +const GMHALF: Float64 = 5.524680040776729583740234375; +const SNUM: [Float64; N + 1] = [ 23531376880.410759688572007674451636754734846804940, 42919803642.649098768957899047001988850926355848959, 35711959237.355668049440185451547166705960488635843, @@ -68,7 +70,7 @@ const SNUM: [f64; N + 1] = [ 210.82427775157934587250973392071336271166969580291, 2.5066282746310002701649081771338373386264310793408, ]; -const SDEN: [f64; N + 1] = [ +const SDEN: [Float64; N + 1] = [ 0.0, 39916800.0, 120543840.0, @@ -84,7 +86,7 @@ const SDEN: [f64; N + 1] = [ 1.0, ]; /* n! for small integer n */ -const FACT: [f64; 23] = [ +const FACT: [Float64; 23] = [ 1.0, 1.0, 2.0, @@ -111,9 +113,9 @@ const FACT: [f64; 23] = [ ]; /* S(x) rational function for positive x */ -fn s(x: f64) -> f64 { - let mut num: f64 = 0.0; - let mut den: f64 = 0.0; +fn s(x: Float64) -> Float64 { + let mut num: Float64 = 0.0; + let mut den: Float64 = 0.0; /* to avoid overflow handle large x differently */ if x < 8.0 { @@ -130,14 +132,15 @@ fn s(x: f64) -> f64 { return num / den; } +/// Returns the gamma function of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tgamma(mut x: f64) -> f64 { +pub fn tgamma(mut x: Float64) -> Float64 { let u: u64 = x.to_bits(); - let absx: f64; - let mut y: f64; - let mut dy: f64; - let mut z: f64; - let mut r: f64; + let absx: Float64; + let mut y: Float64; + let mut dy: Float64; + let mut z: Float64; + let mut r: Float64; let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; let sign: bool = (u >> 63) != 0; @@ -157,7 +160,7 @@ pub fn tgamma(mut x: f64) -> f64 { if sign { return 0.0 / 0.0; } - if x <= FACT.len() as f64 { + if x <= FACT.len() as Float64 { return i!(FACT, (x as usize) - 1); } } @@ -167,15 +170,15 @@ pub fn tgamma(mut x: f64) -> f64 { if ix >= 0x40670000 { /* |x| >= 184 */ if sign { - let x1p_126 = f64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 - force_eval!((x1p_126 / x) as f32); + let x1p_126 = Float64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 + force_eval!((x1p_126 / x) as Float32); if floor(x) * 0.5 == floor(x * 0.5) { return 0.0; } else { return -0.0; } } - let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 + let x1p1023 = Float64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 x *= x1p1023; return x; } diff --git a/core/llm/math/tgammaf.rs b/core/llm/math/tgammaf.rs index 23e3814..78c5526 100644 --- a/core/llm/math/tgammaf.rs +++ b/core/llm/math/tgammaf.rs @@ -1,6 +1,9 @@ +use crate::{Float64, Float32}; + use super::tgamma; +/// Returns the gamma function of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn tgammaf(x: f32) -> f32 { - tgamma(x as f64) as f32 +pub fn tgammaf(x: Float32) -> Float32 { + tgamma(x as Float64) as Float32 } diff --git a/core/llm/math/trunc.rs b/core/llm/math/trunc.rs index f7892a2..a3b6a9c 100644 --- a/core/llm/math/trunc.rs +++ b/core/llm/math/trunc.rs @@ -1,16 +1,18 @@ -use core::f64; +use crate::Float64; +/// Returns the integer part of self. +/// This means that non-integer numbers are always truncated towards zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn trunc(x: f64) -> f64 { +pub fn trunc(x: Float64) -> Float64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.trunc` native instruction, so we can leverage this for both code size + // `Float64.trunc` native instruction, so we can leverage this for both code size // and speed. llvm_intrinsically_optimized! { #[cfg(target_arch = "wasm32")] { return unsafe { ::core::intrinsics::truncf64(x) } } } - let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 + let x1p120 = Float64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 let mut i: u64 = x.to_bits(); let mut e: i64 = (i >> 52 & 0x7ff) as i64 - 0x3ff + 12; @@ -28,7 +30,7 @@ pub fn trunc(x: f64) -> f64 { } force_eval!(x + x1p120); i &= !m; - f64::from_bits(i) + Float64::from_bits(i) } #[cfg(test)] diff --git a/core/llm/math/truncf.rs b/core/llm/math/truncf.rs index 20d5b73..7797b4e 100644 --- a/core/llm/math/truncf.rs +++ b/core/llm/math/truncf.rs @@ -1,16 +1,18 @@ -use core::f32; +use crate::Float32; +/// Returns the integer part of self. +/// This means that non-integer numbers are always truncated towards zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf(x: f32) -> f32 { +pub fn truncf(x: Float32) -> Float32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.trunc` native instruction, so we can leverage this for both code size + // `Float32.trunc` native instruction, so we can leverage this for both code size // and speed. llvm_intrinsically_optimized! { #[cfg(target_arch = "wasm32")] { return unsafe { ::core::intrinsics::truncf32(x) } } } - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 let mut i: u32 = x.to_bits(); let mut e: i32 = (i >> 23 & 0xff) as i32 - 0x7f + 9; @@ -28,7 +30,7 @@ pub fn truncf(x: f32) -> f32 { } force_eval!(x + x1p120); i &= !m; - f32::from_bits(i) + Float32::from_bits(i) } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 diff --git a/core/llm/types.rs b/core/llm/types.rs index fde5d99..e59b5ef 100644 --- a/core/llm/types.rs +++ b/core/llm/types.rs @@ -1,14 +1,11 @@ -type __Float64 = f64; -type __Float32 = f32; - -/// Radians -pub type Radian =__Float64; +/// Radians (64bit) +pub type Radian64 = f64; /// Radians (32bit) -pub type Radian32 = __Float32; +pub type Radian32 = f32; -/// A floating point number -pub type Float = __Float64; +/// A floating point number (64bit) +pub type Float64 = f64; /// A floating point number (32bit) -pub type Float32 =__Float32; +pub type Float32 = f32; From 679c4d266d8b1ef78390552014310579d6c78371 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sun, 5 Nov 2023 09:18:28 -0800 Subject: [PATCH 04/93] Kaboom! It trigs --- Cargo.toml | 2 +- EXAMPLE.md | 1 + README.md | 3 + example.rs | 11 ++- libtrig/README.md | 0 libtrig/angle.rs | 161 +++++++++++++++++++++++++++++++---- libtrig/coords/coord2d.rs | 24 +++--- libtrig/main.rs | 4 +- libtrig/odo/config.rs | 39 ++++++--- libtrig/odo/movement_calc.rs | 20 +++-- libtrig/odo/pos/pos2d.rs | 16 ++-- libtrig/traits/float.rs | 85 +++++++++--------- libtrig/traits/mod.rs | 152 +++++++++++---------------------- libtrig/traits/number.rs | 5 +- libtrig/types.rs | 18 ++-- libtrig/vectors/vec2d.rs | 36 ++++---- libtrig/vectors/vec3d.rs | 33 +++---- 17 files changed, 363 insertions(+), 247 deletions(-) create mode 100644 EXAMPLE.md delete mode 100644 libtrig/README.md diff --git a/Cargo.toml b/Cargo.toml index 5b31f3b..2b0d1fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" package = "libtrig-macros" path = "./core/macros" -[dependencies.math] +[dependencies.llm] package = "libtrig-llm" path = "./core/llm" diff --git a/EXAMPLE.md b/EXAMPLE.md new file mode 100644 index 0000000..d218cd3 --- /dev/null +++ b/EXAMPLE.md @@ -0,0 +1 @@ +# Example diff --git a/README.md b/README.md index e69de29..0ee74df 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,3 @@ +# Libtrig + +## A complete trigonometry and odometry library for Rust diff --git a/example.rs b/example.rs index 8aac1a8..5005362 100644 --- a/example.rs +++ b/example.rs @@ -1,3 +1,6 @@ +#![doc = include_str!("./EXAMPLE.md")] +#![doc(hidden)] + use libtrig::odo::*; use libtrig::*; @@ -8,9 +11,9 @@ const CONFIG: OdometryConfig = OdometryConfig::new() .set_ticks_per_revolution(8192.0); struct Robot { - left_encoder: float, - right_encoder: float, - back_encoder: float, + left_encoder: Float64, + right_encoder: Float64, + back_encoder: Float64, odo: Odometry, } @@ -23,7 +26,7 @@ impl Robot { odo: Odometry::new(CONFIG), } } - fn update(&mut self, movement: (float, float, float)) { + fn update(&mut self, movement: (Float64, Float64, Float64)) { self.left_encoder += movement.0; self.right_encoder += movement.1; self.back_encoder += movement.2; diff --git a/libtrig/README.md b/libtrig/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/libtrig/angle.rs b/libtrig/angle.rs index 4ed11c0..719495d 100644 --- a/libtrig/angle.rs +++ b/libtrig/angle.rs @@ -5,25 +5,25 @@ use crate::*; /// It can be created from either radians or degrees, and can be converted to either radians or degrees. #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Angle2D(float, bool); +pub struct Angle2D(RadianOrDegree64, bool); impl Angle2D { /// Creates a new `Angle2D` from the given `value` and `is_radians` flag. #[inline] #[must_use] - pub const fn new(value: float, is_radians: bool) -> Self { + pub const fn new(value: RadianOrDegree64, is_radians: bool) -> Self { Self(value, is_radians) } /// Creates a new `Angle2D` from the given `value` in radians. #[inline] #[must_use] - pub const fn from_radians(value: float) -> Self { + pub const fn from_radians(value: Radian64) -> Self { Self::new(value, true) } /// Creates a new `Angle2D` from the given `value` in degrees. #[inline] #[must_use] - pub const fn from_degrees(value: float) -> Self { + pub const fn from_degrees(value: Degree64) -> Self { Self::new(value, false) } /// Creates a new `Angle2D` with a value of `0.0` radians. @@ -41,7 +41,7 @@ impl Angle2D { /// Returns the value of the angle in radians. #[inline] #[must_use] - pub fn to_radians(&self) -> float { + pub fn to_radians(&self) -> Radian64 { if self.1 { self.0 } else { @@ -51,7 +51,7 @@ impl Angle2D { /// Returns the value of the angle in degrees. #[inline] #[must_use] - pub fn to_degrees(&self) -> float { + pub fn to_degrees(&self) -> Degree64 { if self.1 { self.0.to_degrees() } else { @@ -79,7 +79,7 @@ impl core::ops::Add for THIS { #[macros::mass_impl( $THIS = @ORM Angle2D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::Add for THIS { type Output = Angle2D; @@ -111,7 +111,7 @@ impl core::ops::AddAssign for THIS { #[macros::mass_impl( $THIS = @OM Angle2D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::AddAssign for THIS { #[inline] @@ -143,7 +143,7 @@ impl core::ops::Sub for THIS { #[macros::mass_impl( $THIS = @ORM Angle2D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::Sub for THIS { type Output = Angle2D; @@ -175,7 +175,7 @@ impl core::ops::SubAssign for THIS { #[macros::mass_impl( $THIS = @OM Angle2D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::SubAssign for THIS { #[inline] @@ -190,7 +190,24 @@ impl core::ops::SubAssign for THIS { #[macros::mass_impl( $THIS = @ORM Angle2D, - $OTHER = @OR float + $OTHER = @OR Angle2D +)] +impl core::ops::Mul for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn mul(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() * rhs.to_radians()) + } else { + Angle2D::from_degrees(self.to_degrees() * rhs.to_degrees()) + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR Float64 )] impl core::ops::Mul for THIS { type Output = Angle2D; @@ -207,7 +224,22 @@ impl core::ops::Mul for THIS { #[macros::mass_impl( $THIS = @OM Angle2D, - $OTHER = @OR float + $OTHER = @OR Angle2D +)] +impl core::ops::MulAssign for THIS { + #[inline] + fn mul_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() * rhs.to_radians(); + } else { + self.0 = self.to_degrees() * rhs.to_degrees(); + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Float64 )] impl core::ops::MulAssign for THIS { #[inline] @@ -220,9 +252,26 @@ impl core::ops::MulAssign for THIS { } } +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR Angle2D +)] +impl core::ops::Div for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn div(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() / rhs.to_radians()) + } else { + Angle2D::from_degrees(self.to_degrees() / rhs.to_degrees()) + } + } +} + #[macros::mass_impl( $THIS = @OM Angle2D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::Div for THIS { type Output = Angle2D; @@ -239,7 +288,22 @@ impl core::ops::Div for THIS { #[macros::mass_impl( $THIS = @OM Angle2D, - $OTHER = @OR float + $OTHER = @OR Angle2D +)] +impl core::ops::DivAssign for THIS { + #[inline] + fn div_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() / rhs.to_radians(); + } else { + self.0 = self.to_degrees() / rhs.to_degrees(); + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Float64 )] impl core::ops::DivAssign for THIS { #[inline] @@ -281,9 +345,9 @@ impl core::fmt::Display for Angle2D { } write!(f, "{}°", self.to_degrees()) } -} +} -impl> From<(F, bool)> for Angle2D { +impl> From<(F, bool)> for Angle2D { #[inline] #[must_use] fn from((f, r): (F, bool)) -> Self { @@ -294,3 +358,68 @@ impl> From<(F, bool)> for Angle2D { } } } + +impl crate::traits::Number for Angle2D {} + +macro_rules! i { + ($n:ident $($t:tt)*) => ( + #[inline] + #[must_use] + fn $n(&self) -> Float64 { + self.0.$n() + } + i!($($t)*); + ); + () => (); +} + +impl crate::traits::Float for Angle2D { + #[inline] + #[must_use] + fn mul_add(&self, a: Self, b: Self) -> Float64 { + self.0.mul_add(a.0, b.0) + } + #[inline] + #[must_use] + fn div_euclid(&self, rhs: Self) -> Float64 { + self.0.div_euclid(rhs.0) + } + #[inline] + #[must_use] + fn rem_euclid(&self, rhs: Self) -> Float64 { + self.0.rem_euclid(rhs.0) + } + #[inline] + #[must_use] + fn powi(&self, n: Int) -> Float64 { + self.0.powi(n) + } + #[inline] + #[must_use] + fn powf(&self, n: Self) -> Float64 { + self.0.powf(n.0) + } + #[inline] + #[must_use] + fn log(&self, base: Self) -> Float64 { + self.0.log(base.0) + } + #[inline] + #[must_use] + fn atan2(&self, other: Self) -> Float64 { + self.0.atan2(other.0) + } + #[inline] + #[must_use] + fn hypot(&self, other: Self) -> Float64 { + self.0.hypot(other.0) + } + #[inline] + #[must_use] + fn sin_cos(&self) -> (Float64, Float64) { + self.0.sin_cos() + } + + i!(floor ceil round trunc fract abs signum sqrt exp exp2 ln log2 log10 cbrt + sin cos tan asin acos atan exp_m1 ln_1p sinh cosh tanh asinh acosh atanh); +} diff --git a/libtrig/coords/coord2d.rs b/libtrig/coords/coord2d.rs index 4b8c482..66358bd 100644 --- a/libtrig/coords/coord2d.rs +++ b/libtrig/coords/coord2d.rs @@ -1,4 +1,3 @@ -use crate::traits::Float; use crate::*; /// A wrapper around a `float` value that represents a 2D coordinate. @@ -6,16 +5,16 @@ use crate::*; #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] pub struct Coord2D { /// The x coordinate. - pub x: float, + pub x: Float64, /// The y coordinate. - pub y: float, + pub y: Float64, } impl Coord2D { /// Creates a new `Vec2D` from the given `x` and `y` values. #[inline] #[must_use] - pub const fn new(x: float, y: float) -> Self { + pub const fn new(x: Float64, y: Float64) -> Self { Self { x, y } } /// Creates a new `Vec2D` located at the origin. @@ -25,8 +24,11 @@ impl Coord2D { Self::new(0.0, 0.0) } /// Rotates the vector by the given angle in radians. + #[inline] #[must_use] pub fn rotate_by(&self, angle: Angle2D) -> Self { + #[allow(unused_imports)] + use crate::traits::Float; let angle = angle.to_radians(); let (sin, cos) = angle.sin_cos(); Self::new( @@ -38,6 +40,8 @@ impl Coord2D { #[inline] #[must_use] pub fn angle(&self) -> Angle2D { + #[allow(unused_imports)] + use crate::traits::Float; Angle2D::from_radians(self.y.atan2(self.x)) } /// Returns the inverted position. @@ -152,7 +156,7 @@ impl core::ops::SubAssign for THIS { #[macros::mass_impl( $THIS = @ORM Coord2D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::Mul for THIS { type Output = Coord2D; @@ -178,7 +182,7 @@ impl core::ops::Mul for THIS { #[macros::mass_impl( $THIS = @OM Coord2D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::MulAssign for THIS { #[inline] @@ -202,7 +206,7 @@ impl core::ops::MulAssign for THIS { #[macros::mass_impl( $THIS = @ORM Coord2D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::Div for THIS { type Output = Coord2D; @@ -228,7 +232,7 @@ impl core::ops::Div for THIS { #[macros::mass_impl( $THIS = @OM Coord2D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::DivAssign for THIS { #[inline] @@ -275,7 +279,7 @@ impl Default for Coord2D { } } -impl> From<(F, F)> for Coord2D { +impl> From<(F, F)> for Coord2D { #[inline] #[must_use] fn from((x, y): (F, F)) -> Self { @@ -283,7 +287,7 @@ impl> From<(F, F)> for Coord2D { } } -impl From for (float, float) { +impl From for (Float64, Float64) { #[inline] #[must_use] fn from(Coord2D {x, y}: Coord2D) -> Self { diff --git a/libtrig/main.rs b/libtrig/main.rs index 79761a3..9bc7726 100644 --- a/libtrig/main.rs +++ b/libtrig/main.rs @@ -3,7 +3,7 @@ #![no_std] #![warn(missing_docs, unused, clippy::all)] -#![doc = include_str!("./README.md")] +#![doc = include_str!("../README.md")] pub(crate) mod vectors; pub(crate) mod traits; @@ -12,6 +12,8 @@ pub(crate) mod angle; pub(crate) mod types; pub mod odo; +pub use llm; + pub mod prelude { //! Re-exports all the traits. pub use super::traits::*; diff --git a/libtrig/odo/config.rs b/libtrig/odo/config.rs index 0925b71..a3845d4 100644 --- a/libtrig/odo/config.rs +++ b/libtrig/odo/config.rs @@ -6,17 +6,19 @@ use core::f64::consts::PI; #[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct OdometryConfig { /// The distance between encoder 1 and encoder 2 in centimeters. - pub lateral_wheel_distance: float, + pub lateral_wheel_distance: Float64, /// The distance between the midpoint of encoder 1 and 2 and encoder 3 in centimeters. - pub longitudinal_wheel_distance: float, + pub longitudinal_wheel_distance: Float64, /// The radius of the wheels in centimeters. - pub wheel_radius: float, + pub wheel_radius: Float64, /// The number of ticks per revolution of the encoders. - pub ticks_per_revolution: float, + pub ticks_per_revolution: Float64, } impl OdometryConfig { /// Creates a new `OdometryConfig` with all fields set to `0.0`. + #[inline] + #[must_use] pub const fn new() -> OdometryConfig { OdometryConfig { lateral_wheel_distance: 0.0, @@ -27,25 +29,33 @@ impl OdometryConfig { } /// Modifies `lateral_wheel_distance` and returns `self`. - pub const fn set_lateral_wheel_distance(mut self, lateral_wheel_distance: float) -> Self { + #[inline] + #[must_use] + pub const fn set_lateral_wheel_distance(mut self, lateral_wheel_distance: Float64) -> Self { self.lateral_wheel_distance = lateral_wheel_distance; self } /// Modifies `longitudinal_wheel_distance` and returns `self`. - pub const fn set_longitudinal_wheel_distance(mut self, longitudinal_wheel_distance: float) -> Self { + #[inline] + #[must_use] + pub const fn set_longitudinal_wheel_distance(mut self, longitudinal_wheel_distance: Float64) -> Self { self.longitudinal_wheel_distance = longitudinal_wheel_distance; self } /// Modifies `wheel_radius` and returns `self`. - pub const fn set_wheel_radius(mut self, wheel_radius: float) -> Self { + #[inline] + #[must_use] + pub const fn set_wheel_radius(mut self, wheel_radius: Float64) -> Self { self.wheel_radius = wheel_radius; self } /// Modifies `ticks_per_revolution` and returns `self`. - pub const fn set_ticks_per_revolution(mut self, ticks_per_revolution: float) -> Self { + #[inline] + #[must_use] + pub const fn set_ticks_per_revolution(mut self, ticks_per_revolution: Float64) -> Self { self.ticks_per_revolution = ticks_per_revolution; self } @@ -55,20 +65,25 @@ impl OdometryConfig { #[derive(Debug, Clone, Copy, PartialEq, Default)] pub(crate) struct OdometryFormulaeConfig { /// The distance between encoder 1 and encoder 2 in centimeters. - pub lateral_wheel_distance: float, + pub lateral_wheel_distance: Float64, /// The distance between the midpoint of encoder 1 and 2 and encoder 3 in centimeters. - pub longitudinal_wheel_distance: float, + pub longitudinal_wheel_distance: Float64, /// The number of centimeters per tick. - pub cm_per_tick: float, + pub cm_per_tick: Float64, } impl OdometryFormulaeConfig { - fn cm_per_tick_calc(wheel_radius: float, ticks_per_revolution: float) -> float { + /// Calculates the number of centimeters per tick. + #[inline] + #[must_use] + fn cm_per_tick_calc(wheel_radius: Float64, ticks_per_revolution: Float64) -> Float64 { wheel_radius * 2.0 * PI / ticks_per_revolution } } impl From for OdometryFormulaeConfig { + #[inline] + #[must_use] fn from(config: OdometryConfig) -> Self { Self { lateral_wheel_distance: config.lateral_wheel_distance, diff --git a/libtrig/odo/movement_calc.rs b/libtrig/odo/movement_calc.rs index 2088258..f8fedf5 100644 --- a/libtrig/odo/movement_calc.rs +++ b/libtrig/odo/movement_calc.rs @@ -37,6 +37,8 @@ impl Odometry { /// #[doc = include_str!("./FORMULA.md")] pub fn update(&mut self, movement: Vec3D) { + #[allow(unused_imports)] + use crate::traits::Float; let old_encoder_values = self.encoder_values; self.encoder_values += movement; @@ -49,15 +51,15 @@ impl Odometry { let dx = self.config.cm_per_tick * ((dn1 + dn2) / 2.0); let dy = self.config.cm_per_tick * (dn3 + ( (dn2 - dn1) / 2.0 )); - // pos.h += dtheta / 2; - // pos.x += dx * Math.cos(pos.h) - dy * Math.sin(pos.h); - // pos.y += dx * Math.sin(pos.h) + dy * Math.cos(pos.h); - // pos.h += dtheta / 2; - // pos.h = normDiff(pos.h); - // let new_angle = self.current_position.angle() + (dtheta / 2.0); - // self.current_position.setAngle(new_angle); - // let new_x = dx * new_angle.cos() - dy * new_angle.sin(); - // self.current_position.setX(new_x); + let mut new_angle = self.current_position.angle() + (dtheta / 2.0); + self.current_position.setAngle(new_angle); + let new_x = dx * new_angle.cos() - dy * new_angle.sin(); + let new_y = dx * new_angle.sin() + dy * new_angle.cos(); + self.current_position.setX(new_x); + self.current_position.setY(new_y); + new_angle += dtheta / 2.0; + self.current_position.setAngle(new_angle); + } /// Returns the current position. diff --git a/libtrig/odo/pos/pos2d.rs b/libtrig/odo/pos/pos2d.rs index ad51136..367ca76 100644 --- a/libtrig/odo/pos/pos2d.rs +++ b/libtrig/odo/pos/pos2d.rs @@ -23,27 +23,25 @@ impl Pos2D { /// Returns the x coordinate of the position. #[inline] #[must_use] - pub const fn x(&self) -> float { + pub const fn x(&self) -> Float64 { self.0.x } /// Sets the x coordinate of the position. #[inline] - #[must_use] #[allow(non_snake_case)] - pub const fn setX(&mut self, x: float) { + pub const fn setX(&mut self, x: Float64) { self.0.x = x; } /// Returns the y coordinate of the position. #[inline] #[must_use] - pub const fn y(&self) -> float { + pub const fn y(&self) -> Float64 { self.0.y } /// Sets the y coordinate of the position. #[inline] - #[must_use] #[allow(non_snake_case)] - pub const fn setY(&mut self, y: float) { + pub const fn setY(&mut self, y: Float64) { self.0.y = y; } /// Rotates the position by the given angle in radians. @@ -59,7 +57,6 @@ impl Pos2D { } /// Sets the facing angle. #[inline] - #[must_use] #[allow(non_snake_case)] pub const fn setAngle(&mut self, angle: Angle2D) { self.1 = angle; @@ -301,7 +298,7 @@ impl, A: Into> From<(C, A)> for Pos2D { } } -impl> From<(F, F, F, bool)> for Pos2D { +impl> From<(F, F, F, bool)> for Pos2D { #[inline] #[must_use] fn from(i: (F, F, F, bool)) -> Self { @@ -312,7 +309,8 @@ impl> From<(F, F, F, bool)> for Pos2D { } } -impl> From<(F, F, F)> for Pos2D { +impl> From<(F, F, F)> for Pos2D { + /// Creates a new `Pos2D` from the given `coords` and `angle`. #[inline] #[must_use] fn from(i: (F, F, F)) -> Self { diff --git a/libtrig/traits/float.rs b/libtrig/traits/float.rs index dad8b6a..c918a27 100644 --- a/libtrig/traits/float.rs +++ b/libtrig/traits/float.rs @@ -1,8 +1,8 @@ use super::Number; -use crate::int; +use crate::Int; /// A trait for floating point numbers. -pub trait Float: Number { +pub trait Float: Number { /// Returns the largest integer less than or equal to `self`. /// /// # Examples @@ -17,7 +17,7 @@ pub trait Float: Number { /// assert_eq!(h.floor(), -4.0); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn floor(&self) -> Self; + fn floor(&self) -> Output; /// Returns the smallest integer greater than or equal to `self`. /// @@ -31,7 +31,7 @@ pub trait Float: Number { /// assert_eq!(g.ceil(), 4.0); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn ceil(&self) -> Self; + fn ceil(&self) -> Output; /// Returns the nearest integer to `self`. If a value is half-way between two /// integers, round away from `0.0`. @@ -52,7 +52,7 @@ pub trait Float: Number { /// assert_eq!(j.round(), 5.0); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn round(&self) -> Self; + fn round(&self) -> Output; /// Returns the integer part of `self`. /// This means that non-integer numbers are always truncated towards zero. @@ -69,7 +69,7 @@ pub trait Float: Number { /// assert_eq!(h.trunc(), -3.0); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn trunc(&self) -> Self; + fn trunc(&self) -> Output; /// Returns the fractional part of `self`. /// @@ -84,11 +84,8 @@ pub trait Float: Number { /// assert!(abs_difference_x < 1e-10); /// assert!(abs_difference_y < 1e-10); /// ``` - #[inline] #[must_use = "method returns a new number and does not mutate the original value"] - fn fract(&self) -> Self { - *self - self.trunc() - } + fn fract(&self) -> Output; /// Computes the absolute value of `self`. /// @@ -107,7 +104,7 @@ pub trait Float: Number { /// assert!(f64::NAN.abs().is_nan()); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn abs(&self) -> Self; + fn abs(&self) -> Output; /// Returns a number that represents the sign of `self`. /// @@ -126,7 +123,7 @@ pub trait Float: Number { /// assert!(f64::NAN.signum().is_nan()); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn signum(&self) -> Self; + fn signum(&self) -> Output; /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. @@ -149,7 +146,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn mul_add(&self, a: Self, b: Self) -> Self; + fn mul_add(&self, a: Self, b: Self) -> Output; /// Calculates Euclidean division, the matching method for `rem_euclid`. /// @@ -169,7 +166,7 @@ pub trait Float: Number { /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn div_euclid(&self, rhs: Self) -> Self; + fn div_euclid(&self, rhs: Self) -> Output; /// Calculates the least nonnegative remainder of `self (mod rhs)`. /// @@ -195,7 +192,7 @@ pub trait Float: Number { /// assert!((-f64::EPSILON).rem_euclid(3.0) != 0.0); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn rem_euclid(&self, rhs: Self) -> Self; + fn rem_euclid(&self, rhs: Self) -> Output; /// Raises a number to an integer power. /// @@ -212,7 +209,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn powi(&self, n: int) -> Self; + fn powi(&self, n: Int) -> Output; /// Raises a number to a floating point power. /// @@ -225,7 +222,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn powf(&self, n: Self) -> Self; + fn powf(&self, n: Self) -> Output; /// Returns the square root of a number. /// @@ -245,7 +242,7 @@ pub trait Float: Number { /// assert!(negative_zero.sqrt() == negative_zero); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn sqrt(&self) -> Self; + fn sqrt(&self) -> Output; /// Returns `e^(self)`, (the exponential function). /// @@ -262,7 +259,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn exp(&self) -> Self; + fn exp(&self) -> Output; /// Returns `2^(self)`. /// @@ -277,7 +274,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn exp2(&self) -> Self; + fn exp2(&self) -> Output; /// Returns the natural logarithm of the number. /// @@ -294,7 +291,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn ln(&self) -> Self; + fn ln(&self) -> Output; /// Returns the logarithm of the number with respect to an arbitrary base. /// @@ -313,7 +310,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn log(&self, base: Self) -> Self; + fn log(&self, base: Self) -> Output; /// Returns the base 2 logarithm of the number. /// @@ -328,7 +325,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn log2(&self) -> Self; + fn log2(&self) -> Output; /// Returns the base 10 logarithm of the number. /// @@ -343,7 +340,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn log10(&self) -> Self; + fn log10(&self) -> Output; /// Returns the cube root of a number. /// @@ -358,7 +355,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn cbrt(&self) -> Self; + fn cbrt(&self) -> Output; /// Compute the distance between the origin and a point (`x`, `y`) on the /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a @@ -377,7 +374,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn hypot(&self, other: Self) -> Self; + fn hypot(&self, other: Self) -> Output; /// Computes the sine of a number (in radians). /// @@ -391,7 +388,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn sin(&self) -> Self; + fn sin(&self) -> Output; /// Computes the cosine of a number (in radians). /// @@ -405,7 +402,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn cos(&self) -> Self; + fn cos(&self) -> Output; /// Computes the tangent of a number (in radians). /// @@ -418,7 +415,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-14); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn tan(&self) -> Self; + fn tan(&self) -> Output; /// Computes the arcsine of a number. Return value is in radians in /// the range [-pi/2, pi/2] or NaN if the number is outside the range @@ -435,7 +432,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn asin(&self) -> Self; + fn asin(&self) -> Output; /// Computes the arccosine of a number. Return value is in radians in /// the range [0, pi] or NaN if the number is outside the range @@ -452,7 +449,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn acos(&self) -> Self; + fn acos(&self) -> Output; /// Computes the arctangent of a number. Return value is in radians in the /// range [-pi/2, pi/2]; @@ -468,7 +465,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn atan(&self) -> Self; + fn atan(&self) -> Output; /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. /// @@ -497,7 +494,7 @@ pub trait Float: Number { /// assert!(abs_difference_2 < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn atan2(&self, other: Self) -> Self; + fn atan2(&self, other: Self) -> Output; /// Simultaneously computes the sine and cosine of the number, `x`. Returns /// `(sin(x), cos(x))`. @@ -514,7 +511,11 @@ pub trait Float: Number { /// assert!(abs_difference_0 < 1e-10); /// assert!(abs_difference_1 < 1e-10); /// ``` - fn sin_cos(&self) -> (Self, Self); + #[inline] + #[must_use = "method returns new numbers and does not mutate the original value"] + fn sin_cos(&self) -> (Output, Output) { + (self.sin(), self.cos()) + } /// Returns `e^(self) - 1` in a way that is accurate even if the /// number is close to zero. @@ -531,7 +532,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-20); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn exp_m1(&self) -> Self; + fn exp_m1(&self) -> Output; /// Returns `ln(1+n)` (natural logarithm) more accurately than if /// the operations were performed separately. @@ -548,7 +549,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-20); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn ln_1p(&self) -> Self; + fn ln_1p(&self) -> Output; /// Hyperbolic sine function. /// @@ -566,7 +567,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn sinh(&self) -> Self; + fn sinh(&self) -> Output; /// Hyperbolic cosine function. /// @@ -584,7 +585,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1.0e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn cosh(&self) -> Self; + fn cosh(&self) -> Output; /// Hyperbolic tangent function. /// @@ -602,7 +603,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1.0e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn tanh(&self) -> Self; + fn tanh(&self) -> Output; /// Inverse hyperbolic sine function. /// @@ -617,7 +618,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1.0e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn asinh(&self) -> Self; + fn asinh(&self) -> Output; /// Inverse hyperbolic cosine function. /// @@ -632,7 +633,7 @@ pub trait Float: Number { /// assert!(abs_difference < 1.0e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn acosh(&self) -> Self; + fn acosh(&self) -> Output; /// Inverse hyperbolic tangent function. /// @@ -647,5 +648,5 @@ pub trait Float: Number { /// assert!(abs_difference < 1.0e-10); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] - fn atanh(&self) -> Self; + fn atanh(&self) -> Output; } diff --git a/libtrig/traits/mod.rs b/libtrig/traits/mod.rs index 8ac1551..041f127 100644 --- a/libtrig/traits/mod.rs +++ b/libtrig/traits/mod.rs @@ -7,131 +7,77 @@ pub use number::Number; pub use float::Float; macro_rules! simpl { - ($n:ident => $m:ident $($o:tt)*) => ( + ($n:ident => $m:ident $($t:tt)*) => ( #[inline] #[must_use] fn $n(&self) -> Self { - math::$m(*self) + llm::$m(*self) } - simpl!($($o)*); - ); - ($n:ident $($o:tt)*) => ( - simpl!($n => $n $($o)*); + simpl!($($t)*); ); + ($n:ident $($t:tt)*) => (simpl!($n => $n $($t)*);); () => (); } -impl Float for crate::float { - fn signum(&self) -> Self { - todo!() - } - +#[allow(unused)] +impl Float for Float64 { + simpl!(floor ceil round trunc abs => fabs sqrt exp exp2 ln log2 log10 cbrt + sin cos tan asin acos atan exp_m1 => expm1 ln_1p => log1p + sinh cosh tanh asinh acosh atanh); + #[inline] + #[must_use] fn mul_add(&self, a: Self, b: Self) -> Self { - todo!() + llm::fma(*self, a, b) } - + #[inline] + #[must_use] fn div_euclid(&self, rhs: Self) -> Self { - todo!() + todo!("div_euclid") } - + #[inline] + #[must_use] fn rem_euclid(&self, rhs: Self) -> Self { - todo!() + todo!("rem_euclid") } - - fn powi(&self, n: int) -> Self { - todo!() + #[inline] + #[must_use] + fn signum(&self) -> Self { + if *self > 0.0 { + 1.0 + } else if *self < 0.0 { + -1.0 + } else { + Float64::NAN + } } - - fn powf(&self, n: Self) -> Self { - todo!() + #[inline] + #[must_use] + fn powi(&self, n: Int) -> Self { + llm::pow(*self, n as Float64) } - simpl!(floor ceil round trunc abs => fabs sqrt exp exp2); - - fn ln(&self) -> Self { - todo!() + #[inline] + #[must_use] + fn powf(&self, n: Self) -> Self { + llm::pow(*self, n) } - + #[inline] + #[must_use] fn log(&self, base: Self) -> Self { - todo!() - } - - fn log2(&self) -> Self { - todo!() - } - - fn log10(&self) -> Self { - todo!() - } - - fn cbrt(&self) -> Self { - todo!() + llm::log(*self) / llm::log(base) } - + #[inline] + #[must_use] fn hypot(&self, other: Self) -> Self { - todo!() - } - - fn sin(&self) -> Self { - todo!() + llm::hypot(*self, other) } - - fn cos(&self) -> Self { - todo!() - } - - fn tan(&self) -> Self { - todo!() - } - - fn asin(&self) -> Self { - todo!() - } - - fn acos(&self) -> Self { - todo!() - } - - fn atan(&self) -> Self { - todo!() - } - + #[inline] + #[must_use] fn atan2(&self, other: Self) -> Self { - todo!() - } - - fn sin_cos(&self) -> (Self, Self) { - todo!() + llm::atan2(*self, other) } - - fn exp_m1(&self) -> Self { - todo!() - } - - fn ln_1p(&self) -> Self { - todo!() - } - - fn sinh(&self) -> Self { - todo!() - } - - fn cosh(&self) -> Self { - todo!() - } - - fn tanh(&self) -> Self { - todo!() - } - - fn asinh(&self) -> Self { - todo!() - } - - fn acosh(&self) -> Self { - todo!() - } - - fn atanh(&self) -> Self { - todo!() + #[inline] + #[must_use] + fn fract(&self) -> Self { + *self - self.floor() } } \ No newline at end of file diff --git a/libtrig/traits/number.rs b/libtrig/traits/number.rs index 4c3775d..36de71b 100644 --- a/libtrig/traits/number.rs +++ b/libtrig/traits/number.rs @@ -7,8 +7,7 @@ pub trait Number: ops::Sub + ops::SubAssign + ops::Mul + ops::MulAssign + ops::Div + ops::DivAssign + - ops::Rem + ops::RemAssign + { } -impl Number for crate::int { } -impl Number for crate::float { } +impl Number for crate::Int { } +impl Number for crate::Float64 { } diff --git a/libtrig/types.rs b/libtrig/types.rs index e3c78fb..71e2971 100644 --- a/libtrig/types.rs +++ b/libtrig/types.rs @@ -1,10 +1,16 @@ -#![allow(non_camel_case_types)] +pub use llm::{Float64, Float32, Radian64, Radian32}; -type __float = f64; -type __int = i32; +/// A degree. (64bit) +pub type Degree64 = f64; -/// A floating point number. -pub type float = __float; +/// A degree. (32bit) +pub type Degree32 = f32; /// An integer. -pub type int = __int; +pub type Int = i32; + +/// A radian or degree. (64bit) +pub type RadianOrDegree64 = Float64; + +/// A radian or degree. (32bit) +pub type RadianOrDegree32 = Float32; diff --git a/libtrig/vectors/vec2d.rs b/libtrig/vectors/vec2d.rs index 90b95da..8dc3248 100644 --- a/libtrig/vectors/vec2d.rs +++ b/libtrig/vectors/vec2d.rs @@ -1,16 +1,15 @@ -use crate::traits::Float; use crate::*; /// A 2D vector. #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Vec2D(float, float); +pub struct Vec2D(Float64, Float64); impl Vec2D { /// Creates a new `Vec2D` from the given `x` and `y` values. #[inline] #[must_use] - pub const fn new(x: float, y: float) -> Self { + pub const fn new(x: Float64, y: Float64) -> Self { Self(x, y) } /// Creates a new `Vec2D` located at the origin. @@ -22,18 +21,21 @@ impl Vec2D { /// Returns the x component of the vector. #[inline] #[must_use] - pub const fn x(&self) -> float { + pub const fn x(&self) -> Float64 { self.0 } /// Returns the y component of the vector. #[inline] #[must_use] - pub const fn y(&self) -> float { + pub const fn y(&self) -> Float64 { self.1 } /// Rotates the vector by the given angle in radians. + #[inline] #[must_use] pub fn rotate_by(&self, angle: Angle2D) -> Self { + #[allow(unused_imports)] + use crate::traits::Float; let angle = angle.to_radians(); let (sin, cos) = angle.sin_cos(); Self( @@ -45,6 +47,8 @@ impl Vec2D { #[inline] #[must_use] pub fn angle(&self) -> Angle2D { + #[allow(unused_imports)] + use crate::traits::Float; Angle2D::from_radians(self.y().atan2(self.x())) } /// Returns the inverted vector. @@ -58,13 +62,15 @@ impl Vec2D { /// Returns the dot product of the vector and the given vector. #[inline] #[must_use] - pub fn dot(&self, other: Self) -> float { + pub fn dot(&self, other: Self) -> Float64 { self.x() * other.x() + self.y() * other.y() } /// Returns the magnitude of the vector. #[inline] #[must_use] - pub fn magnitude(&self) -> float { + pub fn magnitude(&self) -> Float64 { + #[allow(unused_imports)] + use crate::traits::Float; self.dot(*self).sqrt() } /// Normalizes this vector. @@ -129,7 +135,7 @@ impl core::ops::SubAssign for THIS { #[macros::mass_impl( $THIS = @ORM Vec2D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::Mul for THIS { type Output = Vec2D; @@ -142,7 +148,7 @@ impl core::ops::Mul for THIS { #[macros::mass_impl( $THIS = @OM Vec2D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::MulAssign for THIS { #[inline] @@ -154,7 +160,7 @@ impl core::ops::MulAssign for THIS { #[macros::mass_impl( $THIS = @ORM Vec2D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::Div for THIS { type Output = Vec2D; @@ -167,7 +173,7 @@ impl core::ops::Div for THIS { #[macros::mass_impl( $THIS = @OM Vec2D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::DivAssign for THIS { #[inline] @@ -202,15 +208,15 @@ impl Default for Vec2D { } } -impl From<(float, float)> for Vec2D { +impl> From<(F, F)> for Vec2D { #[inline] #[must_use] - fn from((x, y): (float, float)) -> Self { - Self::new(x, y) + fn from((x, y): (F, F)) -> Self { + Self::new(x.into(), y.into()) } } -impl From for (float, float) { +impl From for (Float64, Float64) { #[inline] #[must_use] fn from(Vec2D(x, y): Vec2D) -> Self { diff --git a/libtrig/vectors/vec3d.rs b/libtrig/vectors/vec3d.rs index 101dcc1..3abfdd5 100644 --- a/libtrig/vectors/vec3d.rs +++ b/libtrig/vectors/vec3d.rs @@ -1,16 +1,15 @@ -use crate::traits::Float; use crate::*; /// A 3D vector. #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Vec3D(float, float, float); +pub struct Vec3D(Float64, Float64, Float64); impl Vec3D { /// Creates a new `Vec3D` from the given `x`, `y` and `z` values. #[inline] #[must_use] - pub const fn new(x: float, y: float, z: float) -> Self { + pub const fn new(x: Float64, y: Float64, z: Float64) -> Self { Self(x, y, z) } /// Creates a new `Vec3D` located at the origin. @@ -22,19 +21,19 @@ impl Vec3D { /// Returns the x component of the vector. #[inline] #[must_use] - pub const fn x(&self) -> float { + pub const fn x(&self) -> Float64 { self.0 } /// Returns the y component of the vector. #[inline] #[must_use] - pub const fn y(&self) -> float { + pub const fn y(&self) -> Float64 { self.1 } /// Returns the z component of the vector. #[inline] #[must_use] - pub const fn z(&self) -> float { + pub const fn z(&self) -> Float64 { self.2 } /// Returns the inverted vector. @@ -46,13 +45,15 @@ impl Vec3D { /// Returns the dot product of the vector and the given vector. #[inline] #[must_use] - pub fn dot(&self, other: Self) -> float { + pub fn dot(&self, other: Self) -> Float64 { self.x() * other.x() + self.y() * other.y() + self.z() * other.z() } /// Returns the magnitude of the vector. #[inline] #[must_use] - pub fn magnitude(&self) -> float { + pub fn magnitude(&self) -> Float64 { + #[allow(unused_imports)] + use crate::traits::Float; self.dot(*self).sqrt() } /// Normalizes this vector. @@ -132,7 +133,7 @@ impl core::ops::SubAssign for THIS { #[macros::mass_impl( $THIS = @ORM Vec3D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::Mul for THIS { type Output = Vec3D; @@ -145,7 +146,7 @@ impl core::ops::Mul for THIS { #[macros::mass_impl( $THIS = @OM Vec3D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::MulAssign for THIS { #[inline] @@ -158,7 +159,7 @@ impl core::ops::MulAssign for THIS { #[macros::mass_impl( $THIS = @ORM Vec3D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::Div for THIS { type Output = Vec3D; @@ -171,7 +172,7 @@ impl core::ops::Div for THIS { #[macros::mass_impl( $THIS = @OM Vec3D, - $OTHER = @OR float + $OTHER = @OR Float64 )] impl core::ops::DivAssign for THIS { #[inline] @@ -207,15 +208,15 @@ impl Default for Vec3D { } } -impl From<(float, float, float)> for Vec3D { +impl> From<(F, F, F)> for Vec3D { #[inline] #[must_use] - fn from((x, y, z): (float, float, float)) -> Self { - Self::new(x, y, z) + fn from((x, y, z): (F, F, F)) -> Self { + Self::new(x.into(), y.into(), z.into()) } } -impl From for (float, float, float) { +impl From for (Float64, Float64, Float64) { #[inline] #[must_use] fn from(Vec3D(x, y, z): Vec3D) -> Self { From a23007e48e3b85abf5449cf1288953029c2b27cd Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sun, 5 Nov 2023 11:52:09 -0800 Subject: [PATCH 05/93] Fixed Tests --- core/llm/math/atan.rs | 20 ++++++++++---------- core/llm/math/ceil.rs | 2 +- core/llm/math/ceilf.rs | 2 +- core/llm/math/fabs.rs | 2 +- core/llm/math/fabsf.rs | 2 +- core/llm/math/floor.rs | 2 +- core/llm/math/floorf.rs | 2 +- core/llm/math/fmaf.rs | 8 ++++---- core/llm/math/pow.rs | 5 +++-- core/llm/math/sincos.rs | 5 +++-- core/llm/math/sincosf.rs | 5 +++-- 11 files changed, 29 insertions(+), 26 deletions(-) diff --git a/core/llm/math/atan.rs b/core/llm/math/atan.rs index c0ce6a5..67fb79e 100644 --- a/core/llm/math/atan.rs +++ b/core/llm/math/atan.rs @@ -140,17 +140,17 @@ pub fn atan(x: Float64) -> Radian64 { #[cfg(test)] mod tests { use super::atan; - use core::Float64; + use core::f64; #[test] fn sanity_check() { for (input, answer) in [ - (3.0_f64.sqrt() / 3.0, Float64::consts::FRAC_PI_6), - (1.0, Float64::consts::FRAC_PI_4), - (3.0_f64.sqrt(), Float64::consts::FRAC_PI_3), - (-3.0_f64.sqrt() / 3.0, -Float64::consts::FRAC_PI_6), - (-1.0, -Float64::consts::FRAC_PI_4), - (-3.0_f64.sqrt(), -Float64::consts::FRAC_PI_3), + (3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6), + (1.0, f64::consts::FRAC_PI_4), + (3.0_f64.sqrt(), f64::consts::FRAC_PI_3), + (-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6), + (-1.0, -f64::consts::FRAC_PI_4), + (-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3), ] .iter() { @@ -171,16 +171,16 @@ mod tests { #[test] fn infinity() { - assert_eq!(atan(Float64::INFINITY), Float64::consts::FRAC_PI_2); + assert_eq!(atan(f64::INFINITY), f64::consts::FRAC_PI_2); } #[test] fn minus_infinity() { - assert_eq!(atan(Float64::NEG_INFINITY), -Float64::consts::FRAC_PI_2); + assert_eq!(atan(f64::NEG_INFINITY), -f64::consts::FRAC_PI_2); } #[test] fn nan() { - assert!(atan(Float64::NAN).is_nan()); + assert!(atan(f64::NAN).is_nan()); } } diff --git a/core/llm/math/ceil.rs b/core/llm/math/ceil.rs index 8860e43..02dd057 100644 --- a/core/llm/math/ceil.rs +++ b/core/llm/math/ceil.rs @@ -63,7 +63,7 @@ pub fn ceil(x: Float64) -> Float64 { #[cfg(test)] mod tests { use super::*; - use core::Float64::*; + use core::f64::*; #[test] fn sanity_check() { diff --git a/core/llm/math/ceilf.rs b/core/llm/math/ceilf.rs index 677ccf9..e78d3ad 100644 --- a/core/llm/math/ceilf.rs +++ b/core/llm/math/ceilf.rs @@ -45,7 +45,7 @@ pub fn ceilf(x: Float32) -> Float32 { #[cfg(test)] mod tests { use super::*; - use core::Float32::*; + use core::f32::*; #[test] fn sanity_check() { diff --git a/core/llm/math/fabs.rs b/core/llm/math/fabs.rs index 151bf7d..1c438d2 100644 --- a/core/llm/math/fabs.rs +++ b/core/llm/math/fabs.rs @@ -22,7 +22,7 @@ pub fn fabs(x: Float64) -> Float64 { #[cfg(test)] mod tests { use super::*; - use core::Float64::*; + use core::f64::*; #[test] fn sanity_check() { diff --git a/core/llm/math/fabsf.rs b/core/llm/math/fabsf.rs index 90fcb02..17f3b79 100644 --- a/core/llm/math/fabsf.rs +++ b/core/llm/math/fabsf.rs @@ -22,7 +22,7 @@ pub fn fabsf(x: Float32) -> Float32 { #[cfg(test)] mod tests { use super::*; - use core::Float32::*; + use core::f32::*; #[test] fn sanity_check() { diff --git a/core/llm/math/floor.rs b/core/llm/math/floor.rs index 21df353..8e7c2bd 100644 --- a/core/llm/math/floor.rs +++ b/core/llm/math/floor.rs @@ -62,7 +62,7 @@ pub fn floor(x: Float64) -> Float64 { #[cfg(test)] mod tests { use super::*; - use core::Float64::*; + use core::f64::*; #[test] fn sanity_check() { diff --git a/core/llm/math/floorf.rs b/core/llm/math/floorf.rs index 8f59611..93cb1f4 100644 --- a/core/llm/math/floorf.rs +++ b/core/llm/math/floorf.rs @@ -45,7 +45,7 @@ pub fn floorf(x: Float32) -> Float32 { #[cfg(test)] mod tests { use super::*; - use core::Float32::*; + use core::f32::*; #[test] fn sanity_check() { diff --git a/core/llm/math/fmaf.rs b/core/llm/math/fmaf.rs index 8fc5578..f20dbec 100644 --- a/core/llm/math/fmaf.rs +++ b/core/llm/math/fmaf.rs @@ -107,10 +107,10 @@ pub fn fmaf(x: Float32, y: Float32, mut z: Float32) -> Float32 { mod tests { #[test] fn issue_263() { - let a = Float32::from_bits(1266679807); - let b = Float32::from_bits(1300234242); - let c = Float32::from_bits(1115553792); - let expected = Float32::from_bits(1501560833); + let a = f32::from_bits(1266679807); + let b = f32::from_bits(1300234242); + let c = f32::from_bits(1115553792); + let expected = f32::from_bits(1501560833); assert_eq!(super::fmaf(a, b, c), expected); } } diff --git a/core/llm/math/pow.rs b/core/llm/math/pow.rs index a4267cd..cfc8f39 100644 --- a/core/llm/math/pow.rs +++ b/core/llm/math/pow.rs @@ -415,9 +415,10 @@ pub fn pow(x: Float64, y: Float64) -> Float64 { #[cfg(test)] mod tests { extern crate core; + use super::Float64; - use self::core::Float64::consts::{E, PI}; - use self::core::Float64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; + use self::core::f64::consts::{E, PI}; + use self::core::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; use super::pow; const POS_ZERO: &[Float64] = &[0.0]; diff --git a/core/llm/math/sincos.rs b/core/llm/math/sincos.rs index 75bfe63..b57c505 100644 --- a/core/llm/math/sincos.rs +++ b/core/llm/math/sincos.rs @@ -66,12 +66,13 @@ pub fn sincos(x: Radian64) -> (Float64, Float64) { #[cfg(test)] mod tests { use super::sincos; + use super::Float64; const TOLERANCE: Float64 = 1e-6; #[test] fn with_pi() { - let (s, c) = sincos(core::Float64::consts::PI); + let (s, c) = sincos(core::f64::consts::PI); assert!( (s - 0.0).abs() < TOLERANCE, "|{} - {}| = {} >= {}", @@ -92,7 +93,7 @@ mod tests { #[test] fn rotational_symmetry() { - use core::Float64::consts::PI; + use core::f64::consts::PI; const N: usize = 24; for n in 0..N { let theta = 2. * PI * (n as Float64) / (N as Float64); diff --git a/core/llm/math/sincosf.rs b/core/llm/math/sincosf.rs index 3bf3719..3880d5d 100644 --- a/core/llm/math/sincosf.rs +++ b/core/llm/math/sincosf.rs @@ -131,18 +131,19 @@ pub fn sincosf(x: Radian32) -> (Float32, Float32) { #[cfg(test)] mod tests { use super::sincosf; + use super::Float32; use crate::_eqf; #[test] fn with_pi() { - let (s, c) = sincosf(core::Float32::consts::PI); + let (s, c) = sincosf(core::f32::consts::PI); _eqf(s.abs(), 0.0).unwrap(); _eqf(c, -1.0).unwrap(); } #[test] fn rotational_symmetry() { - use core::Float32::consts::PI; + use core::f32::consts::PI; const N: usize = 24; for n in 0..N { let theta = 2. * PI * (n as Float32) / (N as Float32); From 94e59d94092872b397f3bc83475a77c358f3ef94 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sun, 5 Nov 2023 11:52:22 -0800 Subject: [PATCH 06/93] Finally, Odometry works! --- Cargo.toml | 11 +++++--- EXAMPLE.md | 1 - example.rs | 47 ------------------------------- example/Cargo.toml | 11 ++++++++ example/example.rs | 36 ++++++++++++++++++++++++ libtrig/odo/movement_calc.rs | 54 +++++++++++++++++++++++++----------- libtrig/odo/pos/pos2d.rs | 2 +- libtrig/vectors/vec3d.rs | 1 + 8 files changed, 94 insertions(+), 69 deletions(-) delete mode 100644 EXAMPLE.md delete mode 100644 example.rs create mode 100644 example/Cargo.toml create mode 100644 example/example.rs diff --git a/Cargo.toml b/Cargo.toml index 2b0d1fb..c37131c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,10 @@ +[workspace] +members = [ + "core/llm", + "core/macros", + "example" +] + [package] name = "libtrig" version = "0.1.0" @@ -13,7 +20,3 @@ path = "./core/llm" [lib] path = "./libtrig/main.rs" - -[[bin]] -path = "./example.rs" -name = "example" diff --git a/EXAMPLE.md b/EXAMPLE.md deleted file mode 100644 index d218cd3..0000000 --- a/EXAMPLE.md +++ /dev/null @@ -1 +0,0 @@ -# Example diff --git a/example.rs b/example.rs deleted file mode 100644 index 5005362..0000000 --- a/example.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![doc = include_str!("./EXAMPLE.md")] -#![doc(hidden)] - -use libtrig::odo::*; -use libtrig::*; - -const CONFIG: OdometryConfig = OdometryConfig::new() - .set_lateral_wheel_distance(20.12) - .set_longitudinal_wheel_distance(11.5) - .set_wheel_radius(3.0) - .set_ticks_per_revolution(8192.0); - -struct Robot { - left_encoder: Float64, - right_encoder: Float64, - back_encoder: Float64, - - odo: Odometry, -} - -impl Robot { - fn new() -> Self { Self { - left_encoder: 0.0, - right_encoder: 0.0, - back_encoder: 0.0, - - odo: Odometry::new(CONFIG), - } } - fn update(&mut self, movement: (Float64, Float64, Float64)) { - self.left_encoder += movement.0; - self.right_encoder += movement.1; - self.back_encoder += movement.2; - - self.odo.update(Vec3D::new( - self.left_encoder, self.right_encoder, self.back_encoder - )); - } -} - -fn main() { - let mut robot = Robot::new(); - robot.odo.setCurrentPositionToOrigin(); - - robot.update((10.0, 10.0, 0.0)); - - println!("{}", robot.odo.current_position()); -} \ No newline at end of file diff --git a/example/Cargo.toml b/example/Cargo.toml new file mode 100644 index 0000000..e5e2517 --- /dev/null +++ b/example/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "example" +version = "0.1.0" +edition = "2021" + +[dependencies.libtrig] +path = ".." + +[[bin]] +path = "./example.rs" +name = "example" diff --git a/example/example.rs b/example/example.rs new file mode 100644 index 0000000..e9c72e9 --- /dev/null +++ b/example/example.rs @@ -0,0 +1,36 @@ +use libtrig::odo::*; +use libtrig::*; + +const CONFIG: OdometryConfig = OdometryConfig::new() + .set_lateral_wheel_distance(10.0) + .set_longitudinal_wheel_distance(10.0) + .set_wheel_radius(1.0) + .set_ticks_per_revolution(100.0); + +#[derive(Debug)] +struct Robot(Odometry); + +impl Robot { + fn init() -> Self { + let mut robot = Self(Odometry::new(CONFIG)); + robot.0.reset(); + robot + } + fn update(&mut self, movement: (Float64, Float64, Float64)) { + self.0.update(Vec3D::from(movement)); + } +} + +fn main() { + let mut robot = Robot::init(); + + let mut mv = |x: Float64, y: Float64, theta: Float64| { + println!("Movement: ({}, {}, {})", x, y, theta); + robot.update((x, y, theta)); + println!("Pos: {}", robot.0.current_position()); + }; + + mv(10.0, 10.0, 0.0); + mv(100.0, 100.0, 0.0); + mv(200.0, 000.0, 100.0); +} diff --git a/libtrig/odo/movement_calc.rs b/libtrig/odo/movement_calc.rs index f8fedf5..bed57bb 100644 --- a/libtrig/odo/movement_calc.rs +++ b/libtrig/odo/movement_calc.rs @@ -1,5 +1,7 @@ use crate::*; +use super::Pos2D; + /// Odometry calculations. #[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct Odometry { @@ -26,40 +28,60 @@ impl Odometry { self.current_position = coords.into(); } - /// Forces the current position to be set to the origin. (0, 0, 0) + /// Forces the current encoder values to be set to the given `values`. + #[inline] + #[allow(non_snake_case)] + pub fn setEncoderValues(&mut self, values: impl Into) { + self.encoder_values = values.into(); + } + + /// Resets the current position and encoder values to the origin. #[inline] #[allow(non_snake_case)] - pub fn setCurrentPositionToOrigin(&mut self) { - self.current_position = odo::Pos2D::origin(); + pub fn reset(&mut self) { + self.setCurrentPosition(Pos2D::origin()); + self.setEncoderValues(Vec3D::origin()); } - /// Updates the current position, with the provided 3D vector + /// Updates the current position + /// + /// Where the `movement` is a `Vec3D` of the raw encoder values. + /// **NOT THE DELTA ENCODER VALUES.** /// #[doc = include_str!("./FORMULA.md")] - pub fn update(&mut self, movement: Vec3D) { - #[allow(unused_imports)] + pub fn update>(&mut self, encoder_values: V) { + // Import the `Float` trait. (Needed for the `cos` and `sin` methods.) use crate::traits::Float; - let old_encoder_values = self.encoder_values; - self.encoder_values += movement; + // Converts the encoder values into a `Vec3D`. + let encoder_values: Vec3D = encoder_values.into(); - let dn1 = self.encoder_values.x() - old_encoder_values.x(); - let dn2 = self.encoder_values.y() - old_encoder_values.y(); - let dn3 = self.encoder_values.z() - old_encoder_values.z(); + // Calculates the delta encoder values. + let dn1 = encoder_values.x() - self.encoder_values.x(); + let dn2 = encoder_values.y() - self.encoder_values.y(); + let dn3 = encoder_values.z() - self.encoder_values.z(); + // Updates the encoder values. + self.encoder_values = encoder_values; + + // Calculates the delta x, y, and theta. let dtheta = self.config.cm_per_tick * ((dn1 - dn2) / self.config.lateral_wheel_distance); let dx = self.config.cm_per_tick * ((dn1 + dn2) / 2.0); let dy = self.config.cm_per_tick * (dn3 + ( (dn2 - dn1) / 2.0 )); + // Updates the current angle by first partition let mut new_angle = self.current_position.angle() + (dtheta / 2.0); self.current_position.setAngle(new_angle); - let new_x = dx * new_angle.cos() - dy * new_angle.sin(); - let new_y = dx * new_angle.sin() + dy * new_angle.cos(); - self.current_position.setX(new_x); - self.current_position.setY(new_y); + + // Updates the current x and y + let x_incr = dx * new_angle.cos() - dy * new_angle.sin(); + let y_incr = dx * new_angle.sin() + dy * new_angle.cos(); + self.current_position.setX(self.current_position.x() + x_incr); + self.current_position.setY(self.current_position.y() + y_incr); + + // Updates the current angle by second partition new_angle += dtheta / 2.0; self.current_position.setAngle(new_angle); - } /// Returns the current position. diff --git a/libtrig/odo/pos/pos2d.rs b/libtrig/odo/pos/pos2d.rs index 367ca76..17120d1 100644 --- a/libtrig/odo/pos/pos2d.rs +++ b/libtrig/odo/pos/pos2d.rs @@ -278,7 +278,7 @@ impl core::ops::Neg for THIS { impl core::fmt::Display for Pos2D { #[inline] fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}; {}", self.0, self.1) + write!(f, "({:.3}, {:.3}) {:.1}°", self.0.x, self.0.y, self.1.to_degrees()) } } diff --git a/libtrig/vectors/vec3d.rs b/libtrig/vectors/vec3d.rs index 3abfdd5..fe41dd5 100644 --- a/libtrig/vectors/vec3d.rs +++ b/libtrig/vectors/vec3d.rs @@ -211,6 +211,7 @@ impl Default for Vec3D { impl> From<(F, F, F)> for Vec3D { #[inline] #[must_use] + /// Converts a tuple of 3 Floats into a `Vec3D`. fn from((x, y, z): (F, F, F)) -> Self { Self::new(x.into(), y.into(), z.into()) } From a96b76cd0c3ae2ecd9874fc6fbc05d61b2c44b46 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sun, 5 Nov 2023 15:21:34 -0800 Subject: [PATCH 07/93] Minor Fix --- libtrig/odo/FORMULA.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libtrig/odo/FORMULA.md b/libtrig/odo/FORMULA.md index afcb42d..ca92db0 100644 --- a/libtrig/odo/FORMULA.md +++ b/libtrig/odo/FORMULA.md @@ -42,7 +42,7 @@ Forward Movement Update: The change in forward position (Δy) can be calculated using the average encoder counts from the two parallel dead wheels: ```rust,ignore,no_run - Δy = (FLCount + FRCount + ICount) * DCForward / 2 + Δy = (FLCount + FRCount) * DCForward / 2 ``` Updating Orientation: The change in orientation (Δθ) @@ -50,7 +50,7 @@ can be calculated using the difference in encoder counts between the front-left The distance between these wheels is known as the "track width" (W): ```rust,ignore,no_run - Δθ = (FLCount - FRCount + ICount) * DCAngle / 2 + Δθ = (FLCount - FRCount) * DCAngle / W ``` Combining Updates: From 46a661713e2e328dd68c3a864349e11195fb813f Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 14:18:44 -0800 Subject: [PATCH 08/93] moving Odometry to new library --- Cargo.toml | 5 +- core/llm/Cargo.toml | 2 +- core/llm/math.rs | 289 +++---------------------------- example/Cargo.toml | 11 -- example/example.rs | 36 ---- libtrig/{main.rs => lib.rs} | 1 - libtrig/odo/FORMULA.md | 64 ------- libtrig/odo/config.rs | 94 ----------- libtrig/odo/mod.rs | 11 -- libtrig/odo/movement_calc.rs | 93 ---------- libtrig/odo/pos/mod.rs | 3 - libtrig/odo/pos/pos2d.rs | 319 ----------------------------------- 12 files changed, 31 insertions(+), 897 deletions(-) delete mode 100644 example/Cargo.toml delete mode 100644 example/example.rs rename libtrig/{main.rs => lib.rs} (91%) delete mode 100644 libtrig/odo/FORMULA.md delete mode 100644 libtrig/odo/config.rs delete mode 100644 libtrig/odo/mod.rs delete mode 100644 libtrig/odo/movement_calc.rs delete mode 100644 libtrig/odo/pos/mod.rs delete mode 100644 libtrig/odo/pos/pos2d.rs diff --git a/Cargo.toml b/Cargo.toml index c37131c..4accd25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,7 @@ [workspace] members = [ "core/llm", - "core/macros", - "example" + "core/macros" ] [package] @@ -19,4 +18,4 @@ package = "libtrig-llm" path = "./core/llm" [lib] -path = "./libtrig/main.rs" +path = "./libtrig/lib.rs" diff --git a/core/llm/Cargo.toml b/core/llm/Cargo.toml index 58d6958..5d37b65 100644 --- a/core/llm/Cargo.toml +++ b/core/llm/Cargo.toml @@ -11,5 +11,5 @@ package = "libtrig-macros" path = "../macros" [features] -default = ["unstable"] +# default = ["unstable"] unstable = [] diff --git a/core/llm/math.rs b/core/llm/math.rs index 34ac60b..9ec9163 100644 --- a/core/llm/math.rs +++ b/core/llm/math.rs @@ -60,14 +60,14 @@ macro_rules! i { // the time of this writing this is only used in a few places, and once // rust-lang/rust#72751 is fixed then this macro will no longer be necessary and // the native `/` operator can be used and panics won't be codegen'd. -#[cfg(any(debug_assertions, not(feature = "unstable")))] +#[cfg(debug_assertions)] macro_rules! div { ($a:expr, $b:expr) => { $a / $b }; } -#[cfg(all(not(debug_assertions), feature = "unstable"))] +#[cfg(not(debug_assertions))] macro_rules! div { ($a:expr, $b:expr) => { unsafe { core::intrinsics::unchecked_div($a, $b) } @@ -76,271 +76,38 @@ macro_rules! div { macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all(feature = "unstable", $($clause)*))] - { - if true { // thwart the dead code lint - $e - } - } + #[cfg(all($($clause)*))] + { $e } }; } -// Public modules -mod acos; -mod acosf; -mod acosh; -mod acoshf; -mod asin; -mod asinf; -mod asinh; -mod asinhf; -mod atan; -mod atan2; -mod atan2f; -mod atanf; -mod atanh; -mod atanhf; -mod cbrt; -mod cbrtf; -mod ceil; -mod ceilf; -mod copysign; -mod copysignf; -mod cos; -mod cosf; -mod cosh; -mod coshf; -mod erf; -mod erff; -mod exp; -mod exp10; -mod exp10f; -mod exp2; -mod exp2f; -mod expf; -mod expm1; -mod expm1f; -mod fabs; -mod fabsf; -mod fdim; -mod fdimf; -mod floor; -mod floorf; -mod fma; -mod fmaf; -mod fmax; -mod fmaxf; -mod fmin; -mod fminf; -mod fmod; -mod fmodf; -mod frexp; -mod frexpf; -mod hypot; -mod hypotf; -mod ilogb; -mod ilogbf; -mod j0; -mod j0f; -mod j1; -mod j1f; -mod jn; -mod jnf; -mod ldexp; -mod ldexpf; -mod lgamma; -mod lgamma_r; -mod lgammaf; -mod lgammaf_r; -mod ln; -mod lnf; -mod log; -mod log10; -mod log10f; -mod log1p; -mod log1pf; -mod log2; -mod log2f; -mod logf; -mod modf; -mod modff; -mod nextafter; -mod nextafterf; -mod pow; -mod powf; -mod remainder; -mod remainderf; -mod remquo; -mod remquof; -mod rint; -mod rintf; -mod round; -mod roundf; -mod scalbn; -mod scalbnf; -mod sin; -mod sincos; -mod sincosf; -mod sinf; -mod sinh; -mod sinhf; -mod sqrt; -mod sqrtf; -mod tan; -mod tanf; -mod tanh; -mod tanhf; -mod tgamma; -mod tgammaf; -mod trunc; -mod truncf; +macro_rules! import { + ($p:vis $n:ident) => ( + mod $n; #[allow(unused_imports)] $p use self::$n::*; + ); + ($p:vis $n:ident $(, $m:ident)*) => ( + import!($p $n); import!($p $($m),*); + ); +} -// Use separated imports instead of {}-grouped imports for easier merging. -pub use self::acos::acos; -pub use self::acosf::acosf; -pub use self::acosh::acosh; -pub use self::acoshf::acoshf; -pub use self::asin::asin; -pub use self::asinf::asinf; -pub use self::asinh::asinh; -pub use self::asinhf::asinhf; -pub use self::atan::atan; -pub use self::atan2::atan2; -pub use self::atan2f::atan2f; -pub use self::atanf::atanf; -pub use self::atanh::atanh; -pub use self::atanhf::atanhf; -pub use self::cbrt::cbrt; -pub use self::cbrtf::cbrtf; -pub use self::ceil::ceil; -pub use self::ceilf::ceilf; -pub use self::copysign::copysign; -pub use self::copysignf::copysignf; -pub use self::cos::cos; -pub use self::cosf::cosf; -pub use self::cosh::cosh; -pub use self::coshf::coshf; -pub use self::erf::erf; -pub use self::erf::erfc; -pub use self::erff::erfcf; -pub use self::erff::erff; -pub use self::exp::exp; -pub use self::exp10::exp10; -pub use self::exp10f::exp10f; -pub use self::exp2::exp2; -pub use self::exp2f::exp2f; -pub use self::expf::expf; -pub use self::expm1::expm1; -pub use self::expm1f::expm1f; -pub use self::fabs::fabs; -pub use self::fabsf::fabsf; -pub use self::fdim::fdim; -pub use self::fdimf::fdimf; -pub use self::floor::floor; -pub use self::floorf::floorf; -pub use self::fma::fma; -pub use self::fmaf::fmaf; -pub use self::fmax::fmax; -pub use self::fmaxf::fmaxf; -pub use self::fmin::fmin; -pub use self::fminf::fminf; -pub use self::fmod::fmod; -pub use self::fmodf::fmodf; -pub use self::frexp::frexp; -pub use self::frexpf::frexpf; -pub use self::hypot::hypot; -pub use self::hypotf::hypotf; -pub use self::ilogb::ilogb; -pub use self::ilogbf::ilogbf; -pub use self::j0::j0; -pub use self::j0::y0; -pub use self::j0f::j0f; -pub use self::j0f::y0f; -pub use self::j1::j1; -pub use self::j1::y1; -pub use self::j1f::j1f; -pub use self::j1f::y1f; -pub use self::jn::jn; -pub use self::jn::yn; -pub use self::jnf::jnf; -pub use self::jnf::ynf; -pub use self::ldexp::ldexp; -pub use self::ldexpf::ldexpf; -pub use self::lgamma::lgamma; -pub use self::lgamma_r::lgamma_r; -pub use self::lgammaf::lgammaf; -pub use self::lgammaf_r::lgammaf_r; -pub use self::ln::ln; -pub use self::lnf::lnf; -pub use self::log::log; -pub use self::log10::log10; -pub use self::log10f::log10f; -pub use self::log1p::log1p; -pub use self::log1pf::log1pf; -pub use self::log2::log2; -pub use self::log2f::log2f; -pub use self::logf::logf; -pub use self::modf::modf; -pub use self::modff::modff; -pub use self::nextafter::nextafter; -pub use self::nextafterf::nextafterf; -pub use self::pow::pow; -pub use self::powf::powf; -pub use self::remainder::remainder; -pub use self::remainderf::remainderf; -pub use self::remquo::remquo; -pub use self::remquof::remquof; -pub use self::rint::rint; -pub use self::rintf::rintf; -pub use self::round::round; -pub use self::roundf::roundf; -pub use self::scalbn::scalbn; -pub use self::scalbnf::scalbnf; -pub use self::sin::sin; -pub use self::sincos::sincos; -pub use self::sincosf::sincosf; -pub use self::sinf::sinf; -pub use self::sinh::sinh; -pub use self::sinhf::sinhf; -pub use self::sqrt::sqrt; -pub use self::sqrtf::sqrtf; -pub use self::tan::tan; -pub use self::tanf::tanf; -pub use self::tanh::tanh; -pub use self::tanhf::tanhf; -pub use self::tgamma::tgamma; -pub use self::tgammaf::tgammaf; -pub use self::trunc::trunc; -pub use self::truncf::truncf; +// Public modules +import!(pub acos, acosf, acosh, acoshf, asin, asinf, asinh, asinhf, atan, atan2, atan2f, atanf, atanh, atanhf); +import!(pub cbrt, cbrtf, ceil, ceilf, copysign, copysignf, cos, cosf, cosh, coshf); +import!(pub erf, erff, exp, exp10, exp10f, exp2, exp2f, expf, expm1, expm1f); +import!(pub fabs, fabsf, fdim, fdimf, floor, floorf, fma, fmaf, fmax, fmaxf, fmin, fminf, fmod, fmodf, frexp, frexpf); +import!(pub hypot, hypotf); +import!(pub ilogb, ilogbf); +import!(pub j0, j0f, j1, j1f, jn, jnf); +import!(pub ldexp, ldexpf, lgamma, lgamma_r, lgammaf, lgammaf_r, ln, lnf, log, log10, log10f, log1p, log1pf, log2, log2f, logf); +import!(pub modf, modff); +import!(pub nextafter, nextafterf); +import!(pub pow, powf); +import!(pub remainder, remainderf, remquo, remquof, rint, rintf, round, roundf); +import!(pub scalbn, scalbnf, sin, sincos, sincosf, sinf, sinh, sinhf, sqrt, sqrtf); +import!(pub tan, tanf, tanh, tanhf, tgamma, tgammaf, trunc, truncf); // Private modules -mod expo2; -mod fenv; -mod k_cos; -mod k_cosf; -mod k_expo2; -mod k_expo2f; -mod k_sin; -mod k_sinf; -mod k_tan; -mod k_tanf; -mod rem_pio2; -mod rem_pio2_large; -mod rem_pio2f; - -// Private re-imports -use self::expo2::expo2; -use self::k_cos::k_cos; -use self::k_cosf::k_cosf; -use self::k_expo2::k_expo2; -use self::k_expo2f::k_expo2f; -use self::k_sin::k_sin; -use self::k_sinf::k_sinf; -use self::k_tan::k_tan; -use self::k_tanf::k_tanf; -use self::rem_pio2::rem_pio2; -use self::rem_pio2_large::rem_pio2_large; -use self::rem_pio2f::rem_pio2f; +import!(expo2, fenv, k_cos, k_cosf, k_expo2, k_expo2f, k_sin, k_sinf, k_tan, k_tanf, rem_pio2, rem_pio2_large, rem_pio2f); use crate::Float64; diff --git a/example/Cargo.toml b/example/Cargo.toml deleted file mode 100644 index e5e2517..0000000 --- a/example/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "example" -version = "0.1.0" -edition = "2021" - -[dependencies.libtrig] -path = ".." - -[[bin]] -path = "./example.rs" -name = "example" diff --git a/example/example.rs b/example/example.rs deleted file mode 100644 index e9c72e9..0000000 --- a/example/example.rs +++ /dev/null @@ -1,36 +0,0 @@ -use libtrig::odo::*; -use libtrig::*; - -const CONFIG: OdometryConfig = OdometryConfig::new() - .set_lateral_wheel_distance(10.0) - .set_longitudinal_wheel_distance(10.0) - .set_wheel_radius(1.0) - .set_ticks_per_revolution(100.0); - -#[derive(Debug)] -struct Robot(Odometry); - -impl Robot { - fn init() -> Self { - let mut robot = Self(Odometry::new(CONFIG)); - robot.0.reset(); - robot - } - fn update(&mut self, movement: (Float64, Float64, Float64)) { - self.0.update(Vec3D::from(movement)); - } -} - -fn main() { - let mut robot = Robot::init(); - - let mut mv = |x: Float64, y: Float64, theta: Float64| { - println!("Movement: ({}, {}, {})", x, y, theta); - robot.update((x, y, theta)); - println!("Pos: {}", robot.0.current_position()); - }; - - mv(10.0, 10.0, 0.0); - mv(100.0, 100.0, 0.0); - mv(200.0, 000.0, 100.0); -} diff --git a/libtrig/main.rs b/libtrig/lib.rs similarity index 91% rename from libtrig/main.rs rename to libtrig/lib.rs index 9bc7726..992ffba 100644 --- a/libtrig/main.rs +++ b/libtrig/lib.rs @@ -10,7 +10,6 @@ pub(crate) mod traits; pub(crate) mod coords; pub(crate) mod angle; pub(crate) mod types; -pub mod odo; pub use llm; diff --git a/libtrig/odo/FORMULA.md b/libtrig/odo/FORMULA.md deleted file mode 100644 index ca92db0..0000000 --- a/libtrig/odo/FORMULA.md +++ /dev/null @@ -1,64 +0,0 @@ -In a 3-wheel odometry setup, -where two deadwheels are parallel and the third wheel intersects the two parallel wheels, -we can use this configuration to estimate the robot's position and orientation as it moves on the field. - -Basic Robot Encoder Setup - - -Input: - -- `FLCount` - Encoder count for the front-left dead wheel. (yes we are using encoder) -- `FRCount` - Encoder count for the front-right dead wheel. -- `ICount` - Encoder count for the intersecting dead wheel. -- `DCLateral` - Distance calibration factor for lateral movement (strafe). - This factor relates encoder counts to lateral distance traveled for each wheel. -- `DCForward` - Distance calibration factor for forward/backward movement. - This factor relates encoder counts to forward/backward distance traveled for each wheel. -- `DCAngle` - Angle calibration factor. This factor relates encoder counts to the angle of rotation for the robot. -- `x` - Robot's x-coordinate on the field (lateral position). -- `y` - Robot's y-coordinate on the field (forward position). -- `θ` - Robot's orientation with respect to a reference direction (usually the starting orientation) - -Update Loop: -The robot continuously reads encoder counts from the odometry wheels at regular intervals, -typically every few milliseconds. For each loop iteration, -the robot updates its position and orientation on the field. - -Lateral Movement Update: -The change in lateral position (Δx) -can be calculated using the average encoder counts from the -front-left, front-right, and intersecting dead wheels: - -```rust,ignore,no_run - Δx = (FLCount + FRCount + ICount) * DCLateral / 3 -``` - -Forward Movement Update: The change in forward position (Δy) -can be calculated using the average encoder counts from the two parallel dead wheels: - -```rust,ignore,no_run - Δy = (FLCount + FRCount) * DCForward / 2 -``` - -Updating Orientation: The change in orientation (Δθ) -can be calculated using the difference in encoder counts between the front-left and front-right dead wheels. -The distance between these wheels is known as the "track width" (W): - -```rust,ignore,no_run - Δθ = (FLCount - FRCount) * DCAngle / W -``` - -Combining Updates: -Using the `Δx`, `Δy`, and `Δtheta` calculated in the previous steps, -the robot can update its position and orientation as follows: - -```rust,ignore,no_run - xₙ = xₒ + Δy * cos(θ) - Δx * sin(θ) - yₙ = yₒ + Δy * sin(θ) + Δx * cos(θ) - θₙ = θₒ + Δθ -``` diff --git a/libtrig/odo/config.rs b/libtrig/odo/config.rs deleted file mode 100644 index a3845d4..0000000 --- a/libtrig/odo/config.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::*; - -use core::f64::consts::PI; - -/// The configuration for odometry calculations. -#[derive(Debug, Clone, Copy, PartialEq, Default)] -pub struct OdometryConfig { - /// The distance between encoder 1 and encoder 2 in centimeters. - pub lateral_wheel_distance: Float64, - /// The distance between the midpoint of encoder 1 and 2 and encoder 3 in centimeters. - pub longitudinal_wheel_distance: Float64, - /// The radius of the wheels in centimeters. - pub wheel_radius: Float64, - /// The number of ticks per revolution of the encoders. - pub ticks_per_revolution: Float64, -} - -impl OdometryConfig { - /// Creates a new `OdometryConfig` with all fields set to `0.0`. - #[inline] - #[must_use] - pub const fn new() -> OdometryConfig { - OdometryConfig { - lateral_wheel_distance: 0.0, - longitudinal_wheel_distance: 0.0, - wheel_radius: 0.0, - ticks_per_revolution: 0.0, - } - } - - /// Modifies `lateral_wheel_distance` and returns `self`. - #[inline] - #[must_use] - pub const fn set_lateral_wheel_distance(mut self, lateral_wheel_distance: Float64) -> Self { - self.lateral_wheel_distance = lateral_wheel_distance; - self - } - - /// Modifies `longitudinal_wheel_distance` and returns `self`. - #[inline] - #[must_use] - pub const fn set_longitudinal_wheel_distance(mut self, longitudinal_wheel_distance: Float64) -> Self { - self.longitudinal_wheel_distance = longitudinal_wheel_distance; - self - } - - /// Modifies `wheel_radius` and returns `self`. - #[inline] - #[must_use] - pub const fn set_wheel_radius(mut self, wheel_radius: Float64) -> Self { - self.wheel_radius = wheel_radius; - self - } - - /// Modifies `ticks_per_revolution` and returns `self`. - #[inline] - #[must_use] - pub const fn set_ticks_per_revolution(mut self, ticks_per_revolution: Float64) -> Self { - self.ticks_per_revolution = ticks_per_revolution; - self - } -} - -/// The configuration for odometry formulae. -#[derive(Debug, Clone, Copy, PartialEq, Default)] -pub(crate) struct OdometryFormulaeConfig { - /// The distance between encoder 1 and encoder 2 in centimeters. - pub lateral_wheel_distance: Float64, - /// The distance between the midpoint of encoder 1 and 2 and encoder 3 in centimeters. - pub longitudinal_wheel_distance: Float64, - /// The number of centimeters per tick. - pub cm_per_tick: Float64, -} - -impl OdometryFormulaeConfig { - /// Calculates the number of centimeters per tick. - #[inline] - #[must_use] - fn cm_per_tick_calc(wheel_radius: Float64, ticks_per_revolution: Float64) -> Float64 { - wheel_radius * 2.0 * PI / ticks_per_revolution - } -} - -impl From for OdometryFormulaeConfig { - #[inline] - #[must_use] - fn from(config: OdometryConfig) -> Self { - Self { - lateral_wheel_distance: config.lateral_wheel_distance, - longitudinal_wheel_distance: config.longitudinal_wheel_distance, - cm_per_tick: Self::cm_per_tick_calc(config.wheel_radius, config.ticks_per_revolution), - } - } -} diff --git a/libtrig/odo/mod.rs b/libtrig/odo/mod.rs deleted file mode 100644 index 1c655df..0000000 --- a/libtrig/odo/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Odometry calculations. - -mod movement_calc; -mod config; -mod pos; - -pub(crate) use config::OdometryFormulaeConfig; -pub use config::OdometryConfig; - -pub use movement_calc::Odometry; -pub use pos::Pos2D; diff --git a/libtrig/odo/movement_calc.rs b/libtrig/odo/movement_calc.rs deleted file mode 100644 index bed57bb..0000000 --- a/libtrig/odo/movement_calc.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::*; - -use super::Pos2D; - -/// Odometry calculations. -#[derive(Debug, Clone, Copy, PartialEq, Default)] -pub struct Odometry { - config: odo::OdometryFormulaeConfig, - current_position: odo::Pos2D, - encoder_values: Vec3D, -} - -impl Odometry { - /// Creates a new `Odometry` with the given `config`. - #[must_use] - pub fn new(config: odo::OdometryConfig) -> Self { - Self { - config: config.into(), - current_position: odo::Pos2D::origin(), - encoder_values: Vec3D::origin() - } - } - - /// Forces the current position to be set to the given `coords`. - #[inline] - #[allow(non_snake_case)] - pub fn setCurrentPosition(&mut self, coords: impl Into) { - self.current_position = coords.into(); - } - - /// Forces the current encoder values to be set to the given `values`. - #[inline] - #[allow(non_snake_case)] - pub fn setEncoderValues(&mut self, values: impl Into) { - self.encoder_values = values.into(); - } - - /// Resets the current position and encoder values to the origin. - #[inline] - #[allow(non_snake_case)] - pub fn reset(&mut self) { - self.setCurrentPosition(Pos2D::origin()); - self.setEncoderValues(Vec3D::origin()); - } - - /// Updates the current position - /// - /// Where the `movement` is a `Vec3D` of the raw encoder values. - /// **NOT THE DELTA ENCODER VALUES.** - /// - #[doc = include_str!("./FORMULA.md")] - pub fn update>(&mut self, encoder_values: V) { - // Import the `Float` trait. (Needed for the `cos` and `sin` methods.) - use crate::traits::Float; - - // Converts the encoder values into a `Vec3D`. - let encoder_values: Vec3D = encoder_values.into(); - - // Calculates the delta encoder values. - let dn1 = encoder_values.x() - self.encoder_values.x(); - let dn2 = encoder_values.y() - self.encoder_values.y(); - let dn3 = encoder_values.z() - self.encoder_values.z(); - - // Updates the encoder values. - self.encoder_values = encoder_values; - - // Calculates the delta x, y, and theta. - let dtheta = self.config.cm_per_tick * ((dn1 - dn2) / self.config.lateral_wheel_distance); - let dx = self.config.cm_per_tick * ((dn1 + dn2) / 2.0); - let dy = self.config.cm_per_tick * (dn3 + ( (dn2 - dn1) / 2.0 )); - - // Updates the current angle by first partition - let mut new_angle = self.current_position.angle() + (dtheta / 2.0); - self.current_position.setAngle(new_angle); - - // Updates the current x and y - let x_incr = dx * new_angle.cos() - dy * new_angle.sin(); - let y_incr = dx * new_angle.sin() + dy * new_angle.cos(); - self.current_position.setX(self.current_position.x() + x_incr); - self.current_position.setY(self.current_position.y() + y_incr); - - // Updates the current angle by second partition - new_angle += dtheta / 2.0; - self.current_position.setAngle(new_angle); - } - - /// Returns the current position. - #[inline] - #[must_use] - pub fn current_position(&self) -> odo::Pos2D { - self.current_position - } -} diff --git a/libtrig/odo/pos/mod.rs b/libtrig/odo/pos/mod.rs deleted file mode 100644 index 2c7bc84..0000000 --- a/libtrig/odo/pos/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod pos2d; - -pub use pos2d::Pos2D; \ No newline at end of file diff --git a/libtrig/odo/pos/pos2d.rs b/libtrig/odo/pos/pos2d.rs deleted file mode 100644 index 17120d1..0000000 --- a/libtrig/odo/pos/pos2d.rs +++ /dev/null @@ -1,319 +0,0 @@ -use crate::*; - -/// A 2D position. -/// -/// Contains a `Coord2D` and an `Angle2D`. -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Pos2D(Coord2D, Angle2D); - -impl Pos2D { - /// Creates a new `Pos2D` from the given `coords` and `angle`. - #[inline] - #[must_use] - pub const fn new(coords: Coord2D, angle: Angle2D) -> Self { - Self(coords, angle) - } - /// Creates a new `Pos2D` at the origin, with an angle of `0.0` radians. - #[inline] - #[must_use] - pub const fn origin() -> Self { - Self(Coord2D::origin(), Angle2D::zero()) - } - /// Returns the x coordinate of the position. - #[inline] - #[must_use] - pub const fn x(&self) -> Float64 { - self.0.x - } - /// Sets the x coordinate of the position. - #[inline] - #[allow(non_snake_case)] - pub const fn setX(&mut self, x: Float64) { - self.0.x = x; - } - /// Returns the y coordinate of the position. - #[inline] - #[must_use] - pub const fn y(&self) -> Float64 { - self.0.y - } - /// Sets the y coordinate of the position. - #[inline] - #[allow(non_snake_case)] - pub const fn setY(&mut self, y: Float64) { - self.0.y = y; - } - /// Rotates the position by the given angle in radians. - #[must_use] - pub fn rotate_by(&self, angle: Angle2D) -> Self { - Self(self.0.rotate_by(angle), self.1 + angle) - } - /// Returns the facing angle. - #[inline] - #[must_use] - pub fn angle(&self) -> Angle2D { - self.1 - } - /// Sets the facing angle. - #[inline] - #[allow(non_snake_case)] - pub const fn setAngle(&mut self, angle: Angle2D) { - self.1 = angle; - } - /// Returns the inverted Position. - /// - /// Same as rotating the position by 180 degrees. - #[inline] - #[must_use] - pub fn inverse(&self) -> Self { - -self - } -} - -#[macros::mass_impl( - $THIS = @ORM Pos2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::Add for THIS { - type Output = Pos2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Pos2D::new(Coord2D::new(self.0.x + rhs.x(), self.0.y + rhs.y()), self.1) - } -} - -#[macros::mass_impl( - $THIS = @ORM Pos2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::Add for THIS { - type Output = Pos2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Pos2D::new(Coord2D::new(self.0.x + rhs.x, self.0.y + rhs.y), self.1) - } -} - -#[macros::mass_impl( - $THIS = @ORM Pos2D, - $OTHER = @ORM Pos2D -)] -impl core::ops::Add for THIS { - type Output = Pos2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Pos2D::new(Coord2D::new(self.0.x + rhs.0.x, self.0.y + rhs.0.y), self.1 + rhs.1) - } -} - -#[macros::mass_impl( - $THIS = @ORM Pos2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::Add for THIS { - type Output = Pos2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Pos2D::new(self.0, self.1 + rhs) - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.0 += rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.0 += rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Pos2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.0 += rhs.0; - self.1 += rhs.1; - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.1 += rhs; - } -} - -#[macros::mass_impl( - $THIS = @ORM Pos2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::Sub for THIS { - type Output = Pos2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - Pos2D::new(Coord2D::new(self.0.x - rhs.x(), self.0.y - rhs.y()), self.1) - } -} - -#[macros::mass_impl( - $THIS = @ORM Pos2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::Sub for THIS { - type Output = Pos2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - Pos2D::new(Coord2D::new(self.0.x - rhs.x, self.0.y - rhs.y), self.1) - } -} - -#[macros::mass_impl( - $THIS = @ORM Pos2D, - $OTHER = @ORM Pos2D -)] -impl core::ops::Sub for THIS { - type Output = Pos2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - Pos2D::new(Coord2D::new(self.0.x - rhs.0.x, self.0.y - rhs.0.y), self.1 - rhs.1) - } -} - -#[macros::mass_impl( - $THIS = @ORM Pos2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::Sub for THIS { - type Output = Pos2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - Pos2D::new(self.0, self.1 - rhs) - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.0 -= rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.0 -= rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Pos2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.0 -= rhs.0; - self.1 -= rhs.1; - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @OR Angle2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.1 -= rhs; - } -} - -#[macros::mass_impl($THIS = @ORM Pos2D)] -impl core::ops::Neg for THIS { - type Output = Pos2D; - #[inline] - #[must_use] - fn neg(self) -> Self::Output { - Pos2D::new(-self.0, -self.1) - } -} - -impl core::fmt::Display for Pos2D { - #[inline] - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "({:.3}, {:.3}) {:.1}°", self.0.x, self.0.y, self.1.to_degrees()) - } -} - -impl Default for Pos2D { - #[inline] - #[must_use] - fn default() -> Self { - Self::origin() - } -} - -impl, A: Into> From<(C, A)> for Pos2D { - #[inline] - #[must_use] - fn from((c, a): (C, A)) -> Self { - Self::new(c.into(), a.into()) - } -} - -impl> From<(F, F, F, bool)> for Pos2D { - #[inline] - #[must_use] - fn from(i: (F, F, F, bool)) -> Self { - Self::new( - Coord2D::from((i.0, i.1)), - Angle2D::from((i.2, i.3)) - ) - } -} - -impl> From<(F, F, F)> for Pos2D { - /// Creates a new `Pos2D` from the given `coords` and `angle`. - #[inline] - #[must_use] - fn from(i: (F, F, F)) -> Self { - Self::from((i.0, i.1, i.2, false)) - } -} From 4df3c97c3b3b7a6666254b203d6ae8c578163b67 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 15:30:21 -0800 Subject: [PATCH 09/93] Partial clippy fixes --- core/macros/libtrig-macros-core/ffi/mod.rs | 6 +++--- core/macros/libtrig-macros-core/mass_impl/mod.rs | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/core/macros/libtrig-macros-core/ffi/mod.rs b/core/macros/libtrig-macros-core/ffi/mod.rs index 1127c50..f178805 100644 --- a/core/macros/libtrig-macros-core/ffi/mod.rs +++ b/core/macros/libtrig-macros-core/ffi/mod.rs @@ -55,11 +55,11 @@ fn parse_func(item: TokenStream) -> TokenStream { #body } }; - result.into() + result } /// parses the settings (can be none, const, unsafe or both) -fn parse_settings<'a>(attr: TokenStream) -> (String, String) { +fn parse_settings(attr: TokenStream) -> (String, String) { let modifiers_str = attr.to_string(); let mut res = String::new(); if modifiers_str.contains("const") { @@ -70,7 +70,7 @@ fn parse_settings<'a>(attr: TokenStream) -> (String, String) { } let t = if modifiers_str.contains("type=") { let type_str = modifiers_str.split("type=").collect::>()[1]; - type_str.split(" ").collect::>()[0] + type_str.split(' ').collect::>()[0] } else { "C" }; diff --git a/core/macros/libtrig-macros-core/mass_impl/mod.rs b/core/macros/libtrig-macros-core/mass_impl/mod.rs index dd09978..df384c6 100644 --- a/core/macros/libtrig-macros-core/mass_impl/mod.rs +++ b/core/macros/libtrig-macros-core/mass_impl/mod.rs @@ -13,9 +13,7 @@ pub fn mass_impl>(cfg: T, input: T) -> TokenStream { return err.to_compile_error(); } }; - let input = input.to_string(); - let mut results = Vec::new(); - results.push(input); + let mut results = vec![input.to_string()]; for tv in &config.type_variants { let mut temp_results = Vec::new(); From cbce943de7e80d3a338ff2f310e622dafc7978df Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 15:30:52 -0800 Subject: [PATCH 10/93] A & C --- core/llm/math/acos.rs | 16 ++++----- core/llm/math/acosf.rs | 2 ++ core/llm/math/acosh.rs | 2 ++ core/llm/math/acoshf.rs | 2 ++ core/llm/math/asin.rs | 29 ++++++---------- core/llm/math/asinf.rs | 4 ++- core/llm/math/asinh.rs | 2 ++ core/llm/math/asinhf.rs | 4 +-- core/llm/math/atan.rs | 14 ++++---- core/llm/math/atan2.rs | 19 +++++++---- core/llm/math/atan2f.rs | 23 ++++++++----- core/llm/math/atanf.rs | 2 ++ core/llm/math/cbrt.rs | 74 +++++++++++++++++++---------------------- core/llm/math/ceil.rs | 3 +- core/llm/math/erf.rs | 44 +++++++++--------------- 15 files changed, 117 insertions(+), 123 deletions(-) diff --git a/core/llm/math/acos.rs b/core/llm/math/acos.rs index d4a1360..eaedfeb 100644 --- a/core/llm/math/acos.rs +++ b/core/llm/math/acos.rs @@ -38,6 +38,7 @@ use crate::{Float64, Radian64}; use super::sqrt; +consts!{ const PIO2_HI: Float64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ const PIO2_LO: Float64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ const PS0: Float64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ @@ -50,6 +51,7 @@ const QS1: Float64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ const QS2: Float64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ const QS3: Float64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ const QS4: Float64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ +} fn r(z: Float64) -> Float64 { let p: Float64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); @@ -68,13 +70,8 @@ pub fn acos(x: Float64) -> Radian64 { let z: Float64; let w: Float64; let s: Float64; - let c: Float64; - let df: Float64; - let hx: u32; - let ix: u32; - - hx = (x.to_bits() >> 32) as u32; - ix = hx & 0x7fffffff; + let hx: u32 = (x.to_bits() >> 32) as u32; + let ix: u32 = hx & 0x7fffffff; /* |x| >= 1 or nan */ if ix >= 0x3ff00000 { let lx: u32 = x.to_bits() as u32; @@ -107,9 +104,8 @@ pub fn acos(x: Float64) -> Radian64 { z = (1.0 - x) * 0.5; s = sqrt(z); // Set the low 4 bytes to zero - df = Float64::from_bits(s.to_bits() & 0xff_ff_ff_ff_00_00_00_00); - - c = (z - df * df) / (s + df); + let df: Float64 = Float64::from_bits(s.to_bits() & 0xff_ff_ff_ff_00_00_00_00); + let c: Float64 = (z - df * df) / (s + df); w = r(z) * s + c; 2. * (df + w) } diff --git a/core/llm/math/acosf.rs b/core/llm/math/acosf.rs index a5d9176..1871639 100644 --- a/core/llm/math/acosf.rs +++ b/core/llm/math/acosf.rs @@ -17,12 +17,14 @@ use crate::{Float32, Radian32}; use super::sqrtf::sqrtf; +consts!{ const PIO2_HI: Float32 = 1.5707962513e+00; /* 0x3fc90fda */ const PIO2_LO: Float32 = 7.5497894159e-08; /* 0x33a22168 */ const P_S0: Float32 = 1.6666586697e-01; const P_S1: Float32 = -4.2743422091e-02; const P_S2: Float32 = -8.6563630030e-03; const Q_S1: Float32 = -7.0662963390e-01; +} fn r(z: Float32) -> Float32 { let p = z * (P_S0 + z * (P_S1 + z * P_S2)); diff --git a/core/llm/math/acosh.rs b/core/llm/math/acosh.rs index b722cdf..94fbefb 100644 --- a/core/llm/math/acosh.rs +++ b/core/llm/math/acosh.rs @@ -2,7 +2,9 @@ use crate::{Float64, Radian64}; use super::{log, log1p, sqrt}; +consts!{ const LN2: Float64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ +} /// Inverse hyperbolic cosine /// diff --git a/core/llm/math/acoshf.rs b/core/llm/math/acoshf.rs index 617178a..6ac6212 100644 --- a/core/llm/math/acoshf.rs +++ b/core/llm/math/acoshf.rs @@ -2,7 +2,9 @@ use crate::{Float32, Radian32}; use super::{log1pf, logf, sqrtf}; +consts!{ const LN2: Float32 = 0.693147180559945309417232121458176568; +} /// Inverse hyperbolic cosine /// diff --git a/core/llm/math/asin.rs b/core/llm/math/asin.rs index a44c490..16687ad 100644 --- a/core/llm/math/asin.rs +++ b/core/llm/math/asin.rs @@ -44,6 +44,7 @@ use crate::{Float64, Radian64}; use super::{fabs, get_high_word, get_low_word, sqrt, with_set_low_word}; +consts!{ const PIO2_HI: Float64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ const PIO2_LO: Float64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ /* coefficients for R(x^2) */ @@ -57,6 +58,7 @@ const Q_S1: Float64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ const Q_S2: Float64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ const Q_S3: Float64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ const Q_S4: Float64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ +} fn comp_r(z: Float64) -> Float64 { let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); @@ -71,18 +73,11 @@ fn comp_r(z: Float64) -> Float64 { /// Returns values in radians, in the range of -pi/2 to pi/2. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asin(mut x: Float64) -> Radian64 { - let z: Float64; - let r: Float64; - let s: Float64; - let hx: u32; - let ix: u32; - - hx = get_high_word(x); - ix = hx & 0x7fffffff; + let hx: u32 = get_high_word(x); + let ix: u32 = hx & 0x7fffffff; /* |x| >= 1 or nan */ if ix >= 0x3ff00000 { - let lx: u32; - lx = get_low_word(x); + let lx: u32 = get_low_word(x); if ((ix - 0x3ff00000) | lx) == 0 { /* asin(1) = +-pi/2 with inexact */ return x * PIO2_HI + Float64::from_bits(0x3870000000000000); @@ -93,25 +88,23 @@ pub fn asin(mut x: Float64) -> Radian64 { /* |x| < 0.5 */ if ix < 0x3fe00000 { /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ - if ix < 0x3e500000 && ix >= 0x00100000 { + if (0x00100000..0x3e500000).contains(&ix) { return x; } else { return x + x * comp_r(x * x); } } /* 1 > |x| >= 0.5 */ - z = (1.0 - fabs(x)) * 0.5; - s = sqrt(z); - r = comp_r(z); + let z: Float64 = (1.0 - fabs(x)) * 0.5; + let s: Float64 = sqrt(z); + let r: Float64 = comp_r(z); if ix >= 0x3fef3333 { /* if |x| > 0.975 */ x = PIO2_HI - (2. * (s + s * r) - PIO2_LO); } else { - let f: Float64; - let c: Float64; /* f+c = sqrt(z) */ - f = with_set_low_word(s, 0); - c = (z - f * f) / (s + f); + let f: Float64 = with_set_low_word(s, 0); + let c: Float64 = (z - f * f) / (s + f); x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f)); } if hx >> 31 != 0 { diff --git a/core/llm/math/asinf.rs b/core/llm/math/asinf.rs index dcd4b3a..3755131 100644 --- a/core/llm/math/asinf.rs +++ b/core/llm/math/asinf.rs @@ -18,6 +18,7 @@ use crate::{Float64, Float32, Radian32}; use super::fabsf::fabsf; use super::sqrt::sqrt; +consts!{ const PIO2: Float64 = 1.570796326794896558e+00; /* coefficients for R(x^2) */ @@ -25,6 +26,7 @@ const P_S0: Float32 = 1.6666586697e-01; const P_S1: Float32 = -4.2743422091e-02; const P_S2: Float32 = -8.6563630030e-03; const Q_S1: Float32 = -7.0662963390e-01; +} fn r(z: Float32) -> Float32 { let p = z * (P_S0 + z * (P_S1 + z * P_S2)); @@ -56,7 +58,7 @@ pub fn asinf(mut x: Float32) -> Radian32 { if ix < 0x3f000000 { /* |x| < 0.5 */ /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ - if (ix < 0x39800000) && (ix >= 0x00800000) { + if (0x00800000..0x39800000).contains(&ix) { return x; } return x + x * r(x * x); diff --git a/core/llm/math/asinh.rs b/core/llm/math/asinh.rs index 4ac7d17..1b630f0 100644 --- a/core/llm/math/asinh.rs +++ b/core/llm/math/asinh.rs @@ -2,7 +2,9 @@ use crate::{Float64, Radian64}; use super::{log, log1p, sqrt}; +consts!{ const LN2: Float64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ +} /* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ /// Inverse hyperbolic sine diff --git a/core/llm/math/asinhf.rs b/core/llm/math/asinhf.rs index 5a56fd7..6b117a7 100644 --- a/core/llm/math/asinhf.rs +++ b/core/llm/math/asinhf.rs @@ -2,7 +2,7 @@ use crate::{Float32, Radian32}; use super::{log1pf, logf, sqrtf}; -const LN2: Float32 = 0.693147180559945309417232121458176568; +use core::f32::consts::LN_2; /* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ /// Inverse hyperbolic sine @@ -20,7 +20,7 @@ pub fn asinhf(mut x: Float32) -> Radian32 { if i >= 0x3f800000 + (12 << 23) { /* |x| >= 0x1p12 or inf or nan */ - x = logf(x) + LN2; + x = logf(x) + LN_2; } else if i >= 0x3f800000 + (1 << 23) { /* |x| >= 2 */ x = logf(2.0 * x + 1.0 / (sqrtf(x * x + 1.0) + x)); diff --git a/core/llm/math/atan.rs b/core/llm/math/atan.rs index 67fb79e..c1d3e65 100644 --- a/core/llm/math/atan.rs +++ b/core/llm/math/atan.rs @@ -34,11 +34,12 @@ use crate::{Float64, Float32, Radian64}; use super::fabs; +consts!{ const ATANHI: [Float64; 4] = [ - 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ - 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ - 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ - 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + core::f64::consts::FRAC_PI_2, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ ]; const ATANLO: [Float64; 4] = [ @@ -61,6 +62,7 @@ const AT: [Float64; 11] = [ -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ ]; +} /// Arctangent /// @@ -148,9 +150,9 @@ mod tests { (3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6), (1.0, f64::consts::FRAC_PI_4), (3.0_f64.sqrt(), f64::consts::FRAC_PI_3), - (-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6), + (-(3.0_f64.sqrt()) / 3.0, -f64::consts::FRAC_PI_6), (-1.0, -f64::consts::FRAC_PI_4), - (-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3), + (-(3.0_f64.sqrt()), -f64::consts::FRAC_PI_3), ] .iter() { diff --git a/core/llm/math/atan2.rs b/core/llm/math/atan2.rs index 4479dc5..fe233db 100644 --- a/core/llm/math/atan2.rs +++ b/core/llm/math/atan2.rs @@ -43,8 +43,13 @@ use crate::{Float64, Radian64}; use super::atan; use super::fabs; -const PI: Float64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ +use core::f64::consts::PI; +use core::f64::consts::FRAC_PI_2; +use core::f64::consts::FRAC_PI_4; + +consts!{ const PI_LO: Float64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ +} /// Arctangent of y/x /// @@ -78,16 +83,16 @@ pub fn atan2(y: Float64, x: Float64) -> Radian64 { } /* when x = 0 */ if (ix | lx) == 0 { - return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; + return if m & 1 != 0 { -FRAC_PI_2 } else { FRAC_PI_2 }; } /* when x is INF */ if ix == 0x7ff00000 { if iy == 0x7ff00000 { return match m { - 0 => PI / 4.0, /* atan(+INF,+INF) */ - 1 => -PI / 4.0, /* atan(-INF,+INF) */ - 2 => 3.0 * PI / 4.0, /* atan(+INF,-INF) */ - _ => -3.0 * PI / 4.0, /* atan(-INF,-INF) */ + 0 => FRAC_PI_4, /* atan(+INF,+INF) */ + 1 => -FRAC_PI_4, /* atan(-INF,+INF) */ + 2 => 3.0 * FRAC_PI_4, /* atan(+INF,-INF) */ + _ => -3.0 * FRAC_PI_4, /* atan(-INF,-INF) */ }; } else { return match m { @@ -100,7 +105,7 @@ pub fn atan2(y: Float64, x: Float64) -> Radian64 { } /* |y/x| > 0x1p64 */ if ix.wrapping_add(64 << 20) < iy || iy == 0x7ff00000 { - return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; + return if m & 1 != 0 { -FRAC_PI_2 } else { FRAC_PI_2 }; } /* z = atan(|y/x|) without spurious underflow */ diff --git a/core/llm/math/atan2f.rs b/core/llm/math/atan2f.rs index f711504..009909c 100644 --- a/core/llm/math/atan2f.rs +++ b/core/llm/math/atan2f.rs @@ -18,8 +18,13 @@ use crate::{Float32, Radian32}; use super::atanf; use super::fabsf; -const PI: Float32 = 3.1415927410e+00; /* 0x40490fdb */ +use core::f32::consts::PI; +use core::f32::consts::FRAC_PI_2; +use core::f32::consts::FRAC_PI_4; + +consts!{ const PI_LO: Float32 = -8.7422776573e-08; /* 0xb3bbbd2e */ +} /// Arctangent of y/x /// @@ -47,34 +52,34 @@ pub fn atan2f(y: Float32, x: Float32) -> Radian32 { return match m { 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ 2 => PI, /* atan(+0,-anything) = pi */ - 3 | _ => -PI, /* atan(-0,-anything) =-pi */ + _ => -PI, /* atan(-0,-anything) =-pi */ }; } /* when x = 0 */ if ix == 0 { - return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + return if m & 1 != 0 { -FRAC_PI_2 } else { FRAC_PI_2 }; } /* when x is INF */ if ix == 0x7f800000 { return if iy == 0x7f800000 { match m { - 0 => PI / 4., /* atan(+INF,+INF) */ - 1 => -PI / 4., /* atan(-INF,+INF) */ - 2 => 3. * PI / 4., /* atan(+INF,-INF)*/ - 3 | _ => -3. * PI / 4., /* atan(-INF,-INF)*/ + 0 => FRAC_PI_4, /* atan(+INF,+INF) */ + 1 => -FRAC_PI_4, /* atan(-INF,+INF) */ + 2 => 3. * FRAC_PI_4, /* atan(+INF,-INF)*/ + _ => -3. * FRAC_PI_4, /* atan(-INF,-INF)*/ } } else { match m { 0 => 0., /* atan(+...,+INF) */ 1 => -0., /* atan(-...,+INF) */ 2 => PI, /* atan(+...,-INF) */ - 3 | _ => -PI, /* atan(-...,-INF) */ + _ => -PI, /* atan(-...,-INF) */ } }; } /* |y/x| > 0x1p26 */ if (ix + (26 << 23) < iy) || (iy == 0x7f800000) { - return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + return if m & 1 != 0 { -FRAC_PI_2 } else { FRAC_PI_2 }; } /* z = atan(|y/x|) with correct underflow */ diff --git a/core/llm/math/atanf.rs b/core/llm/math/atanf.rs index f283fbe..50b0db7 100644 --- a/core/llm/math/atanf.rs +++ b/core/llm/math/atanf.rs @@ -17,6 +17,7 @@ use crate::{Float32, Radian32}; use super::fabsf; +consts!{ const ATAN_HI: [Float32; 4] = [ 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ @@ -38,6 +39,7 @@ const A_T: [Float32; 5] = [ -1.0648017377e-01, 6.1687607318e-02, ]; +} /// Arctangent /// diff --git a/core/llm/math/cbrt.rs b/core/llm/math/cbrt.rs index 4dc3cd1..115ad55 100644 --- a/core/llm/math/cbrt.rs +++ b/core/llm/math/cbrt.rs @@ -18,6 +18,7 @@ use crate::Float64; +consts!{ const B1: u32 = 715094163; /* B1 = (1023-1023/3-0.03306235651)*2**20 */ const B2: u32 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */ @@ -27,6 +28,7 @@ const P1: Float64 = -1.88497979543377169875; /* 0xbffe28e0, 0x92f02420 */ const P2: Float64 = 1.621429720105354466140; /* 0x3ff9f160, 0x4a49d6c2 */ const P3: Float64 = -0.758397934778766047437; /* 0xbfe844cb, 0xbee751d9 */ const P4: Float64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ +} // Cube root /// @@ -37,9 +39,9 @@ pub fn cbrt(x: Float64) -> Float64 { let mut ui: u64 = x.to_bits(); let mut r: Float64; - let s: Float64; + let mut t: Float64; - let w: Float64; + let mut hx: u32 = (ui >> 32) as u32 & 0x7fffffff; if hx >= 0x7ff00000 { @@ -47,21 +49,19 @@ pub fn cbrt(x: Float64) -> Float64 { return x + x; } - /* - * Rough cbrt to 5 bits: - * cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3) - * where e is integral and >= 0, m is real and in [0, 1), and "/" and - * "%" are integer division and modulus with rounding towards minus - * infinity. The RHS is always >= the LHS and has a maximum relative - * error of about 1 in 16. Adding a bias of -0.03306235651 to the - * (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE - * floating point representation, for finite positive normal values, - * ordinary integer divison of the value in bits magically gives - * almost exactly the RHS of the above provided we first subtract the - * exponent bias (1023 for doubles) and later add it back. We do the - * subtraction virtually to keep e >= 0 so that ordinary integer - * division rounds towards minus infinity; this is also efficient. - */ + // Rough cbrt to 5 bits: + // cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3) + // where e is integral and >= 0, m is real and in [0, 1), and "/" and + // "%" are integer division and modulus with rounding towards minus + // infinity. The RHS is always >= the LHS and has a maximum relative + // error of about 1 in 16. Adding a bias of -0.03306235651 to the + // (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE + // floating point representation, for finite positive normal values, + // ordinary integer divison of the value in bits magically gives + // almost exactly the RHS of the above provided we first subtract the + // exponent bias (1023 for doubles) and later add it back. We do the + // subtraction virtually to keep e >= 0 so that ordinary integer + // division rounds towards minus infinity; this is also efficient. if hx < 0x00100000 { /* zero or subnormal? */ ui = (x * x1p54).to_bits(); @@ -77,37 +77,33 @@ pub fn cbrt(x: Float64) -> Float64 { ui |= (hx as u64) << 32; t = Float64::from_bits(ui); - /* - * New cbrt to 23 bits: - * cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x) - * where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r) - * to within 2**-23.5 when |r - 1| < 1/10. The rough approximation - * has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this - * gives us bounds for r = t**3/x. - * - * Try to optimize for parallel evaluation as in __tanf.c. - */ + // New cbrt to 23 bits: + // cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x) + // where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r) + // to within 2**-23.5 when |r - 1| < 1/10. The rough approximation + // has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this + // gives us bounds for r = t**3/x. + // + // Try to optimize for parallel evaluation as in __tanf.c. r = (t * t) * (t / x); t = t * ((P0 + r * (P1 + r * P2)) + ((r * r) * r) * (P3 + r * P4)); - /* - * Round t away from zero to 23 bits (sloppily except for ensuring that - * the result is larger in magnitude than cbrt(x) but not much more than - * 2 23-bit ulps larger). With rounding towards zero, the error bound - * would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps - * in the rounded t, the infinite-precision error in the Newton - * approximation barely affects third digit in the final error - * 0.667; the error in the rounded t can be up to about 3 23-bit ulps - * before the final error is larger than 0.667 ulps. - */ + // Round t away from zero to 23 bits (sloppily except for ensuring that + // the result is larger in magnitude than cbrt(x) but not much more than + // 2 23-bit ulps larger). With rounding towards zero, the error bound + // would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps + // in the rounded t, the infinite-precision error in the Newton + // approximation barely affects third digit in the final error + // 0.667; the error in the rounded t can be up to about 3 23-bit ulps + // before the final error is larger than 0.667 ulps. ui = t.to_bits(); ui = (ui + 0x80000000) & 0xffffffffc0000000; t = Float64::from_bits(ui); /* one step Newton iteration to 53 bits with error < 0.667 ulps */ - s = t * t; /* t*t is exact */ + let s: Float64 = t * t; /* t*t is exact */ r = x / s; /* error <= 0.5 ulps; |r| < |t| */ - w = t + t; /* t+t is exact */ + let w: Float64 = t + t; /* t+t is exact */ r = (r - t) / (w + r); /* r-t is exact; w+r ~= 3*t */ t = t + t * r; /* error <= 0.5 + 0.5/3 + epsilon */ t diff --git a/core/llm/math/ceil.rs b/core/llm/math/ceil.rs index 02dd057..70771fb 100644 --- a/core/llm/math/ceil.rs +++ b/core/llm/math/ceil.rs @@ -37,13 +37,12 @@ pub fn ceil(x: Float64) -> Float64 { } let u: u64 = x.to_bits(); let e: i64 = (u >> 52 & 0x7ff) as i64; - let y: Float64; if e >= 0x3ff + 52 || x == 0. { return x; } // y = int(x) - x, where int(x) is an integer neighbor of x - y = if (u >> 63) != 0 { + let y = if (u >> 63) != 0 { x - TOINT + TOINT - x } else { x + TOINT - TOINT - x diff --git a/core/llm/math/erf.rs b/core/llm/math/erf.rs index 0eb0253..eb1a00b 100644 --- a/core/llm/math/erf.rs +++ b/core/llm/math/erf.rs @@ -108,10 +108,9 @@ use crate::Float64; use super::{exp, fabs, get_high_word, with_set_low_word}; +consts!{ const ERX: Float64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ -/** - * Coefficients for approximation to erf on [0,0.84375] -*/ +/* Coefficients for approximation to erf on [0,0.84375] */ const EFX8: Float64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ const PP0: Float64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ const PP1: Float64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ @@ -123,9 +122,7 @@ const QQ2: Float64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ const QQ3: Float64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ const QQ4: Float64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ const QQ5: Float64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ -/** - * Coefficients for approximation to erf in [0.84375,1.25] -*/ +/* Coefficients for approximation to erf in [0.84375,1.25] */ const PA0: Float64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ const PA1: Float64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ const PA2: Float64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ @@ -139,9 +136,7 @@ const QA3: Float64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ const QA4: Float64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ const QA5: Float64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ const QA6: Float64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ -/** - * Coefficients for approximation to erfc in [1.25,1/0.35] -*/ +/* Coefficients for approximation to erfc in [1.25,1/0.35] */ const RA0: Float64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ const RA1: Float64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ const RA2: Float64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ @@ -158,9 +153,7 @@ const SA5: Float64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ const SA6: Float64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ const SA7: Float64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ const SA8: Float64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ -/** - * Coefficients for approximation to erfc in [1/.35,28] -*/ +/* Coefficients for approximation to erfc in [1/.35,28] */ const RB0: Float64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ const RB1: Float64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ const RB2: Float64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ @@ -175,32 +168,25 @@ const SB4: Float64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ const SB5: Float64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ const SB6: Float64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ const SB7: Float64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ +} fn erfc1(x: Float64) -> Float64 { - let s: Float64; - let p: Float64; - let q: Float64; - - s = fabs(x) - 1.0; - p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); - q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); - + let s = fabs(x) - 1.0; + let p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); + let q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); 1.0 - ERX - p / q } fn erfc2(ix: u32, mut x: Float64) -> Float64 { - let s: Float64; let r: Float64; let big_s: Float64; - let z: Float64; - if ix < 0x3ff40000 { /* |x| < 1.25 */ return erfc1(x); } x = fabs(x); - s = 1.0 / (x * x); + let s: Float64 = 1.0 / (x * x); if ix < 0x4006db6d { /* |x| < 1/.35 ~ 2.85714 */ r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); @@ -213,7 +199,7 @@ fn erfc2(ix: u32, mut x: Float64) -> Float64 { big_s = 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); } - z = with_set_low_word(x, 0); + let z: Float64 = with_set_low_word(x, 0); exp(-z * z - 0.5625) * exp((z - x) * (z + x) + r / big_s) / x } @@ -230,10 +216,10 @@ pub fn erf(x: Float64) -> Float64 { let z: Float64; let y: Float64; let mut ix: u32; - let sign: usize; + ix = get_high_word(x); - sign = (ix >> 31) as usize; + let sign: usize = (ix >> 31) as usize; ix &= 0x7fffffff; if ix >= 0x7ff00000 { /* erf(nan)=nan, erf(+-inf)=+-1 */ @@ -279,10 +265,10 @@ pub fn erfc(x: Float64) -> Float64 { let z: Float64; let y: Float64; let mut ix: u32; - let sign: usize; + ix = get_high_word(x); - sign = (ix >> 31) as usize; + let sign: usize = (ix >> 31) as usize; ix &= 0x7fffffff; if ix >= 0x7ff00000 { /* erfc(nan)=nan, erfc(+-inf)=0,2 */ From d13fd6b7194347ad534ec38f88953e45e8f69927 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 15:31:05 -0800 Subject: [PATCH 11/93] E --- core/llm/math/erff.rs | 54 ++++++++++++----------------------------- core/llm/math/exp.rs | 23 +++++++----------- core/llm/math/exp10.rs | 2 ++ core/llm/math/exp10f.rs | 5 ++-- core/llm/math/exp2.rs | 2 +- core/llm/math/exp2f.rs | 2 +- core/llm/math/expf.rs | 2 ++ core/llm/math/expm1.rs | 4 ++- core/llm/math/expm1f.rs | 6 +++-- 9 files changed, 40 insertions(+), 60 deletions(-) diff --git a/core/llm/math/erff.rs b/core/llm/math/erff.rs index b25d595..f2a67f3 100644 --- a/core/llm/math/erff.rs +++ b/core/llm/math/erff.rs @@ -17,10 +17,9 @@ use crate::Float32; use super::{expf, fabsf}; +consts!{ const ERX: Float32 = 8.4506291151e-01; /* 0x3f58560b */ -/* - * Coefficients for approximation to erf on [0,0.84375] - */ +/* Coefficients for approximation to erf on [0,0.84375] */ const EFX8: Float32 = 1.0270333290e+00; /* 0x3f8375d4 */ const PP0: Float32 = 1.2837916613e-01; /* 0x3e0375d4 */ const PP1: Float32 = -3.2504209876e-01; /* 0xbea66beb */ @@ -32,9 +31,7 @@ const QQ2: Float32 = 6.5022252500e-02; /* 0x3d852a63 */ const QQ3: Float32 = 5.0813062117e-03; /* 0x3ba68116 */ const QQ4: Float32 = 1.3249473704e-04; /* 0x390aee49 */ const QQ5: Float32 = -3.9602282413e-06; /* 0xb684e21a */ -/* - * Coefficients for approximation to erf in [0.84375,1.25] - */ +/* Coefficients for approximation to erf in [0.84375,1.25] */ const PA0: Float32 = -2.3621185683e-03; /* 0xbb1acdc6 */ const PA1: Float32 = 4.1485610604e-01; /* 0x3ed46805 */ const PA2: Float32 = -3.7220788002e-01; /* 0xbebe9208 */ @@ -48,9 +45,7 @@ const QA3: Float32 = 7.1828655899e-02; /* 0x3d931ae7 */ const QA4: Float32 = 1.2617121637e-01; /* 0x3e013307 */ const QA5: Float32 = 1.3637083583e-02; /* 0x3c5f6e13 */ const QA6: Float32 = 1.1984500103e-02; /* 0x3c445aa3 */ -/* - * Coefficients for approximation to erfc in [1.25,1/0.35] - */ +/* Coefficients for approximation to erfc in [1.25,1/0.35] */ const RA0: Float32 = -9.8649440333e-03; /* 0xbc21a093 */ const RA1: Float32 = -6.9385856390e-01; /* 0xbf31a0b7 */ const RA2: Float32 = -1.0558626175e+01; /* 0xc128f022 */ @@ -67,9 +62,7 @@ const SA5: Float32 = 4.2900814819e+02; /* 0x43d6810b */ const SA6: Float32 = 1.0863500214e+02; /* 0x42d9451f */ const SA7: Float32 = 6.5702495575e+00; /* 0x40d23f7c */ const SA8: Float32 = -6.0424413532e-02; /* 0xbd777f97 */ -/* - * Coefficients for approximation to erfc in [1/.35,28] - */ +/* Coefficients for approximation to erfc in [1/.35,28] */ const RB0: Float32 = -9.8649431020e-03; /* 0xbc21a092 */ const RB1: Float32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ const RB2: Float32 = -1.7757955551e+01; /* 0xc18e104b */ @@ -84,31 +77,24 @@ const SB4: Float32 = 3.1998581543e+03; /* 0x4547fdbb */ const SB5: Float32 = 2.5530502930e+03; /* 0x451f90ce */ const SB6: Float32 = 4.7452853394e+02; /* 0x43ed43a7 */ const SB7: Float32 = -2.2440952301e+01; /* 0xc1b38712 */ +} fn erfc1(x: Float32) -> Float32 { - let s: Float32; - let p: Float32; - let q: Float32; - - s = fabsf(x) - 1.0; - p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); - q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); + let s = fabsf(x) - 1.0; + let p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); + let q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); return 1.0 - ERX - p / q; } fn erfc2(mut ix: u32, mut x: Float32) -> Float32 { - let s: Float32; let r: Float32; let big_s: Float32; - let z: Float32; - if ix < 0x3fa00000 { /* |x| < 1.25 */ return erfc1(x); } - x = fabsf(x); - s = 1.0 / (x * x); + let s: Float32 = 1.0 / (x * x); if ix < 0x4036db6d { /* |x| < 1/0.35 */ r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); @@ -122,8 +108,7 @@ fn erfc2(mut ix: u32, mut x: Float32) -> Float32 { 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); } ix = x.to_bits(); - z = Float32::from_bits(ix & 0xffffe000); - + let z = Float32::from_bits(ix & 0xffffe000); expf(-z * z - 0.5625) * expf((z - x) * (z + x) + r / big_s) / x } @@ -138,12 +123,8 @@ pub fn erff(x: Float32) -> Float32 { let s: Float32; let z: Float32; let y: Float32; - let mut ix: u32; - let sign: usize; - - ix = x.to_bits(); - sign = (ix >> 31) as usize; - ix &= 0x7fffffff; + let ix: u32 = x.to_bits() & 0x7fffffff; + let sign: usize = (ix >> 31) as usize; if ix >= 0x7f800000 { /* erf(nan)=nan, erf(+-inf)=+-1 */ return 1.0 - 2.0 * (sign as Float32) + 1.0 / x; @@ -187,17 +168,12 @@ pub fn erfcf(x: Float32) -> Float32 { let s: Float32; let z: Float32; let y: Float32; - let mut ix: u32; - let sign: usize; - - ix = x.to_bits(); - sign = (ix >> 31) as usize; - ix &= 0x7fffffff; + let ix: u32 = x.to_bits() & 0x7fffffff; + let sign: usize = (ix >> 31) as usize; if ix >= 0x7f800000 { /* erfc(nan)=nan, erfc(+-inf)=0,2 */ return 2.0 * (sign as Float32) + 1.0 / x; } - if ix < 0x3f580000 { /* |x| < 0.84375 */ if ix < 0x23800000 { diff --git a/core/llm/math/exp.rs b/core/llm/math/exp.rs index 3b931bd..48c51a4 100644 --- a/core/llm/math/exp.rs +++ b/core/llm/math/exp.rs @@ -70,6 +70,7 @@ use crate::{Float64, Float32}; use super::scalbn; +consts!{ const HALF: [Float64; 2] = [0.5, -0.5]; const LN2HI: Float64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ const LN2LO: Float64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ @@ -79,6 +80,7 @@ const P2: Float64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ const P3: Float64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ const P4: Float64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ const P5: Float64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ +} /// Exponential, base *e* /// @@ -88,35 +90,28 @@ const P5: Float64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ pub fn exp(mut x: Float64) -> Float64 { let x1p1023 = Float64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 let x1p_149 = Float64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149 - let hi: Float64; let lo: Float64; - let c: Float64; - let xx: Float64; - let y: Float64; let k: i32; - let sign: i32; let mut hx: u32; - hx = (x.to_bits() >> 32) as u32; - sign = (hx >> 31) as i32; + let sign: i32 = (hx >> 31) as i32; hx &= 0x7fffffff; /* high word of |x| */ - /* special cases */ if hx >= 0x4086232b { /* if |x| >= 708.39... */ if x.is_nan() { return x; } - if x > 709.782712893383973096 { + if x > 709.782_712_893_384 { /* overflow if x!=inf */ x *= x1p1023; return x; } - if x < -708.39641853226410622 { + if x < -708.396_418_532_264_1 { /* underflow if x!=-inf */ force_eval!((-x1p_149 / x) as Float32); - if x < -745.13321910194110842 { + if x < -745.133_219_101_941_1 { return 0.; } } @@ -146,9 +141,9 @@ pub fn exp(mut x: Float64) -> Float64 { } /* x is now in primary range */ - xx = x * x; - c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); - y = 1. + (x * c / (2. - c) - lo + hi); + let xx: Float64 = x * x; + let c: Float64 = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); + let y: Float64 = 1. + (x * c / (2. - c) - lo + hi); if k == 0 { y } else { diff --git a/core/llm/math/exp10.rs b/core/llm/math/exp10.rs index 3a132b8..9c6722d 100644 --- a/core/llm/math/exp10.rs +++ b/core/llm/math/exp10.rs @@ -2,11 +2,13 @@ use crate::Float64; use super::{exp2, modf, pow}; +consts!{ const LN10: Float64 = 3.32192809488736234787031942948939; const P10: &[Float64] = &[ 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, ]; +} /// Exponential, base 10 /// diff --git a/core/llm/math/exp10f.rs b/core/llm/math/exp10f.rs index 10fa27c..0b602eb 100644 --- a/core/llm/math/exp10f.rs +++ b/core/llm/math/exp10f.rs @@ -2,8 +2,9 @@ use crate::{Float64, Float32}; use super::{exp2, exp2f, modff}; -const LN10_F32: Float32 = 3.32192809488736234787031942948939; -const LN10_F64: Float64 = 3.32192809488736234787031942948939; +use core::f64::consts::LN_10 as LN10_F64; +use core::f32::consts::LN_10 as LN10_F32; + const P10: &[Float32] = &[ 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, ]; diff --git a/core/llm/math/exp2.rs b/core/llm/math/exp2.rs index 3b7e9dd..3f37829 100644 --- a/core/llm/math/exp2.rs +++ b/core/llm/math/exp2.rs @@ -30,7 +30,7 @@ use super::scalbn; const TBLSIZE: usize = 256; -#[cfg_attr(rustfmt, rustfmt_skip)] +#[rustfmt::skip] static TBL: [u64; TBLSIZE * 2] = [ // exp2(z + eps) eps 0x3fe6a09e667f3d5d, 0x3d39880000000000, diff --git a/core/llm/math/exp2f.rs b/core/llm/math/exp2f.rs index 2b4fb35..7db3658 100644 --- a/core/llm/math/exp2f.rs +++ b/core/llm/math/exp2f.rs @@ -98,7 +98,7 @@ pub fn exp2f(mut x: Float32) -> Float32 { /* NaN */ return x; } - if ui >= 0x43000000 && ui < 0x80000000 { + if (0x43000000..0x80000000).contains(&ui) { /* x >= 128 */ x *= x1p127; return x; diff --git a/core/llm/math/expf.rs b/core/llm/math/expf.rs index 2054e08..7c6c104 100644 --- a/core/llm/math/expf.rs +++ b/core/llm/math/expf.rs @@ -17,6 +17,7 @@ use crate::Float32; use super::scalbnf; +consts!{ const HALF: [Float32; 2] = [0.5, -0.5]; const LN2_HI: Float32 = 6.9314575195e-01; /* 0x3f317200 */ const LN2_LO: Float32 = 1.4286067653e-06; /* 0x35bfbe8e */ @@ -27,6 +28,7 @@ const INV_LN2: Float32 = 1.4426950216e+00; /* 0x3fb8aa3b */ */ const P1: Float32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ const P2: Float32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ +} /// Exponential, base *e* /// diff --git a/core/llm/math/expm1.rs b/core/llm/math/expm1.rs index e9d00ee..7f48dd5 100644 --- a/core/llm/math/expm1.rs +++ b/core/llm/math/expm1.rs @@ -12,6 +12,7 @@ use crate::Float64; +consts!{ const O_THRESHOLD: Float64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ const LN2_HI: Float64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ const LN2_LO: Float64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ @@ -22,6 +23,7 @@ const Q2: Float64 = 1.58730158725481460165e-03; /* 3F5A01A0 19FE5585 */ const Q3: Float64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ const Q4: Float64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ const Q5: Float64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ +} /// Exponential, base *e*, of x-1 /// @@ -115,7 +117,7 @@ pub fn expm1(mut x: Float64) -> Float64 { } ui = ((0x3ff + k) as u64) << 52; /* 2^k */ let twopk = Float64::from_bits(ui); - if k < 0 || k > 56 { + if !(0..=56).contains(&k) { /* suffice to return exp(x)-1 */ y = x - e + 1.0; if k == 1024 { diff --git a/core/llm/math/expm1f.rs b/core/llm/math/expm1f.rs index 5a73f40..fb77837 100644 --- a/core/llm/math/expm1f.rs +++ b/core/llm/math/expm1f.rs @@ -15,17 +15,19 @@ use crate::Float32; +consts!{ const O_THRESHOLD: Float32 = 8.8721679688e+01; /* 0x42b17180 */ const LN2_HI: Float32 = 6.9313812256e-01; /* 0x3f317180 */ const LN2_LO: Float32 = 9.0580006145e-06; /* 0x3717f7d1 */ const INV_LN2: Float32 = 1.4426950216e+00; /* 0x3fb8aa3b */ -/** +/* * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): */ const Q1: Float32 = -3.3333212137e-2; /* -0x888868.0p-28 */ const Q2: Float32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ +} /// Exponential, base *e*, of x-1 /// @@ -117,7 +119,7 @@ pub fn expm1f(mut x: Float32) -> Float32 { return 1. + 2. * (x - e); } let twopk = Float32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */ - if (k < 0) || (k > 56) { + if !(0..=56).contains(&k) { /* suffice to return exp(x)-1 */ let mut y = x - e + 1.; if k == 128 { From db0eec2fb0f7f66e3ff41813ce0975d69b5e67df Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 15:31:17 -0800 Subject: [PATCH 12/93] F --- core/llm/math/fdim.rs | 1 + core/llm/math/fdimf.rs | 1 + core/llm/math/fmaf.rs | 9 +++------ 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core/llm/math/fdim.rs b/core/llm/math/fdim.rs index 43f00c8..92da694 100644 --- a/core/llm/math/fdim.rs +++ b/core/llm/math/fdim.rs @@ -1,5 +1,6 @@ use crate::Float64; +#[allow(clippy::tabs_in_doc_comments)] /// Positive difference /// /// Determines the positive difference between arguments, returning: diff --git a/core/llm/math/fdimf.rs b/core/llm/math/fdimf.rs index 48ada35..3b337dd 100644 --- a/core/llm/math/fdimf.rs +++ b/core/llm/math/fdimf.rs @@ -1,5 +1,6 @@ use crate::Float32; +#[allow(clippy::tabs_in_doc_comments)] /// Positive difference /// /// Determines the positive difference between arguments, returning: diff --git a/core/llm/math/fmaf.rs b/core/llm/math/fmaf.rs index f20dbec..f453007 100644 --- a/core/llm/math/fmaf.rs +++ b/core/llm/math/fmaf.rs @@ -48,15 +48,12 @@ use super::fenv::{ /// according to the rounding mode characterized by the value of FLT_ROUNDS. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaf(x: Float32, y: Float32, mut z: Float32) -> Float32 { - let xy: Float64; let mut result: Float64; let mut ui: u64; - let e: i32; - - xy = x as Float64 * y as Float64; + let xy: Float64 = x as Float64 * y as Float64; result = xy + z as Float64; ui = result.to_bits(); - e = (ui >> 52) as i32 & 0x7ff; + let e: i32 = (ui >> 52) as i32 & 0x7ff; /* Common case: The double precision result is fine. */ if ( /* not a halfway case */ @@ -72,7 +69,7 @@ pub fn fmaf(x: Float32, y: Float32, mut z: Float32) -> Float32 { underflow may not be raised correctly, example: fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) */ - if e < 0x3ff - 126 && e >= 0x3ff - 149 && fetestexcept(FE_INEXACT) != 0 { + if (0x3ff - 149..0x3ff - 126).contains(&e) && fetestexcept(FE_INEXACT) != 0 { feclearexcept(FE_INEXACT); // prevent `xy + vz` from being CSE'd with `xy + z` above let vz: Float32 = unsafe { read_volatile(&z) }; From 4603fed9b5fe946f26ddc9ca049f64fa06439264 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 15:31:23 -0800 Subject: [PATCH 13/93] H --- core/llm/math/hypot.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/core/llm/math/hypot.rs b/core/llm/math/hypot.rs index ac5e255..df53bab 100644 --- a/core/llm/math/hypot.rs +++ b/core/llm/math/hypot.rs @@ -5,13 +5,9 @@ use super::sqrt; const SPLIT: Float64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 fn sq(x: Float64) -> (Float64, Float64) { - let xh: Float64; - let xl: Float64; - let xc: Float64; - - xc = x * SPLIT; - xh = x - xc + xc; - xl = x - xh; + let xc = x * SPLIT; + let xh = x - xc + xc; + let xl = x - xh; let hi = x * x; let lo = xh * xh - hi + 2. * xh * xl + xl * xl; (hi, lo) @@ -26,8 +22,6 @@ pub fn hypot(mut x: Float64, mut y: Float64) -> Float64 { let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); let uti; - let ex: i64; - let ey: i64; let mut z: Float64; /* arrange |x| >= |y| */ @@ -40,8 +34,8 @@ pub fn hypot(mut x: Float64, mut y: Float64) -> Float64 { } /* special cases */ - ex = (uxi >> 52) as i64; - ey = (uyi >> 52) as i64; + let ex: i64 = (uxi >> 52) as i64; + let ey: i64 = (uyi >> 52) as i64; x = Float64::from_bits(uxi); y = Float64::from_bits(uyi); /* note: hypot(inf,nan) == inf */ From b7d51dd507c6d755d66ffb59af63d40bacc622ca Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 15:32:03 -0800 Subject: [PATCH 14/93] Also This --- core/llm/math.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/llm/math.rs b/core/llm/math.rs index 9ec9163..84e9869 100644 --- a/core/llm/math.rs +++ b/core/llm/math.rs @@ -74,6 +74,17 @@ macro_rules! div { }; } + +macro_rules! consts { + (const $name:ident: $ty:ty = $value:expr; $($t:tt)* ) => ( + #[allow(clippy::excessive_precision)] + #[deny(clippy::approx_constant)] + const $name: $ty = $value; + consts!($($t)*); + ); + () => (); +} + macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { #[cfg(all($($clause)*))] From 390cbd75b4962f2682df88fdb27bd001e8aa1e3d Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 15:46:32 -0800 Subject: [PATCH 15/93] Fixed 2 bugs --- core/llm/math/erff.rs | 10 ++++++---- core/llm/math/exp.rs | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/core/llm/math/erff.rs b/core/llm/math/erff.rs index f2a67f3..58a12a3 100644 --- a/core/llm/math/erff.rs +++ b/core/llm/math/erff.rs @@ -123,8 +123,9 @@ pub fn erff(x: Float32) -> Float32 { let s: Float32; let z: Float32; let y: Float32; - let ix: u32 = x.to_bits() & 0x7fffffff; - let sign: usize = (ix >> 31) as usize; + let mut ix: u32 = x.to_bits(); + let sign = (ix >> 31) as usize; + ix &= 0x7fffffff; if ix >= 0x7f800000 { /* erf(nan)=nan, erf(+-inf)=+-1 */ return 1.0 - 2.0 * (sign as Float32) + 1.0 / x; @@ -168,8 +169,9 @@ pub fn erfcf(x: Float32) -> Float32 { let s: Float32; let z: Float32; let y: Float32; - let ix: u32 = x.to_bits() & 0x7fffffff; - let sign: usize = (ix >> 31) as usize; + let mut ix = x.to_bits(); + let sign = (ix >> 31) as usize; + ix &= 0x7fffffff; if ix >= 0x7f800000 { /* erfc(nan)=nan, erfc(+-inf)=0,2 */ return 2.0 * (sign as Float32) + 1.0 / x; diff --git a/core/llm/math/exp.rs b/core/llm/math/exp.rs index 48c51a4..9e4800b 100644 --- a/core/llm/math/exp.rs +++ b/core/llm/math/exp.rs @@ -103,15 +103,18 @@ pub fn exp(mut x: Float64) -> Float64 { if x.is_nan() { return x; } - if x > 709.782_712_893_384 { + #[allow(clippy::excessive_precision)] + if x > 709.782_712_893_383_973_096 { /* overflow if x!=inf */ x *= x1p1023; return x; } - if x < -708.396_418_532_264_1 { + #[allow(clippy::excessive_precision)] + if x < -708.396_418_532_264_106_22 { /* underflow if x!=-inf */ force_eval!((-x1p_149 / x) as Float32); - if x < -745.133_219_101_941_1 { + #[allow(clippy::excessive_precision)] + if x < -745.133_219_101_941_108_42 { return 0.; } } From 6937557d1adfc0af5ec66e7ded0eff5d14da0dad Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 15:59:02 -0800 Subject: [PATCH 16/93] Refactor --- Cargo.toml | 22 +- README.md | 9 +- core/llm/math/jnf.rs | 264 ----------------- core/macros/Cargo.toml | 13 - libtrig/Cargo.toml | 15 + {core => libtrig}/README.md | 0 libtrig/lib.rs | 2 +- {core/llm => llm}/Cargo.toml | 8 +- {core/llm => llm}/README.md | 0 {core/llm => llm}/lib.rs | 0 {core/llm => llm}/math.rs | 0 {core/llm => llm}/math/acos.rs | 0 {core/llm => llm}/math/acosf.rs | 0 {core/llm => llm}/math/acosh.rs | 0 {core/llm => llm}/math/acoshf.rs | 0 {core/llm => llm}/math/asin.rs | 0 {core/llm => llm}/math/asinf.rs | 0 {core/llm => llm}/math/asinh.rs | 0 {core/llm => llm}/math/asinhf.rs | 0 {core/llm => llm}/math/atan.rs | 0 {core/llm => llm}/math/atan2.rs | 0 {core/llm => llm}/math/atan2f.rs | 0 {core/llm => llm}/math/atanf.rs | 0 {core/llm => llm}/math/atanh.rs | 0 {core/llm => llm}/math/atanhf.rs | 0 {core/llm => llm}/math/cbrt.rs | 0 {core/llm => llm}/math/cbrtf.rs | 0 {core/llm => llm}/math/ceil.rs | 0 {core/llm => llm}/math/ceilf.rs | 0 {core/llm => llm}/math/copysign.rs | 0 {core/llm => llm}/math/copysignf.rs | 0 {core/llm => llm}/math/cos.rs | 0 {core/llm => llm}/math/cosf.rs | 0 {core/llm => llm}/math/cosh.rs | 0 {core/llm => llm}/math/coshf.rs | 0 {core/llm => llm}/math/erf.rs | 0 {core/llm => llm}/math/erff.rs | 0 {core/llm => llm}/math/exp.rs | 0 {core/llm => llm}/math/exp10.rs | 0 {core/llm => llm}/math/exp10f.rs | 0 {core/llm => llm}/math/exp2.rs | 0 {core/llm => llm}/math/exp2f.rs | 0 {core/llm => llm}/math/expf.rs | 0 {core/llm => llm}/math/expm1.rs | 0 {core/llm => llm}/math/expm1f.rs | 0 {core/llm => llm}/math/expo2.rs | 0 {core/llm => llm}/math/fabs.rs | 0 {core/llm => llm}/math/fabsf.rs | 0 {core/llm => llm}/math/fdim.rs | 0 {core/llm => llm}/math/fdimf.rs | 0 {core/llm => llm}/math/fenv.rs | 0 {core/llm => llm}/math/floor.rs | 0 {core/llm => llm}/math/floorf.rs | 0 {core/llm => llm}/math/fma.rs | 0 {core/llm => llm}/math/fmaf.rs | 0 {core/llm => llm}/math/fmax.rs | 0 {core/llm => llm}/math/fmaxf.rs | 0 {core/llm => llm}/math/fmin.rs | 0 {core/llm => llm}/math/fminf.rs | 0 {core/llm => llm}/math/fmod.rs | 0 {core/llm => llm}/math/fmodf.rs | 0 {core/llm => llm}/math/frexp.rs | 0 {core/llm => llm}/math/frexpf.rs | 0 {core/llm => llm}/math/hypot.rs | 0 {core/llm => llm}/math/hypotf.rs | 0 {core/llm => llm}/math/ilogb.rs | 0 {core/llm => llm}/math/ilogbf.rs | 0 {core/llm => llm}/math/j0.rs | 47 +-- {core/llm => llm}/math/j0f.rs | 49 ++-- {core/llm => llm}/math/j1.rs | 158 +++++----- {core/llm => llm}/math/j1f.rs | 270 +++++++++--------- {core/llm => llm}/math/jn.rs | 242 ++++++++-------- llm/math/jnf.rs | 262 +++++++++++++++++ {core/llm => llm}/math/k_cos.rs | 12 +- {core/llm => llm}/math/k_cosf.rs | 8 +- {core/llm => llm}/math/k_expo2.rs | 0 {core/llm => llm}/math/k_expo2f.rs | 0 {core/llm => llm}/math/k_sin.rs | 12 +- {core/llm => llm}/math/k_sinf.rs | 8 +- {core/llm => llm}/math/k_tan.rs | 30 +- {core/llm => llm}/math/k_tanf.rs | 12 +- {core/llm => llm}/math/ldexp.rs | 0 {core/llm => llm}/math/ldexpf.rs | 0 {core/llm => llm}/math/lgamma.rs | 0 {core/llm => llm}/math/lgamma_r.rs | 132 ++++----- {core/llm => llm}/math/lgammaf.rs | 0 {core/llm => llm}/math/lgammaf_r.rs | 134 ++++----- {core/llm => llm}/math/ln.rs | 0 {core/llm => llm}/math/lnf.rs | 0 {core/llm => llm}/math/log.rs | 18 +- {core/llm => llm}/math/log10.rs | 62 ++-- {core/llm => llm}/math/log10f.rs | 56 ++-- {core/llm => llm}/math/log1p.rs | 31 +- {core/llm => llm}/math/log1pf.rs | 48 ++-- {core/llm => llm}/math/log2.rs | 54 ++-- {core/llm => llm}/math/log2f.rs | 48 ++-- {core/llm => llm}/math/logf.rs | 12 +- {core/llm => llm}/math/modf.rs | 4 +- {core/llm => llm}/math/modff.rs | 4 +- {core/llm => llm}/math/nextafter.rs | 4 +- {core/llm => llm}/math/nextafterf.rs | 0 {core/llm => llm}/math/pow.rs | 58 ++-- {core/llm => llm}/math/powf.rs | 72 ++--- {core/llm => llm}/math/rem_pio2.rs | 16 +- {core/llm => llm}/math/rem_pio2_large.rs | 16 +- {core/llm => llm}/math/rem_pio2f.rs | 6 +- {core/llm => llm}/math/remainder.rs | 0 {core/llm => llm}/math/remainderf.rs | 0 {core/llm => llm}/math/remquo.rs | 0 {core/llm => llm}/math/remquof.rs | 0 {core/llm => llm}/math/rint.rs | 0 {core/llm => llm}/math/rintf.rs | 0 {core/llm => llm}/math/round.rs | 0 {core/llm => llm}/math/roundf.rs | 0 {core/llm => llm}/math/scalbn.rs | 0 {core/llm => llm}/math/scalbnf.rs | 0 {core/llm => llm}/math/sin.rs | 0 {core/llm => llm}/math/sincos.rs | 8 +- {core/llm => llm}/math/sincosf.rs | 32 +-- {core/llm => llm}/math/sinf.rs | 0 {core/llm => llm}/math/sinh.rs | 8 +- {core/llm => llm}/math/sinhf.rs | 0 {core/llm => llm}/math/sqrt.rs | 0 {core/llm => llm}/math/sqrtf.rs | 2 +- {core/llm => llm}/math/tan.rs | 0 {core/llm => llm}/math/tanf.rs | 0 {core/llm => llm}/math/tanh.rs | 8 +- {core/llm => llm}/math/tanhf.rs | 0 {core/llm => llm}/math/tgamma.rs | 34 +-- {core/llm => llm}/math/tgammaf.rs | 0 {core/llm => llm}/math/trunc.rs | 4 +- {core/llm => llm}/math/truncf.rs | 4 +- {core/llm => llm}/types.rs | 0 utils/README.md | 1 + utils/macros/Cargo.toml | 12 + {core => utils}/macros/README.md | 0 .../macros/core}/Cargo.toml | 2 +- .../macros/core}/ffi/mod.rs | 0 .../macros/core}/lib.rs | 0 .../macros/core}/mass_impl/args.rs | 0 .../macros/core}/mass_impl/mod.rs | 0 .../macros/core}/mass_impl/variants.rs | 0 {core => utils}/macros/lib.rs | 0 143 files changed, 1162 insertions(+), 1171 deletions(-) delete mode 100644 core/llm/math/jnf.rs delete mode 100644 core/macros/Cargo.toml create mode 100644 libtrig/Cargo.toml rename {core => libtrig}/README.md (100%) rename {core/llm => llm}/Cargo.toml (52%) rename {core/llm => llm}/README.md (100%) rename {core/llm => llm}/lib.rs (100%) rename {core/llm => llm}/math.rs (100%) rename {core/llm => llm}/math/acos.rs (100%) rename {core/llm => llm}/math/acosf.rs (100%) rename {core/llm => llm}/math/acosh.rs (100%) rename {core/llm => llm}/math/acoshf.rs (100%) rename {core/llm => llm}/math/asin.rs (100%) rename {core/llm => llm}/math/asinf.rs (100%) rename {core/llm => llm}/math/asinh.rs (100%) rename {core/llm => llm}/math/asinhf.rs (100%) rename {core/llm => llm}/math/atan.rs (100%) rename {core/llm => llm}/math/atan2.rs (100%) rename {core/llm => llm}/math/atan2f.rs (100%) rename {core/llm => llm}/math/atanf.rs (100%) rename {core/llm => llm}/math/atanh.rs (100%) rename {core/llm => llm}/math/atanhf.rs (100%) rename {core/llm => llm}/math/cbrt.rs (100%) rename {core/llm => llm}/math/cbrtf.rs (100%) rename {core/llm => llm}/math/ceil.rs (100%) rename {core/llm => llm}/math/ceilf.rs (100%) rename {core/llm => llm}/math/copysign.rs (100%) rename {core/llm => llm}/math/copysignf.rs (100%) rename {core/llm => llm}/math/cos.rs (100%) rename {core/llm => llm}/math/cosf.rs (100%) rename {core/llm => llm}/math/cosh.rs (100%) rename {core/llm => llm}/math/coshf.rs (100%) rename {core/llm => llm}/math/erf.rs (100%) rename {core/llm => llm}/math/erff.rs (100%) rename {core/llm => llm}/math/exp.rs (100%) rename {core/llm => llm}/math/exp10.rs (100%) rename {core/llm => llm}/math/exp10f.rs (100%) rename {core/llm => llm}/math/exp2.rs (100%) rename {core/llm => llm}/math/exp2f.rs (100%) rename {core/llm => llm}/math/expf.rs (100%) rename {core/llm => llm}/math/expm1.rs (100%) rename {core/llm => llm}/math/expm1f.rs (100%) rename {core/llm => llm}/math/expo2.rs (100%) rename {core/llm => llm}/math/fabs.rs (100%) rename {core/llm => llm}/math/fabsf.rs (100%) rename {core/llm => llm}/math/fdim.rs (100%) rename {core/llm => llm}/math/fdimf.rs (100%) rename {core/llm => llm}/math/fenv.rs (100%) rename {core/llm => llm}/math/floor.rs (100%) rename {core/llm => llm}/math/floorf.rs (100%) rename {core/llm => llm}/math/fma.rs (100%) rename {core/llm => llm}/math/fmaf.rs (100%) rename {core/llm => llm}/math/fmax.rs (100%) rename {core/llm => llm}/math/fmaxf.rs (100%) rename {core/llm => llm}/math/fmin.rs (100%) rename {core/llm => llm}/math/fminf.rs (100%) rename {core/llm => llm}/math/fmod.rs (100%) rename {core/llm => llm}/math/fmodf.rs (100%) rename {core/llm => llm}/math/frexp.rs (100%) rename {core/llm => llm}/math/frexpf.rs (100%) rename {core/llm => llm}/math/hypot.rs (100%) rename {core/llm => llm}/math/hypotf.rs (100%) rename {core/llm => llm}/math/ilogb.rs (100%) rename {core/llm => llm}/math/ilogbf.rs (100%) rename {core/llm => llm}/math/j0.rs (96%) rename {core/llm => llm}/math/j0f.rs (93%) rename {core/llm => llm}/math/j1.rs (73%) rename {core/llm => llm}/math/j1f.rs (51%) rename {core/llm => llm}/math/jn.rs (59%) create mode 100644 llm/math/jnf.rs rename {core/llm => llm}/math/k_cos.rs (85%) rename {core/llm => llm}/math/k_cosf.rs (76%) rename {core/llm => llm}/math/k_expo2.rs (100%) rename {core/llm => llm}/math/k_expo2f.rs (100%) rename {core/llm => llm}/math/k_sin.rs (83%) rename {core/llm => llm}/math/k_sinf.rs (73%) rename {core/llm => llm}/math/k_tan.rs (78%) rename {core/llm => llm}/math/k_tanf.rs (81%) rename {core/llm => llm}/math/ldexp.rs (100%) rename {core/llm => llm}/math/ldexpf.rs (100%) rename {core/llm => llm}/math/lgamma.rs (100%) rename {core/llm => llm}/math/lgamma_r.rs (65%) rename {core/llm => llm}/math/lgammaf.rs (100%) rename {core/llm => llm}/math/lgammaf_r.rs (60%) rename {core/llm => llm}/math/ln.rs (100%) rename {core/llm => llm}/math/lnf.rs (100%) rename {core/llm => llm}/math/log.rs (86%) rename {core/llm => llm}/math/log10.rs (67%) rename {core/llm => llm}/math/log10f.rs (66%) rename {core/llm => llm}/math/log1p.rs (91%) rename {core/llm => llm}/math/log1pf.rs (75%) rename {core/llm => llm}/math/log2.rs (68%) rename {core/llm => llm}/math/log2f.rs (70%) rename {core/llm => llm}/math/logf.rs (83%) rename {core/llm => llm}/math/modf.rs (94%) rename {core/llm => llm}/math/modff.rs (94%) rename {core/llm => llm}/math/nextafter.rs (93%) rename {core/llm => llm}/math/nextafterf.rs (100%) rename {core/llm => llm}/math/pow.rs (90%) rename {core/llm => llm}/math/powf.rs (83%) rename {core/llm => llm}/math/rem_pio2.rs (91%) rename {core/llm => llm}/math/rem_pio2_large.rs (97%) rename {core/llm => llm}/math/rem_pio2f.rs (90%) rename {core/llm => llm}/math/remainder.rs (100%) rename {core/llm => llm}/math/remainderf.rs (100%) rename {core/llm => llm}/math/remquo.rs (100%) rename {core/llm => llm}/math/remquof.rs (100%) rename {core/llm => llm}/math/rint.rs (100%) rename {core/llm => llm}/math/rintf.rs (100%) rename {core/llm => llm}/math/round.rs (100%) rename {core/llm => llm}/math/roundf.rs (100%) rename {core/llm => llm}/math/scalbn.rs (100%) rename {core/llm => llm}/math/scalbnf.rs (100%) rename {core/llm => llm}/math/sin.rs (100%) rename {core/llm => llm}/math/sincos.rs (97%) rename {core/llm => llm}/math/sincosf.rs (88%) rename {core/llm => llm}/math/sinf.rs (100%) rename {core/llm => llm}/math/sinh.rs (94%) rename {core/llm => llm}/math/sinhf.rs (100%) rename {core/llm => llm}/math/sqrt.rs (100%) rename {core/llm => llm}/math/sqrtf.rs (99%) rename {core/llm => llm}/math/tan.rs (100%) rename {core/llm => llm}/math/tanf.rs (100%) rename {core/llm => llm}/math/tanh.rs (93%) rename {core/llm => llm}/math/tanhf.rs (100%) rename {core/llm => llm}/math/tgamma.rs (83%) rename {core/llm => llm}/math/tgammaf.rs (100%) rename {core/llm => llm}/math/trunc.rs (96%) rename {core/llm => llm}/math/truncf.rs (96%) rename {core/llm => llm}/types.rs (100%) create mode 100644 utils/README.md create mode 100644 utils/macros/Cargo.toml rename {core => utils}/macros/README.md (100%) rename {core/macros/libtrig-macros-core => utils/macros/core}/Cargo.toml (80%) rename {core/macros/libtrig-macros-core => utils/macros/core}/ffi/mod.rs (100%) rename {core/macros/libtrig-macros-core => utils/macros/core}/lib.rs (100%) rename {core/macros/libtrig-macros-core => utils/macros/core}/mass_impl/args.rs (100%) rename {core/macros/libtrig-macros-core => utils/macros/core}/mass_impl/mod.rs (100%) rename {core/macros/libtrig-macros-core => utils/macros/core}/mass_impl/variants.rs (100%) rename {core => utils}/macros/lib.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 4accd25..c663bb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,21 +1,7 @@ [workspace] +resolver = "2" members = [ - "core/llm", - "core/macros" + "libtrig", + "llm", + "utils/macros" ] - -[package] -name = "libtrig" -version = "0.1.0" -edition = "2021" - -[dependencies.macros] -package = "libtrig-macros" -path = "./core/macros" - -[dependencies.llm] -package = "libtrig-llm" -path = "./core/llm" - -[lib] -path = "./libtrig/lib.rs" diff --git a/README.md b/README.md index 0ee74df..143db78 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ -# Libtrig +# `LibRoboMath` -## A complete trigonometry and odometry library for Rust +## A complete trigonometry, odometry, and pathing library + +### Modules + +- **[`llm`](./llm/)** - Low Level Math - Fundamental math functions and types +- **[`libtrig`](./libtrig/)** - Trigonometry functionality (angles, vectors, etc.) diff --git a/core/llm/math/jnf.rs b/core/llm/math/jnf.rs deleted file mode 100644 index 35bb33a..0000000 --- a/core/llm/math/jnf.rs +++ /dev/null @@ -1,264 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::Float32; - -use super::{fabsf, j0f, j1f, logf, y0f, y1f}; - -/// Bessel function of the first kind of order zero -/// -/// Calculates the Bessel function of the first kind of order zero of `x`. -pub fn jnf(n: i32, mut x: Float32) -> Float32 { - let mut ix: u32; - let mut nm1: i32; - let mut sign: bool; - let mut i: i32; - let mut a: Float32; - let mut b: Float32; - let mut temp: Float32; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix > 0x7f800000 { - /* nan */ - return x; - } - - /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ - if n == 0 { - return j0f(x); - } - if n < 0 { - nm1 = -(n + 1); - x = -x; - sign = !sign; - } else { - nm1 = n - 1; - } - if nm1 == 0 { - return j1f(x); - } - - sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ - x = fabsf(x); - if ix == 0 || ix == 0x7f800000 { - /* if x is 0 or inf */ - b = 0.0; - } else if (nm1 as Float32) < x { - /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ - a = j0f(x); - b = j1f(x); - i = 0; - while i < nm1 { - i += 1; - temp = b; - b = b * (2.0 * (i as Float32) / x) - a; - a = temp; - } - } else { - if ix < 0x35800000 { - // x < 2**-20 - //x is tiny, return the first Taylor expansion of J(n,x) - // J(n,x) = 1/n!*(x/2)^n - ... - if nm1 > 8 { - /* underflow */ - nm1 = 8; - } - temp = 0.5 * x; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as Float32; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } else { - // use backward recurrence - // x x^2 x^2 - // J(n,x)/J(n-1,x) = ---- ------ ------ ..... - // 2n - 2(n+1) - 2(n+2) - // - // 1 1 1 - // (for large x) = ---- ------ ------ ..... - // 2n 2(n+1) 2(n+2) - // -- - ------ - ------ - - // x x x - // - // Let w = 2n/x and h=2/x, then the above quotient - // is equal to the continued fraction: - // 1 - // = ----------------------- - // 1 - // w - ----------------- - // 1 - // w+h - --------- - // w+2h - ... - // - // To determine how many terms needed, let - // Q(0) = w, Q(1) = w(w+h) - 1, - // Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - // When Q(k) > 1e4 good for single - // When Q(k) > 1e9 good for double - // When Q(k) > 1e17 good for quadruple - /* determine k */ - let mut t: Float32; - let mut q0: Float32; - let mut q1: Float32; - let mut w: Float32; - let h: Float32; - let mut z: Float32; - let mut tmp: Float32; - let nf: Float32; - let mut k: i32; - - nf = (nm1 as Float32) + 1.0; - w = 2.0 * (nf as Float32) / x; - h = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e4 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as Float32) + nf) / x - t); - i -= 1; - } - a = t; - b = 1.0; - // estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - // Hence, if n*(log(2n/x)) > ... - // single 8.8722839355e+01 - // double 7.09782712893383973096e+02 - // long double 1.1356523406294143949491931077970765006170e+04 - // then recurrent value may overflow and the result is - // likely underflow to zero - tmp = nf * logf(fabsf(w)); - if tmp < 88.721679688 { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as Float32) * b / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as Float32) * b / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p60 = Float32::from_bits(0x5d800000); // 0x1p60 == 2^60 - if b > x1p60 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; - } - } - z = j0f(x); - w = j1f(x); - if fabsf(z) >= fabsf(w) { - b = t * z / b; - } else { - b = t * w / a; - } - } - } - - if sign { - -b - } else { - b - } -} - -/// Bessel function of the second kind of order zero -/// -/// Calculates the Bessel function of the second kind of order zero of `x`. -pub fn ynf(n: i32, x: Float32) -> Float32 { - let mut ix: u32; - let mut ib: u32; - let nm1: i32; - let mut sign: bool; - let mut i: i32; - let mut a: Float32; - let mut b: Float32; - let mut temp: Float32; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix > 0x7f800000 { - /* nan */ - return x; - } - if sign && ix != 0 { - /* x < 0 */ - return 0.0 / 0.0; - } - if ix == 0x7f800000 { - return 0.0; - } - - if n == 0 { - return y0f(x); - } - if n < 0 { - nm1 = -(n + 1); - sign = (n & 1) != 0; - } else { - nm1 = n - 1; - sign = false; - } - if nm1 == 0 { - if sign { - return -y1f(x); - } else { - return y1f(x); - } - } - - a = y0f(x); - b = y1f(x); - /* quit if b is -inf */ - ib = b.to_bits(); - i = 0; - while i < nm1 && ib != 0xff800000 { - i += 1; - temp = b; - b = (2.0 * (i as Float32) / x) * b - a; - ib = b.to_bits(); - a = temp; - } - - if sign { - -b - } else { - b - } -} diff --git a/core/macros/Cargo.toml b/core/macros/Cargo.toml deleted file mode 100644 index ea674f4..0000000 --- a/core/macros/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "libtrig-macros" -version = "0.1.0" -edition = "2021" - -[lib] -name = "libtrig_macros" -proc-macro = true -path = "lib.rs" - -[dependencies.mc] -package = "libtrig-macros-core" -path = "./libtrig-macros-core" diff --git a/libtrig/Cargo.toml b/libtrig/Cargo.toml new file mode 100644 index 0000000..819b6bd --- /dev/null +++ b/libtrig/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "libtrig" +version = "0.1.0" +edition = "2021" + +[dependencies.macros] +package = "macros" +path = "../utils/macros" + +[dependencies.llm] +package = "llm" +path = "../llm" + +[lib] +path = "lib.rs" diff --git a/core/README.md b/libtrig/README.md similarity index 100% rename from core/README.md rename to libtrig/README.md diff --git a/libtrig/lib.rs b/libtrig/lib.rs index 992ffba..b4a993b 100644 --- a/libtrig/lib.rs +++ b/libtrig/lib.rs @@ -3,7 +3,7 @@ #![no_std] #![warn(missing_docs, unused, clippy::all)] -#![doc = include_str!("../README.md")] +#![doc = include_str!("./README.md")] pub(crate) mod vectors; pub(crate) mod traits; diff --git a/core/llm/Cargo.toml b/llm/Cargo.toml similarity index 52% rename from core/llm/Cargo.toml rename to llm/Cargo.toml index 5d37b65..800a966 100644 --- a/core/llm/Cargo.toml +++ b/llm/Cargo.toml @@ -1,15 +1,15 @@ [package] -name = "libtrig-llm" +name = "llm" version = "0.1.0" edition = "2021" [lib] path = "lib.rs" +doctest = false [dependencies.macros] -package = "libtrig-macros" -path = "../macros" +path = "../utils/macros" [features] -# default = ["unstable"] +default = ["unstable"] unstable = [] diff --git a/core/llm/README.md b/llm/README.md similarity index 100% rename from core/llm/README.md rename to llm/README.md diff --git a/core/llm/lib.rs b/llm/lib.rs similarity index 100% rename from core/llm/lib.rs rename to llm/lib.rs diff --git a/core/llm/math.rs b/llm/math.rs similarity index 100% rename from core/llm/math.rs rename to llm/math.rs diff --git a/core/llm/math/acos.rs b/llm/math/acos.rs similarity index 100% rename from core/llm/math/acos.rs rename to llm/math/acos.rs diff --git a/core/llm/math/acosf.rs b/llm/math/acosf.rs similarity index 100% rename from core/llm/math/acosf.rs rename to llm/math/acosf.rs diff --git a/core/llm/math/acosh.rs b/llm/math/acosh.rs similarity index 100% rename from core/llm/math/acosh.rs rename to llm/math/acosh.rs diff --git a/core/llm/math/acoshf.rs b/llm/math/acoshf.rs similarity index 100% rename from core/llm/math/acoshf.rs rename to llm/math/acoshf.rs diff --git a/core/llm/math/asin.rs b/llm/math/asin.rs similarity index 100% rename from core/llm/math/asin.rs rename to llm/math/asin.rs diff --git a/core/llm/math/asinf.rs b/llm/math/asinf.rs similarity index 100% rename from core/llm/math/asinf.rs rename to llm/math/asinf.rs diff --git a/core/llm/math/asinh.rs b/llm/math/asinh.rs similarity index 100% rename from core/llm/math/asinh.rs rename to llm/math/asinh.rs diff --git a/core/llm/math/asinhf.rs b/llm/math/asinhf.rs similarity index 100% rename from core/llm/math/asinhf.rs rename to llm/math/asinhf.rs diff --git a/core/llm/math/atan.rs b/llm/math/atan.rs similarity index 100% rename from core/llm/math/atan.rs rename to llm/math/atan.rs diff --git a/core/llm/math/atan2.rs b/llm/math/atan2.rs similarity index 100% rename from core/llm/math/atan2.rs rename to llm/math/atan2.rs diff --git a/core/llm/math/atan2f.rs b/llm/math/atan2f.rs similarity index 100% rename from core/llm/math/atan2f.rs rename to llm/math/atan2f.rs diff --git a/core/llm/math/atanf.rs b/llm/math/atanf.rs similarity index 100% rename from core/llm/math/atanf.rs rename to llm/math/atanf.rs diff --git a/core/llm/math/atanh.rs b/llm/math/atanh.rs similarity index 100% rename from core/llm/math/atanh.rs rename to llm/math/atanh.rs diff --git a/core/llm/math/atanhf.rs b/llm/math/atanhf.rs similarity index 100% rename from core/llm/math/atanhf.rs rename to llm/math/atanhf.rs diff --git a/core/llm/math/cbrt.rs b/llm/math/cbrt.rs similarity index 100% rename from core/llm/math/cbrt.rs rename to llm/math/cbrt.rs diff --git a/core/llm/math/cbrtf.rs b/llm/math/cbrtf.rs similarity index 100% rename from core/llm/math/cbrtf.rs rename to llm/math/cbrtf.rs diff --git a/core/llm/math/ceil.rs b/llm/math/ceil.rs similarity index 100% rename from core/llm/math/ceil.rs rename to llm/math/ceil.rs diff --git a/core/llm/math/ceilf.rs b/llm/math/ceilf.rs similarity index 100% rename from core/llm/math/ceilf.rs rename to llm/math/ceilf.rs diff --git a/core/llm/math/copysign.rs b/llm/math/copysign.rs similarity index 100% rename from core/llm/math/copysign.rs rename to llm/math/copysign.rs diff --git a/core/llm/math/copysignf.rs b/llm/math/copysignf.rs similarity index 100% rename from core/llm/math/copysignf.rs rename to llm/math/copysignf.rs diff --git a/core/llm/math/cos.rs b/llm/math/cos.rs similarity index 100% rename from core/llm/math/cos.rs rename to llm/math/cos.rs diff --git a/core/llm/math/cosf.rs b/llm/math/cosf.rs similarity index 100% rename from core/llm/math/cosf.rs rename to llm/math/cosf.rs diff --git a/core/llm/math/cosh.rs b/llm/math/cosh.rs similarity index 100% rename from core/llm/math/cosh.rs rename to llm/math/cosh.rs diff --git a/core/llm/math/coshf.rs b/llm/math/coshf.rs similarity index 100% rename from core/llm/math/coshf.rs rename to llm/math/coshf.rs diff --git a/core/llm/math/erf.rs b/llm/math/erf.rs similarity index 100% rename from core/llm/math/erf.rs rename to llm/math/erf.rs diff --git a/core/llm/math/erff.rs b/llm/math/erff.rs similarity index 100% rename from core/llm/math/erff.rs rename to llm/math/erff.rs diff --git a/core/llm/math/exp.rs b/llm/math/exp.rs similarity index 100% rename from core/llm/math/exp.rs rename to llm/math/exp.rs diff --git a/core/llm/math/exp10.rs b/llm/math/exp10.rs similarity index 100% rename from core/llm/math/exp10.rs rename to llm/math/exp10.rs diff --git a/core/llm/math/exp10f.rs b/llm/math/exp10f.rs similarity index 100% rename from core/llm/math/exp10f.rs rename to llm/math/exp10f.rs diff --git a/core/llm/math/exp2.rs b/llm/math/exp2.rs similarity index 100% rename from core/llm/math/exp2.rs rename to llm/math/exp2.rs diff --git a/core/llm/math/exp2f.rs b/llm/math/exp2f.rs similarity index 100% rename from core/llm/math/exp2f.rs rename to llm/math/exp2f.rs diff --git a/core/llm/math/expf.rs b/llm/math/expf.rs similarity index 100% rename from core/llm/math/expf.rs rename to llm/math/expf.rs diff --git a/core/llm/math/expm1.rs b/llm/math/expm1.rs similarity index 100% rename from core/llm/math/expm1.rs rename to llm/math/expm1.rs diff --git a/core/llm/math/expm1f.rs b/llm/math/expm1f.rs similarity index 100% rename from core/llm/math/expm1f.rs rename to llm/math/expm1f.rs diff --git a/core/llm/math/expo2.rs b/llm/math/expo2.rs similarity index 100% rename from core/llm/math/expo2.rs rename to llm/math/expo2.rs diff --git a/core/llm/math/fabs.rs b/llm/math/fabs.rs similarity index 100% rename from core/llm/math/fabs.rs rename to llm/math/fabs.rs diff --git a/core/llm/math/fabsf.rs b/llm/math/fabsf.rs similarity index 100% rename from core/llm/math/fabsf.rs rename to llm/math/fabsf.rs diff --git a/core/llm/math/fdim.rs b/llm/math/fdim.rs similarity index 100% rename from core/llm/math/fdim.rs rename to llm/math/fdim.rs diff --git a/core/llm/math/fdimf.rs b/llm/math/fdimf.rs similarity index 100% rename from core/llm/math/fdimf.rs rename to llm/math/fdimf.rs diff --git a/core/llm/math/fenv.rs b/llm/math/fenv.rs similarity index 100% rename from core/llm/math/fenv.rs rename to llm/math/fenv.rs diff --git a/core/llm/math/floor.rs b/llm/math/floor.rs similarity index 100% rename from core/llm/math/floor.rs rename to llm/math/floor.rs diff --git a/core/llm/math/floorf.rs b/llm/math/floorf.rs similarity index 100% rename from core/llm/math/floorf.rs rename to llm/math/floorf.rs diff --git a/core/llm/math/fma.rs b/llm/math/fma.rs similarity index 100% rename from core/llm/math/fma.rs rename to llm/math/fma.rs diff --git a/core/llm/math/fmaf.rs b/llm/math/fmaf.rs similarity index 100% rename from core/llm/math/fmaf.rs rename to llm/math/fmaf.rs diff --git a/core/llm/math/fmax.rs b/llm/math/fmax.rs similarity index 100% rename from core/llm/math/fmax.rs rename to llm/math/fmax.rs diff --git a/core/llm/math/fmaxf.rs b/llm/math/fmaxf.rs similarity index 100% rename from core/llm/math/fmaxf.rs rename to llm/math/fmaxf.rs diff --git a/core/llm/math/fmin.rs b/llm/math/fmin.rs similarity index 100% rename from core/llm/math/fmin.rs rename to llm/math/fmin.rs diff --git a/core/llm/math/fminf.rs b/llm/math/fminf.rs similarity index 100% rename from core/llm/math/fminf.rs rename to llm/math/fminf.rs diff --git a/core/llm/math/fmod.rs b/llm/math/fmod.rs similarity index 100% rename from core/llm/math/fmod.rs rename to llm/math/fmod.rs diff --git a/core/llm/math/fmodf.rs b/llm/math/fmodf.rs similarity index 100% rename from core/llm/math/fmodf.rs rename to llm/math/fmodf.rs diff --git a/core/llm/math/frexp.rs b/llm/math/frexp.rs similarity index 100% rename from core/llm/math/frexp.rs rename to llm/math/frexp.rs diff --git a/core/llm/math/frexpf.rs b/llm/math/frexpf.rs similarity index 100% rename from core/llm/math/frexpf.rs rename to llm/math/frexpf.rs diff --git a/core/llm/math/hypot.rs b/llm/math/hypot.rs similarity index 100% rename from core/llm/math/hypot.rs rename to llm/math/hypot.rs diff --git a/core/llm/math/hypotf.rs b/llm/math/hypotf.rs similarity index 100% rename from core/llm/math/hypotf.rs rename to llm/math/hypotf.rs diff --git a/core/llm/math/ilogb.rs b/llm/math/ilogb.rs similarity index 100% rename from core/llm/math/ilogb.rs rename to llm/math/ilogb.rs diff --git a/core/llm/math/ilogbf.rs b/llm/math/ilogbf.rs similarity index 100% rename from core/llm/math/ilogbf.rs rename to llm/math/ilogbf.rs diff --git a/core/llm/math/j0.rs b/llm/math/j0.rs similarity index 96% rename from core/llm/math/j0.rs rename to llm/math/j0.rs index 2f2d5ca..d030b64 100644 --- a/core/llm/math/j0.rs +++ b/llm/math/j0.rs @@ -58,12 +58,15 @@ use crate::Float64; use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; + +consts!{ const INVSQRTPI: Float64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ const TPI: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +} /* common method when |x|>=2 */ fn common(ix: u32, x: Float64, y0: bool) -> Float64 { - let s: Float64; + let mut c: Float64; let mut ss: Float64; let mut cc: Float64; @@ -77,7 +80,7 @@ fn common(ix: u32, x: Float64, y0: bool) -> Float64 { * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) */ - s = sin(x); + let s = sin(x); c = cos(x); if y0 { c = -c; @@ -103,6 +106,7 @@ fn common(ix: u32, x: Float64, y0: bool) -> Float64 { } /* R0/S0 on [0, 2.00] */ +consts!{ const R02: Float64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ const R03: Float64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ const R04: Float64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ @@ -111,6 +115,7 @@ const S01: Float64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ const S02: Float64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ const S03: Float64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ const S04: Float64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ +} /// Bessel function of the first kind of order zero /// @@ -119,7 +124,7 @@ pub fn j0(mut x: Float64) -> Float64 { let z: Float64; let r: Float64; let s: Float64; - let mut ix: u32; + let mut ix; ix = get_high_word(x); ix &= 0x7fffffff; @@ -156,6 +161,7 @@ pub fn j0(mut x: Float64) -> Float64 { return 1.0 - x; } +consts!{ const U00: Float64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ const U01: Float64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ const U02: Float64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ @@ -167,6 +173,7 @@ const V01: Float64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ const V02: Float64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ const V03: Float64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ const V04: Float64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ +} /// Bessel function of the second kind of order zero /// @@ -175,12 +182,8 @@ pub fn y0(x: Float64) -> Float64 { let z: Float64; let u: Float64; let v: Float64; - let ix: u32; - let lx: u32; - - ix = get_high_word(x); - lx = get_low_word(x); - + let ix = get_high_word(x); + let lx = get_low_word(x); /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ if ((ix << 1) | lx) == 0 { return -1.0 / 0.0; @@ -210,6 +213,7 @@ pub fn y0(x: Float64) -> Float64 { return U00 + TPI * log(x); } +consts!{ /* The asymptotic expansions of pzero is * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. * For x >= 2, We approximate pzero by @@ -218,7 +222,7 @@ pub fn y0(x: Float64) -> Float64 { * S = 1 + pS0*s^2 + ... + pS4*s^10 * and * | pzero(x)-1-R/S | <= 2 ** ( -60.26) - */ +*/ const PR8: [Float64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ @@ -286,13 +290,11 @@ const PS2: [Float64; 5] = [ 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ ]; +} fn pzero(x: Float64) -> Float64 { let p: &[Float64; 6]; let q: &[Float64; 5]; - let z: Float64; - let r: Float64; - let s: Float64; let mut ix: u32; ix = get_high_word(x); @@ -312,12 +314,13 @@ fn pzero(x: Float64) -> Float64 { p = &PR2; q = &PS2; } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + let z = 1.0 / (x * x); + let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); return 1.0 + r / s; } +consts!{ /* For x >= 8, the asymptotic expansions of qzero is * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. * We approximate pzero by @@ -326,7 +329,7 @@ fn pzero(x: Float64) -> Float64 { * S = 1 + qS0*s^2 + ... + qS5*s^12 * and * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) - */ +*/ const QR8: [Float64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ @@ -398,13 +401,11 @@ const QS2: [Float64; 6] = [ 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ ]; +} fn qzero(x: Float64) -> Float64 { let p: &[Float64; 6]; let q: &[Float64; 6]; - let s: Float64; - let r: Float64; - let z: Float64; let mut ix: u32; ix = get_high_word(x); @@ -424,8 +425,8 @@ fn qzero(x: Float64) -> Float64 { p = &QR2; q = &QS2; } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + let z = 1.0 / (x * x); + let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); return (-0.125 + r / s) / x; } diff --git a/core/llm/math/j0f.rs b/llm/math/j0f.rs similarity index 93% rename from core/llm/math/j0f.rs rename to llm/math/j0f.rs index 5c69714..40db71f 100644 --- a/core/llm/math/j0f.rs +++ b/llm/math/j0f.rs @@ -17,12 +17,13 @@ use crate::Float32; use super::{cosf, fabsf, logf, sinf, sqrtf}; +consts!{ const INVSQRTPI: Float32 = 5.6418961287e-01; /* 0x3f106ebb */ const TPI: Float32 = 6.3661974669e-01; /* 0x3f22f983 */ +} fn common(ix: u32, x: Float32, y0: bool) -> Float32 { let z: Float32; - let s: Float32; let mut c: Float32; let mut ss: Float32; let mut cc: Float32; @@ -30,7 +31,7 @@ fn common(ix: u32, x: Float32, y0: bool) -> Float32 { * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) */ - s = sinf(x); + let s = sinf(x); c = cosf(x); if y0 { c = -c; @@ -55,6 +56,7 @@ fn common(ix: u32, x: Float32, y0: bool) -> Float32 { } /* R0/S0 on [0, 2.00] */ +consts!{ const R02: Float32 = 1.5625000000e-02; /* 0x3c800000 */ const R03: Float32 = -1.8997929874e-04; /* 0xb947352e */ const R04: Float32 = 1.8295404516e-06; /* 0x35f58e88 */ @@ -63,14 +65,15 @@ const S01: Float32 = 1.5619102865e-02; /* 0x3c7fe744 */ const S02: Float32 = 1.1692678527e-04; /* 0x38f53697 */ const S03: Float32 = 5.1354652442e-07; /* 0x3509daa6 */ const S04: Float32 = 1.1661400734e-09; /* 0x30a045e8 */ +} /// Bessel function of the first kind of order zero /// /// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/j0.html) pub fn j0f(mut x: Float32) -> Float32 { - let z: Float32; - let r: Float32; - let s: Float32; + let z; + let r; + let s; let mut ix: u32; ix = x.to_bits(); @@ -100,6 +103,7 @@ pub fn j0f(mut x: Float32) -> Float32 { return 1.0 - x; } +consts!{ const U00: Float32 = -7.3804296553e-02; /* 0xbd9726b5 */ const U01: Float32 = 1.7666645348e-01; /* 0x3e34e80d */ const U02: Float32 = -1.3818567619e-02; /* 0xbc626746 */ @@ -111,17 +115,16 @@ const V01: Float32 = 1.2730483897e-02; /* 0x3c509385 */ const V02: Float32 = 7.6006865129e-05; /* 0x389f65e0 */ const V03: Float32 = 2.5915085189e-07; /* 0x348b216c */ const V04: Float32 = 4.4111031494e-10; /* 0x2ff280c2 */ +} /// Bessel function of the second kind of order zero /// /// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/y0.html) pub fn y0f(x: Float32) -> Float32 { - let z: Float32; - let u: Float32; - let v: Float32; - let ix: u32; - - ix = x.to_bits(); + let z; + let u; + let v; + let ix: u32 = x.to_bits(); if (ix & 0x7fffffff) == 0 { return -1.0 / 0.0; } @@ -147,6 +150,7 @@ pub fn y0f(x: Float32) -> Float32 { return U00 + TPI * logf(x); } +consts!{ /* The asymptotic expansions of pzero is * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. * For x >= 2, We approximate pzero by @@ -155,7 +159,7 @@ pub fn y0f(x: Float32) -> Float32 { * S = 1 + pS0*s^2 + ... + pS4*s^10 * and * | pzero(x)-1-R/S | <= 2 ** ( -60.26) - */ +*/ const PR8: [Float32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ @@ -222,13 +226,11 @@ const PS2: [Float32; 5] = [ 1.5387539673e+02, /* 0x4319e01a */ 1.4657617569e+01, /* 0x416a859a */ ]; +} fn pzerof(x: Float32) -> Float32 { let p: &[Float32; 6]; let q: &[Float32; 5]; - let z: Float32; - let r: Float32; - let s: Float32; let mut ix: u32; ix = x.to_bits(); @@ -248,12 +250,13 @@ fn pzerof(x: Float32) -> Float32 { p = &PR2; q = &PS2; } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + let z = 1.0 / (x * x); + let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); return 1.0 + r / s; } +consts!{ /* For x >= 8, the asymptotic expansions of qzero is * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. * We approximate pzero by @@ -334,13 +337,11 @@ const QS2: [Float32; 6] = [ 2.1266638184e+02, /* 0x4354aa98 */ -5.3109550476e+00, /* 0xc0a9f358 */ ]; +} fn qzerof(x: Float32) -> Float32 { let p: &[Float32; 6]; let q: &[Float32; 6]; - let s: Float32; - let r: Float32; - let z: Float32; let mut ix: u32; ix = x.to_bits(); @@ -360,8 +361,8 @@ fn qzerof(x: Float32) -> Float32 { p = &QR2; q = &QS2; } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + let z = 1.0 / (x * x); + let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); return (-0.125 + r / s) / x; } diff --git a/core/llm/math/j1.rs b/llm/math/j1.rs similarity index 73% rename from core/llm/math/j1.rs rename to llm/math/j1.rs index ef056ed..904dd4a 100644 --- a/core/llm/math/j1.rs +++ b/llm/math/j1.rs @@ -59,13 +59,14 @@ use crate::Float64; use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; +consts!{ const INVSQRTPI: Float64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ const TPI: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +} fn common(ix: u32, x: Float64, y1: bool, sign: bool) -> Float64 { let z: Float64; let mut s: Float64; - let c: Float64; let mut ss: Float64; let mut cc: Float64; @@ -81,7 +82,7 @@ fn common(ix: u32, x: Float64, y1: bool, sign: bool) -> Float64 { if y1 { s = -s; } - c = cos(x); + let c = cos(x); cc = s - c; if ix < 0x7fe00000 { /* avoid overflow in 2*x */ @@ -105,6 +106,7 @@ fn common(ix: u32, x: Float64, y1: bool, sign: bool) -> Float64 { return INVSQRTPI * cc / sqrt(x); } +consts!{ /* R0/S0 on [0,2] */ const R00: Float64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ const R01: Float64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ @@ -115,6 +117,7 @@ const S02: Float64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ const S03: Float64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ const S04: Float64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ const S05: Float64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ +} /// Bessel function of the first kind of order one /// @@ -124,10 +127,8 @@ pub fn j1(x: Float64) -> Float64 { let r: Float64; let s: Float64; let mut ix: u32; - let sign: bool; - ix = get_high_word(x); - sign = (ix >> 31) != 0; + let sign: bool = (ix >> 31) != 0; ix &= 0x7fffffff; if ix >= 0x7ff00000 { return 1.0 / (x * x); @@ -150,32 +151,32 @@ pub fn j1(x: Float64) -> Float64 { } const U0: [Float64; 5] = [ - -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ - 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ - -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ - 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ - -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ + -1.960_570_906_462_389_4e-1, /* 0xBFC91866, 0x143CBC8A */ + 5.044_387_166_398_113e-2, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.912_568_958_757_635_5e-3, /* 0xBF5F55E5, 0x4844F50F */ + 2.352_526_005_616_105e-5, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.190_991_580_398_789e-8, /* 0xBE78AC00, 0x569105B8 */ ]; const V0: [Float64; 5] = [ - 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ - 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ - 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ - 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ - 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ + 1.991_673_182_366_499e-2, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.025_525_810_251_351_7e-4, /* 0x3F2A8C89, 0x6C257764 */ + 1.356_088_010_975_162_3e-6, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.227_414_523_646_215e-9, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.665_592_462_079_920_8e-11, /* 0x3DB25039, 0xDACA772A */ ]; /// Bessel function of the second kind of order one /// /// Calculates the Bessel function of the second kind of order one of `x`. pub fn y1(x: Float64) -> Float64 { - let z: Float64; - let u: Float64; - let v: Float64; - let ix: u32; - let lx: u32; + + + + + - ix = get_high_word(x); - lx = get_low_word(x); + let ix: u32 = get_high_word(x); + let lx: u32 = get_low_word(x); /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ if (ix << 1 | lx) == 0 { @@ -196,9 +197,9 @@ pub fn y1(x: Float64) -> Float64 { /* x < 2**-54 */ return -TPI / x; } - z = x * x; - u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); - v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + let z: Float64 = x * x; + let u: Float64 = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + let v: Float64 = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); return x * (u / v) + TPI * (j1(x) * log(x) - 1.0 / x); } @@ -215,76 +216,76 @@ pub fn y1(x: Float64) -> Float64 { const PR8: [Float64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ - 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ - 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ - 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ - 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ + 1.171_874_999_999_886_5e-1, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.323_948_065_930_735_8e1, /* 0x402A7A9D, 0x357F7FCE */ + 4.120_518_543_073_785_6e2, /* 0x4079C0D4, 0x652EA590 */ + 3.874_745_389_139_605_3e3, /* 0x40AE457D, 0xA3A532CC */ + 7.914_479_540_318_917e3, /* 0x40BEEA7A, 0xC32782DD */ ]; const PS8: [Float64; 5] = [ - 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ - 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ - 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ - 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ - 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ + 1.142_073_703_756_784_1e2, /* 0x405C8D45, 0x8E656CAC */ + 3.650_930_834_208_534_6e3, /* 0x40AC85DC, 0x964D274F */ + 3.695_620_602_690_334_6e4, /* 0x40E20B86, 0x97C5BB7F */ + 9.760_279_359_349_508e4, /* 0x40F7D42C, 0xB28F17BB */ + 3.080_427_206_278_888e4, /* 0x40DE1511, 0x697A0B2D */ ]; const PR5: [Float64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ - 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ - 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ - 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ - 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ - 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ + 1.319_905_195_562_435_2e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.171_874_931_906_141e-1, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.802_751_278_684_329, /* 0x401B3604, 0x6E6315E3 */ + 1.083_081_829_901_891_1e2, /* 0x405B13B9, 0x452602ED */ + 5.176_361_395_331_998e2, /* 0x40802D16, 0xD052D649 */ + 5.287_152_013_633_375e2, /* 0x408085B8, 0xBB7E0CB7 */ ]; const PS5: [Float64; 5] = [ - 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ - 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ - 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ - 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ - 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ + 5.928_059_872_211_313e1, /* 0x404DA3EA, 0xA8AF633D */ + 9.914_014_187_336_144e2, /* 0x408EFB36, 0x1B066701 */ + 5.353_266_952_914_88e3, /* 0x40B4E944, 0x5706B6FB */ + 7.844_690_317_495_512e3, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.504_046_888_103_610_6e3, /* 0x40978030, 0x036F5E51 */ ]; const PR3: [Float64; 6] = [ - 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ - 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ - 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ - 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ - 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ - 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ + 3.025_039_161_373_736e-9, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.171_868_655_672_535_9e-1, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.932_977_500_333_156_4, /* 0x400F76BC, 0xE85EAD8A */ + 3.511_940_355_916_369e1, /* 0x40418F48, 0x9DA6D129 */ + 9.105_501_107_507_813e1, /* 0x4056C385, 0x4D2C1837 */ + 4.855_906_851_973_649e1, /* 0x4048478F, 0x8EA83EE5 */ ]; const PS3: [Float64; 5] = [ - 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ - 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ - 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ - 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ - 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ + 3.479_130_950_012_515e1, /* 0x40416549, 0xA134069C */ + 3.367_624_587_478_257_5e2, /* 0x40750C33, 0x07F1A75F */ + 1.046_871_399_757_751_3e3, /* 0x40905B7C, 0x5037D523 */ + 8.908_113_463_982_564e2, /* 0x408BD67D, 0xA32E31E9 */ + 1.037_879_324_396_392_8e2, /* 0x4059F26D, 0x7C2EED53 */ ]; const PR2: [Float64; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ - 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ - 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ - 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ - 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ - 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ + 1.077_108_301_068_737_4e-7, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.171_762_194_626_833_5e-1, /* 0x3FBDFF42, 0xBE760D83 */ + 2.368_514_966_676_088, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.224_261_091_482_612_3e1, /* 0x40287C37, 0x7F71A964 */ + 1.769_397_112_716_877_3e1, /* 0x4031B1A8, 0x177F8EE2 */ + 5.073_523_125_888_185, /* 0x40144B49, 0xA574C1FE */ ]; const PS2: [Float64; 5] = [ - 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ - 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ - 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ - 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ - 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ + 2.143_648_593_638_214e1, /* 0x40356FBD, 0x8AD5ECDC */ + 1.252_902_271_684_027_5e2, /* 0x405F5293, 0x14F92CD5 */ + 2.322_764_690_571_628e2, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.176_793_732_871_471e2, /* 0x405D6B7A, 0xDA1884A9 */ + 8.364_638_933_716_183, /* 0x4020BAB1, 0xF44E5192 */ ]; fn pone(x: Float64) -> Float64 { let p: &[Float64; 6]; let q: &[Float64; 5]; - let z: Float64; - let r: Float64; - let s: Float64; + + + let mut ix: u32; ix = get_high_word(x); @@ -304,9 +305,9 @@ fn pone(x: Float64) -> Float64 { p = &PR2; q = &PS2; } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + let z = 1.0 / (x * x); + let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); return 1.0 + r / s; } @@ -394,9 +395,6 @@ const QS2: [Float64; 6] = [ fn qone(x: Float64) -> Float64 { let p: &[Float64; 6]; let q: &[Float64; 6]; - let s: Float64; - let r: Float64; - let z: Float64; let mut ix: u32; ix = get_high_word(x); @@ -416,8 +414,8 @@ fn qone(x: Float64) -> Float64 { p = &QR2; q = &QS2; } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + let z = 1.0 / (x * x); + let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); return (0.375 + r / s) / x; } diff --git a/core/llm/math/j1f.rs b/llm/math/j1f.rs similarity index 51% rename from core/llm/math/j1f.rs rename to llm/math/j1f.rs index 3fe882e..9cf0c19 100644 --- a/core/llm/math/j1f.rs +++ b/llm/math/j1f.rs @@ -17,13 +17,13 @@ use crate::{Float64, Float32}; use super::{cosf, fabsf, logf, sinf, sqrtf}; -const INVSQRTPI: Float32 = 5.6418961287e-01; /* 0x3f106ebb */ -const TPI: Float32 = 6.3661974669e-01; /* 0x3f22f983 */ +const INVSQRTPI: Float32 = 5.641_896e-1; /* 0x3f106ebb */ +const TPI: Float32 = 6.366_197_5e-1; /* 0x3f22f983 */ fn common(ix: u32, x: Float32, y1: bool, sign: bool) -> Float32 { let z: Float64; let mut s: Float64; - let c: Float64; + let mut ss: Float64; let mut cc: Float64; @@ -31,7 +31,7 @@ fn common(ix: u32, x: Float32, y1: bool, sign: bool) -> Float32 { if y1 { s = -s; } - c = cosf(x) as Float64; + let c: Float64 = cosf(x) as Float64; cc = s - c; if ix < 0x7f000000 { ss = -s - c; @@ -55,15 +55,15 @@ fn common(ix: u32, x: Float32, y1: bool, sign: bool) -> Float32 { } /* R0/S0 on [0,2] */ -const R00: Float32 = -6.2500000000e-02; /* 0xbd800000 */ -const R01: Float32 = 1.4070566976e-03; /* 0x3ab86cfd */ -const R02: Float32 = -1.5995563444e-05; /* 0xb7862e36 */ -const R03: Float32 = 4.9672799207e-08; /* 0x335557d2 */ -const S01: Float32 = 1.9153760746e-02; /* 0x3c9ce859 */ -const S02: Float32 = 1.8594678841e-04; /* 0x3942fab6 */ -const S03: Float32 = 1.1771846857e-06; /* 0x359dffc2 */ -const S04: Float32 = 5.0463624390e-09; /* 0x31ad6446 */ -const S05: Float32 = 1.2354227016e-11; /* 0x2d59567e */ +const R00: Float32 = -6.25e-2; /* 0xbd800000 */ +const R01: Float32 = 1.407_056_7e-3; /* 0x3ab86cfd */ +const R02: Float32 = -1.599_556_3e-5; /* 0xb7862e36 */ +const R03: Float32 = 4.967_28e-8; /* 0x335557d2 */ +const S01: Float32 = 1.915_376e-2; /* 0x3c9ce859 */ +const S02: Float32 = 1.859_467_9e-4; /* 0x3942fab6 */ +const S03: Float32 = 1.177_184_7e-6; /* 0x359dffc2 */ +const S04: Float32 = 5.046_362_4e-9; /* 0x31ad6446 */ +const S05: Float32 = 1.235_422_7e-11; /* 0x2d59567e */ /// Bessel function of the first kind of order one /// @@ -73,10 +73,10 @@ pub fn j1f(x: Float32) -> Float32 { let r: Float32; let s: Float32; let mut ix: u32; - let sign: bool; + ix = x.to_bits(); - sign = (ix >> 31) != 0; + let sign: bool = (ix >> 31) != 0; ix &= 0x7fffffff; if ix >= 0x7f800000 { return 1.0 / (x * x); @@ -98,30 +98,30 @@ pub fn j1f(x: Float32) -> Float32 { } const U0: [Float32; 5] = [ - -1.9605709612e-01, /* 0xbe48c331 */ - 5.0443872809e-02, /* 0x3d4e9e3c */ - -1.9125689287e-03, /* 0xbafaaf2a */ - 2.3525259166e-05, /* 0x37c5581c */ - -9.1909917899e-08, /* 0xb3c56003 */ + -1.960_571e-1, /* 0xbe48c331 */ + 5.044_387_3e-2, /* 0x3d4e9e3c */ + -1.912_568_9e-3, /* 0xbafaaf2a */ + 2.352_526e-5, /* 0x37c5581c */ + -9.190_992e-8, /* 0xb3c56003 */ ]; const V0: [Float32; 5] = [ - 1.9916731864e-02, /* 0x3ca3286a */ - 2.0255257550e-04, /* 0x3954644b */ - 1.3560879779e-06, /* 0x35b602d4 */ - 6.2274145840e-09, /* 0x31d5f8eb */ - 1.6655924903e-11, /* 0x2d9281cf */ + 1.991_673_2e-2, /* 0x3ca3286a */ + 2.025_525_8e-4, /* 0x3954644b */ + 1.356_088e-6, /* 0x35b602d4 */ + 6.227_414_6e-9, /* 0x31d5f8eb */ + 1.665_592_5e-11, /* 0x2d9281cf */ ]; /// Bessel function of the second kind of order one /// /// Calculates the Bessel function of the second kind of order one of `x`. pub fn y1f(x: Float32) -> Float32 { - let z: Float32; - let u: Float32; - let v: Float32; - let ix: u32; + + + + - ix = x.to_bits(); + let ix: u32 = x.to_bits(); if (ix & 0x7fffffff) == 0 { return -1.0 / 0.0; } @@ -139,9 +139,9 @@ pub fn y1f(x: Float32) -> Float32 { /* x < 2**-25 */ return -TPI / x; } - z = x * x; - u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); - v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + let z: Float32 = x * x; + let u: Float32 = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + let v: Float32 = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); return x * (u / v) + TPI * (j1f(x) * logf(x) - 1.0 / x); } @@ -158,76 +158,76 @@ pub fn y1f(x: Float32) -> Float32 { const PR8: [Float32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ - 1.1718750000e-01, /* 0x3df00000 */ - 1.3239480972e+01, /* 0x4153d4ea */ - 4.1205184937e+02, /* 0x43ce06a3 */ - 3.8747453613e+03, /* 0x45722bed */ - 7.9144794922e+03, /* 0x45f753d6 */ + 1.171_875e-1, /* 0x3df00000 */ + 1.323_948_1e1, /* 0x4153d4ea */ + 4.120_518_5e2, /* 0x43ce06a3 */ + 3.874_745_4e3, /* 0x45722bed */ + 7.914_479_5e3, /* 0x45f753d6 */ ]; const PS8: [Float32; 5] = [ - 1.1420736694e+02, /* 0x42e46a2c */ - 3.6509309082e+03, /* 0x45642ee5 */ - 3.6956207031e+04, /* 0x47105c35 */ - 9.7602796875e+04, /* 0x47bea166 */ - 3.0804271484e+04, /* 0x46f0a88b */ + 1.142_073_7e2, /* 0x42e46a2c */ + 3.650_931e3, /* 0x45642ee5 */ + 3.695_620_7e4, /* 0x47105c35 */ + 9.760_28e4, /* 0x47bea166 */ + 3.080_427_1e4, /* 0x46f0a88b */ ]; const PR5: [Float32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.3199052094e-11, /* 0x2d68333f */ - 1.1718749255e-01, /* 0x3defffff */ - 6.8027510643e+00, /* 0x40d9b023 */ - 1.0830818176e+02, /* 0x42d89dca */ - 5.1763616943e+02, /* 0x440168b7 */ - 5.2871520996e+02, /* 0x44042dc6 */ + 1.319_905_2e-11, /* 0x2d68333f */ + 1.171_874_9e-1, /* 0x3defffff */ + 6.802_751, /* 0x40d9b023 */ + 1.083_081_8e2, /* 0x42d89dca */ + 5.176_361_7e2, /* 0x440168b7 */ + 5.287_152e2, /* 0x44042dc6 */ ]; const PS5: [Float32; 5] = [ - 5.9280597687e+01, /* 0x426d1f55 */ - 9.9140142822e+02, /* 0x4477d9b1 */ - 5.3532670898e+03, /* 0x45a74a23 */ - 7.8446904297e+03, /* 0x45f52586 */ - 1.5040468750e+03, /* 0x44bc0180 */ + 5.928_059_8e1, /* 0x426d1f55 */ + 9.914_014e2, /* 0x4477d9b1 */ + 5.353_267e3, /* 0x45a74a23 */ + 7.844_690_4e3, /* 0x45f52586 */ + 1.504_046_9e3, /* 0x44bc0180 */ ]; const PR3: [Float32; 6] = [ - 3.0250391081e-09, /* 0x314fe10d */ - 1.1718686670e-01, /* 0x3defffab */ - 3.9329774380e+00, /* 0x407bb5e7 */ - 3.5119403839e+01, /* 0x420c7a45 */ - 9.1055007935e+01, /* 0x42b61c2a */ - 4.8559066772e+01, /* 0x42423c7c */ + 3.025_039e-9, /* 0x314fe10d */ + 1.171_868_7e-1, /* 0x3defffab */ + 3.932_977_4, /* 0x407bb5e7 */ + 3.511_940_4e1, /* 0x420c7a45 */ + 9.105_501e1, /* 0x42b61c2a */ + 4.855_906_7e1, /* 0x42423c7c */ ]; const PS3: [Float32; 5] = [ - 3.4791309357e+01, /* 0x420b2a4d */ - 3.3676245117e+02, /* 0x43a86198 */ - 1.0468714600e+03, /* 0x4482dbe3 */ - 8.9081134033e+02, /* 0x445eb3ed */ - 1.0378793335e+02, /* 0x42cf936c */ + 3.479_131e1, /* 0x420b2a4d */ + 3.367_624_5e2, /* 0x43a86198 */ + 1.046_871_5e3, /* 0x4482dbe3 */ + 8.908_113_4e2, /* 0x445eb3ed */ + 1.037_879_3e2, /* 0x42cf936c */ ]; const PR2: [Float32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.0771083225e-07, /* 0x33e74ea8 */ - 1.1717621982e-01, /* 0x3deffa16 */ - 2.3685150146e+00, /* 0x401795c0 */ - 1.2242610931e+01, /* 0x4143e1bc */ - 1.7693971634e+01, /* 0x418d8d41 */ - 5.0735230446e+00, /* 0x40a25a4d */ + 1.077_108_3e-7, /* 0x33e74ea8 */ + 1.171_762_2e-1, /* 0x3deffa16 */ + 2.368_515, /* 0x401795c0 */ + 1.224_261_1e1, /* 0x4143e1bc */ + 1.769_397_2e1, /* 0x418d8d41 */ + 5.073_523, /* 0x40a25a4d */ ]; const PS2: [Float32; 5] = [ - 2.1436485291e+01, /* 0x41ab7dec */ - 1.2529022980e+02, /* 0x42fa9499 */ - 2.3227647400e+02, /* 0x436846c7 */ - 1.1767937469e+02, /* 0x42eb5bd7 */ - 8.3646392822e+00, /* 0x4105d590 */ + 2.143_648_5e1, /* 0x41ab7dec */ + 1.252_902_3e2, /* 0x42fa9499 */ + 2.322_764_7e2, /* 0x436846c7 */ + 1.176_793_75e2, /* 0x42eb5bd7 */ + 8.364_639, /* 0x4105d590 */ ]; fn ponef(x: Float32) -> Float32 { let p: &[Float32; 6]; let q: &[Float32; 5]; - let z: Float32; - let r: Float32; - let s: Float32; + + + let mut ix: u32; ix = x.to_bits(); @@ -247,9 +247,9 @@ fn ponef(x: Float32) -> Float32 { p = &PR2; q = &PS2; } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + let z: Float32 = 1.0 / (x * x); + let r: Float32 = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + let s: Float32 = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); return 1.0 + r / s; } @@ -267,80 +267,80 @@ fn ponef(x: Float32) -> Float32 { const QR8: [Float32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ - -1.0253906250e-01, /* 0xbdd20000 */ - -1.6271753311e+01, /* 0xc1822c8d */ - -7.5960174561e+02, /* 0xc43de683 */ - -1.1849806641e+04, /* 0xc639273a */ - -4.8438511719e+04, /* 0xc73d3683 */ + -1.025_390_6e-1, /* 0xbdd20000 */ + -1.627_175_3e1, /* 0xc1822c8d */ + -7.596_017_5e2, /* 0xc43de683 */ + -1.184_980_7e4, /* 0xc639273a */ + -4.843_851e4, /* 0xc73d3683 */ ]; const QS8: [Float32; 6] = [ - 1.6139537048e+02, /* 0x43216537 */ - 7.8253862305e+03, /* 0x45f48b17 */ - 1.3387534375e+05, /* 0x4802bcd6 */ - 7.1965775000e+05, /* 0x492fb29c */ - 6.6660125000e+05, /* 0x4922be94 */ - -2.9449025000e+05, /* 0xc88fcb48 */ + 1.613_953_7e2, /* 0x43216537 */ + 7.825_386e3, /* 0x45f48b17 */ + 1.338_753_4e5, /* 0x4802bcd6 */ + 7.196_577_5e5, /* 0x492fb29c */ + 6.666_012_5e5, /* 0x4922be94 */ + -2.944_902_5e5, /* 0xc88fcb48 */ ]; const QR5: [Float32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -2.0897993405e-11, /* 0xadb7d219 */ - -1.0253904760e-01, /* 0xbdd1fffe */ - -8.0564479828e+00, /* 0xc100e736 */ - -1.8366960144e+02, /* 0xc337ab6b */ - -1.3731937256e+03, /* 0xc4aba633 */ - -2.6124443359e+03, /* 0xc523471c */ + -2.089_799_3e-11, /* 0xadb7d219 */ + -1.025_390_5e-1, /* 0xbdd1fffe */ + -8.056_448, /* 0xc100e736 */ + -1.836_696e2, /* 0xc337ab6b */ + -1.373_193_7e3, /* 0xc4aba633 */ + -2.612_444_3e3, /* 0xc523471c */ ]; const QS5: [Float32; 6] = [ - 8.1276550293e+01, /* 0x42a28d98 */ - 1.9917987061e+03, /* 0x44f8f98f */ - 1.7468484375e+04, /* 0x468878f8 */ - 4.9851425781e+04, /* 0x4742bb6d */ - 2.7948074219e+04, /* 0x46da5826 */ - -4.7191835938e+03, /* 0xc5937978 */ + 8.127_655e1, /* 0x42a28d98 */ + 1.991_798_7e3, /* 0x44f8f98f */ + 1.746_848_4e4, /* 0x468878f8 */ + 4.985_142_6e4, /* 0x4742bb6d */ + 2.794_807_4e4, /* 0x46da5826 */ + -4.719_183_6e3, /* 0xc5937978 */ ]; const QR3: [Float32; 6] = [ - -5.0783124372e-09, /* 0xb1ae7d4f */ - -1.0253783315e-01, /* 0xbdd1ff5b */ - -4.6101160049e+00, /* 0xc0938612 */ - -5.7847221375e+01, /* 0xc267638e */ - -2.2824453735e+02, /* 0xc3643e9a */ - -2.1921012878e+02, /* 0xc35b35cb */ + -5.078_312_4e-9, /* 0xb1ae7d4f */ + -1.025_378_3e-1, /* 0xbdd1ff5b */ + -4.610_116, /* 0xc0938612 */ + -5.784_722e1, /* 0xc267638e */ + -2.282_445_4e2, /* 0xc3643e9a */ + -2.192_101_3e2, /* 0xc35b35cb */ ]; const QS3: [Float32; 6] = [ - 4.7665153503e+01, /* 0x423ea91e */ - 6.7386511230e+02, /* 0x4428775e */ - 3.3801528320e+03, /* 0x45534272 */ - 5.5477290039e+03, /* 0x45ad5dd5 */ - 1.9031191406e+03, /* 0x44ede3d0 */ - -1.3520118713e+02, /* 0xc3073381 */ + 4.766_515_4e1, /* 0x423ea91e */ + 6.738_651e2, /* 0x4428775e */ + 3.380_152_8e3, /* 0x45534272 */ + 5.547_729e3, /* 0x45ad5dd5 */ + 1.903_119_1e3, /* 0x44ede3d0 */ + -1.352_011_9e2, /* 0xc3073381 */ ]; const QR2: [Float32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -1.7838172539e-07, /* 0xb43f8932 */ - -1.0251704603e-01, /* 0xbdd1f475 */ - -2.7522056103e+00, /* 0xc0302423 */ - -1.9663616180e+01, /* 0xc19d4f16 */ - -4.2325313568e+01, /* 0xc2294d1f */ - -2.1371921539e+01, /* 0xc1aaf9b2 */ + -1.783_817_3e-7, /* 0xb43f8932 */ + -1.025_170_46e-1, /* 0xbdd1f475 */ + -2.752_205_6, /* 0xc0302423 */ + -1.966_361_6e1, /* 0xc19d4f16 */ + -4.232_531_4e1, /* 0xc2294d1f */ + -2.137_192_2e1, /* 0xc1aaf9b2 */ ]; const QS2: [Float32; 6] = [ - 2.9533363342e+01, /* 0x41ec4454 */ - 2.5298155212e+02, /* 0x437cfb47 */ - 7.5750280762e+02, /* 0x443d602e */ - 7.3939318848e+02, /* 0x4438d92a */ - 1.5594900513e+02, /* 0x431bf2f2 */ - -4.9594988823e+00, /* 0xc09eb437 */ + 2.953_336_3e1, /* 0x41ec4454 */ + 2.529_815_5e2, /* 0x437cfb47 */ + 7.575_028e2, /* 0x443d602e */ + 7.393_932e2, /* 0x4438d92a */ + 1.559_49e2, /* 0x431bf2f2 */ + -4.959_499, /* 0xc09eb437 */ ]; fn qonef(x: Float32) -> Float32 { let p: &[Float32; 6]; let q: &[Float32; 6]; - let s: Float32; - let r: Float32; - let z: Float32; + + + let mut ix: u32; ix = x.to_bits(); @@ -360,9 +360,9 @@ fn qonef(x: Float32) -> Float32 { p = &QR2; q = &QS2; } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + let z: Float32 = 1.0 / (x * x); + let r: Float32 = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + let s: Float32 = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); return (0.375 + r / s) / x; } diff --git a/core/llm/math/jn.rs b/llm/math/jn.rs similarity index 59% rename from core/llm/math/jn.rs rename to llm/math/jn.rs index 22e09a2..32bd134 100644 --- a/core/llm/math/jn.rs +++ b/llm/math/jn.rs @@ -38,14 +38,14 @@ use crate::Float64; use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, y1}; -const INVSQRTPI: Float64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const INVSQRTPI: Float64 = 5.641_895_835_477_563e-1; /* 0x3FE20DD7, 0x50429B6D */ /// Bessel function of the first kind of order zero of `x`. /// /// Calculates the Bessel function of the first kind of order zero of `x`. pub fn jn(n: i32, mut x: Float64) -> Float64 { let mut ix: u32; - let lx: u32; + let nm1: i32; let mut i: i32; let mut sign: bool; @@ -54,7 +54,7 @@ pub fn jn(n: i32, mut x: Float64) -> Float64 { let mut temp: Float64; ix = get_high_word(x); - lx = get_low_word(x); + let lx: u32 = get_low_word(x); sign = (ix >> 31) != 0; ix &= 0x7fffffff; @@ -122,130 +122,128 @@ pub fn jn(n: i32, mut x: Float64) -> Float64 { a = temp; } } - } else { - if ix < 0x3e100000 { - /* x < 2**-29 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 32 { - /* underflow */ - b = 0.0; - } else { - temp = x * 0.5; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as Float64; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } + } else if ix < 0x3e100000 { + /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 32 { + /* underflow */ + b = 0.0; } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: Float64; - let mut q0: Float64; - let mut q1: Float64; - let mut w: Float64; - let h: Float64; - let mut z: Float64; - let mut tmp: Float64; - let nf: Float64; + temp = x * 0.5; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as Float64; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: Float64; + let mut q0: Float64; + let mut q1: Float64; + let mut w: Float64; + + let mut z: Float64; + let mut tmp: Float64; + - let mut k: i32; + let mut k: i32; - nf = (nm1 as Float64) + 1.0; - w = 2.0 * nf / x; - h = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e9 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as Float64) + nf) / x - t); + let nf: Float64 = (nm1 as Float64) + 1.0; + w = 2.0 * nf / x; + let h: Float64 = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e9 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as Float64) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * log(fabs(w)); + if tmp < 7.097_827_128_933_84e2 { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as Float64)) / x - a; + a = temp; i -= 1; } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf * log(fabs(w)); - if tmp < 7.09782712893383973096e+02 { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as Float64)) / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as Float64)) / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p500 = Float64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 - if b > x1p500 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; + } else { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as Float64)) / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p500 = Float64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 + if b > x1p500 { + a /= b; + t /= b; + b = 1.0; } + i -= 1; } - z = j0(x); - w = j1(x); - if fabs(z) >= fabs(w) { - b = t * z / b; - } else { - b = t * w / a; - } + } + z = j0(x); + w = j1(x); + if fabs(z) >= fabs(w) { + b = t * z / b; + } else { + b = t * w / a; } } @@ -261,7 +259,7 @@ pub fn jn(n: i32, mut x: Float64) -> Float64 { /// Calculates the Bessel function of the second kind of order zero of `x`. pub fn yn(n: i32, x: Float64) -> Float64 { let mut ix: u32; - let lx: u32; + let mut ib: u32; let nm1: i32; let mut sign: bool; @@ -271,7 +269,7 @@ pub fn yn(n: i32, x: Float64) -> Float64 { let mut temp: Float64; ix = get_high_word(x); - lx = get_low_word(x); + let lx: u32 = get_low_word(x); sign = (ix >> 31) != 0; ix &= 0x7fffffff; diff --git a/llm/math/jnf.rs b/llm/math/jnf.rs new file mode 100644 index 0000000..2532d90 --- /dev/null +++ b/llm/math/jnf.rs @@ -0,0 +1,262 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ +/** + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== +*/ +/** + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. +*/ + +use crate::Float32; + +use super::{fabsf, j0f, j1f, logf, y0f, y1f}; + +/// Bessel function of the first kind of order zero +/// +/// Calculates the Bessel function of the first kind of order zero of `x`. +pub fn jnf(n: i32, mut x: Float32) -> Float32 { + let mut ix: u32; + let mut nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: Float32; + let mut b: Float32; + let mut temp: Float32; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { + /* nan */ + return x; + } + + /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ + if n == 0 { + return j0f(x); + } + if n < 0 { + nm1 = -(n + 1); + x = -x; + sign = !sign; + } else { + nm1 = n - 1; + } + if nm1 == 0 { + return j1f(x); + } + + sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabsf(x); + if ix == 0 || ix == 0x7f800000 { + /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as Float32) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = j0f(x); + b = j1f(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b * (2.0 * (i as Float32) / x) - a; + a = temp; + } + } else if ix < 0x35800000 { + // x < 2**-20 + //x is tiny, return the first Taylor expansion of J(n,x) + // J(n,x) = 1/n!*(x/2)^n - ... + if nm1 > 8 { + /* underflow */ + nm1 = 8; + } + temp = 0.5 * x; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as Float32; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } else { + // use backward recurrence + // x x^2 x^2 + // J(n,x)/J(n-1,x) = ---- ------ ------ ..... + // 2n - 2(n+1) - 2(n+2) + // + // 1 1 1 + // (for large x) = ---- ------ ------ ..... + // 2n 2(n+1) 2(n+2) + // -- - ------ - ------ - + // x x x + // + // Let w = 2n/x and h=2/x, then the above quotient + // is equal to the continued fraction: + // 1 + // = ----------------------- + // 1 + // w - ----------------- + // 1 + // w+h - --------- + // w+2h - ... + // + // To determine how many terms needed, let + // Q(0) = w, Q(1) = w(w+h) - 1, + // Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + // When Q(k) > 1e4 good for single + // When Q(k) > 1e9 good for double + // When Q(k) > 1e17 good for quadruple + /* determine k */ + let mut t: Float32; + let mut q0: Float32; + let mut q1: Float32; + let mut w: Float32; + + let mut z: Float32; + let mut tmp: Float32; + + let mut k: i32; + + let nf: Float32 = (nm1 as Float32) + 1.0; + w = 2.0 * (nf as Float32) / x; + let h: Float32 = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e4 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as Float32) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + // estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + // Hence, if n*(log(2n/x)) > ... + // single 8.8722839355e+01 + // double 7.09782712893383973096e+02 + // long double 1.1356523406294143949491931077970765006170e+04 + // then recurrent value may overflow and the result is + // likely underflow to zero + tmp = nf * logf(fabsf(w)); + if tmp < 88.721_68 { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as Float32) * b / x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as Float32) * b / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p60 = Float32::from_bits(0x5d800000); // 0x1p60 == 2^60 + if b > x1p60 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0f(x); + w = j1f(x); + if fabsf(z) >= fabsf(w) { + b = t * z / b; + } else { + b = t * w / a; + } + } + + if sign { + -b + } else { + b + } +} + +/// Bessel function of the second kind of order zero +/// +/// Calculates the Bessel function of the second kind of order zero of `x`. +pub fn ynf(n: i32, x: Float32) -> Float32 { + let mut ix: u32; + let mut ib: u32; + let nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: Float32; + let mut b: Float32; + let mut temp: Float32; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { + /* nan */ + return x; + } + if sign && ix != 0 { + /* x < 0 */ + return 0.0 / 0.0; + } + if ix == 0x7f800000 { + return 0.0; + } + + if n == 0 { + return y0f(x); + } + if n < 0 { + nm1 = -(n + 1); + sign = (n & 1) != 0; + } else { + nm1 = n - 1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1f(x); + } else { + return y1f(x); + } + } + + a = y0f(x); + b = y1f(x); + /* quit if b is -inf */ + ib = b.to_bits(); + i = 0; + while i < nm1 && ib != 0xff800000 { + i += 1; + temp = b; + b = (2.0 * (i as Float32) / x) * b - a; + ib = b.to_bits(); + a = temp; + } + + if sign { + -b + } else { + b + } +} diff --git a/core/llm/math/k_cos.rs b/llm/math/k_cos.rs similarity index 85% rename from core/llm/math/k_cos.rs rename to llm/math/k_cos.rs index 5ef6334..63dd270 100644 --- a/core/llm/math/k_cos.rs +++ b/llm/math/k_cos.rs @@ -11,12 +11,12 @@ use crate::Float64; -const C1: Float64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ -const C2: Float64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ -const C3: Float64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ -const C4: Float64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ -const C5: Float64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ -const C6: Float64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ +const C1: Float64 = 4.166_666_666_666_66e-2; /* 0x3FA55555, 0x5555554C */ +const C2: Float64 = -1.388_888_888_887_411e-3; /* 0xBF56C16C, 0x16C15177 */ +const C3: Float64 = 2.480_158_728_947_673e-5; /* 0x3EFA01A0, 0x19CB1590 */ +const C4: Float64 = -2.755_731_435_139_066_3e-7; /* 0xBE927E4F, 0x809C52AD */ +const C5: Float64 = 2.087_572_321_298_175e-9; /* 0x3E21EE9E, 0xBDB4B1C4 */ +const C6: Float64 = -1.135_964_755_778_819_5e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ // kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 // Input x is assumed to be bounded by ~pi/4 in magnitude. diff --git a/core/llm/math/k_cosf.rs b/llm/math/k_cosf.rs similarity index 76% rename from core/llm/math/k_cosf.rs rename to llm/math/k_cosf.rs index c2cc739..3ae9105 100644 --- a/core/llm/math/k_cosf.rs +++ b/llm/math/k_cosf.rs @@ -17,10 +17,10 @@ use crate::{Float64, Float32}; /* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ -const C0: Float64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ -const C1: Float64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ -const C2: Float64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ -const C3: Float64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ +const C0: Float64 = -0.499_999_997_251_031; /* -0x1ffffffd0c5e81.0p-54 */ +const C1: Float64 = 0.041_666_623_323_739_06; /* 0x155553e1053a42.0p-57 */ +const C2: Float64 = -0.001_388_676_377_460_993; /* -0x16c087e80f1e27.0p-62 */ +const C3: Float64 = 0.000_024_390_448_796_277_41; /* 0x199342e0ee5069.0p-68 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_cosf(x: Float64) -> Float32 { diff --git a/core/llm/math/k_expo2.rs b/llm/math/k_expo2.rs similarity index 100% rename from core/llm/math/k_expo2.rs rename to llm/math/k_expo2.rs diff --git a/core/llm/math/k_expo2f.rs b/llm/math/k_expo2f.rs similarity index 100% rename from core/llm/math/k_expo2f.rs rename to llm/math/k_expo2f.rs diff --git a/core/llm/math/k_sin.rs b/llm/math/k_sin.rs similarity index 83% rename from core/llm/math/k_sin.rs rename to llm/math/k_sin.rs index 900b59c..aabf3c2 100644 --- a/core/llm/math/k_sin.rs +++ b/llm/math/k_sin.rs @@ -11,12 +11,12 @@ use crate::Float64; -const S1: Float64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ -const S2: Float64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ -const S3: Float64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ -const S4: Float64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ -const S5: Float64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ -const S6: Float64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ +const S1: Float64 = -1.666_666_666_666_663_2e-1; /* 0xBFC55555, 0x55555549 */ +const S2: Float64 = 8.333_333_333_322_49e-3; /* 0x3F811111, 0x1110F8A6 */ +const S3: Float64 = -1.984_126_982_985_795e-4; /* 0xBF2A01A0, 0x19C161D5 */ +const S4: Float64 = 2.755_731_370_707_006_8e-6; /* 0x3EC71DE3, 0x57B1FE7D */ +const S5: Float64 = -2.505_076_025_340_686_3e-8; /* 0xBE5AE5E6, 0x8A2B9CEB */ +const S6: Float64 = 1.589_690_995_211_55e-10; /* 0x3DE5D93A, 0x5ACFD57C */ // kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 // Input x is assumed to be bounded by ~pi/4 in magnitude. diff --git a/core/llm/math/k_sinf.rs b/llm/math/k_sinf.rs similarity index 73% rename from core/llm/math/k_sinf.rs rename to llm/math/k_sinf.rs index 80aa6f8..fad39a3 100644 --- a/core/llm/math/k_sinf.rs +++ b/llm/math/k_sinf.rs @@ -17,10 +17,10 @@ use crate::{Float64, Float32}; /* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ -const S1: Float64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ -const S2: Float64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ -const S3: Float64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ -const S4: Float64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ +const S1: Float64 = -0.166_666_666_416_265_24; /* -0x15555554cbac77.0p-55 */ +const S2: Float64 = 0.008_333_329_385_889_463; /* 0x111110896efbb2.0p-59 */ +const S3: Float64 = -0.000_198_393_348_360_966_32; /* -0x1a00f9e2cae774.0p-65 */ +const S4: Float64 = 0.000_002_718_311_493_989_822; /* 0x16cd878c3b46a7.0p-71 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_sinf(x: Float64) -> Float32 { diff --git a/core/llm/math/k_tan.rs b/llm/math/k_tan.rs similarity index 78% rename from core/llm/math/k_tan.rs rename to llm/math/k_tan.rs index 6c7c12b..29b66ed 100644 --- a/core/llm/math/k_tan.rs +++ b/llm/math/k_tan.rs @@ -43,22 +43,22 @@ use crate::Float64; // tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) // = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) static T: [Float64; 13] = [ - 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ - 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ - 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ - 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ - 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ - 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ - 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ - 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ - 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ - 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ - 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ - -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ - 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ + 3.333_333_333_333_341e-1, /* 3FD55555, 55555563 */ + 1.333_333_333_332_012_4e-1, /* 3FC11111, 1110FE7A */ + 5.396_825_397_622_605e-2, /* 3FABA1BA, 1BB341FE */ + 2.186_948_829_485_954_2e-2, /* 3F9664F4, 8406D637 */ + 8.863_239_823_599_3e-3, /* 3F8226E3, E96E8493 */ + 3.592_079_107_591_312_4e-3, /* 3F6D6D22, C9560328 */ + 1.456_209_454_325_290_3e-3, /* 3F57DBC8, FEE08315 */ + 5.880_412_408_202_641e-4, /* 3F4344D8, F2F26501 */ + 2.464_631_348_184_699e-4, /* 3F3026F7, 1A8D1068 */ + 7.817_944_429_395_571e-5, /* 3F147E88, A03792A6 */ + 7.140_724_913_826_082e-5, /* 3F12B80F, 32F0A7E9 */ + -1.855_863_748_552_754_6e-5, /* BEF375CB, DB605373 */ + 2.590_730_518_636_337e-5, /* 3EFB2A70, 74BF7AD4 */ ]; -const PIO4: Float64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ -const PIO4_LO: Float64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ +const PIO4: Float64 = 7.853_981_633_974_483e-1; /* 3FE921FB, 54442D18 */ +const PIO4_LO: Float64 = 3.061_616_997_868_383e-17; /* 3C81A626, 33145C07 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_tan(mut x: Float64, mut y: Float64, odd: i32) -> Float64 { diff --git a/core/llm/math/k_tanf.rs b/llm/math/k_tanf.rs similarity index 81% rename from core/llm/math/k_tanf.rs rename to llm/math/k_tanf.rs index cba17d7..3f05159 100644 --- a/core/llm/math/k_tanf.rs +++ b/llm/math/k_tanf.rs @@ -13,12 +13,12 @@ use crate::{Float64, Float32}; /* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ const T: [Float64; 6] = [ - 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ - 0.133392002712976742718, /* 0x1112fd38999f72.0p-55 */ - 0.0533812378445670393523, /* 0x1b54c91d865afe.0p-57 */ - 0.0245283181166547278873, /* 0x191df3908c33ce.0p-58 */ - 0.00297435743359967304927, /* 0x185dadfcecf44e.0p-61 */ - 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ + 0.333_331_395_030_791_4, /* 0x15554d3418c99f.0p-54 */ + 0.133_392_002_712_976_74, /* 0x1112fd38999f72.0p-55 */ + 0.053_381_237_844_567_04, /* 0x1b54c91d865afe.0p-57 */ + 0.024_528_318_116_654_728, /* 0x191df3908c33ce.0p-58 */ + 0.002_974_357_433_599_673, /* 0x185dadfcecf44e.0p-61 */ + 0.009_465_647_849_436_732, /* 0x1362b9bf971bcd.0p-59 */ ]; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/core/llm/math/ldexp.rs b/llm/math/ldexp.rs similarity index 100% rename from core/llm/math/ldexp.rs rename to llm/math/ldexp.rs diff --git a/core/llm/math/ldexpf.rs b/llm/math/ldexpf.rs similarity index 100% rename from core/llm/math/ldexpf.rs rename to llm/math/ldexpf.rs diff --git a/core/llm/math/lgamma.rs b/llm/math/lgamma.rs similarity index 100% rename from core/llm/math/lgamma.rs rename to llm/math/lgamma.rs diff --git a/core/llm/math/lgamma_r.rs b/llm/math/lgamma_r.rs similarity index 65% rename from core/llm/math/lgamma_r.rs rename to llm/math/lgamma_r.rs index ca48670..90ce778 100644 --- a/core/llm/math/lgamma_r.rs +++ b/llm/math/lgamma_r.rs @@ -83,69 +83,69 @@ use crate::Float64; use super::{floor, k_cos, k_sin, log}; -const PI: Float64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ -const A0: Float64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ -const A1: Float64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ -const A2: Float64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ -const A3: Float64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ -const A4: Float64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ -const A5: Float64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ -const A6: Float64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ -const A7: Float64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ -const A8: Float64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ -const A9: Float64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ -const A10: Float64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ -const A11: Float64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ -const TC: Float64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ -const TF: Float64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ +const PI: Float64 = 3.141_592_653_589_793; /* 0x400921FB, 0x54442D18 */ +const A0: Float64 = 7.721_566_490_153_287e-2; /* 0x3FB3C467, 0xE37DB0C8 */ +const A1: Float64 = 3.224_670_334_241_136e-1; /* 0x3FD4A34C, 0xC4A60FAD */ +const A2: Float64 = 6.735_230_105_312_927e-2; /* 0x3FB13E00, 0x1A5562A7 */ +const A3: Float64 = 2.058_080_843_251_673_3e-2; /* 0x3F951322, 0xAC92547B */ +const A4: Float64 = 7.385_550_860_814_029e-3; /* 0x3F7E404F, 0xB68FEFE8 */ +const A5: Float64 = 2.890_513_836_734_156_3e-3; /* 0x3F67ADD8, 0xCCB7926B */ +const A6: Float64 = 1.192_707_631_833_620_7e-3; /* 0x3F538A94, 0x116F3F5D */ +const A7: Float64 = 5.100_697_921_535_113e-4; /* 0x3F40B6C6, 0x89B99C00 */ +const A8: Float64 = 2.208_627_907_139_083_9e-4; /* 0x3F2CF2EC, 0xED10E54D */ +const A9: Float64 = 1.080_115_672_475_839_4e-4; /* 0x3F1C5088, 0x987DFB07 */ +const A10: Float64 = 2.521_445_654_512_573_3e-5; /* 0x3EFA7074, 0x428CFA52 */ +const A11: Float64 = 4.486_409_496_189_151_6e-5; /* 0x3F07858E, 0x90A45837 */ +const TC: Float64 = 1.461_632_144_968_362_2; /* 0x3FF762D8, 0x6356BE3F */ +const TF: Float64 = -1.214_862_905_358_496_1e-1; /* 0xBFBF19B9, 0xBCC38A42 */ /* tt = -(tail of TF) */ -const TT: Float64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ -const T0: Float64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ -const T1: Float64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ -const T2: Float64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ -const T3: Float64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ -const T4: Float64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ -const T5: Float64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ -const T6: Float64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ -const T7: Float64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ -const T8: Float64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ -const T9: Float64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ -const T10: Float64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ -const T11: Float64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ -const T12: Float64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ -const T13: Float64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ -const T14: Float64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ -const U0: Float64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const U1: Float64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ -const U2: Float64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ -const U3: Float64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ -const U4: Float64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ -const U5: Float64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ -const V1: Float64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ -const V2: Float64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ -const V3: Float64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ -const V4: Float64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ -const V5: Float64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ -const S0: Float64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const S1: Float64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ -const S2: Float64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ -const S3: Float64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ -const S4: Float64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ -const S5: Float64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ -const S6: Float64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ -const R1: Float64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ -const R2: Float64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ -const R3: Float64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ -const R4: Float64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ -const R5: Float64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ -const R6: Float64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ -const W0: Float64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ -const W1: Float64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ -const W2: Float64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ -const W3: Float64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ -const W4: Float64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ -const W5: Float64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ -const W6: Float64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ +const TT: Float64 = -3.638_676_997_039_505e-18; /* 0xBC50C7CA, 0xA48A971F */ +const T0: Float64 = 4.838_361_227_238_100_5e-1; /* 0x3FDEF72B, 0xC8EE38A2 */ +const T1: Float64 = -1.475_877_229_945_939e-1; /* 0xBFC2E427, 0x8DC6C509 */ +const T2: Float64 = 6.462_494_023_913_339e-2; /* 0x3FB08B42, 0x94D5419B */ +const T3: Float64 = -3.278_854_107_598_596_5e-2; /* 0xBFA0C9A8, 0xDF35B713 */ +const T4: Float64 = 1.797_067_508_118_204e-2; /* 0x3F9266E7, 0x970AF9EC */ +const T5: Float64 = -1.031_422_412_983_414_4e-2; /* 0xBF851F9F, 0xBA91EC6A */ +const T6: Float64 = 6.100_538_702_462_913e-3; /* 0x3F78FCE0, 0xE370E344 */ +const T7: Float64 = -3.684_520_167_811_382_6e-3; /* 0xBF6E2EFF, 0xB3E914D7 */ +const T8: Float64 = 2.259_647_809_006_124_7e-3; /* 0x3F6282D3, 0x2E15C915 */ +const T9: Float64 = -1.403_464_699_892_328_4e-3; /* 0xBF56FE8E, 0xBF2D1AF1 */ +const T10: Float64 = 8.810_818_824_376_54e-4; /* 0x3F4CDF0C, 0xEF61A8E9 */ +const T11: Float64 = -5.385_953_053_567_405e-4; /* 0xBF41A610, 0x9C73E0EC */ +const T12: Float64 = 3.156_320_709_036_259_5e-4; /* 0x3F34AF6D, 0x6C0EBBF7 */ +const T13: Float64 = -3.127_541_683_751_208_6e-4; /* 0xBF347F24, 0xECC38C38 */ +const T14: Float64 = 3.355_291_926_355_191e-4; /* 0x3F35FD3E, 0xE8C2D3F4 */ +const U0: Float64 = -7.721_566_490_153_287e-2; /* 0xBFB3C467, 0xE37DB0C8 */ +const U1: Float64 = 6.328_270_640_250_934e-1; /* 0x3FE4401E, 0x8B005DFF */ +const U2: Float64 = 1.454_922_501_372_347_7; /* 0x3FF7475C, 0xD119BD6F */ +const U3: Float64 = 9.777_175_279_633_727e-1; /* 0x3FEF4976, 0x44EA8450 */ +const U4: Float64 = 2.289_637_280_646_924_5e-1; /* 0x3FCD4EAE, 0xF6010924 */ +const U5: Float64 = 1.338_109_185_367_876_6e-2; /* 0x3F8B678B, 0xBF2BAB09 */ +const V1: Float64 = 2.455_977_937_130_411_3; /* 0x4003A5D7, 0xC2BD619C */ +const V2: Float64 = 2.128_489_763_798_934; /* 0x40010725, 0xA42B18F5 */ +const V3: Float64 = 7.692_851_504_566_728e-1; /* 0x3FE89DFB, 0xE45050AF */ +const V4: Float64 = 1.042_226_455_933_691_3e-1; /* 0x3FBAAE55, 0xD6537C88 */ +const V5: Float64 = 3.217_092_422_824_239e-3; /* 0x3F6A5ABB, 0x57D0CF61 */ +const S0: Float64 = -7.721_566_490_153_287e-2; /* 0xBFB3C467, 0xE37DB0C8 */ +const S1: Float64 = 2.149_824_159_606_088_5e-1; /* 0x3FCB848B, 0x36E20878 */ +const S2: Float64 = 3.257_787_964_089_31e-1; /* 0x3FD4D98F, 0x4F139F59 */ +const S3: Float64 = 1.463_504_726_524_644_5e-1; /* 0x3FC2BB9C, 0xBEE5F2F7 */ +const S4: Float64 = 2.664_227_030_336_386e-2; /* 0x3F9B481C, 0x7E939961 */ +const S5: Float64 = 1.840_284_514_073_377_2e-3; /* 0x3F5E26B6, 0x7368F239 */ +const S6: Float64 = 3.194_753_265_841_009e-5; /* 0x3F00BFEC, 0xDD17E945 */ +const R1: Float64 = 1.392_005_334_676_210_5; /* 0x3FF645A7, 0x62C4AB74 */ +const R2: Float64 = 7.219_355_475_671_381e-1; /* 0x3FE71A18, 0x93D3DCDC */ +const R3: Float64 = 1.719_338_656_328_030_8e-1; /* 0x3FC601ED, 0xCCFBDF27 */ +const R4: Float64 = 1.864_591_917_156_529e-2; /* 0x3F9317EA, 0x742ED475 */ +const R5: Float64 = 7.779_424_963_818_936e-4; /* 0x3F497DDA, 0xCA41A95B */ +const R6: Float64 = 7.326_684_307_446_256e-6; /* 0x3EDEBAF7, 0xA5B38140 */ +const W0: Float64 = 4.189_385_332_046_727e-1; /* 0x3FDACFE3, 0x90C97D69 */ +const W1: Float64 = 8.333_333_333_333_297e-2; /* 0x3FB55555, 0x5555553B */ +const W2: Float64 = -2.777_777_777_287_755_4e-3; /* 0xBF66C16C, 0x16B02E5C */ +const W3: Float64 = 7.936_505_586_430_196e-4; /* 0x3F4A019F, 0x98CF38B6 */ +const W4: Float64 = -5.951_875_574_503_4e-4; /* 0xBF4380CB, 0x8C0FE741 */ +const W5: Float64 = 8.363_399_189_962_821e-4; /* 0x3F4B67BA, 0x4CDAD5D1 */ +const W6: Float64 = -1.630_929_340_965_752_7e-3; /* 0xBF5AB89D, 0x0B9E43E4 */ /* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ fn sin_pi(mut x: Float64) -> Float64 { @@ -185,15 +185,15 @@ pub fn lgamma_r(mut x: Float64) -> (Float64, i32) { let q: Float64; let mut r: Float64; let w: Float64; - let ix: u32; - let sign: bool; + + let i: i32; let mut signgam: i32; /* purge off +-inf, NaN, +-0, tiny and negative arguments */ signgam = 1; - sign = (u >> 63) != 0; - ix = ((u >> 32) as u32) & 0x7fffffff; + let sign: bool = (u >> 63) != 0; + let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; if ix >= 0x7ff00000 { return (x * x, signgam); } diff --git a/core/llm/math/lgammaf.rs b/llm/math/lgammaf.rs similarity index 100% rename from core/llm/math/lgammaf.rs rename to llm/math/lgammaf.rs diff --git a/core/llm/math/lgammaf_r.rs b/llm/math/lgammaf_r.rs similarity index 60% rename from core/llm/math/lgammaf_r.rs rename to llm/math/lgammaf_r.rs index 1b8f994..d0cc8a2 100644 --- a/core/llm/math/lgammaf_r.rs +++ b/llm/math/lgammaf_r.rs @@ -17,69 +17,69 @@ use crate::{Float64, Float32}; use super::{floorf, k_cosf, k_sinf, logf}; -const PI: Float32 = 3.1415927410e+00; /* 0x40490fdb */ -const A0: Float32 = 7.7215664089e-02; /* 0x3d9e233f */ -const A1: Float32 = 3.2246702909e-01; /* 0x3ea51a66 */ -const A2: Float32 = 6.7352302372e-02; /* 0x3d89f001 */ -const A3: Float32 = 2.0580807701e-02; /* 0x3ca89915 */ -const A4: Float32 = 7.3855509982e-03; /* 0x3bf2027e */ -const A5: Float32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ -const A6: Float32 = 1.1927076848e-03; /* 0x3a9c54a1 */ -const A7: Float32 = 5.1006977446e-04; /* 0x3a05b634 */ -const A8: Float32 = 2.2086278477e-04; /* 0x39679767 */ -const A9: Float32 = 1.0801156895e-04; /* 0x38e28445 */ -const A10: Float32 = 2.5214456400e-05; /* 0x37d383a2 */ -const A11: Float32 = 4.4864096708e-05; /* 0x383c2c75 */ -const TC: Float32 = 1.4616321325e+00; /* 0x3fbb16c3 */ -const TF: Float32 = -1.2148628384e-01; /* 0xbdf8cdcd */ +const PI: Float32 = 3.141_592_7; /* 0x40490fdb */ +const A0: Float32 = 7.721_566_4e-2; /* 0x3d9e233f */ +const A1: Float32 = 3.224_670_3e-1; /* 0x3ea51a66 */ +const A2: Float32 = 6.735_23e-2; /* 0x3d89f001 */ +const A3: Float32 = 2.058_080_8e-2; /* 0x3ca89915 */ +const A4: Float32 = 7.385_551e-3; /* 0x3bf2027e */ +const A5: Float32 = 2.890_513_7e-3; /* 0x3b3d6ec6 */ +const A6: Float32 = 1.192_707_7e-3; /* 0x3a9c54a1 */ +const A7: Float32 = 5.100_698e-4; /* 0x3a05b634 */ +const A8: Float32 = 2.208_627_8e-4; /* 0x39679767 */ +const A9: Float32 = 1.080_115_7e-4; /* 0x38e28445 */ +const A10: Float32 = 2.521_445_6e-5; /* 0x37d383a2 */ +const A11: Float32 = 4.486_409_7e-5; /* 0x383c2c75 */ +const TC: Float32 = 1.461_632_1; /* 0x3fbb16c3 */ +const TF: Float32 = -1.214_862_84e-1; /* 0xbdf8cdcd */ /* TT = -(tail of TF) */ -const TT: Float32 = 6.6971006518e-09; /* 0x31e61c52 */ -const T0: Float32 = 4.8383611441e-01; /* 0x3ef7b95e */ -const T1: Float32 = -1.4758771658e-01; /* 0xbe17213c */ -const T2: Float32 = 6.4624942839e-02; /* 0x3d845a15 */ -const T3: Float32 = -3.2788541168e-02; /* 0xbd064d47 */ -const T4: Float32 = 1.7970675603e-02; /* 0x3c93373d */ -const T5: Float32 = -1.0314224288e-02; /* 0xbc28fcfe */ -const T6: Float32 = 6.1005386524e-03; /* 0x3bc7e707 */ -const T7: Float32 = -3.6845202558e-03; /* 0xbb7177fe */ -const T8: Float32 = 2.2596477065e-03; /* 0x3b141699 */ -const T9: Float32 = -1.4034647029e-03; /* 0xbab7f476 */ -const T10: Float32 = 8.8108185446e-04; /* 0x3a66f867 */ -const T11: Float32 = -5.3859531181e-04; /* 0xba0d3085 */ -const T12: Float32 = 3.1563205994e-04; /* 0x39a57b6b */ -const T13: Float32 = -3.1275415677e-04; /* 0xb9a3f927 */ -const T14: Float32 = 3.3552918467e-04; /* 0x39afe9f7 */ -const U0: Float32 = -7.7215664089e-02; /* 0xbd9e233f */ -const U1: Float32 = 6.3282704353e-01; /* 0x3f2200f4 */ -const U2: Float32 = 1.4549225569e+00; /* 0x3fba3ae7 */ -const U3: Float32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ -const U4: Float32 = 2.2896373272e-01; /* 0x3e6a7578 */ -const U5: Float32 = 1.3381091878e-02; /* 0x3c5b3c5e */ -const V1: Float32 = 2.4559779167e+00; /* 0x401d2ebe */ -const V2: Float32 = 2.1284897327e+00; /* 0x4008392d */ -const V3: Float32 = 7.6928514242e-01; /* 0x3f44efdf */ -const V4: Float32 = 1.0422264785e-01; /* 0x3dd572af */ -const V5: Float32 = 3.2170924824e-03; /* 0x3b52d5db */ -const S0: Float32 = -7.7215664089e-02; /* 0xbd9e233f */ -const S1: Float32 = 2.1498242021e-01; /* 0x3e5c245a */ -const S2: Float32 = 3.2577878237e-01; /* 0x3ea6cc7a */ -const S3: Float32 = 1.4635047317e-01; /* 0x3e15dce6 */ -const S4: Float32 = 2.6642270386e-02; /* 0x3cda40e4 */ -const S5: Float32 = 1.8402845599e-03; /* 0x3af135b4 */ -const S6: Float32 = 3.1947532989e-05; /* 0x3805ff67 */ -const R1: Float32 = 1.3920053244e+00; /* 0x3fb22d3b */ -const R2: Float32 = 7.2193557024e-01; /* 0x3f38d0c5 */ -const R3: Float32 = 1.7193385959e-01; /* 0x3e300f6e */ -const R4: Float32 = 1.8645919859e-02; /* 0x3c98bf54 */ -const R5: Float32 = 7.7794247773e-04; /* 0x3a4beed6 */ -const R6: Float32 = 7.3266842264e-06; /* 0x36f5d7bd */ -const W0: Float32 = 4.1893854737e-01; /* 0x3ed67f1d */ -const W1: Float32 = 8.3333335817e-02; /* 0x3daaaaab */ -const W2: Float32 = -2.7777778450e-03; /* 0xbb360b61 */ -const W3: Float32 = 7.9365057172e-04; /* 0x3a500cfd */ -const W4: Float32 = -5.9518753551e-04; /* 0xba1c065c */ -const W5: Float32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ -const W6: Float32 = -1.6309292987e-03; /* 0xbad5c4e8 */ +const TT: Float32 = 6.697_100_7e-9; /* 0x31e61c52 */ +const T0: Float32 = 4.838_361e-1; /* 0x3ef7b95e */ +const T1: Float32 = -1.475_877_2e-1; /* 0xbe17213c */ +const T2: Float32 = 6.462_494e-2; /* 0x3d845a15 */ +const T3: Float32 = -3.278_854e-2; /* 0xbd064d47 */ +const T4: Float32 = 1.797_067_6e-2; /* 0x3c93373d */ +const T5: Float32 = -1.031_422_4e-2; /* 0xbc28fcfe */ +const T6: Float32 = 6.100_538_7e-3; /* 0x3bc7e707 */ +const T7: Float32 = -3.684_520_3e-3; /* 0xbb7177fe */ +const T8: Float32 = 2.259_647_7e-3; /* 0x3b141699 */ +const T9: Float32 = -1.403_464_7e-3; /* 0xbab7f476 */ +const T10: Float32 = 8.810_818_5e-4; /* 0x3a66f867 */ +const T11: Float32 = -5.385_953e-4; /* 0xba0d3085 */ +const T12: Float32 = 3.156_320_6e-4; /* 0x39a57b6b */ +const T13: Float32 = -3.127_541_6e-4; /* 0xb9a3f927 */ +const T14: Float32 = 3.355_291_8e-4; /* 0x39afe9f7 */ +const U0: Float32 = -7.721_566_4e-2; /* 0xbd9e233f */ +const U1: Float32 = 6.328_270_4e-1; /* 0x3f2200f4 */ +const U2: Float32 = 1.454_922_6; /* 0x3fba3ae7 */ +const U3: Float32 = 9.777_175e-1; /* 0x3f7a4bb2 */ +const U4: Float32 = 2.289_637_3e-1; /* 0x3e6a7578 */ +const U5: Float32 = 1.338_109_2e-2; /* 0x3c5b3c5e */ +const V1: Float32 = 2.455_978; /* 0x401d2ebe */ +const V2: Float32 = 2.128_489_7; /* 0x4008392d */ +const V3: Float32 = 7.692_851_4e-1; /* 0x3f44efdf */ +const V4: Float32 = 1.042_226_5e-1; /* 0x3dd572af */ +const V5: Float32 = 3.217_092_5e-3; /* 0x3b52d5db */ +const S0: Float32 = -7.721_566_4e-2; /* 0xbd9e233f */ +const S1: Float32 = 2.149_824_2e-1; /* 0x3e5c245a */ +const S2: Float32 = 3.257_787_8e-1; /* 0x3ea6cc7a */ +const S3: Float32 = 1.463_504_7e-1; /* 0x3e15dce6 */ +const S4: Float32 = 2.664_227e-2; /* 0x3cda40e4 */ +const S5: Float32 = 1.840_284_6e-3; /* 0x3af135b4 */ +const S6: Float32 = 3.194_753_3e-5; /* 0x3805ff67 */ +const R1: Float32 = 1.392_005_3; /* 0x3fb22d3b */ +const R2: Float32 = 7.219_356e-1; /* 0x3f38d0c5 */ +const R3: Float32 = 1.719_338_6e-1; /* 0x3e300f6e */ +const R4: Float32 = 1.864_592e-2; /* 0x3c98bf54 */ +const R5: Float32 = 7.779_425e-4; /* 0x3a4beed6 */ +const R6: Float32 = 7.326_684e-6; /* 0x36f5d7bd */ +const W0: Float32 = 4.189_385_5e-1; /* 0x3ed67f1d */ +const W1: Float32 = 8.333_333_6e-2; /* 0x3daaaaab */ +const W2: Float32 = -2.777_777_8e-3; /* 0xbb360b61 */ +const W3: Float32 = 7.936_506e-4; /* 0x3a500cfd */ +const W4: Float32 = -5.951_875_4e-4; /* 0xba1c065c */ +const W5: Float32 = 8.363_399e-4; /* 0x3a5b3dd2 */ +const W6: Float32 = -1.630_929_3e-3; /* 0xbad5c4e8 */ /* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ fn sin_pi(mut x: Float32) -> Float32 { @@ -92,7 +92,7 @@ fn sin_pi(mut x: Float32) -> Float32 { n = (x * 4.0) as isize; n = div!(n + 1, 2); y = (x as Float64) - (n as Float64) * 0.5; - y *= 3.14159265358979323846; + y *= 3.141_592_653_589_793; match n { 1 => k_cosf(y), 2 => k_sinf(-y), @@ -119,15 +119,15 @@ pub fn lgammaf_r(mut x: Float32) -> (Float32, i32) { let q: Float32; let mut r: Float32; let w: Float32; - let ix: u32; + let i: i32; - let sign: bool; + let mut signgam: i32; /* purge off +-inf, NaN, +-0, tiny and negative arguments */ signgam = 1; - sign = (u >> 31) != 0; - ix = u & 0x7fffffff; + let sign: bool = (u >> 31) != 0; + let ix: u32 = u & 0x7fffffff; if ix >= 0x7f800000 { return (x * x, signgam); } diff --git a/core/llm/math/ln.rs b/llm/math/ln.rs similarity index 100% rename from core/llm/math/ln.rs rename to llm/math/ln.rs diff --git a/core/llm/math/lnf.rs b/llm/math/lnf.rs similarity index 100% rename from core/llm/math/lnf.rs rename to llm/math/lnf.rs diff --git a/core/llm/math/log.rs b/llm/math/log.rs similarity index 86% rename from core/llm/math/log.rs rename to llm/math/log.rs index 6ff860c..eb63029 100644 --- a/core/llm/math/log.rs +++ b/llm/math/log.rs @@ -63,15 +63,15 @@ use crate::Float64; -const LN2_HI: Float64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ -const LN2_LO: Float64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ -const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +const LN2_HI: Float64 = 6.931_471_803_691_238e-1; /* 3fe62e42 fee00000 */ +const LN2_LO: Float64 = 1.908_214_929_270_587_7e-10; /* 3dea39ef 35793c76 */ +const LG1: Float64 = 6.666_666_666_666_735e-1; /* 3FE55555 55555593 */ +const LG2: Float64 = 3.999_999_999_940_942e-1; /* 3FD99999 9997FA04 */ +const LG3: Float64 = 2.857_142_874_366_239e-1; /* 3FD24924 94229359 */ +const LG4: Float64 = 2.222_219_843_214_978_4e-1; /* 3FCC71C5 1D8E78AF */ +const LG5: Float64 = 1.818_357_216_161_805e-1; /* 3FC74664 96CB03DE */ +const LG6: Float64 = 1.531_383_769_920_937_3e-1; /* 3FC39A09 D078C69F */ +const LG7: Float64 = 1.479_819_860_511_658_6e-1; /* 3FC2F112 DF3E5244 */ /// Returns the logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/core/llm/math/log10.rs b/llm/math/log10.rs similarity index 67% rename from core/llm/math/log10.rs rename to llm/math/log10.rs index c128eab..4b71306 100644 --- a/core/llm/math/log10.rs +++ b/llm/math/log10.rs @@ -19,17 +19,17 @@ use crate::Float64; -const IVLN10HI: Float64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ -const IVLN10LO: Float64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ -const LOG10_2HI: Float64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ -const LOG10_2LO: Float64 = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ -const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +const IVLN10HI: Float64 = 4.342_944_818_781_689e-1; /* 0x3fdbcb7b, 0x15200000 */ +const IVLN10LO: Float64 = 2.508_294_671_164_527_5e-11; /* 0x3dbb9438, 0xca9aadd5 */ +const LOG10_2HI: Float64 = 3.010_299_956_636_117_7e-1; /* 0x3FD34413, 0x509F6000 */ +const LOG10_2LO: Float64 = 3.694_239_077_158_931e-13; /* 0x3D59FEF3, 0x11F12B36 */ +const LG1: Float64 = 6.666_666_666_666_735e-1; /* 3FE55555 55555593 */ +const LG2: Float64 = 3.999_999_999_940_942e-1; /* 3FD99999 9997FA04 */ +const LG3: Float64 = 2.857_142_874_366_239e-1; /* 3FD24924 94229359 */ +const LG4: Float64 = 2.222_219_843_214_978_4e-1; /* 3FCC71C5 1D8E78AF */ +const LG5: Float64 = 1.818_357_216_161_805e-1; /* 3FC74664 96CB03DE */ +const LG6: Float64 = 1.531_383_769_920_937_3e-1; /* 3FC39A09 D078C69F */ +const LG7: Float64 = 1.479_819_860_511_658_6e-1; /* 3FC2F112 DF3E5244 */ /// Returns the base 10 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -37,18 +37,18 @@ pub fn log10(mut x: Float64) -> Float64 { let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 let mut ui: u64 = x.to_bits(); - let hfsq: Float64; - let f: Float64; - let s: Float64; - let z: Float64; - let r: Float64; + + + + + let mut w: Float64; - let t1: Float64; - let t2: Float64; - let dk: Float64; - let y: Float64; + + + + let mut hi: Float64; - let lo: Float64; + let mut val_hi: Float64; let mut val_lo: Float64; let mut hx: u32; @@ -81,14 +81,14 @@ pub fn log10(mut x: Float64) -> Float64 { ui = (hx as u64) << 32 | (ui & 0xffffffff); x = Float64::from_bits(ui); - f = x - 1.0; - hfsq = 0.5 * f * f; - s = f / (2.0 + f); - z = s * s; + let f: Float64 = x - 1.0; + let hfsq: Float64 = 0.5 * f * f; + let s: Float64 = f / (2.0 + f); + let z: Float64 = s * s; w = z * z; - t1 = w * (LG2 + w * (LG4 + w * LG6)); - t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - r = t2 + t1; + let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); + let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + let r: Float64 = t2 + t1; /* See log2.c for details. */ /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ @@ -96,12 +96,12 @@ pub fn log10(mut x: Float64) -> Float64 { ui = hi.to_bits(); ui &= (-1i64 as u64) << 32; hi = Float64::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); + let lo: Float64 = f - hi - hfsq + s * (hfsq + r); /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ val_hi = hi * IVLN10HI; - dk = k as Float64; - y = dk * LOG10_2HI; + let dk: Float64 = k as Float64; + let y: Float64 = dk * LOG10_2HI; val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI; /* diff --git a/core/llm/math/log10f.rs b/llm/math/log10f.rs similarity index 66% rename from core/llm/math/log10f.rs rename to llm/math/log10f.rs index 45d5c32..6759055 100644 --- a/core/llm/math/log10f.rs +++ b/llm/math/log10f.rs @@ -15,15 +15,15 @@ use crate::Float32; -const IVLN10HI: Float32 = 4.3432617188e-01; /* 0x3ede6000 */ -const IVLN10LO: Float32 = -3.1689971365e-05; /* 0xb804ead9 */ -const LOG10_2HI: Float32 = 3.0102920532e-01; /* 0x3e9a2080 */ -const LOG10_2LO: Float32 = 7.9034151668e-07; /* 0x355427db */ +const IVLN10HI: Float32 = 4.343_261_7e-1; /* 0x3ede6000 */ +const IVLN10LO: Float32 = -3.168_997e-5; /* 0xb804ead9 */ +const LOG10_2HI: Float32 = 3.010_292e-1; /* 0x3e9a2080 */ +const LOG10_2LO: Float32 = 7.903_415e-7; /* 0x355427db */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ +const LG1: Float32 = 0.666_666_6; /* 0xaaaaaa.0p-24 */ +const LG2: Float32 = 0.400_009_72; /* 0xccce13.0p-25 */ +const LG3: Float32 = 0.284_987_87; /* 0x91e9ee.0p-25 */ +const LG4: Float32 = 0.242_790_79; /* 0xf89e26.0p-26 */ /// Returns the base 10 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -31,17 +31,17 @@ pub fn log10f(mut x: Float32) -> Float32 { let x1p25f = Float32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ui: u32 = x.to_bits(); - let hfsq: Float32; - let f: Float32; - let s: Float32; - let z: Float32; - let r: Float32; - let w: Float32; - let t1: Float32; - let t2: Float32; - let dk: Float32; + + + + + + + + + let mut hi: Float32; - let lo: Float32; + let mut ix: u32; let mut k: i32; @@ -73,20 +73,20 @@ pub fn log10f(mut x: Float32) -> Float32 { ui = ix; x = Float32::from_bits(ui); - f = x - 1.0; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * LG4); - t2 = z * (LG1 + w * LG3); - r = t2 + t1; - hfsq = 0.5 * f * f; + let f: Float32 = x - 1.0; + let s: Float32 = f / (2.0 + f); + let z: Float32 = s * s; + let w: Float32 = z * z; + let t1: Float32 = w * (LG2 + w * LG4); + let t2: Float32 = z * (LG1 + w * LG3); + let r: Float32 = t2 + t1; + let hfsq: Float32 = 0.5 * f * f; hi = f - hfsq; ui = hi.to_bits(); ui &= 0xfffff000; hi = Float32::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); - dk = k as Float32; + let lo: Float32 = f - hi - hfsq + s * (hfsq + r); + let dk: Float32 = k as Float32; dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI } diff --git a/core/llm/math/log1p.rs b/llm/math/log1p.rs similarity index 91% rename from core/llm/math/log1p.rs rename to llm/math/log1p.rs index dab5e19..1d618b7 100644 --- a/core/llm/math/log1p.rs +++ b/llm/math/log1p.rs @@ -9,7 +9,7 @@ * is preserved. * ==================================================== */ -/** +/* * double log1p(double x) * Return the natural logarithm of 1+x. * @@ -56,6 +56,7 @@ use crate::{Float64, Float32}; +consts!{ const LN2_HI: Float64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ const LN2_LO: Float64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ @@ -65,26 +66,18 @@ const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +} /// Return the natural logarithm of `1+x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1p(x: Float64) -> Float64 { let mut ui: u64 = x.to_bits(); - let hfsq: Float64; let mut f: Float64 = 0.; let mut c: Float64 = 0.; - let s: Float64; - let z: Float64; - let r: Float64; - let w: Float64; - let t1: Float64; - let t2: Float64; - let dk: Float64; - let hx: u32; let mut hu: u32; let mut k: i32; - hx = (ui >> 32) as u32; + let hx: u32 = (ui >> 32) as u32; k = 1; if hx < 0x3fda827a || (hx >> 31) > 0 { /* 1+x < sqrt(2)+ */ @@ -133,13 +126,13 @@ pub fn log1p(x: Float64) -> Float64 { ui = (hu as u64) << 32 | (ui & 0xffffffff); f = Float64::from_bits(ui) - 1.; } - hfsq = 0.5 * f * f; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * (LG4 + w * LG6)); - t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - r = t2 + t1; - dk = k as Float64; + let hfsq: Float64 = 0.5 * f * f; + let s: Float64 = f / (2.0 + f); + let z: Float64 = s * s; + let w: Float64 = z * z; + let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); + let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + let r: Float64 = t2 + t1; + let dk: Float64 = k as Float64; s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } diff --git a/core/llm/math/log1pf.rs b/llm/math/log1pf.rs similarity index 75% rename from core/llm/math/log1pf.rs rename to llm/math/log1pf.rs index 0b8cffa..acc1f26 100644 --- a/core/llm/math/log1pf.rs +++ b/llm/math/log1pf.rs @@ -12,33 +12,33 @@ use crate::Float32; -const LN2_HI: Float32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: Float32 = 9.0580006145e-06; /* 0x3717f7d1 */ +const LN2_HI: Float32 = 6.931_381e-1; /* 0x3f317180 */ +const LN2_LO: Float32 = 9.058_001e-6; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ +const LG1: Float32 = 0.666_666_6; /* 0xaaaaaa.0p-24 */ +const LG2: Float32 = 0.400_009_72; /* 0xccce13.0p-25 */ +const LG3: Float32 = 0.284_987_87; /* 0x91e9ee.0p-25 */ +const LG4: Float32 = 0.242_790_79; /* 0xf89e26.0p-26 */ /// Return the natural logarithm of `1+x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1pf(x: Float32) -> Float32 { let mut ui: u32 = x.to_bits(); - let hfsq: Float32; + let mut f: Float32 = 0.; let mut c: Float32 = 0.; - let s: Float32; - let z: Float32; - let r: Float32; - let w: Float32; - let t1: Float32; - let t2: Float32; - let dk: Float32; - let ix: u32; + + + + + + + + let mut iu: u32; let mut k: i32; - ix = ui; + let ix: u32 = ui; k = 1; if ix < 0x3ed413d0 || (ix >> 31) > 0 { /* 1+x < sqrt(2)+ */ @@ -87,13 +87,13 @@ pub fn log1pf(x: Float32) -> Float32 { ui = iu; f = Float32::from_bits(ui) - 1.; } - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * LG4); - t2 = z * (LG1 + w * LG3); - r = t2 + t1; - hfsq = 0.5 * f * f; - dk = k as Float32; + let s: Float32 = f / (2.0 + f); + let z: Float32 = s * s; + let w: Float32 = z * z; + let t1: Float32 = w * (LG2 + w * LG4); + let t2: Float32 = z * (LG1 + w * LG3); + let r: Float32 = t2 + t1; + let hfsq: Float32 = 0.5 * f * f; + let dk: Float32 = k as Float32; s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } diff --git a/core/llm/math/log2.rs b/llm/math/log2.rs similarity index 68% rename from core/llm/math/log2.rs rename to llm/math/log2.rs index 02f6957..1d1173d 100644 --- a/core/llm/math/log2.rs +++ b/llm/math/log2.rs @@ -19,15 +19,15 @@ use crate::Float64; -const IVLN2HI: Float64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ -const IVLN2LO: Float64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ -const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +const IVLN2HI: Float64 = 1.442_695_040_721_446_3; /* 0x3ff71547, 0x65200000 */ +const IVLN2LO: Float64 = 1.675_171_316_488_651_2e-10; /* 0x3de705fc, 0x2eefa200 */ +const LG1: Float64 = 6.666_666_666_666_735e-1; /* 3FE55555 55555593 */ +const LG2: Float64 = 3.999_999_999_940_942e-1; /* 3FD99999 9997FA04 */ +const LG3: Float64 = 2.857_142_874_366_239e-1; /* 3FD24924 94229359 */ +const LG4: Float64 = 2.222_219_843_214_978_4e-1; /* 3FCC71C5 1D8E78AF */ +const LG5: Float64 = 1.818_357_216_161_805e-1; /* 3FC74664 96CB03DE */ +const LG6: Float64 = 1.531_383_769_920_937_3e-1; /* 3FC39A09 D078C69F */ +const LG7: Float64 = 1.479_819_860_511_658_6e-1; /* 3FC2F112 DF3E5244 */ /// Returns the base 2 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -35,17 +35,17 @@ pub fn log2(mut x: Float64) -> Float64 { let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 let mut ui: u64 = x.to_bits(); - let hfsq: Float64; - let f: Float64; - let s: Float64; - let z: Float64; - let r: Float64; + + + + + let mut w: Float64; - let t1: Float64; - let t2: Float64; - let y: Float64; + + + let mut hi: Float64; - let lo: Float64; + let mut val_hi: Float64; let mut val_lo: Float64; let mut hx: u32; @@ -78,27 +78,27 @@ pub fn log2(mut x: Float64) -> Float64 { ui = (hx as u64) << 32 | (ui & 0xffffffff); x = Float64::from_bits(ui); - f = x - 1.0; - hfsq = 0.5 * f * f; - s = f / (2.0 + f); - z = s * s; + let f: Float64 = x - 1.0; + let hfsq: Float64 = 0.5 * f * f; + let s: Float64 = f / (2.0 + f); + let z: Float64 = s * s; w = z * z; - t1 = w * (LG2 + w * (LG4 + w * LG6)); - t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - r = t2 + t1; + let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); + let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + let r: Float64 = t2 + t1; /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ hi = f - hfsq; ui = hi.to_bits(); ui &= (-1i64 as u64) << 32; hi = Float64::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); + let lo: Float64 = f - hi - hfsq + s * (hfsq + r); val_hi = hi * IVLN2HI; val_lo = (lo + hi) * IVLN2LO + lo * IVLN2HI; /* spadd(val_hi, val_lo, y), except for not using double_t: */ - y = k.into(); + let y: Float64 = k.into(); w = y + val_hi; val_lo += (y - w) + val_hi; val_hi = w; diff --git a/core/llm/math/log2f.rs b/llm/math/log2f.rs similarity index 70% rename from core/llm/math/log2f.rs rename to llm/math/log2f.rs index afa3c17..66ce47f 100644 --- a/core/llm/math/log2f.rs +++ b/llm/math/log2f.rs @@ -15,13 +15,13 @@ use crate::Float32; -const IVLN2HI: Float32 = 1.4428710938e+00; /* 0x3fb8b000 */ -const IVLN2LO: Float32 = -1.7605285393e-04; /* 0xb9389ad4 */ +const IVLN2HI: Float32 = 1.442_871_1; /* 0x3fb8b000 */ +const IVLN2LO: Float32 = -1.760_528_5e-4; /* 0xb9389ad4 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ +const LG1: Float32 = 0.666_666_6; /* 0xaaaaaa.0p-24 */ +const LG2: Float32 = 0.400_009_72; /* 0xccce13.0p-25 */ +const LG3: Float32 = 0.284_987_87; /* 0x91e9ee.0p-25 */ +const LG4: Float32 = 0.242_790_79; /* 0xf89e26.0p-26 */ /// Returns the base 2 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -29,16 +29,16 @@ pub fn log2f(mut x: Float32) -> Float32 { let x1p25f = Float32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ui: u32 = x.to_bits(); - let hfsq: Float32; - let f: Float32; - let s: Float32; - let z: Float32; - let r: Float32; - let w: Float32; - let t1: Float32; - let t2: Float32; + + + + + + + + let mut hi: Float32; - let lo: Float32; + let mut ix: u32; let mut k: i32; @@ -70,19 +70,19 @@ pub fn log2f(mut x: Float32) -> Float32 { ui = ix; x = Float32::from_bits(ui); - f = x - 1.0; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * LG4); - t2 = z * (LG1 + w * LG3); - r = t2 + t1; - hfsq = 0.5 * f * f; + let f: Float32 = x - 1.0; + let s: Float32 = f / (2.0 + f); + let z: Float32 = s * s; + let w: Float32 = z * z; + let t1: Float32 = w * (LG2 + w * LG4); + let t2: Float32 = z * (LG1 + w * LG3); + let r: Float32 = t2 + t1; + let hfsq: Float32 = 0.5 * f * f; hi = f - hfsq; ui = hi.to_bits(); ui &= 0xfffff000; hi = Float32::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); + let lo: Float32 = f - hi - hfsq + s * (hfsq + r); (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as Float32 } diff --git a/core/llm/math/logf.rs b/llm/math/logf.rs similarity index 83% rename from core/llm/math/logf.rs rename to llm/math/logf.rs index 57cfdab..56e5436 100644 --- a/core/llm/math/logf.rs +++ b/llm/math/logf.rs @@ -15,13 +15,13 @@ use crate::Float32; -const LN2_HI: Float32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: Float32 = 9.0580006145e-06; /* 0x3717f7d1 */ +const LN2_HI: Float32 = 6.931_381e-1; /* 0x3f317180 */ +const LN2_LO: Float32 = 9.058_001e-6; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ -const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ +const LG1: Float32 = 0.666_666_6; /* 0xaaaaaa.0p-24*/ +const LG2: Float32 = 0.400_009_72; /* 0xccce13.0p-25 */ +const LG3: Float32 = 0.284_987_87; /* 0x91e9ee.0p-25 */ +const LG4: Float32 = 0.242_790_79; /* 0xf89e26.0p-26 */ /// Returns the logarithm of `x` #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/core/llm/math/modf.rs b/llm/math/modf.rs similarity index 94% rename from core/llm/math/modf.rs rename to llm/math/modf.rs index 4d64cc4..09b8e7f 100644 --- a/core/llm/math/modf.rs +++ b/llm/math/modf.rs @@ -4,7 +4,7 @@ use crate::Float64; pub fn modf(x: Float64) -> (Float64, Float64) { let rv2: Float64; let mut u = x.to_bits(); - let mask: u64; + let e = ((u >> 52 & 0x7ff) as i32) - 0x3ff; /* no fractional part */ @@ -25,7 +25,7 @@ pub fn modf(x: Float64) -> (Float64, Float64) { return (x, rv2); } - mask = ((!0) >> 12) >> e; + let mask: u64 = ((!0) >> 12) >> e; if (u & mask) == 0 { rv2 = x; u &= 1 << 63; diff --git a/core/llm/math/modff.rs b/llm/math/modff.rs similarity index 94% rename from core/llm/math/modff.rs rename to llm/math/modff.rs index 1bbaf1c..965161f 100644 --- a/core/llm/math/modff.rs +++ b/llm/math/modff.rs @@ -4,7 +4,7 @@ use crate::Float32; pub fn modff(x: Float32) -> (Float32, Float32) { let rv2: Float32; let mut u: u32 = x.to_bits(); - let mask: u32; + let e = ((u >> 23 & 0xff) as i32) - 0x7f; /* no fractional part */ @@ -24,7 +24,7 @@ pub fn modff(x: Float32) -> (Float32, Float32) { return (x, rv2); } - mask = 0x007fffff >> e; + let mask: u32 = 0x007fffff >> e; if (u & mask) == 0 { rv2 = x; u &= 0x80000000; diff --git a/core/llm/math/nextafter.rs b/llm/math/nextafter.rs similarity index 93% rename from core/llm/math/nextafter.rs rename to llm/math/nextafter.rs index 9d30ea2..fef4ffc 100644 --- a/core/llm/math/nextafter.rs +++ b/llm/math/nextafter.rs @@ -13,8 +13,8 @@ pub fn nextafter(x: Float64, y: Float64) -> Float64 { return y; } - let ax = ux_i & !1_u64 / 2; - let ay = uy_i & !1_u64 / 2; + let ax = ux_i & (!1_u64 / 2); + let ay = uy_i & (!1_u64 / 2); if ax == 0 { if ay == 0 { return y; diff --git a/core/llm/math/nextafterf.rs b/llm/math/nextafterf.rs similarity index 100% rename from core/llm/math/nextafterf.rs rename to llm/math/nextafterf.rs diff --git a/core/llm/math/pow.rs b/llm/math/pow.rs similarity index 90% rename from core/llm/math/pow.rs rename to llm/math/pow.rs index cfc8f39..8ae76ca 100644 --- a/core/llm/math/pow.rs +++ b/llm/math/pow.rs @@ -63,34 +63,34 @@ use crate::Float64; use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; const BP: [Float64; 2] = [1.0, 1.5]; -const DP_H: [Float64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ -const DP_L: [Float64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ +const DP_H: [Float64; 2] = [0.0, 5.849_624_872_207_642e-1]; /* 0x3fe2b803_40000000 */ +const DP_L: [Float64; 2] = [0.0, 1.350_039_202_129_749e-8]; /* 0x3E4CFDEB, 0x43CFD006 */ const TWO53: Float64 = 9007199254740992.0; /* 0x43400000_00000000 */ const HUGE: Float64 = 1.0e300; const TINY: Float64 = 1.0e-300; // poly coefs for (3/2)*(log(x)-2s-2/3*s**3: -const L1: Float64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ -const L2: Float64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ -const L3: Float64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ -const L4: Float64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ -const L5: Float64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ -const L6: Float64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ -const P1: Float64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ -const P2: Float64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ -const P3: Float64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ -const P4: Float64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ -const P5: Float64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ -const LG2: Float64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ -const LG2_H: Float64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ -const LG2_L: Float64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ -const OVT: Float64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ -const CP: Float64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ -const CP_H: Float64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ -const CP_L: Float64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ -const IVLN2: Float64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ -const IVLN2_H: Float64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ -const IVLN2_L: Float64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ +const L1: Float64 = 5.999_999_999_999_946e-1; /* 0x3fe33333_33333303 */ +const L2: Float64 = 4.285_714_285_785_502e-1; /* 0x3fdb6db6_db6fabff */ +const L3: Float64 = 3.333_333_298_183_774_3e-1; /* 0x3fd55555_518f264d */ +const L4: Float64 = 2.727_281_238_085_34e-1; /* 0x3fd17460_a91d4101 */ +const L5: Float64 = 2.306_607_457_755_617_5e-1; /* 0x3fcd864a_93c9db65 */ +const L6: Float64 = 2.069_750_178_003_384_2e-1; /* 0x3fca7e28_4a454eef */ +const P1: Float64 = 1.666_666_666_666_660_2e-1; /* 0x3fc55555_5555553e */ +const P2: Float64 = -2.777_777_777_701_559_3e-3; /* 0xbf66c16c_16bebd93 */ +const P3: Float64 = 6.613_756_321_437_934e-5; /* 0x3f11566a_af25de2c */ +const P4: Float64 = -1.653_390_220_546_525_2e-6; /* 0xbebbbd41_c5d26bf1 */ +const P5: Float64 = 4.138_136_797_057_238_5e-8; /* 0x3e663769_72bea4d0 */ +const LG2: Float64 = 6.931_471_805_599_453e-1; /* 0x3fe62e42_fefa39ef */ +const LG2_H: Float64 = 6.931_471_824_645_996e-1; /* 0x3fe62e43_00000000 */ +const LG2_L: Float64 = -1.904_654_299_957_768e-9; /* 0xbe205c61_0ca86c39 */ +const OVT: Float64 = 8.008_566_259_537_294e-17; /* -(1024-log2(ovfl+.5ulp)) */ +const CP: Float64 = 9.617_966_939_259_756e-1; /* 0x3feec709_dc3a03fd =2/(3ln2) */ +const CP_H: Float64 = 9.617_967_009_544_373e-1; /* 0x3feec709_e0000000 =(float)cp */ +const CP_L: Float64 = -7.028_461_650_952_758e-9; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ +const IVLN2: Float64 = 1.442_695_040_888_963_4; /* 0x3ff71547_652b82fe =1/ln2 */ +const IVLN2_H: Float64 = 1.442_695_021_629_333_5; /* 0x3ff71547_60000000 =24b 1/ln2*/ +const IVLN2_L: Float64 = 1.925_962_991_126_617_5e-8; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ /// Returns `x` raised to the power `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -101,8 +101,8 @@ pub fn pow(x: Float64, y: Float64) -> Float64 { let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); - let mut ix: i32 = (hx & 0x7fffffff) as i32; - let iy: i32 = (hy & 0x7fffffff) as i32; + let mut ix: i32 = hx & 0x7fffffff; + let iy: i32 = hy & 0x7fffffff; /* x**0 = 1, even if x is NaN */ if ((iy as u32) | ly) == 0 { @@ -267,7 +267,7 @@ pub fn pow(x: Float64, y: Float64) -> Float64 { /* now |1-x| is TINY <= 2**-20, suffice to compute log(x) by x-x^2/2+x^3/3-x^4/4 */ let t: Float64 = ax - 1.0; /* t has 20 trailing zeros */ - let w: Float64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); + let w: Float64 = (t * t) * (0.5 - t * (0.333_333_333_333_333_3 - t * 0.25)); let u: Float64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ let v: Float64 = t * IVLN2_L - w * IVLN2; t1 = with_set_low_word(u + v, 0); @@ -374,7 +374,7 @@ pub fn pow(x: Float64, y: Float64) -> Float64 { } /* compute 2**(p_h+p_l) */ - let i: i32 = j & (0x7fffffff as i32); + let i: i32 = j & 0x7fffffff_i32; k = (i >> 20) - 0x3ff; let mut n: i32 = 0; @@ -613,7 +613,7 @@ mod tests { // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - (&[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS]) + [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS] .iter() .for_each(|int_set| { int_set.iter().for_each(|int| { @@ -625,7 +625,7 @@ mod tests { // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) - (&NEG[1..(NEG.len() - 1)]).iter().for_each(|set| { + NEG[1..(NEG.len() - 1)].iter().for_each(|set| { set.iter().for_each(|val| { test_sets(&ALL[3..7], &|v: Float64| pow(*val, v), &|_| NAN); }) diff --git a/core/llm/math/powf.rs b/llm/math/powf.rs similarity index 83% rename from core/llm/math/powf.rs rename to llm/math/powf.rs index 1cae7c3..e8c1c01 100644 --- a/core/llm/math/powf.rs +++ b/llm/math/powf.rs @@ -18,32 +18,32 @@ use crate::Float32; use super::{fabsf, scalbnf, sqrtf}; const BP: [Float32; 2] = [1.0, 1.5]; -const DP_H: [Float32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ -const DP_L: [Float32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ +const DP_H: [Float32; 2] = [0.0, 5.849_609_4e-1]; /* 0x3f15c000 */ +const DP_L: [Float32; 2] = [0.0, 1.563_220_8e-6]; /* 0x35d1cfdc */ const TWO24: Float32 = 16777216.0; /* 0x4b800000 */ const HUGE: Float32 = 1.0e30; const TINY: Float32 = 1.0e-30; -const L1: Float32 = 6.0000002384e-01; /* 0x3f19999a */ -const L2: Float32 = 4.2857143283e-01; /* 0x3edb6db7 */ -const L3: Float32 = 3.3333334327e-01; /* 0x3eaaaaab */ -const L4: Float32 = 2.7272811532e-01; /* 0x3e8ba305 */ -const L5: Float32 = 2.3066075146e-01; /* 0x3e6c3255 */ -const L6: Float32 = 2.0697501302e-01; /* 0x3e53f142 */ -const P1: Float32 = 1.6666667163e-01; /* 0x3e2aaaab */ -const P2: Float32 = -2.7777778450e-03; /* 0xbb360b61 */ -const P3: Float32 = 6.6137559770e-05; /* 0x388ab355 */ -const P4: Float32 = -1.6533901999e-06; /* 0xb5ddea0e */ -const P5: Float32 = 4.1381369442e-08; /* 0x3331bb4c */ -const LG2: Float32 = 6.9314718246e-01; /* 0x3f317218 */ -const LG2_H: Float32 = 6.93145752e-01; /* 0x3f317200 */ -const LG2_L: Float32 = 1.42860654e-06; /* 0x35bfbe8c */ -const OVT: Float32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ -const CP: Float32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ -const CP_H: Float32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ -const CP_L: Float32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ -const IVLN2: Float32 = 1.4426950216e+00; -const IVLN2_H: Float32 = 1.4426879883e+00; -const IVLN2_L: Float32 = 7.0526075433e-06; +const L1: Float32 = 6e-1; /* 0x3f19999a */ +const L2: Float32 = 4.285_714_3e-1; /* 0x3edb6db7 */ +const L3: Float32 = 3.333_333_4e-1; /* 0x3eaaaaab */ +const L4: Float32 = 2.727_281_2e-1; /* 0x3e8ba305 */ +const L5: Float32 = 2.306_607_5e-1; /* 0x3e6c3255 */ +const L6: Float32 = 2.069_750_1e-1; /* 0x3e53f142 */ +const P1: Float32 = 1.666_666_7e-1; /* 0x3e2aaaab */ +const P2: Float32 = -2.777_777_8e-3; /* 0xbb360b61 */ +const P3: Float32 = 6.613_756e-5; /* 0x388ab355 */ +const P4: Float32 = -1.653_390_2e-6; /* 0xb5ddea0e */ +const P5: Float32 = 4.138_137e-8; /* 0x3331bb4c */ +const LG2: Float32 = 6.931_472e-1; /* 0x3f317218 */ +const LG2_H: Float32 = 6.931_457_5e-1; /* 0x3f317200 */ +const LG2_L: Float32 = 1.428_606_5e-6; /* 0x35bfbe8c */ +const OVT: Float32 = 4.299_566_6e-8; /* -(128-log2(ovfl+.5ulp)) */ +const CP: Float32 = 9.617_967e-1; /* 0x3f76384f =2/(3ln2) */ +const CP_H: Float32 = 9.619_140_6e-1; /* 0x3f764000 =12b cp */ +const CP_L: Float32 = -1.173_685_74e-4; /* 0xb8f623c6 =tail of cp_h */ +const IVLN2: Float32 = 1.442_695; +const IVLN2_H: Float32 = 1.442_688; +const IVLN2_L: Float32 = 7.052_607_5e-6; /// Returns `x` raised to the power `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -54,7 +54,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { let z_l: Float32; let mut p_h: Float32; let mut p_l: Float32; - let y1: Float32; + let mut t1: Float32; let t2: Float32; let mut r: Float32; @@ -64,22 +64,22 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { let mut u: Float32; let mut v: Float32; let mut w: Float32; - let i: i32; + let mut j: i32; let mut k: i32; let mut yisint: i32; let mut n: i32; - let hx: i32; - let hy: i32; + + let mut ix: i32; - let iy: i32; + let mut is: i32; - hx = x.to_bits() as i32; - hy = y.to_bits() as i32; + let hx: i32 = x.to_bits() as i32; + let hy: i32 = y.to_bits() as i32; ix = hx & 0x7fffffff; - iy = hy & 0x7fffffff; + let iy: i32 = hy & 0x7fffffff; /* x**0 = 1, even if x is NaN */ if iy == 0 { @@ -202,7 +202,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { /* now |1-x| is TINY <= 2**-20, suffice to compute log(x) by x-x^2/2+x^3/3-x^4/4 */ t = ax - 1.; /* t has 20 trailing zeros */ - w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); + w = (t * t) * (0.5 - t * (0.333_333_34 - t * 0.25)); u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ v = t * IVLN2_L - w * IVLN2; t1 = u + v; @@ -212,7 +212,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { } else { let mut s2: Float32; let mut s_h: Float32; - let s_l: Float32; + let mut t_h: Float32; let mut t_l: Float32; @@ -251,7 +251,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { is = (((ix as u32 >> 1) & 0xfffff000) | 0x20000000) as i32; t_h = Float32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); t_l = ax - (t_h - i!(BP, k as usize)); - s_l = v * ((u - s_h * t_h) - s_h * t_l); + let s_l: Float32 = v * ((u - s_h * t_h) - s_h * t_l); /* compute log(ax) */ s2 = s * s; r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); @@ -281,7 +281,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ is = y.to_bits() as i32; - y1 = Float32::from_bits(is as u32 & 0xfffff000); + let y1: Float32 = Float32::from_bits(is as u32 & 0xfffff000); p_l = (y - y1) * t1 + y * t2; p_h = y1 * t1; z = p_l + p_h; @@ -308,7 +308,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { /* * compute 2**(p_h+p_l) */ - i = j & 0x7fffffff; + let i: i32 = j & 0x7fffffff; k = (i >> 23) - 0x7f; n = 0; if i > 0x3f000000 { diff --git a/core/llm/math/rem_pio2.rs b/llm/math/rem_pio2.rs similarity index 91% rename from core/llm/math/rem_pio2.rs rename to llm/math/rem_pio2.rs index 04b2701..3dd26c7 100644 --- a/core/llm/math/rem_pio2.rs +++ b/llm/math/rem_pio2.rs @@ -17,7 +17,7 @@ use super::rem_pio2_large; // #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 // #define EPS DBL_EPSILON -const EPS: Float64 = 2.2204460492503131e-16; +const EPS: Float64 = 2.220_446_049_250_313e-16; // #elif FLT_EVAL_METHOD==2 // #define EPS LDBL_EPSILON // #endif @@ -26,19 +26,19 @@ const EPS: Float64 = 2.2204460492503131e-16; const TO_INT: Float64 = 1.5 / EPS; /// 53 bits of 2/pi -const INV_PIO2: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +const INV_PIO2: Float64 = 6.366_197_723_675_814e-1; /* 0x3FE45F30, 0x6DC9C883 */ /// first 33 bits of pi/2 -const PIO2_1: Float64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ +const PIO2_1: Float64 = 1.570_796_326_734_125_6; /* 0x3FF921FB, 0x54400000 */ /// pi/2 - PIO2_1 -const PIO2_1T: Float64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ +const PIO2_1T: Float64 = 6.077_100_506_506_192e-11; /* 0x3DD0B461, 0x1A626331 */ /// second 33 bits of pi/2 -const PIO2_2: Float64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ +const PIO2_2: Float64 = 6.077_100_506_303_966e-11; /* 0x3DD0B461, 0x1A600000 */ /// pi/2 - (PIO2_1+PIO2_2) -const PIO2_2T: Float64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ +const PIO2_2T: Float64 = 2.022_266_248_795_950_6e-21; /* 0x3BA3198A, 0x2E037073 */ /// third 33 bits of pi/2 -const PIO2_3: Float64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ +const PIO2_3: Float64 = 2.022_266_248_711_166_5e-21; /* 0x3BA3198A, 0x2E000000 */ /// pi/2 - (PIO2_1+PIO2_2+PIO2_3) -const PIO2_3T: Float64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ +const PIO2_3T: Float64 = 8.478_427_660_368_9e-32; /* 0x397B839A, 0x252049C1 */ /// return the remainder of x rem pi/2 in y[0]+y[1] /// use rem_pio2_large() for large x diff --git a/core/llm/math/rem_pio2_large.rs b/llm/math/rem_pio2_large.rs similarity index 97% rename from core/llm/math/rem_pio2_large.rs rename to llm/math/rem_pio2_large.rs index 6aa68ef..132b76f 100644 --- a/core/llm/math/rem_pio2_large.rs +++ b/llm/math/rem_pio2_large.rs @@ -122,14 +122,14 @@ const IPIO2: [i32; 690] = [ ]; const PIO2: [Float64; 8] = [ - 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ - 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ - 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ - 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ - 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ - 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ - 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ - 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ + 1.570_796_251_296_997, /* 0x3FF921FB, 0x40000000 */ + 7.549_789_415_861_596e-8, /* 0x3E74442D, 0x00000000 */ + 5.390_302_529_957_765e-15, /* 0x3CF84698, 0x80000000 */ + 3.282_003_415_807_913e-22, /* 0x3B78CC51, 0x60000000 */ + 1.270_655_753_080_676e-29, /* 0x39F01B83, 0x80000000 */ + 1.229_333_089_811_113_3e-36, /* 0x387A2520, 0x40000000 */ + 2.733_700_538_164_645_6e-44, /* 0x36E38222, 0x80000000 */ + 2.167_416_838_778_048_2e-51, /* 0x3569F31D, 0x00000000 */ ]; // fn rem_pio2_large(x : &[Float64], y : &mut [Float64], e0 : i32, prec : usize) -> i32 diff --git a/core/llm/math/rem_pio2f.rs b/llm/math/rem_pio2f.rs similarity index 90% rename from core/llm/math/rem_pio2f.rs rename to llm/math/rem_pio2f.rs index 1a803cd..cc74869 100644 --- a/core/llm/math/rem_pio2f.rs +++ b/llm/math/rem_pio2f.rs @@ -21,11 +21,11 @@ use super::rem_pio2_large; const TOINT: Float64 = 1.5 / Float64::EPSILON; /// 53 bits of 2/pi -const INV_PIO2: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +const INV_PIO2: Float64 = 6.366_197_723_675_814e-1; /* 0x3FE45F30, 0x6DC9C883 */ /// first 25 bits of pi/2 -const PIO2_1: Float64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ +const PIO2_1: Float64 = 1.570_796_310_901_641_8; /* 0x3FF921FB, 0x50000000 */ /// pi/2 - pio2_1 -const PIO2_1T: Float64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ +const PIO2_1T: Float64 = 1.589_325_477_352_819_6e-8; /* 0x3E5110b4, 0x611A6263 */ /// Return the remainder of x rem pi/2 in *y /// diff --git a/core/llm/math/remainder.rs b/llm/math/remainder.rs similarity index 100% rename from core/llm/math/remainder.rs rename to llm/math/remainder.rs diff --git a/core/llm/math/remainderf.rs b/llm/math/remainderf.rs similarity index 100% rename from core/llm/math/remainderf.rs rename to llm/math/remainderf.rs diff --git a/core/llm/math/remquo.rs b/llm/math/remquo.rs similarity index 100% rename from core/llm/math/remquo.rs rename to llm/math/remquo.rs diff --git a/core/llm/math/remquof.rs b/llm/math/remquof.rs similarity index 100% rename from core/llm/math/remquof.rs rename to llm/math/remquof.rs diff --git a/core/llm/math/rint.rs b/llm/math/rint.rs similarity index 100% rename from core/llm/math/rint.rs rename to llm/math/rint.rs diff --git a/core/llm/math/rintf.rs b/llm/math/rintf.rs similarity index 100% rename from core/llm/math/rintf.rs rename to llm/math/rintf.rs diff --git a/core/llm/math/round.rs b/llm/math/round.rs similarity index 100% rename from core/llm/math/round.rs rename to llm/math/round.rs diff --git a/core/llm/math/roundf.rs b/llm/math/roundf.rs similarity index 100% rename from core/llm/math/roundf.rs rename to llm/math/roundf.rs diff --git a/core/llm/math/scalbn.rs b/llm/math/scalbn.rs similarity index 100% rename from core/llm/math/scalbn.rs rename to llm/math/scalbn.rs diff --git a/core/llm/math/scalbnf.rs b/llm/math/scalbnf.rs similarity index 100% rename from core/llm/math/scalbnf.rs rename to llm/math/scalbnf.rs diff --git a/core/llm/math/sin.rs b/llm/math/sin.rs similarity index 100% rename from core/llm/math/sin.rs rename to llm/math/sin.rs diff --git a/core/llm/math/sincos.rs b/llm/math/sincos.rs similarity index 97% rename from core/llm/math/sincos.rs rename to llm/math/sincos.rs index b57c505..38b4864 100644 --- a/core/llm/math/sincos.rs +++ b/llm/math/sincos.rs @@ -17,8 +17,8 @@ use super::{get_high_word, k_cos, k_sin, rem_pio2}; /// Simultaneously computes the sine and cosine of the argument x. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincos(x: Radian64) -> (Float64, Float64) { - let s: Float64; - let c: Float64; + + let mut ix: u32; ix = get_high_word(x); @@ -48,8 +48,8 @@ pub fn sincos(x: Radian64) -> (Float64, Float64) { /* argument reduction needed */ let (n, y0, y1) = rem_pio2(x); - s = k_sin(y0, y1, 1); - c = k_cos(y0, y1); + let s: Float64 = k_sin(y0, y1, 1); + let c: Float64 = k_cos(y0, y1); match n & 3 { 0 => (s, c), 1 => (c, -s), diff --git a/core/llm/math/sincosf.rs b/llm/math/sincosf.rs similarity index 88% rename from core/llm/math/sincosf.rs rename to llm/math/sincosf.rs index 3880d5d..3358968 100644 --- a/core/llm/math/sincosf.rs +++ b/llm/math/sincosf.rs @@ -19,7 +19,7 @@ use crate::{Float64, Float32, Radian32}; use super::{k_cosf, k_sinf, rem_pio2f}; /* Small multiples of pi/2 rounded to double precision. */ -const PI_2: Float32 = 0.5 * 3.1415926535897931160E+00; +const PI_2: Float32 = 0.5 * 3.141_592_7; const S1PIO2: Float32 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ const S2PIO2: Float32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ const S3PIO2: Float32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ @@ -31,10 +31,10 @@ pub fn sincosf(x: Radian32) -> (Float32, Float32) { let s: Float32; let c: Float32; let mut ix: u32; - let sign: bool; + ix = x.to_bits(); - sign = (ix >> 31) != 0; + let sign: bool = (ix >> 31) != 0; ix &= 0x7fffffff; /* |x| ~<= pi/4 */ @@ -67,14 +67,12 @@ pub fn sincosf(x: Radian32) -> (Float32, Float32) { } } /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ - else { - if sign { - s = -k_sinf((x + S2PIO2) as Float64); - c = -k_cosf((x + S2PIO2) as Float64); - } else { - s = -k_sinf((x - S2PIO2) as Float64); - c = -k_cosf((x - S2PIO2) as Float64); - } + else if sign { + s = -k_sinf((x + S2PIO2) as Float64); + c = -k_cosf((x + S2PIO2) as Float64); + } else { + s = -k_sinf((x - S2PIO2) as Float64); + c = -k_cosf((x - S2PIO2) as Float64); } return (s, c); @@ -91,14 +89,12 @@ pub fn sincosf(x: Radian32) -> (Float32, Float32) { s = -k_cosf((x - S3PIO2) as Float64); c = k_sinf((x - S3PIO2) as Float64); } + } else if sign { + s = k_sinf((x + S4PIO2) as Float64); + c = k_cosf((x + S4PIO2) as Float64); } else { - if sign { - s = k_sinf((x + S4PIO2) as Float64); - c = k_cosf((x + S4PIO2) as Float64); - } else { - s = k_sinf((x - S4PIO2) as Float64); - c = k_cosf((x - S4PIO2) as Float64); - } + s = k_sinf((x - S4PIO2) as Float64); + c = k_cosf((x - S4PIO2) as Float64); } return (s, c); diff --git a/core/llm/math/sinf.rs b/llm/math/sinf.rs similarity index 100% rename from core/llm/math/sinf.rs rename to llm/math/sinf.rs diff --git a/core/llm/math/sinh.rs b/llm/math/sinh.rs similarity index 94% rename from core/llm/math/sinh.rs rename to llm/math/sinh.rs index e6ea30c..371050b 100644 --- a/core/llm/math/sinh.rs +++ b/llm/math/sinh.rs @@ -16,10 +16,10 @@ pub fn sinh(x: Radian64) -> Float64 { let mut uf: Float64 = x; let mut ui: u64 = Float64::to_bits(uf); - let w: u32; + let t: Float64; let mut h: Float64; - let absx: Float64; + h = 0.5; if ui >> 63 != 0 { @@ -28,8 +28,8 @@ pub fn sinh(x: Radian64) -> Float64 { /* |x| */ ui &= !1 / 2; uf = Float64::from_bits(ui); - absx = uf; - w = (ui >> 32) as u32; + let absx: Float64 = uf; + let w: u32 = (ui >> 32) as u32; /* |x| < log(DBL_MAX) */ if w < 0x40862e42 { diff --git a/core/llm/math/sinhf.rs b/llm/math/sinhf.rs similarity index 100% rename from core/llm/math/sinhf.rs rename to llm/math/sinhf.rs diff --git a/core/llm/math/sqrt.rs b/llm/math/sqrt.rs similarity index 100% rename from core/llm/math/sqrt.rs rename to llm/math/sqrt.rs diff --git a/core/llm/math/sqrtf.rs b/llm/math/sqrtf.rs similarity index 99% rename from core/llm/math/sqrtf.rs rename to llm/math/sqrtf.rs index 9c2c427..5b32246 100644 --- a/core/llm/math/sqrtf.rs +++ b/llm/math/sqrtf.rs @@ -158,7 +158,7 @@ mod tests { #[test] fn conformance_tests() { let values = [ - 3.14159265359f32, + 3.141_592_7_f32, 10000.0f32, Float32::from_bits(0x0000000f), INFINITY, diff --git a/core/llm/math/tan.rs b/llm/math/tan.rs similarity index 100% rename from core/llm/math/tan.rs rename to llm/math/tan.rs diff --git a/core/llm/math/tanf.rs b/llm/math/tanf.rs similarity index 100% rename from core/llm/math/tanf.rs rename to llm/math/tanf.rs diff --git a/core/llm/math/tanh.rs b/llm/math/tanh.rs similarity index 93% rename from core/llm/math/tanh.rs rename to llm/math/tanh.rs index 51df661..833b545 100644 --- a/core/llm/math/tanh.rs +++ b/llm/math/tanh.rs @@ -14,16 +14,16 @@ pub fn tanh(mut x: Radian64) -> Float64 { let mut uf: Float64 = x; let mut ui: u64 = Float64::to_bits(uf); - let w: u32; - let sign: bool; + + let mut t: Float64; /* x = |x| */ - sign = ui >> 63 != 0; + let sign: bool = ui >> 63 != 0; ui &= !1 / 2; uf = Float64::from_bits(ui); x = uf; - w = (ui >> 32) as u32; + let w: u32 = (ui >> 32) as u32; if w > 0x3fe193ea { /* |x| > log(3)/2 ~= 0.5493 or nan */ diff --git a/core/llm/math/tanhf.rs b/llm/math/tanhf.rs similarity index 100% rename from core/llm/math/tanhf.rs rename to llm/math/tanhf.rs diff --git a/core/llm/math/tgamma.rs b/llm/math/tgamma.rs similarity index 83% rename from core/llm/math/tgamma.rs rename to llm/math/tgamma.rs index 8cc6e54..d45edae 100644 --- a/core/llm/math/tgamma.rs +++ b/llm/math/tgamma.rs @@ -27,7 +27,7 @@ use crate::{Float64, Float32}; use super::{exp, floor, k_cos, k_sin, pow}; -const PI: Float64 = 3.141592653589793238462643383279502884; +const PI: Float64 = 3.141_592_653_589_793; /* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ fn sinpi(mut x: Float64) -> Float64 { @@ -54,21 +54,21 @@ fn sinpi(mut x: Float64) -> Float64 { const N: usize = 12; //static const double g = 6.024680040776729583740234375; -const GMHALF: Float64 = 5.524680040776729583740234375; +const GMHALF: Float64 = 5.524_680_040_776_73; const SNUM: [Float64; N + 1] = [ - 23531376880.410759688572007674451636754734846804940, - 42919803642.649098768957899047001988850926355848959, - 35711959237.355668049440185451547166705960488635843, - 17921034426.037209699919755754458931112671403265390, - 6039542586.3520280050642916443072979210699388420708, - 1439720407.3117216736632230727949123939715485786772, - 248874557.86205415651146038641322942321632125127801, - 31426415.585400194380614231628318205362874684987640, - 2876370.6289353724412254090516208496135991145378768, - 186056.26539522349504029498971604569928220784236328, - 8071.6720023658162106380029022722506138218516325024, - 210.82427775157934587250973392071336271166969580291, - 2.5066282746310002701649081771338373386264310793408, + 23_531_376_880.410_76, + 42_919_803_642.649_1, + 35_711_959_237.355_67, + 17_921_034_426.037_21, + 6_039_542_586.352_028, + 1_439_720_407.311_721_6, + 248_874_557.862_054_17, + 31_426_415.585_400_194, + 2_876_370.628_935_372_5, + 186_056.265_395_223_48, + 8_071.672_002_365_816, + 210.824_277_751_579_36, + 2.506_628_274_631_000_2, ]; const SDEN: [Float64; N + 1] = [ 0.0, @@ -136,7 +136,7 @@ fn s(x: Float64) -> Float64 { #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgamma(mut x: Float64) -> Float64 { let u: u64 = x.to_bits(); - let absx: Float64; + let mut y: Float64; let mut dy: Float64; let mut z: Float64; @@ -183,7 +183,7 @@ pub fn tgamma(mut x: Float64) -> Float64 { return x; } - absx = if sign { -x } else { x }; + let absx: Float64 = if sign { -x } else { x }; /* handle the error of x + g - 0.5 */ y = absx + GMHALF; diff --git a/core/llm/math/tgammaf.rs b/llm/math/tgammaf.rs similarity index 100% rename from core/llm/math/tgammaf.rs rename to llm/math/tgammaf.rs diff --git a/core/llm/math/trunc.rs b/llm/math/trunc.rs similarity index 96% rename from core/llm/math/trunc.rs rename to llm/math/trunc.rs index a3b6a9c..fdf91f7 100644 --- a/core/llm/math/trunc.rs +++ b/llm/math/trunc.rs @@ -16,7 +16,7 @@ pub fn trunc(x: Float64) -> Float64 { let mut i: u64 = x.to_bits(); let mut e: i64 = (i >> 52 & 0x7ff) as i64 - 0x3ff + 12; - let m: u64; + if e >= 52 + 12 { return x; @@ -24,7 +24,7 @@ pub fn trunc(x: Float64) -> Float64 { if e < 12 { e = 1; } - m = -1i64 as u64 >> e; + let m: u64 = -1i64 as u64 >> e; if (i & m) == 0 { return x; } diff --git a/core/llm/math/truncf.rs b/llm/math/truncf.rs similarity index 96% rename from core/llm/math/truncf.rs rename to llm/math/truncf.rs index 7797b4e..0be8c05 100644 --- a/core/llm/math/truncf.rs +++ b/llm/math/truncf.rs @@ -16,7 +16,7 @@ pub fn truncf(x: Float32) -> Float32 { let mut i: u32 = x.to_bits(); let mut e: i32 = (i >> 23 & 0xff) as i32 - 0x7f + 9; - let m: u32; + if e >= 23 + 9 { return x; @@ -24,7 +24,7 @@ pub fn truncf(x: Float32) -> Float32 { if e < 9 { e = 1; } - m = -1i32 as u32 >> e; + let m: u32 = -1i32 as u32 >> e; if (i & m) == 0 { return x; } diff --git a/core/llm/types.rs b/llm/types.rs similarity index 100% rename from core/llm/types.rs rename to llm/types.rs diff --git a/utils/README.md b/utils/README.md new file mode 100644 index 0000000..7267259 --- /dev/null +++ b/utils/README.md @@ -0,0 +1 @@ +# Utilities diff --git a/utils/macros/Cargo.toml b/utils/macros/Cargo.toml new file mode 100644 index 0000000..26f0317 --- /dev/null +++ b/utils/macros/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "macros" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true +path = "lib.rs" + +[dependencies.mc] +package = "macros-core" +path = "./core" diff --git a/core/macros/README.md b/utils/macros/README.md similarity index 100% rename from core/macros/README.md rename to utils/macros/README.md diff --git a/core/macros/libtrig-macros-core/Cargo.toml b/utils/macros/core/Cargo.toml similarity index 80% rename from core/macros/libtrig-macros-core/Cargo.toml rename to utils/macros/core/Cargo.toml index db0398b..07cd871 100644 --- a/core/macros/libtrig-macros-core/Cargo.toml +++ b/utils/macros/core/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "libtrig-macros-core" +name = "macros-core" version = "0.1.0" edition = "2021" diff --git a/core/macros/libtrig-macros-core/ffi/mod.rs b/utils/macros/core/ffi/mod.rs similarity index 100% rename from core/macros/libtrig-macros-core/ffi/mod.rs rename to utils/macros/core/ffi/mod.rs diff --git a/core/macros/libtrig-macros-core/lib.rs b/utils/macros/core/lib.rs similarity index 100% rename from core/macros/libtrig-macros-core/lib.rs rename to utils/macros/core/lib.rs diff --git a/core/macros/libtrig-macros-core/mass_impl/args.rs b/utils/macros/core/mass_impl/args.rs similarity index 100% rename from core/macros/libtrig-macros-core/mass_impl/args.rs rename to utils/macros/core/mass_impl/args.rs diff --git a/core/macros/libtrig-macros-core/mass_impl/mod.rs b/utils/macros/core/mass_impl/mod.rs similarity index 100% rename from core/macros/libtrig-macros-core/mass_impl/mod.rs rename to utils/macros/core/mass_impl/mod.rs diff --git a/core/macros/libtrig-macros-core/mass_impl/variants.rs b/utils/macros/core/mass_impl/variants.rs similarity index 100% rename from core/macros/libtrig-macros-core/mass_impl/variants.rs rename to utils/macros/core/mass_impl/variants.rs diff --git a/core/macros/lib.rs b/utils/macros/lib.rs similarity index 100% rename from core/macros/lib.rs rename to utils/macros/lib.rs From 385213f2d75376910ba806fa3298eebb23d3ead7 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 16:58:49 -0800 Subject: [PATCH 17/93] More LLM Fixes --- llm/math/j0.rs | 7 +- llm/math/j0f.rs | 40 ++--- llm/math/j1.rs | 167 ++++++++++----------- llm/math/j1f.rs | 294 ++++++++++++++++++------------------- llm/math/jn.rs | 247 +++++++++++++++---------------- llm/math/jnf.rs | 224 ++++++++++++++-------------- llm/math/k_cos.rs | 12 +- llm/math/k_cosf.rs | 8 +- llm/math/k_sin.rs | 12 +- llm/math/k_sinf.rs | 8 +- llm/math/k_tan.rs | 30 ++-- llm/math/k_tanf.rs | 12 +- llm/math/lgamma_r.rs | 132 ++++++++--------- llm/math/lgammaf_r.rs | 134 ++++++++--------- llm/math/log.rs | 18 +-- llm/math/log10.rs | 62 ++++---- llm/math/log10f.rs | 56 +++---- llm/math/log1p.rs | 31 ++-- llm/math/log1pf.rs | 48 +++--- llm/math/log2.rs | 54 +++---- llm/math/log2f.rs | 48 +++--- llm/math/logf.rs | 12 +- llm/math/modf.rs | 4 +- llm/math/modff.rs | 4 +- llm/math/nextafter.rs | 4 +- llm/math/pow.rs | 58 ++++---- llm/math/powf.rs | 72 ++++----- llm/math/rem_pio2.rs | 16 +- llm/math/rem_pio2_large.rs | 16 +- llm/math/rem_pio2f.rs | 6 +- llm/math/sincos.rs | 8 +- llm/math/sincosf.rs | 32 ++-- llm/math/sinh.rs | 8 +- llm/math/sqrtf.rs | 2 +- llm/math/tanh.rs | 8 +- llm/math/tgamma.rs | 34 ++--- llm/math/trunc.rs | 4 +- llm/math/truncf.rs | 4 +- 38 files changed, 954 insertions(+), 982 deletions(-) diff --git a/llm/math/j0.rs b/llm/math/j0.rs index d030b64..a7e4432 100644 --- a/llm/math/j0.rs +++ b/llm/math/j0.rs @@ -66,7 +66,6 @@ const TPI: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ /* common method when |x|>=2 */ fn common(ix: u32, x: Float64, y0: bool) -> Float64 { - let mut c: Float64; let mut ss: Float64; let mut cc: Float64; @@ -124,7 +123,7 @@ pub fn j0(mut x: Float64) -> Float64 { let z: Float64; let r: Float64; let s: Float64; - let mut ix; + let mut ix: u32; ix = get_high_word(x); ix &= 0x7fffffff; @@ -213,7 +212,6 @@ pub fn y0(x: Float64) -> Float64 { return U00 + TPI * log(x); } -consts!{ /* The asymptotic expansions of pzero is * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. * For x >= 2, We approximate pzero by @@ -223,6 +221,7 @@ consts!{ * and * | pzero(x)-1-R/S | <= 2 ** ( -60.26) */ +consts!{ const PR8: [Float64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ @@ -320,7 +319,6 @@ fn pzero(x: Float64) -> Float64 { return 1.0 + r / s; } -consts!{ /* For x >= 8, the asymptotic expansions of qzero is * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. * We approximate pzero by @@ -330,6 +328,7 @@ consts!{ * and * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) */ +consts!{ const QR8: [Float64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ diff --git a/llm/math/j0f.rs b/llm/math/j0f.rs index 40db71f..dfcf14e 100644 --- a/llm/math/j0f.rs +++ b/llm/math/j0f.rs @@ -17,13 +17,12 @@ use crate::Float32; use super::{cosf, fabsf, logf, sinf, sqrtf}; -consts!{ const INVSQRTPI: Float32 = 5.6418961287e-01; /* 0x3f106ebb */ const TPI: Float32 = 6.3661974669e-01; /* 0x3f22f983 */ -} fn common(ix: u32, x: Float32, y0: bool) -> Float32 { let z: Float32; + let s: Float32; let mut c: Float32; let mut ss: Float32; let mut cc: Float32; @@ -31,7 +30,7 @@ fn common(ix: u32, x: Float32, y0: bool) -> Float32 { * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) */ - let s = sinf(x); + s = sinf(x); c = cosf(x); if y0 { c = -c; @@ -56,7 +55,6 @@ fn common(ix: u32, x: Float32, y0: bool) -> Float32 { } /* R0/S0 on [0, 2.00] */ -consts!{ const R02: Float32 = 1.5625000000e-02; /* 0x3c800000 */ const R03: Float32 = -1.8997929874e-04; /* 0xb947352e */ const R04: Float32 = 1.8295404516e-06; /* 0x35f58e88 */ @@ -65,15 +63,14 @@ const S01: Float32 = 1.5619102865e-02; /* 0x3c7fe744 */ const S02: Float32 = 1.1692678527e-04; /* 0x38f53697 */ const S03: Float32 = 5.1354652442e-07; /* 0x3509daa6 */ const S04: Float32 = 1.1661400734e-09; /* 0x30a045e8 */ -} /// Bessel function of the first kind of order zero /// /// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/j0.html) pub fn j0f(mut x: Float32) -> Float32 { - let z; - let r; - let s; + let z: Float32; + let r: Float32; + let s: Float32; let mut ix: u32; ix = x.to_bits(); @@ -103,7 +100,6 @@ pub fn j0f(mut x: Float32) -> Float32 { return 1.0 - x; } -consts!{ const U00: Float32 = -7.3804296553e-02; /* 0xbd9726b5 */ const U01: Float32 = 1.7666645348e-01; /* 0x3e34e80d */ const U02: Float32 = -1.3818567619e-02; /* 0xbc626746 */ @@ -115,15 +111,11 @@ const V01: Float32 = 1.2730483897e-02; /* 0x3c509385 */ const V02: Float32 = 7.6006865129e-05; /* 0x389f65e0 */ const V03: Float32 = 2.5915085189e-07; /* 0x348b216c */ const V04: Float32 = 4.4111031494e-10; /* 0x2ff280c2 */ -} /// Bessel function of the second kind of order zero /// /// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/y0.html) pub fn y0f(x: Float32) -> Float32 { - let z; - let u; - let v; let ix: u32 = x.to_bits(); if (ix & 0x7fffffff) == 0 { return -1.0 / 0.0; @@ -142,15 +134,14 @@ pub fn y0f(x: Float32) -> Float32 { if ix >= 0x39000000 { /* x >= 2**-13 */ /* large ulp error at x ~= 0.89 */ - z = x * x; - u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); - v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); + let z = x * x; + let u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); + let v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); return u / v + TPI * (j0f(x) * logf(x)); } return U00 + TPI * logf(x); } -consts!{ /* The asymptotic expansions of pzero is * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. * For x >= 2, We approximate pzero by @@ -160,6 +151,7 @@ consts!{ * and * | pzero(x)-1-R/S | <= 2 ** ( -60.26) */ +consts!{ const PR8: [Float32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ @@ -231,10 +223,7 @@ const PS2: [Float32; 5] = [ fn pzerof(x: Float32) -> Float32 { let p: &[Float32; 6]; let q: &[Float32; 5]; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; + let ix = x.to_bits() & 0x7fffffff; if ix >= 0x41000000 { p = &PR8; q = &PS8; @@ -256,7 +245,6 @@ fn pzerof(x: Float32) -> Float32 { return 1.0 + r / s; } -consts!{ /* For x >= 8, the asymptotic expansions of qzero is * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. * We approximate pzero by @@ -265,7 +253,8 @@ consts!{ * S = 1 + qS0*s^2 + ... + qS5*s^12 * and * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) - */ +*/ +consts!{ const QR8: [Float32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ @@ -342,10 +331,7 @@ const QS2: [Float32; 6] = [ fn qzerof(x: Float32) -> Float32 { let p: &[Float32; 6]; let q: &[Float32; 6]; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; + let ix = x.to_bits() & 0x7fffffff; if ix >= 0x41000000 { p = &QR8; q = &QS8; diff --git a/llm/math/j1.rs b/llm/math/j1.rs index 904dd4a..4cc14ca 100644 --- a/llm/math/j1.rs +++ b/llm/math/j1.rs @@ -65,11 +65,6 @@ const TPI: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ } fn common(ix: u32, x: Float64, y1: bool, sign: bool) -> Float64 { - let z: Float64; - let mut s: Float64; - let mut ss: Float64; - let mut cc: Float64; - /* * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) @@ -78,16 +73,16 @@ fn common(ix: u32, x: Float64, y1: bool, sign: bool) -> Float64 { * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) */ - s = sin(x); + let mut s = sin(x); if y1 { s = -s; } let c = cos(x); - cc = s - c; + let mut cc = s - c; if ix < 0x7fe00000 { /* avoid overflow in 2*x */ - ss = -s - c; - z = cos(2.0 * x); + let mut ss = -s - c; + let z = cos(2.0 * x); if s * c > 0.0 { cc = z / ss; } else { @@ -106,8 +101,8 @@ fn common(ix: u32, x: Float64, y1: bool, sign: bool) -> Float64 { return INVSQRTPI * cc / sqrt(x); } -consts!{ /* R0/S0 on [0,2] */ +consts!{ const R00: Float64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ const R01: Float64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ const R02: Float64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ @@ -126,9 +121,8 @@ pub fn j1(x: Float64) -> Float64 { let mut z: Float64; let r: Float64; let s: Float64; - let mut ix: u32; - ix = get_high_word(x); - let sign: bool = (ix >> 31) != 0; + let mut ix = get_high_word(x); + let sign = (ix >> 31) != 0; ix &= 0x7fffffff; if ix >= 0x7ff00000 { return 1.0 / (x * x); @@ -150,33 +144,29 @@ pub fn j1(x: Float64) -> Float64 { return (0.5 + z) * x; } +consts!{ const U0: [Float64; 5] = [ - -1.960_570_906_462_389_4e-1, /* 0xBFC91866, 0x143CBC8A */ - 5.044_387_166_398_113e-2, /* 0x3FA9D3C7, 0x76292CD1 */ - -1.912_568_958_757_635_5e-3, /* 0xBF5F55E5, 0x4844F50F */ - 2.352_526_005_616_105e-5, /* 0x3EF8AB03, 0x8FA6B88E */ - -9.190_991_580_398_789e-8, /* 0xBE78AC00, 0x569105B8 */ + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ ]; const V0: [Float64; 5] = [ - 1.991_673_182_366_499e-2, /* 0x3F94650D, 0x3F4DA9F0 */ - 2.025_525_810_251_351_7e-4, /* 0x3F2A8C89, 0x6C257764 */ - 1.356_088_010_975_162_3e-6, /* 0x3EB6C05A, 0x894E8CA6 */ - 6.227_414_523_646_215e-9, /* 0x3E3ABF1D, 0x5BA69A86 */ - 1.665_592_462_079_920_8e-11, /* 0x3DB25039, 0xDACA772A */ + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ ]; +} /// Bessel function of the second kind of order one /// /// Calculates the Bessel function of the second kind of order one of `x`. pub fn y1(x: Float64) -> Float64 { - - - - - - - let ix: u32 = get_high_word(x); - let lx: u32 = get_low_word(x); + let ix = get_high_word(x); + let lx = get_low_word(x); /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ if (ix << 1 | lx) == 0 { @@ -197,9 +187,9 @@ pub fn y1(x: Float64) -> Float64 { /* x < 2**-54 */ return -TPI / x; } - let z: Float64 = x * x; - let u: Float64 = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); - let v: Float64 = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + let z = x * x; + let u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + let v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); return x * (u / v) + TPI * (j1(x) * log(x) - 1.0 / x); } @@ -211,85 +201,80 @@ pub fn y1(x: Float64) -> Float64 { * S = 1 + ps0*s^2 + ... + ps4*s^10 * and * | pone(x)-1-R/S | <= 2 ** ( -60.06) - */ - +*/ +consts!{ const PR8: [Float64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - 1.171_874_999_999_886_5e-1, /* 0x3FBDFFFF, 0xFFFFFCCE */ - 1.323_948_065_930_735_8e1, /* 0x402A7A9D, 0x357F7FCE */ - 4.120_518_543_073_785_6e2, /* 0x4079C0D4, 0x652EA590 */ - 3.874_745_389_139_605_3e3, /* 0x40AE457D, 0xA3A532CC */ - 7.914_479_540_318_917e3, /* 0x40BEEA7A, 0xC32782DD */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ ]; const PS8: [Float64; 5] = [ - 1.142_073_703_756_784_1e2, /* 0x405C8D45, 0x8E656CAC */ - 3.650_930_834_208_534_6e3, /* 0x40AC85DC, 0x964D274F */ - 3.695_620_602_690_334_6e4, /* 0x40E20B86, 0x97C5BB7F */ - 9.760_279_359_349_508e4, /* 0x40F7D42C, 0xB28F17BB */ - 3.080_427_206_278_888e4, /* 0x40DE1511, 0x697A0B2D */ + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ ]; const PR5: [Float64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.319_905_195_562_435_2e-11, /* 0x3DAD0667, 0xDAE1CA7D */ - 1.171_874_931_906_141e-1, /* 0x3FBDFFFF, 0xE2C10043 */ - 6.802_751_278_684_329, /* 0x401B3604, 0x6E6315E3 */ - 1.083_081_829_901_891_1e2, /* 0x405B13B9, 0x452602ED */ - 5.176_361_395_331_998e2, /* 0x40802D16, 0xD052D649 */ - 5.287_152_013_633_375e2, /* 0x408085B8, 0xBB7E0CB7 */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ ]; const PS5: [Float64; 5] = [ - 5.928_059_872_211_313e1, /* 0x404DA3EA, 0xA8AF633D */ - 9.914_014_187_336_144e2, /* 0x408EFB36, 0x1B066701 */ - 5.353_266_952_914_88e3, /* 0x40B4E944, 0x5706B6FB */ - 7.844_690_317_495_512e3, /* 0x40BEA4B0, 0xB8A5BB15 */ - 1.504_046_888_103_610_6e3, /* 0x40978030, 0x036F5E51 */ + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ ]; const PR3: [Float64; 6] = [ - 3.025_039_161_373_736e-9, /* 0x3E29FC21, 0xA7AD9EDD */ - 1.171_868_655_672_535_9e-1, /* 0x3FBDFFF5, 0x5B21D17B */ - 3.932_977_500_333_156_4, /* 0x400F76BC, 0xE85EAD8A */ - 3.511_940_355_916_369e1, /* 0x40418F48, 0x9DA6D129 */ - 9.105_501_107_507_813e1, /* 0x4056C385, 0x4D2C1837 */ - 4.855_906_851_973_649e1, /* 0x4048478F, 0x8EA83EE5 */ + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ ]; const PS3: [Float64; 5] = [ - 3.479_130_950_012_515e1, /* 0x40416549, 0xA134069C */ - 3.367_624_587_478_257_5e2, /* 0x40750C33, 0x07F1A75F */ - 1.046_871_399_757_751_3e3, /* 0x40905B7C, 0x5037D523 */ - 8.908_113_463_982_564e2, /* 0x408BD67D, 0xA32E31E9 */ - 1.037_879_324_396_392_8e2, /* 0x4059F26D, 0x7C2EED53 */ + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ ]; const PR2: [Float64; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.077_108_301_068_737_4e-7, /* 0x3E7CE9D4, 0xF65544F4 */ - 1.171_762_194_626_833_5e-1, /* 0x3FBDFF42, 0xBE760D83 */ - 2.368_514_966_676_088, /* 0x4002F2B7, 0xF98FAEC0 */ - 1.224_261_091_482_612_3e1, /* 0x40287C37, 0x7F71A964 */ - 1.769_397_112_716_877_3e1, /* 0x4031B1A8, 0x177F8EE2 */ - 5.073_523_125_888_185, /* 0x40144B49, 0xA574C1FE */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ ]; const PS2: [Float64; 5] = [ - 2.143_648_593_638_214e1, /* 0x40356FBD, 0x8AD5ECDC */ - 1.252_902_271_684_027_5e2, /* 0x405F5293, 0x14F92CD5 */ - 2.322_764_690_571_628e2, /* 0x406D08D8, 0xD5A2DBD9 */ - 1.176_793_732_871_471e2, /* 0x405D6B7A, 0xDA1884A9 */ - 8.364_638_933_716_183, /* 0x4020BAB1, 0xF44E5192 */ + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ ]; +} fn pone(x: Float64) -> Float64 { let p: &[Float64; 6]; let q: &[Float64; 5]; - - - - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; + let ix = get_high_word(x) & 0x7fffffff; if ix >= 0x40200000 { p = &PR8; q = &PS8; @@ -319,8 +304,8 @@ fn pone(x: Float64) -> Float64 { * S = 1 + qs1*s^2 + ... + qs6*s^12 * and * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) - */ - +*/ +consts!{ const QR8: [Float64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ @@ -391,14 +376,12 @@ const QS2: [Float64; 6] = [ 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ ]; +} fn qone(x: Float64) -> Float64 { let p: &[Float64; 6]; let q: &[Float64; 6]; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; + let ix = get_high_word(x) & 0x7fffffff; if ix >= 0x40200000 { p = &QR8; q = &QS8; diff --git a/llm/math/j1f.rs b/llm/math/j1f.rs index 9cf0c19..8c17a6a 100644 --- a/llm/math/j1f.rs +++ b/llm/math/j1f.rs @@ -17,25 +17,21 @@ use crate::{Float64, Float32}; use super::{cosf, fabsf, logf, sinf, sqrtf}; -const INVSQRTPI: Float32 = 5.641_896e-1; /* 0x3f106ebb */ -const TPI: Float32 = 6.366_197_5e-1; /* 0x3f22f983 */ +consts!{ +const INVSQRTPI: Float32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: Float32 = 6.3661974669e-01; /* 0x3f22f983 */ +} fn common(ix: u32, x: Float32, y1: bool, sign: bool) -> Float32 { - let z: Float64; - let mut s: Float64; - - let mut ss: Float64; - let mut cc: Float64; - - s = sinf(x) as Float64; + let mut s = sinf(x) as Float64; if y1 { s = -s; } - let c: Float64 = cosf(x) as Float64; - cc = s - c; + let c = cosf(x) as Float64; + let mut cc = s - c; if ix < 0x7f000000 { - ss = -s - c; - z = cosf(2.0 * x) as Float64; + let mut ss = -s - c; + let z = cosf(2.0 * x) as Float64; if s * c > 0.0 { cc = z / ss; } else { @@ -55,28 +51,25 @@ fn common(ix: u32, x: Float32, y1: bool, sign: bool) -> Float32 { } /* R0/S0 on [0,2] */ -const R00: Float32 = -6.25e-2; /* 0xbd800000 */ -const R01: Float32 = 1.407_056_7e-3; /* 0x3ab86cfd */ -const R02: Float32 = -1.599_556_3e-5; /* 0xb7862e36 */ -const R03: Float32 = 4.967_28e-8; /* 0x335557d2 */ -const S01: Float32 = 1.915_376e-2; /* 0x3c9ce859 */ -const S02: Float32 = 1.859_467_9e-4; /* 0x3942fab6 */ -const S03: Float32 = 1.177_184_7e-6; /* 0x359dffc2 */ -const S04: Float32 = 5.046_362_4e-9; /* 0x31ad6446 */ -const S05: Float32 = 1.235_422_7e-11; /* 0x2d59567e */ +consts!{ +const R00: Float32 = -6.2500000000e-02; /* 0xbd800000 */ +const R01: Float32 = 1.4070566976e-03; /* 0x3ab86cfd */ +const R02: Float32 = -1.5995563444e-05; /* 0xb7862e36 */ +const R03: Float32 = 4.9672799207e-08; /* 0x335557d2 */ +const S01: Float32 = 1.9153760746e-02; /* 0x3c9ce859 */ +const S02: Float32 = 1.8594678841e-04; /* 0x3942fab6 */ +const S03: Float32 = 1.1771846857e-06; /* 0x359dffc2 */ +const S04: Float32 = 5.0463624390e-09; /* 0x31ad6446 */ +const S05: Float32 = 1.2354227016e-11; /* 0x2d59567e */ +} /// Bessel function of the first kind of order one /// /// Calculates the Bessel function of the first kind of order one of `x`. pub fn j1f(x: Float32) -> Float32 { let mut z: Float32; - let r: Float32; - let s: Float32; - let mut ix: u32; - - - ix = x.to_bits(); - let sign: bool = (ix >> 31) != 0; + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; ix &= 0x7fffffff; if ix >= 0x7f800000 { return 1.0 / (x * x); @@ -88,8 +81,8 @@ pub fn j1f(x: Float32) -> Float32 { if ix >= 0x39000000 { /* |x| >= 2**-13 */ z = x * x; - r = z * (R00 + z * (R01 + z * (R02 + z * R03))); - s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); + let r = z * (R00 + z * (R01 + z * (R02 + z * R03))); + let s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); z = 0.5 + r / s; } else { z = 0.5; @@ -97,31 +90,28 @@ pub fn j1f(x: Float32) -> Float32 { return z * x; } +consts!{ const U0: [Float32; 5] = [ - -1.960_571e-1, /* 0xbe48c331 */ - 5.044_387_3e-2, /* 0x3d4e9e3c */ - -1.912_568_9e-3, /* 0xbafaaf2a */ - 2.352_526e-5, /* 0x37c5581c */ - -9.190_992e-8, /* 0xb3c56003 */ + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ ]; const V0: [Float32; 5] = [ - 1.991_673_2e-2, /* 0x3ca3286a */ - 2.025_525_8e-4, /* 0x3954644b */ - 1.356_088e-6, /* 0x35b602d4 */ - 6.227_414_6e-9, /* 0x31d5f8eb */ - 1.665_592_5e-11, /* 0x2d9281cf */ + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ ]; +} /// Bessel function of the second kind of order one /// /// Calculates the Bessel function of the second kind of order one of `x`. pub fn y1f(x: Float32) -> Float32 { - - - - - - let ix: u32 = x.to_bits(); + let ix = x.to_bits(); if (ix & 0x7fffffff) == 0 { return -1.0 / 0.0; } @@ -139,9 +129,9 @@ pub fn y1f(x: Float32) -> Float32 { /* x < 2**-25 */ return -TPI / x; } - let z: Float32 = x * x; - let u: Float32 = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); - let v: Float32 = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + let z = x * x; + let u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + let v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); return x * (u / v) + TPI * (j1f(x) * logf(x) - 1.0 / x); } @@ -158,76 +148,76 @@ pub fn y1f(x: Float32) -> Float32 { const PR8: [Float32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ - 1.171_875e-1, /* 0x3df00000 */ - 1.323_948_1e1, /* 0x4153d4ea */ - 4.120_518_5e2, /* 0x43ce06a3 */ - 3.874_745_4e3, /* 0x45722bed */ - 7.914_479_5e3, /* 0x45f753d6 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ ]; const PS8: [Float32; 5] = [ - 1.142_073_7e2, /* 0x42e46a2c */ - 3.650_931e3, /* 0x45642ee5 */ - 3.695_620_7e4, /* 0x47105c35 */ - 9.760_28e4, /* 0x47bea166 */ - 3.080_427_1e4, /* 0x46f0a88b */ + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ ]; const PR5: [Float32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.319_905_2e-11, /* 0x2d68333f */ - 1.171_874_9e-1, /* 0x3defffff */ - 6.802_751, /* 0x40d9b023 */ - 1.083_081_8e2, /* 0x42d89dca */ - 5.176_361_7e2, /* 0x440168b7 */ - 5.287_152e2, /* 0x44042dc6 */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ ]; const PS5: [Float32; 5] = [ - 5.928_059_8e1, /* 0x426d1f55 */ - 9.914_014e2, /* 0x4477d9b1 */ - 5.353_267e3, /* 0x45a74a23 */ - 7.844_690_4e3, /* 0x45f52586 */ - 1.504_046_9e3, /* 0x44bc0180 */ + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ ]; const PR3: [Float32; 6] = [ - 3.025_039e-9, /* 0x314fe10d */ - 1.171_868_7e-1, /* 0x3defffab */ - 3.932_977_4, /* 0x407bb5e7 */ - 3.511_940_4e1, /* 0x420c7a45 */ - 9.105_501e1, /* 0x42b61c2a */ - 4.855_906_7e1, /* 0x42423c7c */ + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ ]; const PS3: [Float32; 5] = [ - 3.479_131e1, /* 0x420b2a4d */ - 3.367_624_5e2, /* 0x43a86198 */ - 1.046_871_5e3, /* 0x4482dbe3 */ - 8.908_113_4e2, /* 0x445eb3ed */ - 1.037_879_3e2, /* 0x42cf936c */ + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ ]; const PR2: [Float32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.077_108_3e-7, /* 0x33e74ea8 */ - 1.171_762_2e-1, /* 0x3deffa16 */ - 2.368_515, /* 0x401795c0 */ - 1.224_261_1e1, /* 0x4143e1bc */ - 1.769_397_2e1, /* 0x418d8d41 */ - 5.073_523, /* 0x40a25a4d */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ ]; const PS2: [Float32; 5] = [ - 2.143_648_5e1, /* 0x41ab7dec */ - 1.252_902_3e2, /* 0x42fa9499 */ - 2.322_764_7e2, /* 0x436846c7 */ - 1.176_793_75e2, /* 0x42eb5bd7 */ - 8.364_639, /* 0x4105d590 */ + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ ]; fn ponef(x: Float32) -> Float32 { let p: &[Float32; 6]; let q: &[Float32; 5]; - - - + let z: Float32; + let r: Float32; + let s: Float32; let mut ix: u32; ix = x.to_bits(); @@ -247,9 +237,9 @@ fn ponef(x: Float32) -> Float32 { p = &PR2; q = &PS2; } - let z: Float32 = 1.0 / (x * x); - let r: Float32 = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - let s: Float32 = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); return 1.0 + r / s; } @@ -267,80 +257,80 @@ fn ponef(x: Float32) -> Float32 { const QR8: [Float32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ - -1.025_390_6e-1, /* 0xbdd20000 */ - -1.627_175_3e1, /* 0xc1822c8d */ - -7.596_017_5e2, /* 0xc43de683 */ - -1.184_980_7e4, /* 0xc639273a */ - -4.843_851e4, /* 0xc73d3683 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ ]; const QS8: [Float32; 6] = [ - 1.613_953_7e2, /* 0x43216537 */ - 7.825_386e3, /* 0x45f48b17 */ - 1.338_753_4e5, /* 0x4802bcd6 */ - 7.196_577_5e5, /* 0x492fb29c */ - 6.666_012_5e5, /* 0x4922be94 */ - -2.944_902_5e5, /* 0xc88fcb48 */ + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ ]; const QR5: [Float32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -2.089_799_3e-11, /* 0xadb7d219 */ - -1.025_390_5e-1, /* 0xbdd1fffe */ - -8.056_448, /* 0xc100e736 */ - -1.836_696e2, /* 0xc337ab6b */ - -1.373_193_7e3, /* 0xc4aba633 */ - -2.612_444_3e3, /* 0xc523471c */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ ]; const QS5: [Float32; 6] = [ - 8.127_655e1, /* 0x42a28d98 */ - 1.991_798_7e3, /* 0x44f8f98f */ - 1.746_848_4e4, /* 0x468878f8 */ - 4.985_142_6e4, /* 0x4742bb6d */ - 2.794_807_4e4, /* 0x46da5826 */ - -4.719_183_6e3, /* 0xc5937978 */ + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ ]; const QR3: [Float32; 6] = [ - -5.078_312_4e-9, /* 0xb1ae7d4f */ - -1.025_378_3e-1, /* 0xbdd1ff5b */ - -4.610_116, /* 0xc0938612 */ - -5.784_722e1, /* 0xc267638e */ - -2.282_445_4e2, /* 0xc3643e9a */ - -2.192_101_3e2, /* 0xc35b35cb */ + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ ]; const QS3: [Float32; 6] = [ - 4.766_515_4e1, /* 0x423ea91e */ - 6.738_651e2, /* 0x4428775e */ - 3.380_152_8e3, /* 0x45534272 */ - 5.547_729e3, /* 0x45ad5dd5 */ - 1.903_119_1e3, /* 0x44ede3d0 */ - -1.352_011_9e2, /* 0xc3073381 */ + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ ]; const QR2: [Float32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -1.783_817_3e-7, /* 0xb43f8932 */ - -1.025_170_46e-1, /* 0xbdd1f475 */ - -2.752_205_6, /* 0xc0302423 */ - -1.966_361_6e1, /* 0xc19d4f16 */ - -4.232_531_4e1, /* 0xc2294d1f */ - -2.137_192_2e1, /* 0xc1aaf9b2 */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ ]; const QS2: [Float32; 6] = [ - 2.953_336_3e1, /* 0x41ec4454 */ - 2.529_815_5e2, /* 0x437cfb47 */ - 7.575_028e2, /* 0x443d602e */ - 7.393_932e2, /* 0x4438d92a */ - 1.559_49e2, /* 0x431bf2f2 */ - -4.959_499, /* 0xc09eb437 */ + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ ]; fn qonef(x: Float32) -> Float32 { let p: &[Float32; 6]; let q: &[Float32; 6]; - - - + let s: Float32; + let r: Float32; + let z: Float32; let mut ix: u32; ix = x.to_bits(); @@ -360,9 +350,9 @@ fn qonef(x: Float32) -> Float32 { p = &QR2; q = &QS2; } - let z: Float32 = 1.0 / (x * x); - let r: Float32 = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - let s: Float32 = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); return (0.375 + r / s) / x; } diff --git a/llm/math/jn.rs b/llm/math/jn.rs index 32bd134..b26373d 100644 --- a/llm/math/jn.rs +++ b/llm/math/jn.rs @@ -38,23 +38,22 @@ use crate::Float64; use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, y1}; -const INVSQRTPI: Float64 = 5.641_895_835_477_563e-1; /* 0x3FE20DD7, 0x50429B6D */ +consts!{ +const INVSQRTPI: Float64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +} /// Bessel function of the first kind of order zero of `x`. /// /// Calculates the Bessel function of the first kind of order zero of `x`. pub fn jn(n: i32, mut x: Float64) -> Float64 { - let mut ix: u32; - + let mut ix = get_high_word(x); + let lx = get_low_word(x); let nm1: i32; let mut i: i32; let mut sign: bool; let mut a: Float64; let mut b: Float64; let mut temp: Float64; - - ix = get_high_word(x); - let lx: u32 = get_low_word(x); sign = (ix >> 31) != 0; ix &= 0x7fffffff; @@ -122,128 +121,130 @@ pub fn jn(n: i32, mut x: Float64) -> Float64 { a = temp; } } - } else if ix < 0x3e100000 { - /* x < 2**-29 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 32 { - /* underflow */ - b = 0.0; - } else { - temp = x * 0.5; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as Float64; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: Float64; - let mut q0: Float64; - let mut q1: Float64; - let mut w: Float64; - - let mut z: Float64; - let mut tmp: Float64; - + if ix < 0x3e100000 { + /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 32 { + /* underflow */ + b = 0.0; + } else { + temp = x * 0.5; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as Float64; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: Float64; + let mut q0: Float64; + let mut q1: Float64; + let mut w: Float64; + let h: Float64; + let mut z: Float64; + let mut tmp: Float64; + let nf: Float64; - let mut k: i32; + let mut k: i32; - let nf: Float64 = (nm1 as Float64) + 1.0; - w = 2.0 * nf / x; - let h: Float64 = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e9 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as Float64) + nf) / x - t); - i -= 1; - } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf * log(fabs(w)); - if tmp < 7.097_827_128_933_84e2 { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as Float64)) / x - a; - a = temp; + nf = (nm1 as Float64) + 1.0; + w = 2.0 * nf / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e9 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as Float64) + nf) / x - t); i -= 1; } - } else { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as Float64)) / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p500 = Float64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 - if b > x1p500 { - a /= b; - t /= b; - b = 1.0; + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * log(fabs(w)); + if tmp < 7.09782712893383973096e+02 { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as Float64)) / x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as Float64)) / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p500 = Float64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 + if b > x1p500 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; } - i -= 1; } - } - z = j0(x); - w = j1(x); - if fabs(z) >= fabs(w) { - b = t * z / b; - } else { - b = t * w / a; + z = j0(x); + w = j1(x); + if fabs(z) >= fabs(w) { + b = t * z / b; + } else { + b = t * w / a; + } } } @@ -259,7 +260,7 @@ pub fn jn(n: i32, mut x: Float64) -> Float64 { /// Calculates the Bessel function of the second kind of order zero of `x`. pub fn yn(n: i32, x: Float64) -> Float64 { let mut ix: u32; - + let lx: u32; let mut ib: u32; let nm1: i32; let mut sign: bool; @@ -269,7 +270,7 @@ pub fn yn(n: i32, x: Float64) -> Float64 { let mut temp: Float64; ix = get_high_word(x); - let lx: u32 = get_low_word(x); + lx = get_low_word(x); sign = (ix >> 31) != 0; ix &= 0x7fffffff; diff --git a/llm/math/jnf.rs b/llm/math/jnf.rs index 2532d90..35bb33a 100644 --- a/llm/math/jnf.rs +++ b/llm/math/jnf.rs @@ -68,123 +68,125 @@ pub fn jnf(n: i32, mut x: Float32) -> Float32 { b = b * (2.0 * (i as Float32) / x) - a; a = temp; } - } else if ix < 0x35800000 { - // x < 2**-20 - //x is tiny, return the first Taylor expansion of J(n,x) - // J(n,x) = 1/n!*(x/2)^n - ... - if nm1 > 8 { - /* underflow */ - nm1 = 8; - } - temp = 0.5 * x; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as Float32; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; } else { - // use backward recurrence - // x x^2 x^2 - // J(n,x)/J(n-1,x) = ---- ------ ------ ..... - // 2n - 2(n+1) - 2(n+2) - // - // 1 1 1 - // (for large x) = ---- ------ ------ ..... - // 2n 2(n+1) 2(n+2) - // -- - ------ - ------ - - // x x x - // - // Let w = 2n/x and h=2/x, then the above quotient - // is equal to the continued fraction: - // 1 - // = ----------------------- - // 1 - // w - ----------------- - // 1 - // w+h - --------- - // w+2h - ... - // - // To determine how many terms needed, let - // Q(0) = w, Q(1) = w(w+h) - 1, - // Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - // When Q(k) > 1e4 good for single - // When Q(k) > 1e9 good for double - // When Q(k) > 1e17 good for quadruple - /* determine k */ - let mut t: Float32; - let mut q0: Float32; - let mut q1: Float32; - let mut w: Float32; - - let mut z: Float32; - let mut tmp: Float32; - - let mut k: i32; + if ix < 0x35800000 { + // x < 2**-20 + //x is tiny, return the first Taylor expansion of J(n,x) + // J(n,x) = 1/n!*(x/2)^n - ... + if nm1 > 8 { + /* underflow */ + nm1 = 8; + } + temp = 0.5 * x; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as Float32; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } else { + // use backward recurrence + // x x^2 x^2 + // J(n,x)/J(n-1,x) = ---- ------ ------ ..... + // 2n - 2(n+1) - 2(n+2) + // + // 1 1 1 + // (for large x) = ---- ------ ------ ..... + // 2n 2(n+1) 2(n+2) + // -- - ------ - ------ - + // x x x + // + // Let w = 2n/x and h=2/x, then the above quotient + // is equal to the continued fraction: + // 1 + // = ----------------------- + // 1 + // w - ----------------- + // 1 + // w+h - --------- + // w+2h - ... + // + // To determine how many terms needed, let + // Q(0) = w, Q(1) = w(w+h) - 1, + // Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + // When Q(k) > 1e4 good for single + // When Q(k) > 1e9 good for double + // When Q(k) > 1e17 good for quadruple + /* determine k */ + let mut t: Float32; + let mut q0: Float32; + let mut q1: Float32; + let mut w: Float32; + let h: Float32; + let mut z: Float32; + let mut tmp: Float32; + let nf: Float32; + let mut k: i32; - let nf: Float32 = (nm1 as Float32) + 1.0; - w = 2.0 * (nf as Float32) / x; - let h: Float32 = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e4 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as Float32) + nf) / x - t); - i -= 1; - } - a = t; - b = 1.0; - // estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - // Hence, if n*(log(2n/x)) > ... - // single 8.8722839355e+01 - // double 7.09782712893383973096e+02 - // long double 1.1356523406294143949491931077970765006170e+04 - // then recurrent value may overflow and the result is - // likely underflow to zero - tmp = nf * logf(fabsf(w)); - if tmp < 88.721_68 { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as Float32) * b / x - a; - a = temp; + nf = (nm1 as Float32) + 1.0; + w = 2.0 * (nf as Float32) / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e4 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as Float32) + nf) / x - t); i -= 1; } - } else { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as Float32) * b / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p60 = Float32::from_bits(0x5d800000); // 0x1p60 == 2^60 - if b > x1p60 { - a /= b; - t /= b; - b = 1.0; + a = t; + b = 1.0; + // estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + // Hence, if n*(log(2n/x)) > ... + // single 8.8722839355e+01 + // double 7.09782712893383973096e+02 + // long double 1.1356523406294143949491931077970765006170e+04 + // then recurrent value may overflow and the result is + // likely underflow to zero + tmp = nf * logf(fabsf(w)); + if tmp < 88.721679688 { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as Float32) * b / x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as Float32) * b / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p60 = Float32::from_bits(0x5d800000); // 0x1p60 == 2^60 + if b > x1p60 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; } - i -= 1; } - } - z = j0f(x); - w = j1f(x); - if fabsf(z) >= fabsf(w) { - b = t * z / b; - } else { - b = t * w / a; + z = j0f(x); + w = j1f(x); + if fabsf(z) >= fabsf(w) { + b = t * z / b; + } else { + b = t * w / a; + } } } diff --git a/llm/math/k_cos.rs b/llm/math/k_cos.rs index 63dd270..5ef6334 100644 --- a/llm/math/k_cos.rs +++ b/llm/math/k_cos.rs @@ -11,12 +11,12 @@ use crate::Float64; -const C1: Float64 = 4.166_666_666_666_66e-2; /* 0x3FA55555, 0x5555554C */ -const C2: Float64 = -1.388_888_888_887_411e-3; /* 0xBF56C16C, 0x16C15177 */ -const C3: Float64 = 2.480_158_728_947_673e-5; /* 0x3EFA01A0, 0x19CB1590 */ -const C4: Float64 = -2.755_731_435_139_066_3e-7; /* 0xBE927E4F, 0x809C52AD */ -const C5: Float64 = 2.087_572_321_298_175e-9; /* 0x3E21EE9E, 0xBDB4B1C4 */ -const C6: Float64 = -1.135_964_755_778_819_5e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ +const C1: Float64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ +const C2: Float64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ +const C3: Float64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ +const C4: Float64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ +const C5: Float64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ +const C6: Float64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ // kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 // Input x is assumed to be bounded by ~pi/4 in magnitude. diff --git a/llm/math/k_cosf.rs b/llm/math/k_cosf.rs index 3ae9105..c2cc739 100644 --- a/llm/math/k_cosf.rs +++ b/llm/math/k_cosf.rs @@ -17,10 +17,10 @@ use crate::{Float64, Float32}; /* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ -const C0: Float64 = -0.499_999_997_251_031; /* -0x1ffffffd0c5e81.0p-54 */ -const C1: Float64 = 0.041_666_623_323_739_06; /* 0x155553e1053a42.0p-57 */ -const C2: Float64 = -0.001_388_676_377_460_993; /* -0x16c087e80f1e27.0p-62 */ -const C3: Float64 = 0.000_024_390_448_796_277_41; /* 0x199342e0ee5069.0p-68 */ +const C0: Float64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ +const C1: Float64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ +const C2: Float64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ +const C3: Float64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_cosf(x: Float64) -> Float32 { diff --git a/llm/math/k_sin.rs b/llm/math/k_sin.rs index aabf3c2..900b59c 100644 --- a/llm/math/k_sin.rs +++ b/llm/math/k_sin.rs @@ -11,12 +11,12 @@ use crate::Float64; -const S1: Float64 = -1.666_666_666_666_663_2e-1; /* 0xBFC55555, 0x55555549 */ -const S2: Float64 = 8.333_333_333_322_49e-3; /* 0x3F811111, 0x1110F8A6 */ -const S3: Float64 = -1.984_126_982_985_795e-4; /* 0xBF2A01A0, 0x19C161D5 */ -const S4: Float64 = 2.755_731_370_707_006_8e-6; /* 0x3EC71DE3, 0x57B1FE7D */ -const S5: Float64 = -2.505_076_025_340_686_3e-8; /* 0xBE5AE5E6, 0x8A2B9CEB */ -const S6: Float64 = 1.589_690_995_211_55e-10; /* 0x3DE5D93A, 0x5ACFD57C */ +const S1: Float64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ +const S2: Float64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ +const S3: Float64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ +const S4: Float64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ +const S5: Float64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ +const S6: Float64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ // kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 // Input x is assumed to be bounded by ~pi/4 in magnitude. diff --git a/llm/math/k_sinf.rs b/llm/math/k_sinf.rs index fad39a3..80aa6f8 100644 --- a/llm/math/k_sinf.rs +++ b/llm/math/k_sinf.rs @@ -17,10 +17,10 @@ use crate::{Float64, Float32}; /* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ -const S1: Float64 = -0.166_666_666_416_265_24; /* -0x15555554cbac77.0p-55 */ -const S2: Float64 = 0.008_333_329_385_889_463; /* 0x111110896efbb2.0p-59 */ -const S3: Float64 = -0.000_198_393_348_360_966_32; /* -0x1a00f9e2cae774.0p-65 */ -const S4: Float64 = 0.000_002_718_311_493_989_822; /* 0x16cd878c3b46a7.0p-71 */ +const S1: Float64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ +const S2: Float64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ +const S3: Float64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ +const S4: Float64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_sinf(x: Float64) -> Float32 { diff --git a/llm/math/k_tan.rs b/llm/math/k_tan.rs index 29b66ed..6c7c12b 100644 --- a/llm/math/k_tan.rs +++ b/llm/math/k_tan.rs @@ -43,22 +43,22 @@ use crate::Float64; // tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) // = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) static T: [Float64; 13] = [ - 3.333_333_333_333_341e-1, /* 3FD55555, 55555563 */ - 1.333_333_333_332_012_4e-1, /* 3FC11111, 1110FE7A */ - 5.396_825_397_622_605e-2, /* 3FABA1BA, 1BB341FE */ - 2.186_948_829_485_954_2e-2, /* 3F9664F4, 8406D637 */ - 8.863_239_823_599_3e-3, /* 3F8226E3, E96E8493 */ - 3.592_079_107_591_312_4e-3, /* 3F6D6D22, C9560328 */ - 1.456_209_454_325_290_3e-3, /* 3F57DBC8, FEE08315 */ - 5.880_412_408_202_641e-4, /* 3F4344D8, F2F26501 */ - 2.464_631_348_184_699e-4, /* 3F3026F7, 1A8D1068 */ - 7.817_944_429_395_571e-5, /* 3F147E88, A03792A6 */ - 7.140_724_913_826_082e-5, /* 3F12B80F, 32F0A7E9 */ - -1.855_863_748_552_754_6e-5, /* BEF375CB, DB605373 */ - 2.590_730_518_636_337e-5, /* 3EFB2A70, 74BF7AD4 */ + 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ + 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ + 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ + 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ + 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ + 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ + 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ + 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ + 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ + 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ + 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ + -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ + 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ ]; -const PIO4: Float64 = 7.853_981_633_974_483e-1; /* 3FE921FB, 54442D18 */ -const PIO4_LO: Float64 = 3.061_616_997_868_383e-17; /* 3C81A626, 33145C07 */ +const PIO4: Float64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ +const PIO4_LO: Float64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_tan(mut x: Float64, mut y: Float64, odd: i32) -> Float64 { diff --git a/llm/math/k_tanf.rs b/llm/math/k_tanf.rs index 3f05159..cba17d7 100644 --- a/llm/math/k_tanf.rs +++ b/llm/math/k_tanf.rs @@ -13,12 +13,12 @@ use crate::{Float64, Float32}; /* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ const T: [Float64; 6] = [ - 0.333_331_395_030_791_4, /* 0x15554d3418c99f.0p-54 */ - 0.133_392_002_712_976_74, /* 0x1112fd38999f72.0p-55 */ - 0.053_381_237_844_567_04, /* 0x1b54c91d865afe.0p-57 */ - 0.024_528_318_116_654_728, /* 0x191df3908c33ce.0p-58 */ - 0.002_974_357_433_599_673, /* 0x185dadfcecf44e.0p-61 */ - 0.009_465_647_849_436_732, /* 0x1362b9bf971bcd.0p-59 */ + 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ + 0.133392002712976742718, /* 0x1112fd38999f72.0p-55 */ + 0.0533812378445670393523, /* 0x1b54c91d865afe.0p-57 */ + 0.0245283181166547278873, /* 0x191df3908c33ce.0p-58 */ + 0.00297435743359967304927, /* 0x185dadfcecf44e.0p-61 */ + 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ ]; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/llm/math/lgamma_r.rs b/llm/math/lgamma_r.rs index 90ce778..ca48670 100644 --- a/llm/math/lgamma_r.rs +++ b/llm/math/lgamma_r.rs @@ -83,69 +83,69 @@ use crate::Float64; use super::{floor, k_cos, k_sin, log}; -const PI: Float64 = 3.141_592_653_589_793; /* 0x400921FB, 0x54442D18 */ -const A0: Float64 = 7.721_566_490_153_287e-2; /* 0x3FB3C467, 0xE37DB0C8 */ -const A1: Float64 = 3.224_670_334_241_136e-1; /* 0x3FD4A34C, 0xC4A60FAD */ -const A2: Float64 = 6.735_230_105_312_927e-2; /* 0x3FB13E00, 0x1A5562A7 */ -const A3: Float64 = 2.058_080_843_251_673_3e-2; /* 0x3F951322, 0xAC92547B */ -const A4: Float64 = 7.385_550_860_814_029e-3; /* 0x3F7E404F, 0xB68FEFE8 */ -const A5: Float64 = 2.890_513_836_734_156_3e-3; /* 0x3F67ADD8, 0xCCB7926B */ -const A6: Float64 = 1.192_707_631_833_620_7e-3; /* 0x3F538A94, 0x116F3F5D */ -const A7: Float64 = 5.100_697_921_535_113e-4; /* 0x3F40B6C6, 0x89B99C00 */ -const A8: Float64 = 2.208_627_907_139_083_9e-4; /* 0x3F2CF2EC, 0xED10E54D */ -const A9: Float64 = 1.080_115_672_475_839_4e-4; /* 0x3F1C5088, 0x987DFB07 */ -const A10: Float64 = 2.521_445_654_512_573_3e-5; /* 0x3EFA7074, 0x428CFA52 */ -const A11: Float64 = 4.486_409_496_189_151_6e-5; /* 0x3F07858E, 0x90A45837 */ -const TC: Float64 = 1.461_632_144_968_362_2; /* 0x3FF762D8, 0x6356BE3F */ -const TF: Float64 = -1.214_862_905_358_496_1e-1; /* 0xBFBF19B9, 0xBCC38A42 */ +const PI: Float64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ +const A0: Float64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ +const A1: Float64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ +const A2: Float64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ +const A3: Float64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ +const A4: Float64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ +const A5: Float64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ +const A6: Float64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ +const A7: Float64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ +const A8: Float64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ +const A9: Float64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ +const A10: Float64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ +const A11: Float64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ +const TC: Float64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ +const TF: Float64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ /* tt = -(tail of TF) */ -const TT: Float64 = -3.638_676_997_039_505e-18; /* 0xBC50C7CA, 0xA48A971F */ -const T0: Float64 = 4.838_361_227_238_100_5e-1; /* 0x3FDEF72B, 0xC8EE38A2 */ -const T1: Float64 = -1.475_877_229_945_939e-1; /* 0xBFC2E427, 0x8DC6C509 */ -const T2: Float64 = 6.462_494_023_913_339e-2; /* 0x3FB08B42, 0x94D5419B */ -const T3: Float64 = -3.278_854_107_598_596_5e-2; /* 0xBFA0C9A8, 0xDF35B713 */ -const T4: Float64 = 1.797_067_508_118_204e-2; /* 0x3F9266E7, 0x970AF9EC */ -const T5: Float64 = -1.031_422_412_983_414_4e-2; /* 0xBF851F9F, 0xBA91EC6A */ -const T6: Float64 = 6.100_538_702_462_913e-3; /* 0x3F78FCE0, 0xE370E344 */ -const T7: Float64 = -3.684_520_167_811_382_6e-3; /* 0xBF6E2EFF, 0xB3E914D7 */ -const T8: Float64 = 2.259_647_809_006_124_7e-3; /* 0x3F6282D3, 0x2E15C915 */ -const T9: Float64 = -1.403_464_699_892_328_4e-3; /* 0xBF56FE8E, 0xBF2D1AF1 */ -const T10: Float64 = 8.810_818_824_376_54e-4; /* 0x3F4CDF0C, 0xEF61A8E9 */ -const T11: Float64 = -5.385_953_053_567_405e-4; /* 0xBF41A610, 0x9C73E0EC */ -const T12: Float64 = 3.156_320_709_036_259_5e-4; /* 0x3F34AF6D, 0x6C0EBBF7 */ -const T13: Float64 = -3.127_541_683_751_208_6e-4; /* 0xBF347F24, 0xECC38C38 */ -const T14: Float64 = 3.355_291_926_355_191e-4; /* 0x3F35FD3E, 0xE8C2D3F4 */ -const U0: Float64 = -7.721_566_490_153_287e-2; /* 0xBFB3C467, 0xE37DB0C8 */ -const U1: Float64 = 6.328_270_640_250_934e-1; /* 0x3FE4401E, 0x8B005DFF */ -const U2: Float64 = 1.454_922_501_372_347_7; /* 0x3FF7475C, 0xD119BD6F */ -const U3: Float64 = 9.777_175_279_633_727e-1; /* 0x3FEF4976, 0x44EA8450 */ -const U4: Float64 = 2.289_637_280_646_924_5e-1; /* 0x3FCD4EAE, 0xF6010924 */ -const U5: Float64 = 1.338_109_185_367_876_6e-2; /* 0x3F8B678B, 0xBF2BAB09 */ -const V1: Float64 = 2.455_977_937_130_411_3; /* 0x4003A5D7, 0xC2BD619C */ -const V2: Float64 = 2.128_489_763_798_934; /* 0x40010725, 0xA42B18F5 */ -const V3: Float64 = 7.692_851_504_566_728e-1; /* 0x3FE89DFB, 0xE45050AF */ -const V4: Float64 = 1.042_226_455_933_691_3e-1; /* 0x3FBAAE55, 0xD6537C88 */ -const V5: Float64 = 3.217_092_422_824_239e-3; /* 0x3F6A5ABB, 0x57D0CF61 */ -const S0: Float64 = -7.721_566_490_153_287e-2; /* 0xBFB3C467, 0xE37DB0C8 */ -const S1: Float64 = 2.149_824_159_606_088_5e-1; /* 0x3FCB848B, 0x36E20878 */ -const S2: Float64 = 3.257_787_964_089_31e-1; /* 0x3FD4D98F, 0x4F139F59 */ -const S3: Float64 = 1.463_504_726_524_644_5e-1; /* 0x3FC2BB9C, 0xBEE5F2F7 */ -const S4: Float64 = 2.664_227_030_336_386e-2; /* 0x3F9B481C, 0x7E939961 */ -const S5: Float64 = 1.840_284_514_073_377_2e-3; /* 0x3F5E26B6, 0x7368F239 */ -const S6: Float64 = 3.194_753_265_841_009e-5; /* 0x3F00BFEC, 0xDD17E945 */ -const R1: Float64 = 1.392_005_334_676_210_5; /* 0x3FF645A7, 0x62C4AB74 */ -const R2: Float64 = 7.219_355_475_671_381e-1; /* 0x3FE71A18, 0x93D3DCDC */ -const R3: Float64 = 1.719_338_656_328_030_8e-1; /* 0x3FC601ED, 0xCCFBDF27 */ -const R4: Float64 = 1.864_591_917_156_529e-2; /* 0x3F9317EA, 0x742ED475 */ -const R5: Float64 = 7.779_424_963_818_936e-4; /* 0x3F497DDA, 0xCA41A95B */ -const R6: Float64 = 7.326_684_307_446_256e-6; /* 0x3EDEBAF7, 0xA5B38140 */ -const W0: Float64 = 4.189_385_332_046_727e-1; /* 0x3FDACFE3, 0x90C97D69 */ -const W1: Float64 = 8.333_333_333_333_297e-2; /* 0x3FB55555, 0x5555553B */ -const W2: Float64 = -2.777_777_777_287_755_4e-3; /* 0xBF66C16C, 0x16B02E5C */ -const W3: Float64 = 7.936_505_586_430_196e-4; /* 0x3F4A019F, 0x98CF38B6 */ -const W4: Float64 = -5.951_875_574_503_4e-4; /* 0xBF4380CB, 0x8C0FE741 */ -const W5: Float64 = 8.363_399_189_962_821e-4; /* 0x3F4B67BA, 0x4CDAD5D1 */ -const W6: Float64 = -1.630_929_340_965_752_7e-3; /* 0xBF5AB89D, 0x0B9E43E4 */ +const TT: Float64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ +const T0: Float64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ +const T1: Float64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ +const T2: Float64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ +const T3: Float64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ +const T4: Float64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ +const T5: Float64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ +const T6: Float64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ +const T7: Float64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ +const T8: Float64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ +const T9: Float64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ +const T10: Float64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ +const T11: Float64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ +const T12: Float64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ +const T13: Float64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ +const T14: Float64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ +const U0: Float64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const U1: Float64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ +const U2: Float64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ +const U3: Float64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ +const U4: Float64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ +const U5: Float64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ +const V1: Float64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ +const V2: Float64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ +const V3: Float64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ +const V4: Float64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ +const V5: Float64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ +const S0: Float64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const S1: Float64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ +const S2: Float64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ +const S3: Float64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ +const S4: Float64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ +const S5: Float64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ +const S6: Float64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ +const R1: Float64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ +const R2: Float64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ +const R3: Float64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ +const R4: Float64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ +const R5: Float64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ +const R6: Float64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ +const W0: Float64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ +const W1: Float64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ +const W2: Float64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ +const W3: Float64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ +const W4: Float64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ +const W5: Float64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ +const W6: Float64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ /* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ fn sin_pi(mut x: Float64) -> Float64 { @@ -185,15 +185,15 @@ pub fn lgamma_r(mut x: Float64) -> (Float64, i32) { let q: Float64; let mut r: Float64; let w: Float64; - - + let ix: u32; + let sign: bool; let i: i32; let mut signgam: i32; /* purge off +-inf, NaN, +-0, tiny and negative arguments */ signgam = 1; - let sign: bool = (u >> 63) != 0; - let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; + sign = (u >> 63) != 0; + ix = ((u >> 32) as u32) & 0x7fffffff; if ix >= 0x7ff00000 { return (x * x, signgam); } diff --git a/llm/math/lgammaf_r.rs b/llm/math/lgammaf_r.rs index d0cc8a2..1b8f994 100644 --- a/llm/math/lgammaf_r.rs +++ b/llm/math/lgammaf_r.rs @@ -17,69 +17,69 @@ use crate::{Float64, Float32}; use super::{floorf, k_cosf, k_sinf, logf}; -const PI: Float32 = 3.141_592_7; /* 0x40490fdb */ -const A0: Float32 = 7.721_566_4e-2; /* 0x3d9e233f */ -const A1: Float32 = 3.224_670_3e-1; /* 0x3ea51a66 */ -const A2: Float32 = 6.735_23e-2; /* 0x3d89f001 */ -const A3: Float32 = 2.058_080_8e-2; /* 0x3ca89915 */ -const A4: Float32 = 7.385_551e-3; /* 0x3bf2027e */ -const A5: Float32 = 2.890_513_7e-3; /* 0x3b3d6ec6 */ -const A6: Float32 = 1.192_707_7e-3; /* 0x3a9c54a1 */ -const A7: Float32 = 5.100_698e-4; /* 0x3a05b634 */ -const A8: Float32 = 2.208_627_8e-4; /* 0x39679767 */ -const A9: Float32 = 1.080_115_7e-4; /* 0x38e28445 */ -const A10: Float32 = 2.521_445_6e-5; /* 0x37d383a2 */ -const A11: Float32 = 4.486_409_7e-5; /* 0x383c2c75 */ -const TC: Float32 = 1.461_632_1; /* 0x3fbb16c3 */ -const TF: Float32 = -1.214_862_84e-1; /* 0xbdf8cdcd */ +const PI: Float32 = 3.1415927410e+00; /* 0x40490fdb */ +const A0: Float32 = 7.7215664089e-02; /* 0x3d9e233f */ +const A1: Float32 = 3.2246702909e-01; /* 0x3ea51a66 */ +const A2: Float32 = 6.7352302372e-02; /* 0x3d89f001 */ +const A3: Float32 = 2.0580807701e-02; /* 0x3ca89915 */ +const A4: Float32 = 7.3855509982e-03; /* 0x3bf2027e */ +const A5: Float32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ +const A6: Float32 = 1.1927076848e-03; /* 0x3a9c54a1 */ +const A7: Float32 = 5.1006977446e-04; /* 0x3a05b634 */ +const A8: Float32 = 2.2086278477e-04; /* 0x39679767 */ +const A9: Float32 = 1.0801156895e-04; /* 0x38e28445 */ +const A10: Float32 = 2.5214456400e-05; /* 0x37d383a2 */ +const A11: Float32 = 4.4864096708e-05; /* 0x383c2c75 */ +const TC: Float32 = 1.4616321325e+00; /* 0x3fbb16c3 */ +const TF: Float32 = -1.2148628384e-01; /* 0xbdf8cdcd */ /* TT = -(tail of TF) */ -const TT: Float32 = 6.697_100_7e-9; /* 0x31e61c52 */ -const T0: Float32 = 4.838_361e-1; /* 0x3ef7b95e */ -const T1: Float32 = -1.475_877_2e-1; /* 0xbe17213c */ -const T2: Float32 = 6.462_494e-2; /* 0x3d845a15 */ -const T3: Float32 = -3.278_854e-2; /* 0xbd064d47 */ -const T4: Float32 = 1.797_067_6e-2; /* 0x3c93373d */ -const T5: Float32 = -1.031_422_4e-2; /* 0xbc28fcfe */ -const T6: Float32 = 6.100_538_7e-3; /* 0x3bc7e707 */ -const T7: Float32 = -3.684_520_3e-3; /* 0xbb7177fe */ -const T8: Float32 = 2.259_647_7e-3; /* 0x3b141699 */ -const T9: Float32 = -1.403_464_7e-3; /* 0xbab7f476 */ -const T10: Float32 = 8.810_818_5e-4; /* 0x3a66f867 */ -const T11: Float32 = -5.385_953e-4; /* 0xba0d3085 */ -const T12: Float32 = 3.156_320_6e-4; /* 0x39a57b6b */ -const T13: Float32 = -3.127_541_6e-4; /* 0xb9a3f927 */ -const T14: Float32 = 3.355_291_8e-4; /* 0x39afe9f7 */ -const U0: Float32 = -7.721_566_4e-2; /* 0xbd9e233f */ -const U1: Float32 = 6.328_270_4e-1; /* 0x3f2200f4 */ -const U2: Float32 = 1.454_922_6; /* 0x3fba3ae7 */ -const U3: Float32 = 9.777_175e-1; /* 0x3f7a4bb2 */ -const U4: Float32 = 2.289_637_3e-1; /* 0x3e6a7578 */ -const U5: Float32 = 1.338_109_2e-2; /* 0x3c5b3c5e */ -const V1: Float32 = 2.455_978; /* 0x401d2ebe */ -const V2: Float32 = 2.128_489_7; /* 0x4008392d */ -const V3: Float32 = 7.692_851_4e-1; /* 0x3f44efdf */ -const V4: Float32 = 1.042_226_5e-1; /* 0x3dd572af */ -const V5: Float32 = 3.217_092_5e-3; /* 0x3b52d5db */ -const S0: Float32 = -7.721_566_4e-2; /* 0xbd9e233f */ -const S1: Float32 = 2.149_824_2e-1; /* 0x3e5c245a */ -const S2: Float32 = 3.257_787_8e-1; /* 0x3ea6cc7a */ -const S3: Float32 = 1.463_504_7e-1; /* 0x3e15dce6 */ -const S4: Float32 = 2.664_227e-2; /* 0x3cda40e4 */ -const S5: Float32 = 1.840_284_6e-3; /* 0x3af135b4 */ -const S6: Float32 = 3.194_753_3e-5; /* 0x3805ff67 */ -const R1: Float32 = 1.392_005_3; /* 0x3fb22d3b */ -const R2: Float32 = 7.219_356e-1; /* 0x3f38d0c5 */ -const R3: Float32 = 1.719_338_6e-1; /* 0x3e300f6e */ -const R4: Float32 = 1.864_592e-2; /* 0x3c98bf54 */ -const R5: Float32 = 7.779_425e-4; /* 0x3a4beed6 */ -const R6: Float32 = 7.326_684e-6; /* 0x36f5d7bd */ -const W0: Float32 = 4.189_385_5e-1; /* 0x3ed67f1d */ -const W1: Float32 = 8.333_333_6e-2; /* 0x3daaaaab */ -const W2: Float32 = -2.777_777_8e-3; /* 0xbb360b61 */ -const W3: Float32 = 7.936_506e-4; /* 0x3a500cfd */ -const W4: Float32 = -5.951_875_4e-4; /* 0xba1c065c */ -const W5: Float32 = 8.363_399e-4; /* 0x3a5b3dd2 */ -const W6: Float32 = -1.630_929_3e-3; /* 0xbad5c4e8 */ +const TT: Float32 = 6.6971006518e-09; /* 0x31e61c52 */ +const T0: Float32 = 4.8383611441e-01; /* 0x3ef7b95e */ +const T1: Float32 = -1.4758771658e-01; /* 0xbe17213c */ +const T2: Float32 = 6.4624942839e-02; /* 0x3d845a15 */ +const T3: Float32 = -3.2788541168e-02; /* 0xbd064d47 */ +const T4: Float32 = 1.7970675603e-02; /* 0x3c93373d */ +const T5: Float32 = -1.0314224288e-02; /* 0xbc28fcfe */ +const T6: Float32 = 6.1005386524e-03; /* 0x3bc7e707 */ +const T7: Float32 = -3.6845202558e-03; /* 0xbb7177fe */ +const T8: Float32 = 2.2596477065e-03; /* 0x3b141699 */ +const T9: Float32 = -1.4034647029e-03; /* 0xbab7f476 */ +const T10: Float32 = 8.8108185446e-04; /* 0x3a66f867 */ +const T11: Float32 = -5.3859531181e-04; /* 0xba0d3085 */ +const T12: Float32 = 3.1563205994e-04; /* 0x39a57b6b */ +const T13: Float32 = -3.1275415677e-04; /* 0xb9a3f927 */ +const T14: Float32 = 3.3552918467e-04; /* 0x39afe9f7 */ +const U0: Float32 = -7.7215664089e-02; /* 0xbd9e233f */ +const U1: Float32 = 6.3282704353e-01; /* 0x3f2200f4 */ +const U2: Float32 = 1.4549225569e+00; /* 0x3fba3ae7 */ +const U3: Float32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ +const U4: Float32 = 2.2896373272e-01; /* 0x3e6a7578 */ +const U5: Float32 = 1.3381091878e-02; /* 0x3c5b3c5e */ +const V1: Float32 = 2.4559779167e+00; /* 0x401d2ebe */ +const V2: Float32 = 2.1284897327e+00; /* 0x4008392d */ +const V3: Float32 = 7.6928514242e-01; /* 0x3f44efdf */ +const V4: Float32 = 1.0422264785e-01; /* 0x3dd572af */ +const V5: Float32 = 3.2170924824e-03; /* 0x3b52d5db */ +const S0: Float32 = -7.7215664089e-02; /* 0xbd9e233f */ +const S1: Float32 = 2.1498242021e-01; /* 0x3e5c245a */ +const S2: Float32 = 3.2577878237e-01; /* 0x3ea6cc7a */ +const S3: Float32 = 1.4635047317e-01; /* 0x3e15dce6 */ +const S4: Float32 = 2.6642270386e-02; /* 0x3cda40e4 */ +const S5: Float32 = 1.8402845599e-03; /* 0x3af135b4 */ +const S6: Float32 = 3.1947532989e-05; /* 0x3805ff67 */ +const R1: Float32 = 1.3920053244e+00; /* 0x3fb22d3b */ +const R2: Float32 = 7.2193557024e-01; /* 0x3f38d0c5 */ +const R3: Float32 = 1.7193385959e-01; /* 0x3e300f6e */ +const R4: Float32 = 1.8645919859e-02; /* 0x3c98bf54 */ +const R5: Float32 = 7.7794247773e-04; /* 0x3a4beed6 */ +const R6: Float32 = 7.3266842264e-06; /* 0x36f5d7bd */ +const W0: Float32 = 4.1893854737e-01; /* 0x3ed67f1d */ +const W1: Float32 = 8.3333335817e-02; /* 0x3daaaaab */ +const W2: Float32 = -2.7777778450e-03; /* 0xbb360b61 */ +const W3: Float32 = 7.9365057172e-04; /* 0x3a500cfd */ +const W4: Float32 = -5.9518753551e-04; /* 0xba1c065c */ +const W5: Float32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ +const W6: Float32 = -1.6309292987e-03; /* 0xbad5c4e8 */ /* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ fn sin_pi(mut x: Float32) -> Float32 { @@ -92,7 +92,7 @@ fn sin_pi(mut x: Float32) -> Float32 { n = (x * 4.0) as isize; n = div!(n + 1, 2); y = (x as Float64) - (n as Float64) * 0.5; - y *= 3.141_592_653_589_793; + y *= 3.14159265358979323846; match n { 1 => k_cosf(y), 2 => k_sinf(-y), @@ -119,15 +119,15 @@ pub fn lgammaf_r(mut x: Float32) -> (Float32, i32) { let q: Float32; let mut r: Float32; let w: Float32; - + let ix: u32; let i: i32; - + let sign: bool; let mut signgam: i32; /* purge off +-inf, NaN, +-0, tiny and negative arguments */ signgam = 1; - let sign: bool = (u >> 31) != 0; - let ix: u32 = u & 0x7fffffff; + sign = (u >> 31) != 0; + ix = u & 0x7fffffff; if ix >= 0x7f800000 { return (x * x, signgam); } diff --git a/llm/math/log.rs b/llm/math/log.rs index eb63029..6ff860c 100644 --- a/llm/math/log.rs +++ b/llm/math/log.rs @@ -63,15 +63,15 @@ use crate::Float64; -const LN2_HI: Float64 = 6.931_471_803_691_238e-1; /* 3fe62e42 fee00000 */ -const LN2_LO: Float64 = 1.908_214_929_270_587_7e-10; /* 3dea39ef 35793c76 */ -const LG1: Float64 = 6.666_666_666_666_735e-1; /* 3FE55555 55555593 */ -const LG2: Float64 = 3.999_999_999_940_942e-1; /* 3FD99999 9997FA04 */ -const LG3: Float64 = 2.857_142_874_366_239e-1; /* 3FD24924 94229359 */ -const LG4: Float64 = 2.222_219_843_214_978_4e-1; /* 3FCC71C5 1D8E78AF */ -const LG5: Float64 = 1.818_357_216_161_805e-1; /* 3FC74664 96CB03DE */ -const LG6: Float64 = 1.531_383_769_920_937_3e-1; /* 3FC39A09 D078C69F */ -const LG7: Float64 = 1.479_819_860_511_658_6e-1; /* 3FC2F112 DF3E5244 */ +const LN2_HI: Float64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ +const LN2_LO: Float64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ +const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ /// Returns the logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/llm/math/log10.rs b/llm/math/log10.rs index 4b71306..c128eab 100644 --- a/llm/math/log10.rs +++ b/llm/math/log10.rs @@ -19,17 +19,17 @@ use crate::Float64; -const IVLN10HI: Float64 = 4.342_944_818_781_689e-1; /* 0x3fdbcb7b, 0x15200000 */ -const IVLN10LO: Float64 = 2.508_294_671_164_527_5e-11; /* 0x3dbb9438, 0xca9aadd5 */ -const LOG10_2HI: Float64 = 3.010_299_956_636_117_7e-1; /* 0x3FD34413, 0x509F6000 */ -const LOG10_2LO: Float64 = 3.694_239_077_158_931e-13; /* 0x3D59FEF3, 0x11F12B36 */ -const LG1: Float64 = 6.666_666_666_666_735e-1; /* 3FE55555 55555593 */ -const LG2: Float64 = 3.999_999_999_940_942e-1; /* 3FD99999 9997FA04 */ -const LG3: Float64 = 2.857_142_874_366_239e-1; /* 3FD24924 94229359 */ -const LG4: Float64 = 2.222_219_843_214_978_4e-1; /* 3FCC71C5 1D8E78AF */ -const LG5: Float64 = 1.818_357_216_161_805e-1; /* 3FC74664 96CB03DE */ -const LG6: Float64 = 1.531_383_769_920_937_3e-1; /* 3FC39A09 D078C69F */ -const LG7: Float64 = 1.479_819_860_511_658_6e-1; /* 3FC2F112 DF3E5244 */ +const IVLN10HI: Float64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ +const IVLN10LO: Float64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ +const LOG10_2HI: Float64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ +const LOG10_2LO: Float64 = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ +const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ /// Returns the base 10 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -37,18 +37,18 @@ pub fn log10(mut x: Float64) -> Float64 { let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 let mut ui: u64 = x.to_bits(); - - - - - + let hfsq: Float64; + let f: Float64; + let s: Float64; + let z: Float64; + let r: Float64; let mut w: Float64; - - - - + let t1: Float64; + let t2: Float64; + let dk: Float64; + let y: Float64; let mut hi: Float64; - + let lo: Float64; let mut val_hi: Float64; let mut val_lo: Float64; let mut hx: u32; @@ -81,14 +81,14 @@ pub fn log10(mut x: Float64) -> Float64 { ui = (hx as u64) << 32 | (ui & 0xffffffff); x = Float64::from_bits(ui); - let f: Float64 = x - 1.0; - let hfsq: Float64 = 0.5 * f * f; - let s: Float64 = f / (2.0 + f); - let z: Float64 = s * s; + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; w = z * z; - let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); - let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - let r: Float64 = t2 + t1; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; /* See log2.c for details. */ /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ @@ -96,12 +96,12 @@ pub fn log10(mut x: Float64) -> Float64 { ui = hi.to_bits(); ui &= (-1i64 as u64) << 32; hi = Float64::from_bits(ui); - let lo: Float64 = f - hi - hfsq + s * (hfsq + r); + lo = f - hi - hfsq + s * (hfsq + r); /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ val_hi = hi * IVLN10HI; - let dk: Float64 = k as Float64; - let y: Float64 = dk * LOG10_2HI; + dk = k as Float64; + y = dk * LOG10_2HI; val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI; /* diff --git a/llm/math/log10f.rs b/llm/math/log10f.rs index 6759055..45d5c32 100644 --- a/llm/math/log10f.rs +++ b/llm/math/log10f.rs @@ -15,15 +15,15 @@ use crate::Float32; -const IVLN10HI: Float32 = 4.343_261_7e-1; /* 0x3ede6000 */ -const IVLN10LO: Float32 = -3.168_997e-5; /* 0xb804ead9 */ -const LOG10_2HI: Float32 = 3.010_292e-1; /* 0x3e9a2080 */ -const LOG10_2LO: Float32 = 7.903_415e-7; /* 0x355427db */ +const IVLN10HI: Float32 = 4.3432617188e-01; /* 0x3ede6000 */ +const IVLN10LO: Float32 = -3.1689971365e-05; /* 0xb804ead9 */ +const LOG10_2HI: Float32 = 3.0102920532e-01; /* 0x3e9a2080 */ +const LOG10_2LO: Float32 = 7.9034151668e-07; /* 0x355427db */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: Float32 = 0.666_666_6; /* 0xaaaaaa.0p-24 */ -const LG2: Float32 = 0.400_009_72; /* 0xccce13.0p-25 */ -const LG3: Float32 = 0.284_987_87; /* 0x91e9ee.0p-25 */ -const LG4: Float32 = 0.242_790_79; /* 0xf89e26.0p-26 */ +const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ /// Returns the base 10 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -31,17 +31,17 @@ pub fn log10f(mut x: Float32) -> Float32 { let x1p25f = Float32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ui: u32 = x.to_bits(); - - - - - - - - - + let hfsq: Float32; + let f: Float32; + let s: Float32; + let z: Float32; + let r: Float32; + let w: Float32; + let t1: Float32; + let t2: Float32; + let dk: Float32; let mut hi: Float32; - + let lo: Float32; let mut ix: u32; let mut k: i32; @@ -73,20 +73,20 @@ pub fn log10f(mut x: Float32) -> Float32 { ui = ix; x = Float32::from_bits(ui); - let f: Float32 = x - 1.0; - let s: Float32 = f / (2.0 + f); - let z: Float32 = s * s; - let w: Float32 = z * z; - let t1: Float32 = w * (LG2 + w * LG4); - let t2: Float32 = z * (LG1 + w * LG3); - let r: Float32 = t2 + t1; - let hfsq: Float32 = 0.5 * f * f; + f = x - 1.0; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; hi = f - hfsq; ui = hi.to_bits(); ui &= 0xfffff000; hi = Float32::from_bits(ui); - let lo: Float32 = f - hi - hfsq + s * (hfsq + r); - let dk: Float32 = k as Float32; + lo = f - hi - hfsq + s * (hfsq + r); + dk = k as Float32; dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI } diff --git a/llm/math/log1p.rs b/llm/math/log1p.rs index 1d618b7..dab5e19 100644 --- a/llm/math/log1p.rs +++ b/llm/math/log1p.rs @@ -9,7 +9,7 @@ * is preserved. * ==================================================== */ -/* +/** * double log1p(double x) * Return the natural logarithm of 1+x. * @@ -56,7 +56,6 @@ use crate::{Float64, Float32}; -consts!{ const LN2_HI: Float64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ const LN2_LO: Float64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ @@ -66,18 +65,26 @@ const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ -} /// Return the natural logarithm of `1+x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1p(x: Float64) -> Float64 { let mut ui: u64 = x.to_bits(); + let hfsq: Float64; let mut f: Float64 = 0.; let mut c: Float64 = 0.; + let s: Float64; + let z: Float64; + let r: Float64; + let w: Float64; + let t1: Float64; + let t2: Float64; + let dk: Float64; + let hx: u32; let mut hu: u32; let mut k: i32; - let hx: u32 = (ui >> 32) as u32; + hx = (ui >> 32) as u32; k = 1; if hx < 0x3fda827a || (hx >> 31) > 0 { /* 1+x < sqrt(2)+ */ @@ -126,13 +133,13 @@ pub fn log1p(x: Float64) -> Float64 { ui = (hu as u64) << 32 | (ui & 0xffffffff); f = Float64::from_bits(ui) - 1.; } - let hfsq: Float64 = 0.5 * f * f; - let s: Float64 = f / (2.0 + f); - let z: Float64 = s * s; - let w: Float64 = z * z; - let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); - let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - let r: Float64 = t2 + t1; - let dk: Float64 = k as Float64; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + dk = k as Float64; s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } diff --git a/llm/math/log1pf.rs b/llm/math/log1pf.rs index acc1f26..0b8cffa 100644 --- a/llm/math/log1pf.rs +++ b/llm/math/log1pf.rs @@ -12,33 +12,33 @@ use crate::Float32; -const LN2_HI: Float32 = 6.931_381e-1; /* 0x3f317180 */ -const LN2_LO: Float32 = 9.058_001e-6; /* 0x3717f7d1 */ +const LN2_HI: Float32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: Float32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: Float32 = 0.666_666_6; /* 0xaaaaaa.0p-24 */ -const LG2: Float32 = 0.400_009_72; /* 0xccce13.0p-25 */ -const LG3: Float32 = 0.284_987_87; /* 0x91e9ee.0p-25 */ -const LG4: Float32 = 0.242_790_79; /* 0xf89e26.0p-26 */ +const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ /// Return the natural logarithm of `1+x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1pf(x: Float32) -> Float32 { let mut ui: u32 = x.to_bits(); - + let hfsq: Float32; let mut f: Float32 = 0.; let mut c: Float32 = 0.; - - - - - - - - + let s: Float32; + let z: Float32; + let r: Float32; + let w: Float32; + let t1: Float32; + let t2: Float32; + let dk: Float32; + let ix: u32; let mut iu: u32; let mut k: i32; - let ix: u32 = ui; + ix = ui; k = 1; if ix < 0x3ed413d0 || (ix >> 31) > 0 { /* 1+x < sqrt(2)+ */ @@ -87,13 +87,13 @@ pub fn log1pf(x: Float32) -> Float32 { ui = iu; f = Float32::from_bits(ui) - 1.; } - let s: Float32 = f / (2.0 + f); - let z: Float32 = s * s; - let w: Float32 = z * z; - let t1: Float32 = w * (LG2 + w * LG4); - let t2: Float32 = z * (LG1 + w * LG3); - let r: Float32 = t2 + t1; - let hfsq: Float32 = 0.5 * f * f; - let dk: Float32 = k as Float32; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + dk = k as Float32; s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } diff --git a/llm/math/log2.rs b/llm/math/log2.rs index 1d1173d..02f6957 100644 --- a/llm/math/log2.rs +++ b/llm/math/log2.rs @@ -19,15 +19,15 @@ use crate::Float64; -const IVLN2HI: Float64 = 1.442_695_040_721_446_3; /* 0x3ff71547, 0x65200000 */ -const IVLN2LO: Float64 = 1.675_171_316_488_651_2e-10; /* 0x3de705fc, 0x2eefa200 */ -const LG1: Float64 = 6.666_666_666_666_735e-1; /* 3FE55555 55555593 */ -const LG2: Float64 = 3.999_999_999_940_942e-1; /* 3FD99999 9997FA04 */ -const LG3: Float64 = 2.857_142_874_366_239e-1; /* 3FD24924 94229359 */ -const LG4: Float64 = 2.222_219_843_214_978_4e-1; /* 3FCC71C5 1D8E78AF */ -const LG5: Float64 = 1.818_357_216_161_805e-1; /* 3FC74664 96CB03DE */ -const LG6: Float64 = 1.531_383_769_920_937_3e-1; /* 3FC39A09 D078C69F */ -const LG7: Float64 = 1.479_819_860_511_658_6e-1; /* 3FC2F112 DF3E5244 */ +const IVLN2HI: Float64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ +const IVLN2LO: Float64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ +const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ /// Returns the base 2 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -35,17 +35,17 @@ pub fn log2(mut x: Float64) -> Float64 { let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 let mut ui: u64 = x.to_bits(); - - - - - + let hfsq: Float64; + let f: Float64; + let s: Float64; + let z: Float64; + let r: Float64; let mut w: Float64; - - - + let t1: Float64; + let t2: Float64; + let y: Float64; let mut hi: Float64; - + let lo: Float64; let mut val_hi: Float64; let mut val_lo: Float64; let mut hx: u32; @@ -78,27 +78,27 @@ pub fn log2(mut x: Float64) -> Float64 { ui = (hx as u64) << 32 | (ui & 0xffffffff); x = Float64::from_bits(ui); - let f: Float64 = x - 1.0; - let hfsq: Float64 = 0.5 * f * f; - let s: Float64 = f / (2.0 + f); - let z: Float64 = s * s; + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; w = z * z; - let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); - let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - let r: Float64 = t2 + t1; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ hi = f - hfsq; ui = hi.to_bits(); ui &= (-1i64 as u64) << 32; hi = Float64::from_bits(ui); - let lo: Float64 = f - hi - hfsq + s * (hfsq + r); + lo = f - hi - hfsq + s * (hfsq + r); val_hi = hi * IVLN2HI; val_lo = (lo + hi) * IVLN2LO + lo * IVLN2HI; /* spadd(val_hi, val_lo, y), except for not using double_t: */ - let y: Float64 = k.into(); + y = k.into(); w = y + val_hi; val_lo += (y - w) + val_hi; val_hi = w; diff --git a/llm/math/log2f.rs b/llm/math/log2f.rs index 66ce47f..afa3c17 100644 --- a/llm/math/log2f.rs +++ b/llm/math/log2f.rs @@ -15,13 +15,13 @@ use crate::Float32; -const IVLN2HI: Float32 = 1.442_871_1; /* 0x3fb8b000 */ -const IVLN2LO: Float32 = -1.760_528_5e-4; /* 0xb9389ad4 */ +const IVLN2HI: Float32 = 1.4428710938e+00; /* 0x3fb8b000 */ +const IVLN2LO: Float32 = -1.7605285393e-04; /* 0xb9389ad4 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: Float32 = 0.666_666_6; /* 0xaaaaaa.0p-24 */ -const LG2: Float32 = 0.400_009_72; /* 0xccce13.0p-25 */ -const LG3: Float32 = 0.284_987_87; /* 0x91e9ee.0p-25 */ -const LG4: Float32 = 0.242_790_79; /* 0xf89e26.0p-26 */ +const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ /// Returns the base 2 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -29,16 +29,16 @@ pub fn log2f(mut x: Float32) -> Float32 { let x1p25f = Float32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ui: u32 = x.to_bits(); - - - - - - - - + let hfsq: Float32; + let f: Float32; + let s: Float32; + let z: Float32; + let r: Float32; + let w: Float32; + let t1: Float32; + let t2: Float32; let mut hi: Float32; - + let lo: Float32; let mut ix: u32; let mut k: i32; @@ -70,19 +70,19 @@ pub fn log2f(mut x: Float32) -> Float32 { ui = ix; x = Float32::from_bits(ui); - let f: Float32 = x - 1.0; - let s: Float32 = f / (2.0 + f); - let z: Float32 = s * s; - let w: Float32 = z * z; - let t1: Float32 = w * (LG2 + w * LG4); - let t2: Float32 = z * (LG1 + w * LG3); - let r: Float32 = t2 + t1; - let hfsq: Float32 = 0.5 * f * f; + f = x - 1.0; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; hi = f - hfsq; ui = hi.to_bits(); ui &= 0xfffff000; hi = Float32::from_bits(ui); - let lo: Float32 = f - hi - hfsq + s * (hfsq + r); + lo = f - hi - hfsq + s * (hfsq + r); (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as Float32 } diff --git a/llm/math/logf.rs b/llm/math/logf.rs index 56e5436..57cfdab 100644 --- a/llm/math/logf.rs +++ b/llm/math/logf.rs @@ -15,13 +15,13 @@ use crate::Float32; -const LN2_HI: Float32 = 6.931_381e-1; /* 0x3f317180 */ -const LN2_LO: Float32 = 9.058_001e-6; /* 0x3717f7d1 */ +const LN2_HI: Float32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: Float32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: Float32 = 0.666_666_6; /* 0xaaaaaa.0p-24*/ -const LG2: Float32 = 0.400_009_72; /* 0xccce13.0p-25 */ -const LG3: Float32 = 0.284_987_87; /* 0x91e9ee.0p-25 */ -const LG4: Float32 = 0.242_790_79; /* 0xf89e26.0p-26 */ +const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ +const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ /// Returns the logarithm of `x` #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/llm/math/modf.rs b/llm/math/modf.rs index 09b8e7f..4d64cc4 100644 --- a/llm/math/modf.rs +++ b/llm/math/modf.rs @@ -4,7 +4,7 @@ use crate::Float64; pub fn modf(x: Float64) -> (Float64, Float64) { let rv2: Float64; let mut u = x.to_bits(); - + let mask: u64; let e = ((u >> 52 & 0x7ff) as i32) - 0x3ff; /* no fractional part */ @@ -25,7 +25,7 @@ pub fn modf(x: Float64) -> (Float64, Float64) { return (x, rv2); } - let mask: u64 = ((!0) >> 12) >> e; + mask = ((!0) >> 12) >> e; if (u & mask) == 0 { rv2 = x; u &= 1 << 63; diff --git a/llm/math/modff.rs b/llm/math/modff.rs index 965161f..1bbaf1c 100644 --- a/llm/math/modff.rs +++ b/llm/math/modff.rs @@ -4,7 +4,7 @@ use crate::Float32; pub fn modff(x: Float32) -> (Float32, Float32) { let rv2: Float32; let mut u: u32 = x.to_bits(); - + let mask: u32; let e = ((u >> 23 & 0xff) as i32) - 0x7f; /* no fractional part */ @@ -24,7 +24,7 @@ pub fn modff(x: Float32) -> (Float32, Float32) { return (x, rv2); } - let mask: u32 = 0x007fffff >> e; + mask = 0x007fffff >> e; if (u & mask) == 0 { rv2 = x; u &= 0x80000000; diff --git a/llm/math/nextafter.rs b/llm/math/nextafter.rs index fef4ffc..9d30ea2 100644 --- a/llm/math/nextafter.rs +++ b/llm/math/nextafter.rs @@ -13,8 +13,8 @@ pub fn nextafter(x: Float64, y: Float64) -> Float64 { return y; } - let ax = ux_i & (!1_u64 / 2); - let ay = uy_i & (!1_u64 / 2); + let ax = ux_i & !1_u64 / 2; + let ay = uy_i & !1_u64 / 2; if ax == 0 { if ay == 0 { return y; diff --git a/llm/math/pow.rs b/llm/math/pow.rs index 8ae76ca..cfc8f39 100644 --- a/llm/math/pow.rs +++ b/llm/math/pow.rs @@ -63,34 +63,34 @@ use crate::Float64; use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; const BP: [Float64; 2] = [1.0, 1.5]; -const DP_H: [Float64; 2] = [0.0, 5.849_624_872_207_642e-1]; /* 0x3fe2b803_40000000 */ -const DP_L: [Float64; 2] = [0.0, 1.350_039_202_129_749e-8]; /* 0x3E4CFDEB, 0x43CFD006 */ +const DP_H: [Float64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ +const DP_L: [Float64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ const TWO53: Float64 = 9007199254740992.0; /* 0x43400000_00000000 */ const HUGE: Float64 = 1.0e300; const TINY: Float64 = 1.0e-300; // poly coefs for (3/2)*(log(x)-2s-2/3*s**3: -const L1: Float64 = 5.999_999_999_999_946e-1; /* 0x3fe33333_33333303 */ -const L2: Float64 = 4.285_714_285_785_502e-1; /* 0x3fdb6db6_db6fabff */ -const L3: Float64 = 3.333_333_298_183_774_3e-1; /* 0x3fd55555_518f264d */ -const L4: Float64 = 2.727_281_238_085_34e-1; /* 0x3fd17460_a91d4101 */ -const L5: Float64 = 2.306_607_457_755_617_5e-1; /* 0x3fcd864a_93c9db65 */ -const L6: Float64 = 2.069_750_178_003_384_2e-1; /* 0x3fca7e28_4a454eef */ -const P1: Float64 = 1.666_666_666_666_660_2e-1; /* 0x3fc55555_5555553e */ -const P2: Float64 = -2.777_777_777_701_559_3e-3; /* 0xbf66c16c_16bebd93 */ -const P3: Float64 = 6.613_756_321_437_934e-5; /* 0x3f11566a_af25de2c */ -const P4: Float64 = -1.653_390_220_546_525_2e-6; /* 0xbebbbd41_c5d26bf1 */ -const P5: Float64 = 4.138_136_797_057_238_5e-8; /* 0x3e663769_72bea4d0 */ -const LG2: Float64 = 6.931_471_805_599_453e-1; /* 0x3fe62e42_fefa39ef */ -const LG2_H: Float64 = 6.931_471_824_645_996e-1; /* 0x3fe62e43_00000000 */ -const LG2_L: Float64 = -1.904_654_299_957_768e-9; /* 0xbe205c61_0ca86c39 */ -const OVT: Float64 = 8.008_566_259_537_294e-17; /* -(1024-log2(ovfl+.5ulp)) */ -const CP: Float64 = 9.617_966_939_259_756e-1; /* 0x3feec709_dc3a03fd =2/(3ln2) */ -const CP_H: Float64 = 9.617_967_009_544_373e-1; /* 0x3feec709_e0000000 =(float)cp */ -const CP_L: Float64 = -7.028_461_650_952_758e-9; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ -const IVLN2: Float64 = 1.442_695_040_888_963_4; /* 0x3ff71547_652b82fe =1/ln2 */ -const IVLN2_H: Float64 = 1.442_695_021_629_333_5; /* 0x3ff71547_60000000 =24b 1/ln2*/ -const IVLN2_L: Float64 = 1.925_962_991_126_617_5e-8; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ +const L1: Float64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ +const L2: Float64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ +const L3: Float64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ +const L4: Float64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ +const L5: Float64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ +const L6: Float64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ +const P1: Float64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ +const P2: Float64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ +const P3: Float64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ +const P4: Float64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ +const P5: Float64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ +const LG2: Float64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ +const LG2_H: Float64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ +const LG2_L: Float64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ +const OVT: Float64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ +const CP: Float64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ +const CP_H: Float64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ +const CP_L: Float64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ +const IVLN2: Float64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ +const IVLN2_H: Float64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ +const IVLN2_L: Float64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ /// Returns `x` raised to the power `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -101,8 +101,8 @@ pub fn pow(x: Float64, y: Float64) -> Float64 { let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); - let mut ix: i32 = hx & 0x7fffffff; - let iy: i32 = hy & 0x7fffffff; + let mut ix: i32 = (hx & 0x7fffffff) as i32; + let iy: i32 = (hy & 0x7fffffff) as i32; /* x**0 = 1, even if x is NaN */ if ((iy as u32) | ly) == 0 { @@ -267,7 +267,7 @@ pub fn pow(x: Float64, y: Float64) -> Float64 { /* now |1-x| is TINY <= 2**-20, suffice to compute log(x) by x-x^2/2+x^3/3-x^4/4 */ let t: Float64 = ax - 1.0; /* t has 20 trailing zeros */ - let w: Float64 = (t * t) * (0.5 - t * (0.333_333_333_333_333_3 - t * 0.25)); + let w: Float64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); let u: Float64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ let v: Float64 = t * IVLN2_L - w * IVLN2; t1 = with_set_low_word(u + v, 0); @@ -374,7 +374,7 @@ pub fn pow(x: Float64, y: Float64) -> Float64 { } /* compute 2**(p_h+p_l) */ - let i: i32 = j & 0x7fffffff_i32; + let i: i32 = j & (0x7fffffff as i32); k = (i >> 20) - 0x3ff; let mut n: i32 = 0; @@ -613,7 +613,7 @@ mod tests { // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS] + (&[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS]) .iter() .for_each(|int_set| { int_set.iter().for_each(|int| { @@ -625,7 +625,7 @@ mod tests { // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) - NEG[1..(NEG.len() - 1)].iter().for_each(|set| { + (&NEG[1..(NEG.len() - 1)]).iter().for_each(|set| { set.iter().for_each(|val| { test_sets(&ALL[3..7], &|v: Float64| pow(*val, v), &|_| NAN); }) diff --git a/llm/math/powf.rs b/llm/math/powf.rs index e8c1c01..1cae7c3 100644 --- a/llm/math/powf.rs +++ b/llm/math/powf.rs @@ -18,32 +18,32 @@ use crate::Float32; use super::{fabsf, scalbnf, sqrtf}; const BP: [Float32; 2] = [1.0, 1.5]; -const DP_H: [Float32; 2] = [0.0, 5.849_609_4e-1]; /* 0x3f15c000 */ -const DP_L: [Float32; 2] = [0.0, 1.563_220_8e-6]; /* 0x35d1cfdc */ +const DP_H: [Float32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ +const DP_L: [Float32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ const TWO24: Float32 = 16777216.0; /* 0x4b800000 */ const HUGE: Float32 = 1.0e30; const TINY: Float32 = 1.0e-30; -const L1: Float32 = 6e-1; /* 0x3f19999a */ -const L2: Float32 = 4.285_714_3e-1; /* 0x3edb6db7 */ -const L3: Float32 = 3.333_333_4e-1; /* 0x3eaaaaab */ -const L4: Float32 = 2.727_281_2e-1; /* 0x3e8ba305 */ -const L5: Float32 = 2.306_607_5e-1; /* 0x3e6c3255 */ -const L6: Float32 = 2.069_750_1e-1; /* 0x3e53f142 */ -const P1: Float32 = 1.666_666_7e-1; /* 0x3e2aaaab */ -const P2: Float32 = -2.777_777_8e-3; /* 0xbb360b61 */ -const P3: Float32 = 6.613_756e-5; /* 0x388ab355 */ -const P4: Float32 = -1.653_390_2e-6; /* 0xb5ddea0e */ -const P5: Float32 = 4.138_137e-8; /* 0x3331bb4c */ -const LG2: Float32 = 6.931_472e-1; /* 0x3f317218 */ -const LG2_H: Float32 = 6.931_457_5e-1; /* 0x3f317200 */ -const LG2_L: Float32 = 1.428_606_5e-6; /* 0x35bfbe8c */ -const OVT: Float32 = 4.299_566_6e-8; /* -(128-log2(ovfl+.5ulp)) */ -const CP: Float32 = 9.617_967e-1; /* 0x3f76384f =2/(3ln2) */ -const CP_H: Float32 = 9.619_140_6e-1; /* 0x3f764000 =12b cp */ -const CP_L: Float32 = -1.173_685_74e-4; /* 0xb8f623c6 =tail of cp_h */ -const IVLN2: Float32 = 1.442_695; -const IVLN2_H: Float32 = 1.442_688; -const IVLN2_L: Float32 = 7.052_607_5e-6; +const L1: Float32 = 6.0000002384e-01; /* 0x3f19999a */ +const L2: Float32 = 4.2857143283e-01; /* 0x3edb6db7 */ +const L3: Float32 = 3.3333334327e-01; /* 0x3eaaaaab */ +const L4: Float32 = 2.7272811532e-01; /* 0x3e8ba305 */ +const L5: Float32 = 2.3066075146e-01; /* 0x3e6c3255 */ +const L6: Float32 = 2.0697501302e-01; /* 0x3e53f142 */ +const P1: Float32 = 1.6666667163e-01; /* 0x3e2aaaab */ +const P2: Float32 = -2.7777778450e-03; /* 0xbb360b61 */ +const P3: Float32 = 6.6137559770e-05; /* 0x388ab355 */ +const P4: Float32 = -1.6533901999e-06; /* 0xb5ddea0e */ +const P5: Float32 = 4.1381369442e-08; /* 0x3331bb4c */ +const LG2: Float32 = 6.9314718246e-01; /* 0x3f317218 */ +const LG2_H: Float32 = 6.93145752e-01; /* 0x3f317200 */ +const LG2_L: Float32 = 1.42860654e-06; /* 0x35bfbe8c */ +const OVT: Float32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ +const CP: Float32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ +const CP_H: Float32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ +const CP_L: Float32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ +const IVLN2: Float32 = 1.4426950216e+00; +const IVLN2_H: Float32 = 1.4426879883e+00; +const IVLN2_L: Float32 = 7.0526075433e-06; /// Returns `x` raised to the power `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -54,7 +54,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { let z_l: Float32; let mut p_h: Float32; let mut p_l: Float32; - + let y1: Float32; let mut t1: Float32; let t2: Float32; let mut r: Float32; @@ -64,22 +64,22 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { let mut u: Float32; let mut v: Float32; let mut w: Float32; - + let i: i32; let mut j: i32; let mut k: i32; let mut yisint: i32; let mut n: i32; - - + let hx: i32; + let hy: i32; let mut ix: i32; - + let iy: i32; let mut is: i32; - let hx: i32 = x.to_bits() as i32; - let hy: i32 = y.to_bits() as i32; + hx = x.to_bits() as i32; + hy = y.to_bits() as i32; ix = hx & 0x7fffffff; - let iy: i32 = hy & 0x7fffffff; + iy = hy & 0x7fffffff; /* x**0 = 1, even if x is NaN */ if iy == 0 { @@ -202,7 +202,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { /* now |1-x| is TINY <= 2**-20, suffice to compute log(x) by x-x^2/2+x^3/3-x^4/4 */ t = ax - 1.; /* t has 20 trailing zeros */ - w = (t * t) * (0.5 - t * (0.333_333_34 - t * 0.25)); + w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ v = t * IVLN2_L - w * IVLN2; t1 = u + v; @@ -212,7 +212,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { } else { let mut s2: Float32; let mut s_h: Float32; - + let s_l: Float32; let mut t_h: Float32; let mut t_l: Float32; @@ -251,7 +251,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { is = (((ix as u32 >> 1) & 0xfffff000) | 0x20000000) as i32; t_h = Float32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); t_l = ax - (t_h - i!(BP, k as usize)); - let s_l: Float32 = v * ((u - s_h * t_h) - s_h * t_l); + s_l = v * ((u - s_h * t_h) - s_h * t_l); /* compute log(ax) */ s2 = s * s; r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); @@ -281,7 +281,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ is = y.to_bits() as i32; - let y1: Float32 = Float32::from_bits(is as u32 & 0xfffff000); + y1 = Float32::from_bits(is as u32 & 0xfffff000); p_l = (y - y1) * t1 + y * t2; p_h = y1 * t1; z = p_l + p_h; @@ -308,7 +308,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { /* * compute 2**(p_h+p_l) */ - let i: i32 = j & 0x7fffffff; + i = j & 0x7fffffff; k = (i >> 23) - 0x7f; n = 0; if i > 0x3f000000 { diff --git a/llm/math/rem_pio2.rs b/llm/math/rem_pio2.rs index 3dd26c7..04b2701 100644 --- a/llm/math/rem_pio2.rs +++ b/llm/math/rem_pio2.rs @@ -17,7 +17,7 @@ use super::rem_pio2_large; // #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 // #define EPS DBL_EPSILON -const EPS: Float64 = 2.220_446_049_250_313e-16; +const EPS: Float64 = 2.2204460492503131e-16; // #elif FLT_EVAL_METHOD==2 // #define EPS LDBL_EPSILON // #endif @@ -26,19 +26,19 @@ const EPS: Float64 = 2.220_446_049_250_313e-16; const TO_INT: Float64 = 1.5 / EPS; /// 53 bits of 2/pi -const INV_PIO2: Float64 = 6.366_197_723_675_814e-1; /* 0x3FE45F30, 0x6DC9C883 */ +const INV_PIO2: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ /// first 33 bits of pi/2 -const PIO2_1: Float64 = 1.570_796_326_734_125_6; /* 0x3FF921FB, 0x54400000 */ +const PIO2_1: Float64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ /// pi/2 - PIO2_1 -const PIO2_1T: Float64 = 6.077_100_506_506_192e-11; /* 0x3DD0B461, 0x1A626331 */ +const PIO2_1T: Float64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ /// second 33 bits of pi/2 -const PIO2_2: Float64 = 6.077_100_506_303_966e-11; /* 0x3DD0B461, 0x1A600000 */ +const PIO2_2: Float64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ /// pi/2 - (PIO2_1+PIO2_2) -const PIO2_2T: Float64 = 2.022_266_248_795_950_6e-21; /* 0x3BA3198A, 0x2E037073 */ +const PIO2_2T: Float64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ /// third 33 bits of pi/2 -const PIO2_3: Float64 = 2.022_266_248_711_166_5e-21; /* 0x3BA3198A, 0x2E000000 */ +const PIO2_3: Float64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ /// pi/2 - (PIO2_1+PIO2_2+PIO2_3) -const PIO2_3T: Float64 = 8.478_427_660_368_9e-32; /* 0x397B839A, 0x252049C1 */ +const PIO2_3T: Float64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ /// return the remainder of x rem pi/2 in y[0]+y[1] /// use rem_pio2_large() for large x diff --git a/llm/math/rem_pio2_large.rs b/llm/math/rem_pio2_large.rs index 132b76f..6aa68ef 100644 --- a/llm/math/rem_pio2_large.rs +++ b/llm/math/rem_pio2_large.rs @@ -122,14 +122,14 @@ const IPIO2: [i32; 690] = [ ]; const PIO2: [Float64; 8] = [ - 1.570_796_251_296_997, /* 0x3FF921FB, 0x40000000 */ - 7.549_789_415_861_596e-8, /* 0x3E74442D, 0x00000000 */ - 5.390_302_529_957_765e-15, /* 0x3CF84698, 0x80000000 */ - 3.282_003_415_807_913e-22, /* 0x3B78CC51, 0x60000000 */ - 1.270_655_753_080_676e-29, /* 0x39F01B83, 0x80000000 */ - 1.229_333_089_811_113_3e-36, /* 0x387A2520, 0x40000000 */ - 2.733_700_538_164_645_6e-44, /* 0x36E38222, 0x80000000 */ - 2.167_416_838_778_048_2e-51, /* 0x3569F31D, 0x00000000 */ + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ ]; // fn rem_pio2_large(x : &[Float64], y : &mut [Float64], e0 : i32, prec : usize) -> i32 diff --git a/llm/math/rem_pio2f.rs b/llm/math/rem_pio2f.rs index cc74869..1a803cd 100644 --- a/llm/math/rem_pio2f.rs +++ b/llm/math/rem_pio2f.rs @@ -21,11 +21,11 @@ use super::rem_pio2_large; const TOINT: Float64 = 1.5 / Float64::EPSILON; /// 53 bits of 2/pi -const INV_PIO2: Float64 = 6.366_197_723_675_814e-1; /* 0x3FE45F30, 0x6DC9C883 */ +const INV_PIO2: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ /// first 25 bits of pi/2 -const PIO2_1: Float64 = 1.570_796_310_901_641_8; /* 0x3FF921FB, 0x50000000 */ +const PIO2_1: Float64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ /// pi/2 - pio2_1 -const PIO2_1T: Float64 = 1.589_325_477_352_819_6e-8; /* 0x3E5110b4, 0x611A6263 */ +const PIO2_1T: Float64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ /// Return the remainder of x rem pi/2 in *y /// diff --git a/llm/math/sincos.rs b/llm/math/sincos.rs index 38b4864..b57c505 100644 --- a/llm/math/sincos.rs +++ b/llm/math/sincos.rs @@ -17,8 +17,8 @@ use super::{get_high_word, k_cos, k_sin, rem_pio2}; /// Simultaneously computes the sine and cosine of the argument x. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincos(x: Radian64) -> (Float64, Float64) { - - + let s: Float64; + let c: Float64; let mut ix: u32; ix = get_high_word(x); @@ -48,8 +48,8 @@ pub fn sincos(x: Radian64) -> (Float64, Float64) { /* argument reduction needed */ let (n, y0, y1) = rem_pio2(x); - let s: Float64 = k_sin(y0, y1, 1); - let c: Float64 = k_cos(y0, y1); + s = k_sin(y0, y1, 1); + c = k_cos(y0, y1); match n & 3 { 0 => (s, c), 1 => (c, -s), diff --git a/llm/math/sincosf.rs b/llm/math/sincosf.rs index 3358968..3880d5d 100644 --- a/llm/math/sincosf.rs +++ b/llm/math/sincosf.rs @@ -19,7 +19,7 @@ use crate::{Float64, Float32, Radian32}; use super::{k_cosf, k_sinf, rem_pio2f}; /* Small multiples of pi/2 rounded to double precision. */ -const PI_2: Float32 = 0.5 * 3.141_592_7; +const PI_2: Float32 = 0.5 * 3.1415926535897931160E+00; const S1PIO2: Float32 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ const S2PIO2: Float32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ const S3PIO2: Float32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ @@ -31,10 +31,10 @@ pub fn sincosf(x: Radian32) -> (Float32, Float32) { let s: Float32; let c: Float32; let mut ix: u32; - + let sign: bool; ix = x.to_bits(); - let sign: bool = (ix >> 31) != 0; + sign = (ix >> 31) != 0; ix &= 0x7fffffff; /* |x| ~<= pi/4 */ @@ -67,12 +67,14 @@ pub fn sincosf(x: Radian32) -> (Float32, Float32) { } } /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ - else if sign { - s = -k_sinf((x + S2PIO2) as Float64); - c = -k_cosf((x + S2PIO2) as Float64); - } else { - s = -k_sinf((x - S2PIO2) as Float64); - c = -k_cosf((x - S2PIO2) as Float64); + else { + if sign { + s = -k_sinf((x + S2PIO2) as Float64); + c = -k_cosf((x + S2PIO2) as Float64); + } else { + s = -k_sinf((x - S2PIO2) as Float64); + c = -k_cosf((x - S2PIO2) as Float64); + } } return (s, c); @@ -89,12 +91,14 @@ pub fn sincosf(x: Radian32) -> (Float32, Float32) { s = -k_cosf((x - S3PIO2) as Float64); c = k_sinf((x - S3PIO2) as Float64); } - } else if sign { - s = k_sinf((x + S4PIO2) as Float64); - c = k_cosf((x + S4PIO2) as Float64); } else { - s = k_sinf((x - S4PIO2) as Float64); - c = k_cosf((x - S4PIO2) as Float64); + if sign { + s = k_sinf((x + S4PIO2) as Float64); + c = k_cosf((x + S4PIO2) as Float64); + } else { + s = k_sinf((x - S4PIO2) as Float64); + c = k_cosf((x - S4PIO2) as Float64); + } } return (s, c); diff --git a/llm/math/sinh.rs b/llm/math/sinh.rs index 371050b..e6ea30c 100644 --- a/llm/math/sinh.rs +++ b/llm/math/sinh.rs @@ -16,10 +16,10 @@ pub fn sinh(x: Radian64) -> Float64 { let mut uf: Float64 = x; let mut ui: u64 = Float64::to_bits(uf); - + let w: u32; let t: Float64; let mut h: Float64; - + let absx: Float64; h = 0.5; if ui >> 63 != 0 { @@ -28,8 +28,8 @@ pub fn sinh(x: Radian64) -> Float64 { /* |x| */ ui &= !1 / 2; uf = Float64::from_bits(ui); - let absx: Float64 = uf; - let w: u32 = (ui >> 32) as u32; + absx = uf; + w = (ui >> 32) as u32; /* |x| < log(DBL_MAX) */ if w < 0x40862e42 { diff --git a/llm/math/sqrtf.rs b/llm/math/sqrtf.rs index 5b32246..9c2c427 100644 --- a/llm/math/sqrtf.rs +++ b/llm/math/sqrtf.rs @@ -158,7 +158,7 @@ mod tests { #[test] fn conformance_tests() { let values = [ - 3.141_592_7_f32, + 3.14159265359f32, 10000.0f32, Float32::from_bits(0x0000000f), INFINITY, diff --git a/llm/math/tanh.rs b/llm/math/tanh.rs index 833b545..51df661 100644 --- a/llm/math/tanh.rs +++ b/llm/math/tanh.rs @@ -14,16 +14,16 @@ pub fn tanh(mut x: Radian64) -> Float64 { let mut uf: Float64 = x; let mut ui: u64 = Float64::to_bits(uf); - - + let w: u32; + let sign: bool; let mut t: Float64; /* x = |x| */ - let sign: bool = ui >> 63 != 0; + sign = ui >> 63 != 0; ui &= !1 / 2; uf = Float64::from_bits(ui); x = uf; - let w: u32 = (ui >> 32) as u32; + w = (ui >> 32) as u32; if w > 0x3fe193ea { /* |x| > log(3)/2 ~= 0.5493 or nan */ diff --git a/llm/math/tgamma.rs b/llm/math/tgamma.rs index d45edae..8cc6e54 100644 --- a/llm/math/tgamma.rs +++ b/llm/math/tgamma.rs @@ -27,7 +27,7 @@ use crate::{Float64, Float32}; use super::{exp, floor, k_cos, k_sin, pow}; -const PI: Float64 = 3.141_592_653_589_793; +const PI: Float64 = 3.141592653589793238462643383279502884; /* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ fn sinpi(mut x: Float64) -> Float64 { @@ -54,21 +54,21 @@ fn sinpi(mut x: Float64) -> Float64 { const N: usize = 12; //static const double g = 6.024680040776729583740234375; -const GMHALF: Float64 = 5.524_680_040_776_73; +const GMHALF: Float64 = 5.524680040776729583740234375; const SNUM: [Float64; N + 1] = [ - 23_531_376_880.410_76, - 42_919_803_642.649_1, - 35_711_959_237.355_67, - 17_921_034_426.037_21, - 6_039_542_586.352_028, - 1_439_720_407.311_721_6, - 248_874_557.862_054_17, - 31_426_415.585_400_194, - 2_876_370.628_935_372_5, - 186_056.265_395_223_48, - 8_071.672_002_365_816, - 210.824_277_751_579_36, - 2.506_628_274_631_000_2, + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, ]; const SDEN: [Float64; N + 1] = [ 0.0, @@ -136,7 +136,7 @@ fn s(x: Float64) -> Float64 { #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgamma(mut x: Float64) -> Float64 { let u: u64 = x.to_bits(); - + let absx: Float64; let mut y: Float64; let mut dy: Float64; let mut z: Float64; @@ -183,7 +183,7 @@ pub fn tgamma(mut x: Float64) -> Float64 { return x; } - let absx: Float64 = if sign { -x } else { x }; + absx = if sign { -x } else { x }; /* handle the error of x + g - 0.5 */ y = absx + GMHALF; diff --git a/llm/math/trunc.rs b/llm/math/trunc.rs index fdf91f7..a3b6a9c 100644 --- a/llm/math/trunc.rs +++ b/llm/math/trunc.rs @@ -16,7 +16,7 @@ pub fn trunc(x: Float64) -> Float64 { let mut i: u64 = x.to_bits(); let mut e: i64 = (i >> 52 & 0x7ff) as i64 - 0x3ff + 12; - + let m: u64; if e >= 52 + 12 { return x; @@ -24,7 +24,7 @@ pub fn trunc(x: Float64) -> Float64 { if e < 12 { e = 1; } - let m: u64 = -1i64 as u64 >> e; + m = -1i64 as u64 >> e; if (i & m) == 0 { return x; } diff --git a/llm/math/truncf.rs b/llm/math/truncf.rs index 0be8c05..7797b4e 100644 --- a/llm/math/truncf.rs +++ b/llm/math/truncf.rs @@ -16,7 +16,7 @@ pub fn truncf(x: Float32) -> Float32 { let mut i: u32 = x.to_bits(); let mut e: i32 = (i >> 23 & 0xff) as i32 - 0x7f + 9; - + let m: u32; if e >= 23 + 9 { return x; @@ -24,7 +24,7 @@ pub fn truncf(x: Float32) -> Float32 { if e < 9 { e = 1; } - let m: u32 = -1i32 as u32 >> e; + m = -1i32 as u32 >> e; if (i & m) == 0 { return x; } From 0a1158e0ff614abd07fa22b15d9d0e1bbaafd9fe Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 17:19:43 -0800 Subject: [PATCH 18/93] Fmod minor fix --- llm/math/fmod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llm/math/fmod.rs b/llm/math/fmod.rs index 4059c14..8ae63b9 100644 --- a/llm/math/fmod.rs +++ b/llm/math/fmod.rs @@ -79,7 +79,7 @@ pub fn fmod(x: Float64, y: Float64) -> Float64 { } else { uxi >>= -ex + 1; } - uxi |= (sx as u64) << 63; + uxi |= sx << 63; Float64::from_bits(uxi) } From 8f841d264f1e20e9b738611804929ad28877b420 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 17:20:07 -0800 Subject: [PATCH 19/93] Kernel impls update --- llm/math/j0f.rs | 9 +- llm/math/j1f.rs | 204 +++++++++++++++++++-------------------- llm/math/jn.rs | 236 ++++++++++++++++++++++----------------------- llm/math/jnf.rs | 224 +++++++++++++++++++++--------------------- llm/math/k_cos.rs | 2 + llm/math/k_cosf.rs | 2 + llm/math/k_sin.rs | 2 + llm/math/k_sinf.rs | 2 + llm/math/k_tan.rs | 3 + llm/math/k_tanf.rs | 2 + 10 files changed, 350 insertions(+), 336 deletions(-) diff --git a/llm/math/j0f.rs b/llm/math/j0f.rs index dfcf14e..188608c 100644 --- a/llm/math/j0f.rs +++ b/llm/math/j0f.rs @@ -17,12 +17,13 @@ use crate::Float32; use super::{cosf, fabsf, logf, sinf, sqrtf}; +consts!{ const INVSQRTPI: Float32 = 5.6418961287e-01; /* 0x3f106ebb */ const TPI: Float32 = 6.3661974669e-01; /* 0x3f22f983 */ +} fn common(ix: u32, x: Float32, y0: bool) -> Float32 { let z: Float32; - let s: Float32; let mut c: Float32; let mut ss: Float32; let mut cc: Float32; @@ -30,7 +31,7 @@ fn common(ix: u32, x: Float32, y0: bool) -> Float32 { * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) */ - s = sinf(x); + let s: Float32 = sinf(x); c = cosf(x); if y0 { c = -c; @@ -55,6 +56,7 @@ fn common(ix: u32, x: Float32, y0: bool) -> Float32 { } /* R0/S0 on [0, 2.00] */ +consts!{ const R02: Float32 = 1.5625000000e-02; /* 0x3c800000 */ const R03: Float32 = -1.8997929874e-04; /* 0xb947352e */ const R04: Float32 = 1.8295404516e-06; /* 0x35f58e88 */ @@ -63,6 +65,7 @@ const S01: Float32 = 1.5619102865e-02; /* 0x3c7fe744 */ const S02: Float32 = 1.1692678527e-04; /* 0x38f53697 */ const S03: Float32 = 5.1354652442e-07; /* 0x3509daa6 */ const S04: Float32 = 1.1661400734e-09; /* 0x30a045e8 */ +} /// Bessel function of the first kind of order zero /// @@ -100,6 +103,7 @@ pub fn j0f(mut x: Float32) -> Float32 { return 1.0 - x; } +consts!{ const U00: Float32 = -7.3804296553e-02; /* 0xbd9726b5 */ const U01: Float32 = 1.7666645348e-01; /* 0x3e34e80d */ const U02: Float32 = -1.3818567619e-02; /* 0xbc626746 */ @@ -111,6 +115,7 @@ const V01: Float32 = 1.2730483897e-02; /* 0x3c509385 */ const V02: Float32 = 7.6006865129e-05; /* 0x389f65e0 */ const V03: Float32 = 2.5915085189e-07; /* 0x348b216c */ const V04: Float32 = 4.4111031494e-10; /* 0x2ff280c2 */ +} /// Bessel function of the second kind of order zero /// diff --git a/llm/math/j1f.rs b/llm/math/j1f.rs index 8c17a6a..1b8b48b 100644 --- a/llm/math/j1f.rs +++ b/llm/math/j1f.rs @@ -148,76 +148,76 @@ pub fn y1f(x: Float32) -> Float32 { const PR8: [Float32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ - 1.1718750000e-01, /* 0x3df00000 */ - 1.3239480972e+01, /* 0x4153d4ea */ - 4.1205184937e+02, /* 0x43ce06a3 */ - 3.8747453613e+03, /* 0x45722bed */ - 7.9144794922e+03, /* 0x45f753d6 */ + 1.171_875e-1, /* 0x3df00000 */ + 1.323_948_1e1, /* 0x4153d4ea */ + 4.120_518_5e2, /* 0x43ce06a3 */ + 3.874_745_4e3, /* 0x45722bed */ + 7.914_479_5e3, /* 0x45f753d6 */ ]; const PS8: [Float32; 5] = [ - 1.1420736694e+02, /* 0x42e46a2c */ - 3.6509309082e+03, /* 0x45642ee5 */ - 3.6956207031e+04, /* 0x47105c35 */ - 9.7602796875e+04, /* 0x47bea166 */ - 3.0804271484e+04, /* 0x46f0a88b */ + 1.142_073_7e2, /* 0x42e46a2c */ + 3.650_931e3, /* 0x45642ee5 */ + 3.695_620_7e4, /* 0x47105c35 */ + 9.760_28e4, /* 0x47bea166 */ + 3.080_427_1e4, /* 0x46f0a88b */ ]; const PR5: [Float32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.3199052094e-11, /* 0x2d68333f */ - 1.1718749255e-01, /* 0x3defffff */ - 6.8027510643e+00, /* 0x40d9b023 */ - 1.0830818176e+02, /* 0x42d89dca */ - 5.1763616943e+02, /* 0x440168b7 */ - 5.2871520996e+02, /* 0x44042dc6 */ + 1.319_905_2e-11, /* 0x2d68333f */ + 1.171_874_9e-1, /* 0x3defffff */ + 6.802_751, /* 0x40d9b023 */ + 1.083_081_8e2, /* 0x42d89dca */ + 5.176_361_7e2, /* 0x440168b7 */ + 5.287_152e2, /* 0x44042dc6 */ ]; const PS5: [Float32; 5] = [ - 5.9280597687e+01, /* 0x426d1f55 */ - 9.9140142822e+02, /* 0x4477d9b1 */ - 5.3532670898e+03, /* 0x45a74a23 */ - 7.8446904297e+03, /* 0x45f52586 */ - 1.5040468750e+03, /* 0x44bc0180 */ + 5.928_059_8e1, /* 0x426d1f55 */ + 9.914_014e2, /* 0x4477d9b1 */ + 5.353_267e3, /* 0x45a74a23 */ + 7.844_690_4e3, /* 0x45f52586 */ + 1.504_046_9e3, /* 0x44bc0180 */ ]; const PR3: [Float32; 6] = [ - 3.0250391081e-09, /* 0x314fe10d */ - 1.1718686670e-01, /* 0x3defffab */ - 3.9329774380e+00, /* 0x407bb5e7 */ - 3.5119403839e+01, /* 0x420c7a45 */ - 9.1055007935e+01, /* 0x42b61c2a */ - 4.8559066772e+01, /* 0x42423c7c */ + 3.025_039e-9, /* 0x314fe10d */ + 1.171_868_7e-1, /* 0x3defffab */ + 3.932_977_4, /* 0x407bb5e7 */ + 3.511_940_4e1, /* 0x420c7a45 */ + 9.105_501e1, /* 0x42b61c2a */ + 4.855_906_7e1, /* 0x42423c7c */ ]; const PS3: [Float32; 5] = [ - 3.4791309357e+01, /* 0x420b2a4d */ - 3.3676245117e+02, /* 0x43a86198 */ - 1.0468714600e+03, /* 0x4482dbe3 */ - 8.9081134033e+02, /* 0x445eb3ed */ - 1.0378793335e+02, /* 0x42cf936c */ + 3.479_131e1, /* 0x420b2a4d */ + 3.367_624_5e2, /* 0x43a86198 */ + 1.046_871_5e3, /* 0x4482dbe3 */ + 8.908_113_4e2, /* 0x445eb3ed */ + 1.037_879_3e2, /* 0x42cf936c */ ]; const PR2: [Float32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.0771083225e-07, /* 0x33e74ea8 */ - 1.1717621982e-01, /* 0x3deffa16 */ - 2.3685150146e+00, /* 0x401795c0 */ - 1.2242610931e+01, /* 0x4143e1bc */ - 1.7693971634e+01, /* 0x418d8d41 */ - 5.0735230446e+00, /* 0x40a25a4d */ + 1.077_108_3e-7, /* 0x33e74ea8 */ + 1.171_762_2e-1, /* 0x3deffa16 */ + 2.368_515, /* 0x401795c0 */ + 1.224_261_1e1, /* 0x4143e1bc */ + 1.769_397_2e1, /* 0x418d8d41 */ + 5.073_523, /* 0x40a25a4d */ ]; const PS2: [Float32; 5] = [ - 2.1436485291e+01, /* 0x41ab7dec */ - 1.2529022980e+02, /* 0x42fa9499 */ - 2.3227647400e+02, /* 0x436846c7 */ - 1.1767937469e+02, /* 0x42eb5bd7 */ - 8.3646392822e+00, /* 0x4105d590 */ + 2.143_648_5e1, /* 0x41ab7dec */ + 1.252_902_3e2, /* 0x42fa9499 */ + 2.322_764_7e2, /* 0x436846c7 */ + 1.176_793_75e2, /* 0x42eb5bd7 */ + 8.364_639, /* 0x4105d590 */ ]; fn ponef(x: Float32) -> Float32 { let p: &[Float32; 6]; let q: &[Float32; 5]; - let z: Float32; - let r: Float32; - let s: Float32; + + + let mut ix: u32; ix = x.to_bits(); @@ -237,9 +237,9 @@ fn ponef(x: Float32) -> Float32 { p = &PR2; q = &PS2; } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + let z: Float32 = 1.0 / (x * x); + let r: Float32 = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + let s: Float32 = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); return 1.0 + r / s; } @@ -257,80 +257,80 @@ fn ponef(x: Float32) -> Float32 { const QR8: [Float32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ 0.0000000000e+00, /* 0x00000000 */ - -1.0253906250e-01, /* 0xbdd20000 */ - -1.6271753311e+01, /* 0xc1822c8d */ - -7.5960174561e+02, /* 0xc43de683 */ - -1.1849806641e+04, /* 0xc639273a */ - -4.8438511719e+04, /* 0xc73d3683 */ + -1.025_390_6e-1, /* 0xbdd20000 */ + -1.627_175_3e1, /* 0xc1822c8d */ + -7.596_017_5e2, /* 0xc43de683 */ + -1.184_980_7e4, /* 0xc639273a */ + -4.843_851e4, /* 0xc73d3683 */ ]; const QS8: [Float32; 6] = [ - 1.6139537048e+02, /* 0x43216537 */ - 7.8253862305e+03, /* 0x45f48b17 */ - 1.3387534375e+05, /* 0x4802bcd6 */ - 7.1965775000e+05, /* 0x492fb29c */ - 6.6660125000e+05, /* 0x4922be94 */ - -2.9449025000e+05, /* 0xc88fcb48 */ + 1.613_953_7e2, /* 0x43216537 */ + 7.825_386e3, /* 0x45f48b17 */ + 1.338_753_4e5, /* 0x4802bcd6 */ + 7.196_577_5e5, /* 0x492fb29c */ + 6.666_012_5e5, /* 0x4922be94 */ + -2.944_902_5e5, /* 0xc88fcb48 */ ]; const QR5: [Float32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -2.0897993405e-11, /* 0xadb7d219 */ - -1.0253904760e-01, /* 0xbdd1fffe */ - -8.0564479828e+00, /* 0xc100e736 */ - -1.8366960144e+02, /* 0xc337ab6b */ - -1.3731937256e+03, /* 0xc4aba633 */ - -2.6124443359e+03, /* 0xc523471c */ + -2.089_799_3e-11, /* 0xadb7d219 */ + -1.025_390_5e-1, /* 0xbdd1fffe */ + -8.056_448, /* 0xc100e736 */ + -1.836_696e2, /* 0xc337ab6b */ + -1.373_193_7e3, /* 0xc4aba633 */ + -2.612_444_3e3, /* 0xc523471c */ ]; const QS5: [Float32; 6] = [ - 8.1276550293e+01, /* 0x42a28d98 */ - 1.9917987061e+03, /* 0x44f8f98f */ - 1.7468484375e+04, /* 0x468878f8 */ - 4.9851425781e+04, /* 0x4742bb6d */ - 2.7948074219e+04, /* 0x46da5826 */ - -4.7191835938e+03, /* 0xc5937978 */ + 8.127_655e1, /* 0x42a28d98 */ + 1.991_798_7e3, /* 0x44f8f98f */ + 1.746_848_4e4, /* 0x468878f8 */ + 4.985_142_6e4, /* 0x4742bb6d */ + 2.794_807_4e4, /* 0x46da5826 */ + -4.719_183_6e3, /* 0xc5937978 */ ]; const QR3: [Float32; 6] = [ - -5.0783124372e-09, /* 0xb1ae7d4f */ - -1.0253783315e-01, /* 0xbdd1ff5b */ - -4.6101160049e+00, /* 0xc0938612 */ - -5.7847221375e+01, /* 0xc267638e */ - -2.2824453735e+02, /* 0xc3643e9a */ - -2.1921012878e+02, /* 0xc35b35cb */ + -5.078_312_4e-9, /* 0xb1ae7d4f */ + -1.025_378_3e-1, /* 0xbdd1ff5b */ + -4.610_116, /* 0xc0938612 */ + -5.784_722e1, /* 0xc267638e */ + -2.282_445_4e2, /* 0xc3643e9a */ + -2.192_101_3e2, /* 0xc35b35cb */ ]; const QS3: [Float32; 6] = [ - 4.7665153503e+01, /* 0x423ea91e */ - 6.7386511230e+02, /* 0x4428775e */ - 3.3801528320e+03, /* 0x45534272 */ - 5.5477290039e+03, /* 0x45ad5dd5 */ - 1.9031191406e+03, /* 0x44ede3d0 */ - -1.3520118713e+02, /* 0xc3073381 */ + 4.766_515_4e1, /* 0x423ea91e */ + 6.738_651e2, /* 0x4428775e */ + 3.380_152_8e3, /* 0x45534272 */ + 5.547_729e3, /* 0x45ad5dd5 */ + 1.903_119_1e3, /* 0x44ede3d0 */ + -1.352_011_9e2, /* 0xc3073381 */ ]; const QR2: [Float32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -1.7838172539e-07, /* 0xb43f8932 */ - -1.0251704603e-01, /* 0xbdd1f475 */ - -2.7522056103e+00, /* 0xc0302423 */ - -1.9663616180e+01, /* 0xc19d4f16 */ - -4.2325313568e+01, /* 0xc2294d1f */ - -2.1371921539e+01, /* 0xc1aaf9b2 */ + -1.783_817_3e-7, /* 0xb43f8932 */ + -1.025_170_46e-1, /* 0xbdd1f475 */ + -2.752_205_6, /* 0xc0302423 */ + -1.966_361_6e1, /* 0xc19d4f16 */ + -4.232_531_4e1, /* 0xc2294d1f */ + -2.137_192_2e1, /* 0xc1aaf9b2 */ ]; const QS2: [Float32; 6] = [ - 2.9533363342e+01, /* 0x41ec4454 */ - 2.5298155212e+02, /* 0x437cfb47 */ - 7.5750280762e+02, /* 0x443d602e */ - 7.3939318848e+02, /* 0x4438d92a */ - 1.5594900513e+02, /* 0x431bf2f2 */ - -4.9594988823e+00, /* 0xc09eb437 */ + 2.953_336_3e1, /* 0x41ec4454 */ + 2.529_815_5e2, /* 0x437cfb47 */ + 7.575_028e2, /* 0x443d602e */ + 7.393_932e2, /* 0x4438d92a */ + 1.559_49e2, /* 0x431bf2f2 */ + -4.959_499, /* 0xc09eb437 */ ]; fn qonef(x: Float32) -> Float32 { let p: &[Float32; 6]; let q: &[Float32; 6]; - let s: Float32; - let r: Float32; - let z: Float32; + + + let mut ix: u32; ix = x.to_bits(); @@ -350,9 +350,9 @@ fn qonef(x: Float32) -> Float32 { p = &QR2; q = &QS2; } - z = 1.0 / (x * x); - r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + let z: Float32 = 1.0 / (x * x); + let r: Float32 = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + let s: Float32 = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); return (0.375 + r / s) / x; } diff --git a/llm/math/jn.rs b/llm/math/jn.rs index b26373d..29f6e70 100644 --- a/llm/math/jn.rs +++ b/llm/math/jn.rs @@ -121,130 +121,128 @@ pub fn jn(n: i32, mut x: Float64) -> Float64 { a = temp; } } - } else { - if ix < 0x3e100000 { - /* x < 2**-29 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 32 { - /* underflow */ - b = 0.0; - } else { - temp = x * 0.5; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as Float64; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } + } else if ix < 0x3e100000 { + /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 32 { + /* underflow */ + b = 0.0; } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: Float64; - let mut q0: Float64; - let mut q1: Float64; - let mut w: Float64; - let h: Float64; - let mut z: Float64; - let mut tmp: Float64; - let nf: Float64; + temp = x * 0.5; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as Float64; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: Float64; + let mut q0: Float64; + let mut q1: Float64; + let mut w: Float64; + + let mut z: Float64; + let mut tmp: Float64; + - let mut k: i32; + let mut k: i32; - nf = (nm1 as Float64) + 1.0; - w = 2.0 * nf / x; - h = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e9 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as Float64) + nf) / x - t); + let nf: Float64 = (nm1 as Float64) + 1.0; + w = 2.0 * nf / x; + let h: Float64 = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e9 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as Float64) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * log(fabs(w)); + if tmp < 7.097_827_128_933_84e2 { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as Float64)) / x - a; + a = temp; i -= 1; } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf * log(fabs(w)); - if tmp < 7.09782712893383973096e+02 { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as Float64)) / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as Float64)) / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p500 = Float64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 - if b > x1p500 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; + } else { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as Float64)) / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p500 = Float64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 + if b > x1p500 { + a /= b; + t /= b; + b = 1.0; } + i -= 1; } - z = j0(x); - w = j1(x); - if fabs(z) >= fabs(w) { - b = t * z / b; - } else { - b = t * w / a; - } + } + z = j0(x); + w = j1(x); + if fabs(z) >= fabs(w) { + b = t * z / b; + } else { + b = t * w / a; } } @@ -260,7 +258,7 @@ pub fn jn(n: i32, mut x: Float64) -> Float64 { /// Calculates the Bessel function of the second kind of order zero of `x`. pub fn yn(n: i32, x: Float64) -> Float64 { let mut ix: u32; - let lx: u32; + let mut ib: u32; let nm1: i32; let mut sign: bool; @@ -270,7 +268,7 @@ pub fn yn(n: i32, x: Float64) -> Float64 { let mut temp: Float64; ix = get_high_word(x); - lx = get_low_word(x); + let lx: u32 = get_low_word(x); sign = (ix >> 31) != 0; ix &= 0x7fffffff; diff --git a/llm/math/jnf.rs b/llm/math/jnf.rs index 35bb33a..2532d90 100644 --- a/llm/math/jnf.rs +++ b/llm/math/jnf.rs @@ -68,125 +68,123 @@ pub fn jnf(n: i32, mut x: Float32) -> Float32 { b = b * (2.0 * (i as Float32) / x) - a; a = temp; } + } else if ix < 0x35800000 { + // x < 2**-20 + //x is tiny, return the first Taylor expansion of J(n,x) + // J(n,x) = 1/n!*(x/2)^n - ... + if nm1 > 8 { + /* underflow */ + nm1 = 8; + } + temp = 0.5 * x; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as Float32; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; } else { - if ix < 0x35800000 { - // x < 2**-20 - //x is tiny, return the first Taylor expansion of J(n,x) - // J(n,x) = 1/n!*(x/2)^n - ... - if nm1 > 8 { - /* underflow */ - nm1 = 8; - } - temp = 0.5 * x; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as Float32; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } else { - // use backward recurrence - // x x^2 x^2 - // J(n,x)/J(n-1,x) = ---- ------ ------ ..... - // 2n - 2(n+1) - 2(n+2) - // - // 1 1 1 - // (for large x) = ---- ------ ------ ..... - // 2n 2(n+1) 2(n+2) - // -- - ------ - ------ - - // x x x - // - // Let w = 2n/x and h=2/x, then the above quotient - // is equal to the continued fraction: - // 1 - // = ----------------------- - // 1 - // w - ----------------- - // 1 - // w+h - --------- - // w+2h - ... - // - // To determine how many terms needed, let - // Q(0) = w, Q(1) = w(w+h) - 1, - // Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - // When Q(k) > 1e4 good for single - // When Q(k) > 1e9 good for double - // When Q(k) > 1e17 good for quadruple - /* determine k */ - let mut t: Float32; - let mut q0: Float32; - let mut q1: Float32; - let mut w: Float32; - let h: Float32; - let mut z: Float32; - let mut tmp: Float32; - let nf: Float32; - let mut k: i32; + // use backward recurrence + // x x^2 x^2 + // J(n,x)/J(n-1,x) = ---- ------ ------ ..... + // 2n - 2(n+1) - 2(n+2) + // + // 1 1 1 + // (for large x) = ---- ------ ------ ..... + // 2n 2(n+1) 2(n+2) + // -- - ------ - ------ - + // x x x + // + // Let w = 2n/x and h=2/x, then the above quotient + // is equal to the continued fraction: + // 1 + // = ----------------------- + // 1 + // w - ----------------- + // 1 + // w+h - --------- + // w+2h - ... + // + // To determine how many terms needed, let + // Q(0) = w, Q(1) = w(w+h) - 1, + // Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + // When Q(k) > 1e4 good for single + // When Q(k) > 1e9 good for double + // When Q(k) > 1e17 good for quadruple + /* determine k */ + let mut t: Float32; + let mut q0: Float32; + let mut q1: Float32; + let mut w: Float32; + + let mut z: Float32; + let mut tmp: Float32; + + let mut k: i32; - nf = (nm1 as Float32) + 1.0; - w = 2.0 * (nf as Float32) / x; - h = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e4 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as Float32) + nf) / x - t); + let nf: Float32 = (nm1 as Float32) + 1.0; + w = 2.0 * (nf as Float32) / x; + let h: Float32 = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e4 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as Float32) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + // estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + // Hence, if n*(log(2n/x)) > ... + // single 8.8722839355e+01 + // double 7.09782712893383973096e+02 + // long double 1.1356523406294143949491931077970765006170e+04 + // then recurrent value may overflow and the result is + // likely underflow to zero + tmp = nf * logf(fabsf(w)); + if tmp < 88.721_68 { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as Float32) * b / x - a; + a = temp; i -= 1; } - a = t; - b = 1.0; - // estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - // Hence, if n*(log(2n/x)) > ... - // single 8.8722839355e+01 - // double 7.09782712893383973096e+02 - // long double 1.1356523406294143949491931077970765006170e+04 - // then recurrent value may overflow and the result is - // likely underflow to zero - tmp = nf * logf(fabsf(w)); - if tmp < 88.721679688 { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as Float32) * b / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as Float32) * b / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p60 = Float32::from_bits(0x5d800000); // 0x1p60 == 2^60 - if b > x1p60 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; + } else { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as Float32) * b / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p60 = Float32::from_bits(0x5d800000); // 0x1p60 == 2^60 + if b > x1p60 { + a /= b; + t /= b; + b = 1.0; } + i -= 1; } - z = j0f(x); - w = j1f(x); - if fabsf(z) >= fabsf(w) { - b = t * z / b; - } else { - b = t * w / a; - } + } + z = j0f(x); + w = j1f(x); + if fabsf(z) >= fabsf(w) { + b = t * z / b; + } else { + b = t * w / a; } } diff --git a/llm/math/k_cos.rs b/llm/math/k_cos.rs index 5ef6334..9cf6506 100644 --- a/llm/math/k_cos.rs +++ b/llm/math/k_cos.rs @@ -11,12 +11,14 @@ use crate::Float64; +consts!{ const C1: Float64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ const C2: Float64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ const C3: Float64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ const C4: Float64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ const C5: Float64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ const C6: Float64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ +} // kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 // Input x is assumed to be bounded by ~pi/4 in magnitude. diff --git a/llm/math/k_cosf.rs b/llm/math/k_cosf.rs index c2cc739..b8a7680 100644 --- a/llm/math/k_cosf.rs +++ b/llm/math/k_cosf.rs @@ -17,10 +17,12 @@ use crate::{Float64, Float32}; /* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +consts!{ const C0: Float64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ const C1: Float64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ const C2: Float64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ const C3: Float64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ +} #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_cosf(x: Float64) -> Float32 { diff --git a/llm/math/k_sin.rs b/llm/math/k_sin.rs index 900b59c..204e2bc 100644 --- a/llm/math/k_sin.rs +++ b/llm/math/k_sin.rs @@ -11,12 +11,14 @@ use crate::Float64; +consts!{ const S1: Float64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ const S2: Float64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ const S3: Float64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ const S4: Float64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ const S5: Float64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ const S6: Float64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ +} // kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 // Input x is assumed to be bounded by ~pi/4 in magnitude. diff --git a/llm/math/k_sinf.rs b/llm/math/k_sinf.rs index 80aa6f8..22a80fb 100644 --- a/llm/math/k_sinf.rs +++ b/llm/math/k_sinf.rs @@ -17,10 +17,12 @@ use crate::{Float64, Float32}; /* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +consts!{ const S1: Float64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ const S2: Float64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ const S3: Float64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ const S4: Float64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ +} #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_sinf(x: Float64) -> Float32 { diff --git a/llm/math/k_tan.rs b/llm/math/k_tan.rs index 6c7c12b..26d7982 100644 --- a/llm/math/k_tan.rs +++ b/llm/math/k_tan.rs @@ -42,6 +42,7 @@ use crate::Float64; // 4. For x in [0.67434,pi/4], let y = pi/4 - x, then // tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) // = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) +#[allow(clippy::excessive_precision)] static T: [Float64; 13] = [ 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ @@ -57,8 +58,10 @@ static T: [Float64; 13] = [ -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ ]; +consts!{ const PIO4: Float64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ const PIO4_LO: Float64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ +} #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_tan(mut x: Float64, mut y: Float64, odd: i32) -> Float64 { diff --git a/llm/math/k_tanf.rs b/llm/math/k_tanf.rs index cba17d7..e441a42 100644 --- a/llm/math/k_tanf.rs +++ b/llm/math/k_tanf.rs @@ -12,6 +12,7 @@ use crate::{Float64, Float32}; /* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ +consts!{ const T: [Float64; 6] = [ 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ 0.133392002712976742718, /* 0x1112fd38999f72.0p-55 */ @@ -20,6 +21,7 @@ const T: [Float64; 6] = [ 0.00297435743359967304927, /* 0x185dadfcecf44e.0p-61 */ 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ ]; +} #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_tanf(x: Float64, odd: bool) -> Float32 { From cb1ceae22122bcd8c1e5ed7437a216e4b339ea1b Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 17:20:25 -0800 Subject: [PATCH 20/93] Logarithms --- llm/math/lgamma_r.rs | 10 ++++++---- llm/math/lgammaf_r.rs | 13 ++++++------- llm/math/log.rs | 2 ++ llm/math/log10.rs | 33 ++++++++++++--------------------- llm/math/log10f.rs | 32 ++++++++++++-------------------- llm/math/log1p.rs | 29 +++++++++++------------------ llm/math/log1pf.rs | 30 +++++++++++------------------- llm/math/log2.rs | 30 +++++++++++------------------- llm/math/log2f.rs | 30 +++++++++++------------------- llm/math/logf.rs | 2 ++ 10 files changed, 84 insertions(+), 127 deletions(-) diff --git a/llm/math/lgamma_r.rs b/llm/math/lgamma_r.rs index ca48670..7d3c40b 100644 --- a/llm/math/lgamma_r.rs +++ b/llm/math/lgamma_r.rs @@ -83,6 +83,7 @@ use crate::Float64; use super::{floor, k_cos, k_sin, log}; +consts!{ const PI: Float64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ const A0: Float64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ const A1: Float64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ @@ -146,6 +147,7 @@ const W3: Float64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ const W4: Float64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ const W5: Float64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ const W6: Float64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ +} /* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ fn sin_pi(mut x: Float64) -> Float64 { @@ -185,15 +187,15 @@ pub fn lgamma_r(mut x: Float64) -> (Float64, i32) { let q: Float64; let mut r: Float64; let w: Float64; - let ix: u32; - let sign: bool; + + let i: i32; let mut signgam: i32; /* purge off +-inf, NaN, +-0, tiny and negative arguments */ signgam = 1; - sign = (u >> 63) != 0; - ix = ((u >> 32) as u32) & 0x7fffffff; + let sign: bool = (u >> 63) != 0; + let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; if ix >= 0x7ff00000 { return (x * x, signgam); } diff --git a/llm/math/lgammaf_r.rs b/llm/math/lgammaf_r.rs index 1b8f994..2acd18c 100644 --- a/llm/math/lgammaf_r.rs +++ b/llm/math/lgammaf_r.rs @@ -17,6 +17,7 @@ use crate::{Float64, Float32}; use super::{floorf, k_cosf, k_sinf, logf}; +consts!{ const PI: Float32 = 3.1415927410e+00; /* 0x40490fdb */ const A0: Float32 = 7.7215664089e-02; /* 0x3d9e233f */ const A1: Float32 = 3.2246702909e-01; /* 0x3ea51a66 */ @@ -80,6 +81,7 @@ const W3: Float32 = 7.9365057172e-04; /* 0x3a500cfd */ const W4: Float32 = -5.9518753551e-04; /* 0xba1c065c */ const W5: Float32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ const W6: Float32 = -1.6309292987e-03; /* 0xbad5c4e8 */ +} /* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ fn sin_pi(mut x: Float32) -> Float32 { @@ -92,7 +94,7 @@ fn sin_pi(mut x: Float32) -> Float32 { n = (x * 4.0) as isize; n = div!(n + 1, 2); y = (x as Float64) - (n as Float64) * 0.5; - y *= 3.14159265358979323846; + y *= 3.141_592_653_589_793; match n { 1 => k_cosf(y), 2 => k_sinf(-y), @@ -119,15 +121,12 @@ pub fn lgammaf_r(mut x: Float32) -> (Float32, i32) { let q: Float32; let mut r: Float32; let w: Float32; - let ix: u32; let i: i32; - let sign: bool; - let mut signgam: i32; + let mut signgam = 1; /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - sign = (u >> 31) != 0; - ix = u & 0x7fffffff; + let sign: bool = (u >> 31) != 0; + let ix: u32 = u & 0x7fffffff; if ix >= 0x7f800000 { return (x * x, signgam); } diff --git a/llm/math/log.rs b/llm/math/log.rs index 6ff860c..7fdfc40 100644 --- a/llm/math/log.rs +++ b/llm/math/log.rs @@ -63,6 +63,7 @@ use crate::Float64; +consts!{ const LN2_HI: Float64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ const LN2_LO: Float64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ @@ -72,6 +73,7 @@ const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +} /// Returns the logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/llm/math/log10.rs b/llm/math/log10.rs index c128eab..978c150 100644 --- a/llm/math/log10.rs +++ b/llm/math/log10.rs @@ -19,6 +19,7 @@ use crate::Float64; +consts!{ const IVLN10HI: Float64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ const IVLN10LO: Float64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ const LOG10_2HI: Float64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ @@ -30,25 +31,15 @@ const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +} /// Returns the base 10 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10(mut x: Float64) -> Float64 { let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 - let mut ui: u64 = x.to_bits(); - let hfsq: Float64; - let f: Float64; - let s: Float64; - let z: Float64; - let r: Float64; let mut w: Float64; - let t1: Float64; - let t2: Float64; - let dk: Float64; - let y: Float64; let mut hi: Float64; - let lo: Float64; let mut val_hi: Float64; let mut val_lo: Float64; let mut hx: u32; @@ -81,14 +72,14 @@ pub fn log10(mut x: Float64) -> Float64 { ui = (hx as u64) << 32 | (ui & 0xffffffff); x = Float64::from_bits(ui); - f = x - 1.0; - hfsq = 0.5 * f * f; - s = f / (2.0 + f); - z = s * s; + let f: Float64 = x - 1.0; + let hfsq: Float64 = 0.5 * f * f; + let s: Float64 = f / (2.0 + f); + let z: Float64 = s * s; w = z * z; - t1 = w * (LG2 + w * (LG4 + w * LG6)); - t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - r = t2 + t1; + let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); + let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + let r: Float64 = t2 + t1; /* See log2.c for details. */ /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ @@ -96,12 +87,12 @@ pub fn log10(mut x: Float64) -> Float64 { ui = hi.to_bits(); ui &= (-1i64 as u64) << 32; hi = Float64::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); + let lo: Float64 = f - hi - hfsq + s * (hfsq + r); /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ val_hi = hi * IVLN10HI; - dk = k as Float64; - y = dk * LOG10_2HI; + let dk: Float64 = k as Float64; + let y: Float64 = dk * LOG10_2HI; val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI; /* diff --git a/llm/math/log10f.rs b/llm/math/log10f.rs index 45d5c32..c8104ae 100644 --- a/llm/math/log10f.rs +++ b/llm/math/log10f.rs @@ -15,6 +15,7 @@ use crate::Float32; +consts!{ const IVLN10HI: Float32 = 4.3432617188e-01; /* 0x3ede6000 */ const IVLN10LO: Float32 = -3.1689971365e-05; /* 0xb804ead9 */ const LOG10_2HI: Float32 = 3.0102920532e-01; /* 0x3e9a2080 */ @@ -24,6 +25,7 @@ const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ +} /// Returns the base 10 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -31,17 +33,7 @@ pub fn log10f(mut x: Float32) -> Float32 { let x1p25f = Float32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ui: u32 = x.to_bits(); - let hfsq: Float32; - let f: Float32; - let s: Float32; - let z: Float32; - let r: Float32; - let w: Float32; - let t1: Float32; - let t2: Float32; - let dk: Float32; let mut hi: Float32; - let lo: Float32; let mut ix: u32; let mut k: i32; @@ -73,20 +65,20 @@ pub fn log10f(mut x: Float32) -> Float32 { ui = ix; x = Float32::from_bits(ui); - f = x - 1.0; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * LG4); - t2 = z * (LG1 + w * LG3); - r = t2 + t1; - hfsq = 0.5 * f * f; + let f: Float32 = x - 1.0; + let s: Float32 = f / (2.0 + f); + let z: Float32 = s * s; + let w: Float32 = z * z; + let t1: Float32 = w * (LG2 + w * LG4); + let t2: Float32 = z * (LG1 + w * LG3); + let r: Float32 = t2 + t1; + let hfsq: Float32 = 0.5 * f * f; hi = f - hfsq; ui = hi.to_bits(); ui &= 0xfffff000; hi = Float32::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); - dk = k as Float32; + let lo: Float32 = f - hi - hfsq + s * (hfsq + r); + let dk: Float32 = k as Float32; dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI } diff --git a/llm/math/log1p.rs b/llm/math/log1p.rs index dab5e19..2b0eff1 100644 --- a/llm/math/log1p.rs +++ b/llm/math/log1p.rs @@ -56,6 +56,7 @@ use crate::{Float64, Float32}; +consts!{ const LN2_HI: Float64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ const LN2_LO: Float64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ @@ -65,26 +66,18 @@ const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +} /// Return the natural logarithm of `1+x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1p(x: Float64) -> Float64 { let mut ui: u64 = x.to_bits(); - let hfsq: Float64; let mut f: Float64 = 0.; let mut c: Float64 = 0.; - let s: Float64; - let z: Float64; - let r: Float64; - let w: Float64; - let t1: Float64; - let t2: Float64; - let dk: Float64; - let hx: u32; let mut hu: u32; let mut k: i32; - hx = (ui >> 32) as u32; + let hx: u32 = (ui >> 32) as u32; k = 1; if hx < 0x3fda827a || (hx >> 31) > 0 { /* 1+x < sqrt(2)+ */ @@ -133,13 +126,13 @@ pub fn log1p(x: Float64) -> Float64 { ui = (hu as u64) << 32 | (ui & 0xffffffff); f = Float64::from_bits(ui) - 1.; } - hfsq = 0.5 * f * f; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * (LG4 + w * LG6)); - t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - r = t2 + t1; - dk = k as Float64; + let hfsq: Float64 = 0.5 * f * f; + let s: Float64 = f / (2.0 + f); + let z: Float64 = s * s; + let w: Float64 = z * z; + let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); + let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + let r: Float64 = t2 + t1; + let dk: Float64 = k as Float64; s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } diff --git a/llm/math/log1pf.rs b/llm/math/log1pf.rs index 0b8cffa..70735c9 100644 --- a/llm/math/log1pf.rs +++ b/llm/math/log1pf.rs @@ -12,6 +12,7 @@ use crate::Float32; +consts!{ const LN2_HI: Float32 = 6.9313812256e-01; /* 0x3f317180 */ const LN2_LO: Float32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ @@ -19,26 +20,17 @@ const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ +} /// Return the natural logarithm of `1+x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1pf(x: Float32) -> Float32 { let mut ui: u32 = x.to_bits(); - let hfsq: Float32; let mut f: Float32 = 0.; let mut c: Float32 = 0.; - let s: Float32; - let z: Float32; - let r: Float32; - let w: Float32; - let t1: Float32; - let t2: Float32; - let dk: Float32; - let ix: u32; let mut iu: u32; let mut k: i32; - - ix = ui; + let ix: u32 = ui; k = 1; if ix < 0x3ed413d0 || (ix >> 31) > 0 { /* 1+x < sqrt(2)+ */ @@ -87,13 +79,13 @@ pub fn log1pf(x: Float32) -> Float32 { ui = iu; f = Float32::from_bits(ui) - 1.; } - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * LG4); - t2 = z * (LG1 + w * LG3); - r = t2 + t1; - hfsq = 0.5 * f * f; - dk = k as Float32; + let s: Float32 = f / (2.0 + f); + let z: Float32 = s * s; + let w: Float32 = z * z; + let t1: Float32 = w * (LG2 + w * LG4); + let t2: Float32 = z * (LG1 + w * LG3); + let r: Float32 = t2 + t1; + let hfsq: Float32 = 0.5 * f * f; + let dk: Float32 = k as Float32; s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } diff --git a/llm/math/log2.rs b/llm/math/log2.rs index 02f6957..289852a 100644 --- a/llm/math/log2.rs +++ b/llm/math/log2.rs @@ -19,6 +19,7 @@ use crate::Float64; +consts!{ const IVLN2HI: Float64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ const IVLN2LO: Float64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ @@ -28,24 +29,15 @@ const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +} /// Returns the base 2 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2(mut x: Float64) -> Float64 { let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 - let mut ui: u64 = x.to_bits(); - let hfsq: Float64; - let f: Float64; - let s: Float64; - let z: Float64; - let r: Float64; let mut w: Float64; - let t1: Float64; - let t2: Float64; - let y: Float64; let mut hi: Float64; - let lo: Float64; let mut val_hi: Float64; let mut val_lo: Float64; let mut hx: u32; @@ -78,27 +70,27 @@ pub fn log2(mut x: Float64) -> Float64 { ui = (hx as u64) << 32 | (ui & 0xffffffff); x = Float64::from_bits(ui); - f = x - 1.0; - hfsq = 0.5 * f * f; - s = f / (2.0 + f); - z = s * s; + let f: Float64 = x - 1.0; + let hfsq: Float64 = 0.5 * f * f; + let s: Float64 = f / (2.0 + f); + let z: Float64 = s * s; w = z * z; - t1 = w * (LG2 + w * (LG4 + w * LG6)); - t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - r = t2 + t1; + let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); + let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + let r: Float64 = t2 + t1; /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ hi = f - hfsq; ui = hi.to_bits(); ui &= (-1i64 as u64) << 32; hi = Float64::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); + let lo: Float64 = f - hi - hfsq + s * (hfsq + r); val_hi = hi * IVLN2HI; val_lo = (lo + hi) * IVLN2LO + lo * IVLN2HI; /* spadd(val_hi, val_lo, y), except for not using double_t: */ - y = k.into(); + let y: Float64 = k.into(); w = y + val_hi; val_lo += (y - w) + val_hi; val_hi = w; diff --git a/llm/math/log2f.rs b/llm/math/log2f.rs index afa3c17..cd2cdac 100644 --- a/llm/math/log2f.rs +++ b/llm/math/log2f.rs @@ -15,6 +15,7 @@ use crate::Float32; +consts!{ const IVLN2HI: Float32 = 1.4428710938e+00; /* 0x3fb8b000 */ const IVLN2LO: Float32 = -1.7605285393e-04; /* 0xb9389ad4 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ @@ -22,23 +23,14 @@ const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ +} /// Returns the base 2 logarithm of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2f(mut x: Float32) -> Float32 { let x1p25f = Float32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 - let mut ui: u32 = x.to_bits(); - let hfsq: Float32; - let f: Float32; - let s: Float32; - let z: Float32; - let r: Float32; - let w: Float32; - let t1: Float32; - let t2: Float32; let mut hi: Float32; - let lo: Float32; let mut ix: u32; let mut k: i32; @@ -70,19 +62,19 @@ pub fn log2f(mut x: Float32) -> Float32 { ui = ix; x = Float32::from_bits(ui); - f = x - 1.0; - s = f / (2.0 + f); - z = s * s; - w = z * z; - t1 = w * (LG2 + w * LG4); - t2 = z * (LG1 + w * LG3); - r = t2 + t1; - hfsq = 0.5 * f * f; + let f: Float32 = x - 1.0; + let s: Float32 = f / (2.0 + f); + let z: Float32 = s * s; + let w: Float32 = z * z; + let t1: Float32 = w * (LG2 + w * LG4); + let t2: Float32 = z * (LG1 + w * LG3); + let r: Float32 = t2 + t1; + let hfsq: Float32 = 0.5 * f * f; hi = f - hfsq; ui = hi.to_bits(); ui &= 0xfffff000; hi = Float32::from_bits(ui); - lo = f - hi - hfsq + s * (hfsq + r); + let lo: Float32 = f - hi - hfsq + s * (hfsq + r); (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as Float32 } diff --git a/llm/math/logf.rs b/llm/math/logf.rs index 57cfdab..0042b26 100644 --- a/llm/math/logf.rs +++ b/llm/math/logf.rs @@ -15,6 +15,7 @@ use crate::Float32; +consts!{ const LN2_HI: Float32 = 6.9313812256e-01; /* 0x3f317180 */ const LN2_LO: Float32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ @@ -22,6 +23,7 @@ const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ +} /// Returns the logarithm of `x` #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] From 53cb16b1e77631a93e0742e7211e6714cb04d226 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 17:20:43 -0800 Subject: [PATCH 21/93] Finished LLM changes --- llm/math/modf.rs | 3 +-- llm/math/modff.rs | 3 +-- llm/math/nextafter.rs | 4 ++-- llm/math/pow.rs | 13 ++++++----- llm/math/powf.rs | 25 +++++++++------------ llm/math/rem_pio2.rs | 29 ++++++++++++------------ llm/math/rem_pio2_large.rs | 2 ++ llm/math/rem_pio2f.rs | 8 ++++--- llm/math/sincos.rs | 11 +++------ llm/math/sincosf.rs | 46 +++++++++++++++++--------------------- llm/math/sinh.rs | 6 ++--- llm/math/sqrtf.rs | 1 + llm/math/tanh.rs | 7 ++---- llm/math/tgamma.rs | 17 +++++++------- llm/math/trunc.rs | 3 +-- llm/math/truncf.rs | 3 +-- 16 files changed, 81 insertions(+), 100 deletions(-) diff --git a/llm/math/modf.rs b/llm/math/modf.rs index 4d64cc4..9b47899 100644 --- a/llm/math/modf.rs +++ b/llm/math/modf.rs @@ -4,7 +4,6 @@ use crate::Float64; pub fn modf(x: Float64) -> (Float64, Float64) { let rv2: Float64; let mut u = x.to_bits(); - let mask: u64; let e = ((u >> 52 & 0x7ff) as i32) - 0x3ff; /* no fractional part */ @@ -25,7 +24,7 @@ pub fn modf(x: Float64) -> (Float64, Float64) { return (x, rv2); } - mask = ((!0) >> 12) >> e; + let mask: u64 = ((!0) >> 12) >> e; if (u & mask) == 0 { rv2 = x; u &= 1 << 63; diff --git a/llm/math/modff.rs b/llm/math/modff.rs index 1bbaf1c..43f3891 100644 --- a/llm/math/modff.rs +++ b/llm/math/modff.rs @@ -4,7 +4,6 @@ use crate::Float32; pub fn modff(x: Float32) -> (Float32, Float32) { let rv2: Float32; let mut u: u32 = x.to_bits(); - let mask: u32; let e = ((u >> 23 & 0xff) as i32) - 0x7f; /* no fractional part */ @@ -24,7 +23,7 @@ pub fn modff(x: Float32) -> (Float32, Float32) { return (x, rv2); } - mask = 0x007fffff >> e; + let mask: u32 = 0x007fffff >> e; if (u & mask) == 0 { rv2 = x; u &= 0x80000000; diff --git a/llm/math/nextafter.rs b/llm/math/nextafter.rs index 9d30ea2..fef4ffc 100644 --- a/llm/math/nextafter.rs +++ b/llm/math/nextafter.rs @@ -13,8 +13,8 @@ pub fn nextafter(x: Float64, y: Float64) -> Float64 { return y; } - let ax = ux_i & !1_u64 / 2; - let ay = uy_i & !1_u64 / 2; + let ax = ux_i & (!1_u64 / 2); + let ay = uy_i & (!1_u64 / 2); if ax == 0 { if ay == 0 { return y; diff --git a/llm/math/pow.rs b/llm/math/pow.rs index cfc8f39..89d6ed8 100644 --- a/llm/math/pow.rs +++ b/llm/math/pow.rs @@ -62,6 +62,7 @@ use crate::Float64; use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; +consts!{ const BP: [Float64; 2] = [1.0, 1.5]; const DP_H: [Float64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ const DP_L: [Float64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ @@ -91,6 +92,7 @@ const CP_L: Float64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail const IVLN2: Float64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ const IVLN2_H: Float64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ const IVLN2_L: Float64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ +} /// Returns `x` raised to the power `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -101,8 +103,8 @@ pub fn pow(x: Float64, y: Float64) -> Float64 { let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); - let mut ix: i32 = (hx & 0x7fffffff) as i32; - let iy: i32 = (hy & 0x7fffffff) as i32; + let mut ix: i32 = hx & 0x7fffffff; + let iy: i32 = hy & 0x7fffffff; /* x**0 = 1, even if x is NaN */ if ((iy as u32) | ly) == 0 { @@ -267,6 +269,7 @@ pub fn pow(x: Float64, y: Float64) -> Float64 { /* now |1-x| is TINY <= 2**-20, suffice to compute log(x) by x-x^2/2+x^3/3-x^4/4 */ let t: Float64 = ax - 1.0; /* t has 20 trailing zeros */ + #[allow(clippy::excessive_precision)] let w: Float64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); let u: Float64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ let v: Float64 = t * IVLN2_L - w * IVLN2; @@ -374,7 +377,7 @@ pub fn pow(x: Float64, y: Float64) -> Float64 { } /* compute 2**(p_h+p_l) */ - let i: i32 = j & (0x7fffffff as i32); + let i: i32 = j & 0x7fffffff_i32; k = (i >> 20) - 0x3ff; let mut n: i32 = 0; @@ -613,7 +616,7 @@ mod tests { // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - (&[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS]) + [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS] .iter() .for_each(|int_set| { int_set.iter().for_each(|int| { @@ -625,7 +628,7 @@ mod tests { // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) - (&NEG[1..(NEG.len() - 1)]).iter().for_each(|set| { + NEG[1..(NEG.len() - 1)].iter().for_each(|set| { set.iter().for_each(|val| { test_sets(&ALL[3..7], &|v: Float64| pow(*val, v), &|_| NAN); }) diff --git a/llm/math/powf.rs b/llm/math/powf.rs index 1cae7c3..2fdeaae 100644 --- a/llm/math/powf.rs +++ b/llm/math/powf.rs @@ -17,6 +17,7 @@ use crate::Float32; use super::{fabsf, scalbnf, sqrtf}; +consts!{ const BP: [Float32; 2] = [1.0, 1.5]; const DP_H: [Float32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ const DP_L: [Float32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ @@ -44,6 +45,7 @@ const CP_L: Float32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ const IVLN2: Float32 = 1.4426950216e+00; const IVLN2_H: Float32 = 1.4426879883e+00; const IVLN2_L: Float32 = 7.0526075433e-06; +} /// Returns `x` raised to the power `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -54,7 +56,6 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { let z_l: Float32; let mut p_h: Float32; let mut p_l: Float32; - let y1: Float32; let mut t1: Float32; let t2: Float32; let mut r: Float32; @@ -64,22 +65,16 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { let mut u: Float32; let mut v: Float32; let mut w: Float32; - let i: i32; let mut j: i32; let mut k: i32; let mut yisint: i32; let mut n: i32; - let hx: i32; - let hy: i32; let mut ix: i32; - let iy: i32; let mut is: i32; - - hx = x.to_bits() as i32; - hy = y.to_bits() as i32; - + let hx: i32 = x.to_bits() as i32; + let hy: i32 = y.to_bits() as i32; ix = hx & 0x7fffffff; - iy = hy & 0x7fffffff; + let iy: i32 = hy & 0x7fffffff; /* x**0 = 1, even if x is NaN */ if iy == 0 { @@ -202,7 +197,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { /* now |1-x| is TINY <= 2**-20, suffice to compute log(x) by x-x^2/2+x^3/3-x^4/4 */ t = ax - 1.; /* t has 20 trailing zeros */ - w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); + w = (t * t) * (0.5 - t * (0.333_333_34 - t * 0.25)); u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ v = t * IVLN2_L - w * IVLN2; t1 = u + v; @@ -212,7 +207,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { } else { let mut s2: Float32; let mut s_h: Float32; - let s_l: Float32; + let mut t_h: Float32; let mut t_l: Float32; @@ -251,7 +246,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { is = (((ix as u32 >> 1) & 0xfffff000) | 0x20000000) as i32; t_h = Float32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); t_l = ax - (t_h - i!(BP, k as usize)); - s_l = v * ((u - s_h * t_h) - s_h * t_l); + let s_l: Float32 = v * ((u - s_h * t_h) - s_h * t_l); /* compute log(ax) */ s2 = s * s; r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); @@ -281,7 +276,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ is = y.to_bits() as i32; - y1 = Float32::from_bits(is as u32 & 0xfffff000); + let y1: Float32 = Float32::from_bits(is as u32 & 0xfffff000); p_l = (y - y1) * t1 + y * t2; p_h = y1 * t1; z = p_l + p_h; @@ -308,7 +303,7 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { /* * compute 2**(p_h+p_l) */ - i = j & 0x7fffffff; + let i: i32 = j & 0x7fffffff; k = (i >> 23) - 0x7f; n = 0; if i > 0x3f000000 { diff --git a/llm/math/rem_pio2.rs b/llm/math/rem_pio2.rs index 04b2701..d4b4545 100644 --- a/llm/math/rem_pio2.rs +++ b/llm/math/rem_pio2.rs @@ -15,30 +15,29 @@ use crate::Float64; use super::rem_pio2_large; -// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 -// #define EPS DBL_EPSILON +consts!{ const EPS: Float64 = 2.2204460492503131e-16; -// #elif FLT_EVAL_METHOD==2 -// #define EPS LDBL_EPSILON -// #endif +} // TODO: Support FLT_EVAL_METHOD? +consts!{ const TO_INT: Float64 = 1.5 / EPS; -/// 53 bits of 2/pi +// 53 bits of 2/pi const INV_PIO2: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -/// first 33 bits of pi/2 -const PIO2_1: Float64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ -/// pi/2 - PIO2_1 +// first 33 bits of pi/2 +const PIO2_1: Float64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ +// pi/2 - PIO2_1 const PIO2_1T: Float64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ -/// second 33 bits of pi/2 -const PIO2_2: Float64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ -/// pi/2 - (PIO2_1+PIO2_2) +// second 33 bits of pi/2 +const PIO2_2: Float64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ +// pi/2 - (PIO2_1+PIO2_2) const PIO2_2T: Float64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ -/// third 33 bits of pi/2 -const PIO2_3: Float64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ -/// pi/2 - (PIO2_1+PIO2_2+PIO2_3) +// third 33 bits of pi/2 +const PIO2_3: Float64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ +// pi/2 - (PIO2_1+PIO2_2+PIO2_3) const PIO2_3T: Float64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ +} /// return the remainder of x rem pi/2 in y[0]+y[1] /// use rem_pio2_large() for large x diff --git a/llm/math/rem_pio2_large.rs b/llm/math/rem_pio2_large.rs index 6aa68ef..45bfeab 100644 --- a/llm/math/rem_pio2_large.rs +++ b/llm/math/rem_pio2_large.rs @@ -121,6 +121,7 @@ const IPIO2: [i32; 690] = [ 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, ]; +consts!{ const PIO2: [Float64; 8] = [ 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ @@ -131,6 +132,7 @@ const PIO2: [Float64; 8] = [ 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ ]; +} // fn rem_pio2_large(x : &[Float64], y : &mut [Float64], e0 : i32, prec : usize) -> i32 // diff --git a/llm/math/rem_pio2f.rs b/llm/math/rem_pio2f.rs index 1a803cd..6397c92 100644 --- a/llm/math/rem_pio2f.rs +++ b/llm/math/rem_pio2f.rs @@ -20,12 +20,14 @@ use super::rem_pio2_large; const TOINT: Float64 = 1.5 / Float64::EPSILON; -/// 53 bits of 2/pi +consts!{ +// 53 bits of 2/pi const INV_PIO2: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -/// first 25 bits of pi/2 +// first 25 bits of pi/2 const PIO2_1: Float64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ -/// pi/2 - pio2_1 +// pi/2 - pio2_1 const PIO2_1T: Float64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ +} /// Return the remainder of x rem pi/2 in *y /// diff --git a/llm/math/sincos.rs b/llm/math/sincos.rs index b57c505..0a2dac2 100644 --- a/llm/math/sincos.rs +++ b/llm/math/sincos.rs @@ -17,12 +17,7 @@ use super::{get_high_word, k_cos, k_sin, rem_pio2}; /// Simultaneously computes the sine and cosine of the argument x. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincos(x: Radian64) -> (Float64, Float64) { - let s: Float64; - let c: Float64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; + let ix = get_high_word(x) & 0x7fffffff; /* |x| ~< pi/4 */ if ix <= 0x3fe921fb { @@ -48,8 +43,8 @@ pub fn sincos(x: Radian64) -> (Float64, Float64) { /* argument reduction needed */ let (n, y0, y1) = rem_pio2(x); - s = k_sin(y0, y1, 1); - c = k_cos(y0, y1); + let s = k_sin(y0, y1, 1); + let c = k_cos(y0, y1); match n & 3 { 0 => (s, c), 1 => (c, -s), diff --git a/llm/math/sincosf.rs b/llm/math/sincosf.rs index 3880d5d..fc92ae2 100644 --- a/llm/math/sincosf.rs +++ b/llm/math/sincosf.rs @@ -18,23 +18,21 @@ use crate::{Float64, Float32, Radian32}; use super::{k_cosf, k_sinf, rem_pio2f}; -/* Small multiples of pi/2 rounded to double precision. */ -const PI_2: Float32 = 0.5 * 3.1415926535897931160E+00; -const S1PIO2: Float32 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ -const S2PIO2: Float32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ -const S3PIO2: Float32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const S4PIO2: Float32 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ +use core::f32::consts::FRAC_PI_2; +use core::f32::consts::PI; + +const S1PIO2: Float32 = FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2PIO2: Float32 = PI; /* 0x400921FB, 0x54442D18 */ +const S3PIO2: Float32 = 3.0 * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4PIO2: Float32 = 2.0 * PI; /* 0x401921FB, 0x54442D18 */ /// Simultaneously computes the sine and cosine of the argument x. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincosf(x: Radian32) -> (Float32, Float32) { let s: Float32; let c: Float32; - let mut ix: u32; - let sign: bool; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; + let mut ix = x.to_bits(); + let sign: bool = (ix >> 31) != 0; ix &= 0x7fffffff; /* |x| ~<= pi/4 */ @@ -67,14 +65,12 @@ pub fn sincosf(x: Radian32) -> (Float32, Float32) { } } /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ - else { - if sign { - s = -k_sinf((x + S2PIO2) as Float64); - c = -k_cosf((x + S2PIO2) as Float64); - } else { - s = -k_sinf((x - S2PIO2) as Float64); - c = -k_cosf((x - S2PIO2) as Float64); - } + else if sign { + s = -k_sinf((x + S2PIO2) as Float64); + c = -k_cosf((x + S2PIO2) as Float64); + } else { + s = -k_sinf((x - S2PIO2) as Float64); + c = -k_cosf((x - S2PIO2) as Float64); } return (s, c); @@ -91,14 +87,12 @@ pub fn sincosf(x: Radian32) -> (Float32, Float32) { s = -k_cosf((x - S3PIO2) as Float64); c = k_sinf((x - S3PIO2) as Float64); } + } else if sign { + s = k_sinf((x + S4PIO2) as Float64); + c = k_cosf((x + S4PIO2) as Float64); } else { - if sign { - s = k_sinf((x + S4PIO2) as Float64); - c = k_cosf((x + S4PIO2) as Float64); - } else { - s = k_sinf((x - S4PIO2) as Float64); - c = k_cosf((x - S4PIO2) as Float64); - } + s = k_sinf((x - S4PIO2) as Float64); + c = k_cosf((x - S4PIO2) as Float64); } return (s, c); diff --git a/llm/math/sinh.rs b/llm/math/sinh.rs index e6ea30c..89005cf 100644 --- a/llm/math/sinh.rs +++ b/llm/math/sinh.rs @@ -16,10 +16,8 @@ pub fn sinh(x: Radian64) -> Float64 { let mut uf: Float64 = x; let mut ui: u64 = Float64::to_bits(uf); - let w: u32; let t: Float64; let mut h: Float64; - let absx: Float64; h = 0.5; if ui >> 63 != 0 { @@ -28,8 +26,8 @@ pub fn sinh(x: Radian64) -> Float64 { /* |x| */ ui &= !1 / 2; uf = Float64::from_bits(ui); - absx = uf; - w = (ui >> 32) as u32; + let absx: Float64 = uf; + let w: u32 = (ui >> 32) as u32; /* |x| < log(DBL_MAX) */ if w < 0x40862e42 { diff --git a/llm/math/sqrtf.rs b/llm/math/sqrtf.rs index 9c2c427..992cd71 100644 --- a/llm/math/sqrtf.rs +++ b/llm/math/sqrtf.rs @@ -156,6 +156,7 @@ mod tests { } #[test] + #[allow(clippy::excessive_precision)] fn conformance_tests() { let values = [ 3.14159265359f32, diff --git a/llm/math/tanh.rs b/llm/math/tanh.rs index 51df661..8b3e5c2 100644 --- a/llm/math/tanh.rs +++ b/llm/math/tanh.rs @@ -13,17 +13,14 @@ use super::expm1; pub fn tanh(mut x: Radian64) -> Float64 { let mut uf: Float64 = x; let mut ui: u64 = Float64::to_bits(uf); - - let w: u32; - let sign: bool; let mut t: Float64; /* x = |x| */ - sign = ui >> 63 != 0; + let sign: bool = ui >> 63 != 0; ui &= !1 / 2; uf = Float64::from_bits(ui); x = uf; - w = (ui >> 32) as u32; + let w: u32 = (ui >> 32) as u32; if w > 0x3fe193ea { /* |x| > log(3)/2 ~= 0.5493 or nan */ diff --git a/llm/math/tgamma.rs b/llm/math/tgamma.rs index 8cc6e54..00db919 100644 --- a/llm/math/tgamma.rs +++ b/llm/math/tgamma.rs @@ -27,7 +27,7 @@ use crate::{Float64, Float32}; use super::{exp, floor, k_cos, k_sin, pow}; -const PI: Float64 = 3.141592653589793238462643383279502884; +use core::f64::consts::PI; /* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ fn sinpi(mut x: Float64) -> Float64 { @@ -52,6 +52,7 @@ fn sinpi(mut x: Float64) -> Float64 { } } +consts!{ const N: usize = 12; //static const double g = 6.024680040776729583740234375; const GMHALF: Float64 = 5.524680040776729583740234375; @@ -111,6 +112,7 @@ const FACT: [Float64; 23] = [ 51090942171709440000.0, 1124000727777607680000.0, ]; +} /* S(x) rational function for positive x */ fn s(x: Float64) -> Float64 { @@ -136,11 +138,6 @@ fn s(x: Float64) -> Float64 { #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgamma(mut x: Float64) -> Float64 { let u: u64 = x.to_bits(); - let absx: Float64; - let mut y: Float64; - let mut dy: Float64; - let mut z: Float64; - let mut r: Float64; let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; let sign: bool = (u >> 63) != 0; @@ -183,10 +180,12 @@ pub fn tgamma(mut x: Float64) -> Float64 { return x; } - absx = if sign { -x } else { x }; + let absx: Float64 = if sign { -x } else { x }; /* handle the error of x + g - 0.5 */ - y = absx + GMHALF; + let mut y = absx + GMHALF; + let mut dy: Float64; + let mut z: Float64; if absx > GMHALF { dy = y - absx; dy -= GMHALF; @@ -196,7 +195,7 @@ pub fn tgamma(mut x: Float64) -> Float64 { } z = absx - 0.5; - r = s(absx) * exp(-y); + let mut r = s(absx) * exp(-y); if x < 0.0 { /* reflection formula for negative x */ /* sinpi(absx) is not 0, integers are already handled */ diff --git a/llm/math/trunc.rs b/llm/math/trunc.rs index a3b6a9c..79a873f 100644 --- a/llm/math/trunc.rs +++ b/llm/math/trunc.rs @@ -16,7 +16,6 @@ pub fn trunc(x: Float64) -> Float64 { let mut i: u64 = x.to_bits(); let mut e: i64 = (i >> 52 & 0x7ff) as i64 - 0x3ff + 12; - let m: u64; if e >= 52 + 12 { return x; @@ -24,7 +23,7 @@ pub fn trunc(x: Float64) -> Float64 { if e < 12 { e = 1; } - m = -1i64 as u64 >> e; + let m: u64 = -1i64 as u64 >> e; if (i & m) == 0 { return x; } diff --git a/llm/math/truncf.rs b/llm/math/truncf.rs index 7797b4e..a38b9bf 100644 --- a/llm/math/truncf.rs +++ b/llm/math/truncf.rs @@ -16,7 +16,6 @@ pub fn truncf(x: Float32) -> Float32 { let mut i: u32 = x.to_bits(); let mut e: i32 = (i >> 23 & 0xff) as i32 - 0x7f + 9; - let m: u32; if e >= 23 + 9 { return x; @@ -24,7 +23,7 @@ pub fn truncf(x: Float32) -> Float32 { if e < 9 { e = 1; } - m = -1i32 as u32 >> e; + let m: u32 = -1i32 as u32 >> e; if (i & m) == 0 { return x; } From edfade499cf19c7a3411f997b075533a7253c180 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 9 Nov 2023 17:48:27 -0800 Subject: [PATCH 22/93] Complete LLM Clippy fix --- llm/math/ilogb.rs | 1 + llm/math/ilogbf.rs | 1 + llm/math/j0.rs | 1 + llm/math/j0f.rs | 1 + llm/math/j1.rs | 1 + llm/math/j1f.rs | 1 + llm/math/jn.rs | 5 +++-- llm/math/jnf.rs | 1 + llm/math/lgamma_r.rs | 2 +- llm/math/lgammaf_r.rs | 4 ++-- llm/math/powf.rs | 13 ++++++------- llm/math/tgamma.rs | 4 ++-- 12 files changed, 21 insertions(+), 14 deletions(-) diff --git a/llm/math/ilogb.rs b/llm/math/ilogb.rs index e731321..2d3adf3 100644 --- a/llm/math/ilogb.rs +++ b/llm/math/ilogb.rs @@ -5,6 +5,7 @@ const FP_ILOGB0: i32 = FP_ILOGBNAN; /// Get exponent of floating point value #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[allow(clippy::zero_divided_by_zero)] pub fn ilogb(x: Float64) -> i32 { let mut i: u64 = x.to_bits(); let e = ((i >> 52) & 0x7ff) as i32; diff --git a/llm/math/ilogbf.rs b/llm/math/ilogbf.rs index b1f71b8..9f00ffb 100644 --- a/llm/math/ilogbf.rs +++ b/llm/math/ilogbf.rs @@ -5,6 +5,7 @@ const FP_ILOGB0: i32 = FP_ILOGBNAN; /// Get exponent of floating point value #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[allow(clippy::zero_divided_by_zero)] pub fn ilogbf(x: Float32) -> i32 { let mut i = x.to_bits(); let e = ((i >> 23) & 0xff) as i32; diff --git a/llm/math/j0.rs b/llm/math/j0.rs index a7e4432..fea0564 100644 --- a/llm/math/j0.rs +++ b/llm/math/j0.rs @@ -177,6 +177,7 @@ const V04: Float64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ /// Bessel function of the second kind of order zero /// /// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/y0.html) +#[allow(clippy::zero_divided_by_zero)] pub fn y0(x: Float64) -> Float64 { let z: Float64; let u: Float64; diff --git a/llm/math/j0f.rs b/llm/math/j0f.rs index 188608c..42b3f64 100644 --- a/llm/math/j0f.rs +++ b/llm/math/j0f.rs @@ -120,6 +120,7 @@ const V04: Float32 = 4.4111031494e-10; /* 0x2ff280c2 */ /// Bessel function of the second kind of order zero /// /// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/y0.html) +#[allow(clippy::zero_divided_by_zero)] pub fn y0f(x: Float32) -> Float32 { let ix: u32 = x.to_bits(); if (ix & 0x7fffffff) == 0 { diff --git a/llm/math/j1.rs b/llm/math/j1.rs index 4cc14ca..037472e 100644 --- a/llm/math/j1.rs +++ b/llm/math/j1.rs @@ -164,6 +164,7 @@ const V0: [Float64; 5] = [ /// Bessel function of the second kind of order one /// /// Calculates the Bessel function of the second kind of order one of `x`. +#[allow(clippy::zero_divided_by_zero)] pub fn y1(x: Float64) -> Float64 { let ix = get_high_word(x); let lx = get_low_word(x); diff --git a/llm/math/j1f.rs b/llm/math/j1f.rs index 1b8b48b..cf7ceb4 100644 --- a/llm/math/j1f.rs +++ b/llm/math/j1f.rs @@ -110,6 +110,7 @@ const V0: [Float32; 5] = [ /// Bessel function of the second kind of order one /// /// Calculates the Bessel function of the second kind of order one of `x`. +#[allow(clippy::zero_divided_by_zero)] pub fn y1f(x: Float32) -> Float32 { let ix = x.to_bits(); if (ix & 0x7fffffff) == 0 { diff --git a/llm/math/jn.rs b/llm/math/jn.rs index 29f6e70..c9684d2 100644 --- a/llm/math/jn.rs +++ b/llm/math/jn.rs @@ -107,7 +107,7 @@ pub fn jn(n: i32, mut x: Float64) -> Float64 { 0 => -cos(x) + sin(x), 1 => -cos(x) - sin(x), 2 => cos(x) - sin(x), - 3 | _ => cos(x) + sin(x), + _ => cos(x) + sin(x), }; b = INVSQRTPI * temp / sqrt(x); } else { @@ -256,6 +256,7 @@ pub fn jn(n: i32, mut x: Float64) -> Float64 { /// Bessel function of the second kind of order zero of `x`. /// /// Calculates the Bessel function of the second kind of order zero of `x`. +#[allow(clippy::zero_divided_by_zero)] pub fn yn(n: i32, x: Float64) -> Float64 { let mut ix: u32; @@ -322,7 +323,7 @@ pub fn yn(n: i32, x: Float64) -> Float64 { 0 => -sin(x) - cos(x), 1 => -sin(x) + cos(x), 2 => sin(x) + cos(x), - 3 | _ => sin(x) - cos(x), + _ => sin(x) - cos(x), }; b = INVSQRTPI * temp / sqrt(x); } else { diff --git a/llm/math/jnf.rs b/llm/math/jnf.rs index 2532d90..c3ed1c3 100644 --- a/llm/math/jnf.rs +++ b/llm/math/jnf.rs @@ -198,6 +198,7 @@ pub fn jnf(n: i32, mut x: Float32) -> Float32 { /// Bessel function of the second kind of order zero /// /// Calculates the Bessel function of the second kind of order zero of `x`. +#[allow(clippy::zero_divided_by_zero)] pub fn ynf(n: i32, x: Float32) -> Float32 { let mut ix: u32; let mut ib: u32; diff --git a/llm/math/lgamma_r.rs b/llm/math/lgamma_r.rs index 7d3c40b..3bbec43 100644 --- a/llm/math/lgamma_r.rs +++ b/llm/math/lgamma_r.rs @@ -165,7 +165,7 @@ fn sin_pi(mut x: Float64) -> Float64 { 1 => k_cos(x, 0.0), 2 => k_sin(-x, 0.0, 0), 3 => -k_cos(x, 0.0), - 0 | _ => k_sin(x, 0.0, 0), + _ => k_sin(x, 0.0, 0), } } diff --git a/llm/math/lgammaf_r.rs b/llm/math/lgammaf_r.rs index 2acd18c..27f07f3 100644 --- a/llm/math/lgammaf_r.rs +++ b/llm/math/lgammaf_r.rs @@ -94,12 +94,12 @@ fn sin_pi(mut x: Float32) -> Float32 { n = (x * 4.0) as isize; n = div!(n + 1, 2); y = (x as Float64) - (n as Float64) * 0.5; - y *= 3.141_592_653_589_793; + y *= core::f64::consts::PI; match n { 1 => k_cosf(y), 2 => k_sinf(-y), 3 => -k_cosf(y), - 0 | _ => k_sinf(y), + _ => k_sinf(y), } } diff --git a/llm/math/powf.rs b/llm/math/powf.rs index 2fdeaae..63497ab 100644 --- a/llm/math/powf.rs +++ b/llm/math/powf.rs @@ -49,6 +49,7 @@ const IVLN2_L: Float32 = 7.0526075433e-06; /// Returns `x` raised to the power `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[allow(clippy::comparison_chain)] pub fn powf(x: Float32, y: Float32) -> Float32 { let mut z: Float32; let mut ax: Float32; @@ -289,13 +290,11 @@ pub fn powf(x: Float32, y: Float32) -> Float32 { if p_l + OVT > z - p_h { return sn * HUGE * HUGE; /* overflow */ } - } else if (j & 0x7fffffff) > 0x43160000 { - /* z < -150 */ - // FIXME: check should be (uint32_t)j > 0xc3160000 - return sn * TINY * TINY; /* underflow */ - } else if j as u32 == 0xc3160000 - /* z == -150 */ - && p_l <= z - p_h + } else if + ((j & 0x7fffffff) > 0x43160000) || + (j as u32 == 0xc3160000 + /* z == -150 */ + && p_l <= z - p_h) { return sn * TINY * TINY; /* underflow */ } diff --git a/llm/math/tgamma.rs b/llm/math/tgamma.rs index 00db919..428bd51 100644 --- a/llm/math/tgamma.rs +++ b/llm/math/tgamma.rs @@ -48,7 +48,7 @@ fn sinpi(mut x: Float64) -> Float64 { 1 => k_cos(x, 0.0), 2 => k_sin(-x, 0.0, 0), 3 => -k_cos(x, 0.0), - 0 | _ => k_sin(x, 0.0, 0), + _ => k_sin(x, 0.0, 0), } } @@ -155,7 +155,7 @@ pub fn tgamma(mut x: Float64) -> Float64 { /* raise inexact when non-integer */ if x == floor(x) { if sign { - return 0.0 / 0.0; + return Float64::NAN; } if x <= FACT.len() as Float64 { return i!(FACT, (x as usize) - 1); From 5b37e108ab9ad27e3268464830ce6531fce3fad6 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 08:09:37 -0800 Subject: [PATCH 23/93] Doc Improvements + Minor Restructure --- .gitignore | 1 + .markdownlint.json | 4 +++ Cargo.toml | 13 ++++++- README.md | 16 ++++++--- docs/CONTRIBUTING.md | 9 +++++ docs/GUIDE.md | 3 ++ epearl | 17 +++++++++ epearl.bat | 35 +++++++++++++++++++ libs/README.md | 4 +++ libs/macros-core/Cargo.toml | 16 +++++++++ .../core => libs/macros-core}/ffi/mod.rs | 4 +-- .../macros/core => libs/macros-core}/lib.rs | 0 .../macros-core}/mass_impl/args.rs | 0 .../macros-core}/mass_impl/mod.rs | 0 .../macros-core}/mass_impl/variants.rs | 4 +-- libs/macros/Cargo.toml | 16 +++++++++ {utils => libs}/macros/README.md | 0 {utils => libs}/macros/lib.rs | 0 libs/scripts.py | 12 +++++++ libtrig/Cargo.toml | 10 ++++-- libtrig/README.md | 7 ++++ libtrig/vectors/vec2d.rs | 5 ++- llm/Cargo.toml | 10 ++++-- llm/README.md | 2 ++ utils/README.md | 1 - utils/macros/Cargo.toml | 12 ------- utils/macros/core/Cargo.toml | 12 ------- 27 files changed, 169 insertions(+), 44 deletions(-) create mode 100644 .markdownlint.json create mode 100644 docs/CONTRIBUTING.md create mode 100644 docs/GUIDE.md create mode 100644 epearl create mode 100644 epearl.bat create mode 100644 libs/README.md create mode 100644 libs/macros-core/Cargo.toml rename {utils/macros/core => libs/macros-core}/ffi/mod.rs (94%) rename {utils/macros/core => libs/macros-core}/lib.rs (100%) rename {utils/macros/core => libs/macros-core}/mass_impl/args.rs (100%) rename {utils/macros/core => libs/macros-core}/mass_impl/mod.rs (100%) rename {utils/macros/core => libs/macros-core}/mass_impl/variants.rs (95%) create mode 100644 libs/macros/Cargo.toml rename {utils => libs}/macros/README.md (100%) rename {utils => libs}/macros/lib.rs (100%) create mode 100644 libs/scripts.py delete mode 100644 utils/README.md delete mode 100644 utils/macros/Cargo.toml delete mode 100644 utils/macros/core/Cargo.toml diff --git a/.gitignore b/.gitignore index c4c79e0..b74fd02 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +# Rust files /*.lock target \ No newline at end of file diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..79251c3 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,4 @@ +{ + "no-inline-html": false, + "line-length": false +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index c663bb7..259ae00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,18 @@ [workspace] resolver = "2" members = [ + # Helper crates + "libs/macros-core", + "libs/macros", + + # Main crates "libtrig", "llm", - "utils/macros" ] + +[workspace.package] +authors = ["Матвей Т AtomicGamer9523@github"] +repository = "https://github.com/AtomicGamer9523/librobomath" +version = "0.1.0-dev" +edition = "2021" +license = "MIT" diff --git a/README.md b/README.md index 143db78..16efcae 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,14 @@ -# `LibRoboMath` +# `LibRoboTOP` -## A complete trigonometry, odometry, and pathing library +## A **Lib**rary for **Robo**tics, featuring **T**rigonometry, **O**dometry, and **P**athing -### Modules +### Features -- **[`llm`](./llm/)** - Low Level Math - Fundamental math functions and types -- **[`libtrig`](./libtrig/)** - Trigonometry functionality (angles, vectors, etc.) +- **[`libtrig`](./libs/libtrig//)** - Trigonometry functionality (angles, vectors, etc.) +- **[`llm`](./libs/llm/)** - Low Level Math - Fundamental math functions and types + +### Documentation + +For Developers who are planning on using this [read here](./docs/GUIDE.md). + +For Developers who are going to be contributing to this [read here](./docs/CONTRIBUTING.md). diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 0000000..35498f1 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Development Guide + +## TODO + +### Testing + +```bash +cargo tarpaulin --help +``` diff --git a/docs/GUIDE.md b/docs/GUIDE.md new file mode 100644 index 0000000..e670d8f --- /dev/null +++ b/docs/GUIDE.md @@ -0,0 +1,3 @@ +# Usage Guide + +## TODO diff --git a/epearl b/epearl new file mode 100644 index 0000000..b851886 --- /dev/null +++ b/epearl @@ -0,0 +1,17 @@ +#!/bin/sh + +app_path=$0 +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +exec "python" "$APP_HOME/libs/scripts.py" "$APP_HOME" "$@" diff --git a/epearl.bat b/epearl.bat new file mode 100644 index 0000000..4d18ea4 --- /dev/null +++ b/epearl.bat @@ -0,0 +1,35 @@ +@REM !/bin/bat + +@echo off + +@REM Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@REM Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@REM Build +set PYTHON_EXE=python.exe +%PYTHON_EXE% --version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: no 'python' command could be found in your PATH. +echo. +echo Please install Python + +:execute +"%PYTHON_EXE%" "%APP_HOME%\libs\scripts.py" "%APP_HOME%" "%*%" +:end +@REM End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd +:fail +exit /b 1 +:mainEnd +if "%OS%"=="Windows_NT" endlocal +:omega \ No newline at end of file diff --git a/libs/README.md b/libs/README.md new file mode 100644 index 0000000..10afd8a --- /dev/null +++ b/libs/README.md @@ -0,0 +1,4 @@ +# Helper Libraries + +- [**`macros`**](./macros/) - Macros used throughout the project. +- [**`macros-core`**](./macros-core/) - Core functionality for the macros. diff --git a/libs/macros-core/Cargo.toml b/libs/macros-core/Cargo.toml new file mode 100644 index 0000000..96f3c28 --- /dev/null +++ b/libs/macros-core/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "macros-core" +description = "Core functionality for the 'macros' crate" +repository.workspace = true +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true + +[lib] +path = "lib.rs" + +[dependencies] +syn = { version = "2.0", features = ["full"] } +proc-macro2 = "1.0" +quote = "1.0" diff --git a/utils/macros/core/ffi/mod.rs b/libs/macros-core/ffi/mod.rs similarity index 94% rename from utils/macros/core/ffi/mod.rs rename to libs/macros-core/ffi/mod.rs index f178805..74603b5 100644 --- a/utils/macros/core/ffi/mod.rs +++ b/libs/macros-core/ffi/mod.rs @@ -3,8 +3,8 @@ use crate::TokenStream; /// Simplifies the creation of FFI functions /// /// # Example -/// ``` -/// #[utils::ffi(type = "system")] +/// ```rust,ignore,no_run +/// #[macros::ffi(type = "system")] /// pub fn Java_Main_greet<'a>( /// mut env: JNIEnv<'a>, _class: JClass<'a>, input: JString<'a> /// ) -> jstring { diff --git a/utils/macros/core/lib.rs b/libs/macros-core/lib.rs similarity index 100% rename from utils/macros/core/lib.rs rename to libs/macros-core/lib.rs diff --git a/utils/macros/core/mass_impl/args.rs b/libs/macros-core/mass_impl/args.rs similarity index 100% rename from utils/macros/core/mass_impl/args.rs rename to libs/macros-core/mass_impl/args.rs diff --git a/utils/macros/core/mass_impl/mod.rs b/libs/macros-core/mass_impl/mod.rs similarity index 100% rename from utils/macros/core/mass_impl/mod.rs rename to libs/macros-core/mass_impl/mod.rs diff --git a/utils/macros/core/mass_impl/variants.rs b/libs/macros-core/mass_impl/variants.rs similarity index 95% rename from utils/macros/core/mass_impl/variants.rs rename to libs/macros-core/mass_impl/variants.rs index 1af0dd3..52ed5bc 100644 --- a/utils/macros/core/mass_impl/variants.rs +++ b/libs/macros-core/mass_impl/variants.rs @@ -2,7 +2,7 @@ /// /// Input generally looks like this: /// -/// ```rust,no_run,ignore +/// ```rust,ignore,no_run /// $NAME = @RM SomeStruct /// ``` /// @@ -54,7 +54,7 @@ impl std::fmt::Debug for TypeVariant { impl syn::parse::Parse for TypeVariant { /// Turns this: /// - /// ``` + /// ```rust,ignore,no_run /// $NAME = @RM SomeStruct, /// ``` /// diff --git a/libs/macros/Cargo.toml b/libs/macros/Cargo.toml new file mode 100644 index 0000000..6a9d92c --- /dev/null +++ b/libs/macros/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "macros" +description = "A collection of macros used throughout the project" +repository.workspace = true +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true + +[lib] +proc-macro = true +path = "lib.rs" + +[dependencies.mc] +package = "macros-core" +path = "../macros-core" diff --git a/utils/macros/README.md b/libs/macros/README.md similarity index 100% rename from utils/macros/README.md rename to libs/macros/README.md diff --git a/utils/macros/lib.rs b/libs/macros/lib.rs similarity index 100% rename from utils/macros/lib.rs rename to libs/macros/lib.rs diff --git a/libs/scripts.py b/libs/scripts.py new file mode 100644 index 0000000..b3c6ca2 --- /dev/null +++ b/libs/scripts.py @@ -0,0 +1,12 @@ +def main(): + raise Exception("TODO!") + +if __name__ == "__main__": + try: main() + except KeyboardInterrupt: + print("Interrupted by user") + exit(1) + except Exception as e: + print("Error: {}".format(e)) + exit(1) + exit(0) \ No newline at end of file diff --git a/libtrig/Cargo.toml b/libtrig/Cargo.toml index 819b6bd..27173ba 100644 --- a/libtrig/Cargo.toml +++ b/libtrig/Cargo.toml @@ -1,11 +1,15 @@ [package] name = "libtrig" -version = "0.1.0" -edition = "2021" +description = "Trigonometry functionality" +repository.workspace = true +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true [dependencies.macros] package = "macros" -path = "../utils/macros" +path = "../libs/macros" [dependencies.llm] package = "llm" diff --git a/libtrig/README.md b/libtrig/README.md index e69de29..32d5557 100644 --- a/libtrig/README.md +++ b/libtrig/README.md @@ -0,0 +1,7 @@ +# LibTrig + +## Trigonometry functionality (angles, vectors, etc.) + +Uses [`llm`](../llm/) for math functions. + +It is primarily intended to be used by other libraries that require trigonometry functionality. Such as [`libodo`](../libodo/) for odometry, and [`libpath`](../libpath/) for pathing. diff --git a/libtrig/vectors/vec2d.rs b/libtrig/vectors/vec2d.rs index 8dc3248..3d4b036 100644 --- a/libtrig/vectors/vec2d.rs +++ b/libtrig/vectors/vec2d.rs @@ -76,10 +76,9 @@ impl Vec2D { /// Normalizes this vector. #[inline] #[must_use] - pub fn normalize(&mut self) { + pub fn normalize(&self) -> Self { let magnitude = self.magnitude(); - self.0 /= magnitude; - self.1 /= magnitude; + Self(self.x() / magnitude, self.y() / magnitude) } } diff --git a/llm/Cargo.toml b/llm/Cargo.toml index 800a966..acd533d 100644 --- a/llm/Cargo.toml +++ b/llm/Cargo.toml @@ -1,14 +1,18 @@ [package] name = "llm" -version = "0.1.0" -edition = "2021" +description = "Low Level Math" +repository.workspace = true +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true [lib] path = "lib.rs" doctest = false [dependencies.macros] -path = "../utils/macros" +path = "../libs/macros" [features] default = ["unstable"] diff --git a/llm/README.md b/llm/README.md index 4f5506b..25892dc 100644 --- a/llm/README.md +++ b/llm/README.md @@ -1,3 +1,5 @@ # **L**ow **L**evel **M**ath

A port of MUSL's Math library to Rust for no_std environments.

+ +### It is exceptionally rare that you should use this library directly. It is intended to be used by other libraries that require math functionality. If you are looking for a math library, you should probably be using [`libtrig`](../libtrig/). diff --git a/utils/README.md b/utils/README.md deleted file mode 100644 index 7267259..0000000 --- a/utils/README.md +++ /dev/null @@ -1 +0,0 @@ -# Utilities diff --git a/utils/macros/Cargo.toml b/utils/macros/Cargo.toml deleted file mode 100644 index 26f0317..0000000 --- a/utils/macros/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "macros" -version = "0.1.0" -edition = "2021" - -[lib] -proc-macro = true -path = "lib.rs" - -[dependencies.mc] -package = "macros-core" -path = "./core" diff --git a/utils/macros/core/Cargo.toml b/utils/macros/core/Cargo.toml deleted file mode 100644 index 07cd871..0000000 --- a/utils/macros/core/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "macros-core" -version = "0.1.0" -edition = "2021" - -[lib] -path = "lib.rs" - -[dependencies] -syn = { version = "2.0", features = ["full"] } -proc-macro2 = "1.0" -quote = "1.0" From e25d1bad6fbdf9d7be12d73cde3ba6250d160933 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 08:49:32 -0800 Subject: [PATCH 24/93] Links Fix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 16efcae..c523ec0 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ ### Features -- **[`libtrig`](./libs/libtrig//)** - Trigonometry functionality (angles, vectors, etc.) -- **[`llm`](./libs/llm/)** - Low Level Math - Fundamental math functions and types +- **[`libtrig`](./libtrig//)** - Trigonometry functionality (angles, vectors, etc.) +- **[`llm`](./llm/)** - Low Level Math - Fundamental math functions and types ### Documentation From 984e4259bed751751751e578ccd92bf868f328f5 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 15:37:52 -0800 Subject: [PATCH 25/93] Tooling + Workflows --- .github/funding.yml | 1 + .github/workflows/ci.yml | 73 ++++++++++++++++++++++++++++++++++++++++ .gitignore | 5 ++- epearl | 2 +- epearl.bat | 2 +- epearl.py | 43 +++++++++++++++++++++++ libs/__init__.py | 0 libs/scripts.py | 38 +++++++++++++++------ 8 files changed, 150 insertions(+), 14 deletions(-) create mode 100644 .github/funding.yml create mode 100644 .github/workflows/ci.yml create mode 100644 epearl.py create mode 100644 libs/__init__.py diff --git a/.github/funding.yml b/.github/funding.yml new file mode 100644 index 0000000..a5330d2 --- /dev/null +++ b/.github/funding.yml @@ -0,0 +1 @@ +github: Atomicgamer9523 \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4e5acae --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,73 @@ +name: CI + +on: + push: + branches: [ main ] + pull_request: + workflow_dispatch: + +jobs: + # If anything fails, the whole workflow fails. + ci-pass: + name: CI Pass + needs: [style, android, linux] + runs-on: ubuntu-latest + + # Check style. + style: + name: Style + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Rust + uses: dtolnay/rust-toolchain@stable + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + - name: Check style + run: ./epearl fmt --check + + # Check if the Android build works. + android: + name: Android + needs: [style] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Rust + uses: dtolnay/rust-toolchain@stable + with: + profile: minimal + target: aarch64-linux-android + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + - name: Build Android + run: ./epearl build --target aarch64-linux-android + - name: Test Android + run: ./epearl test --target aarch64-linux-android + + # Check if the Linux build works. + linux: + name: Linux + needs: [style] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Rust + uses: dtolnay/rust-toolchain@stable + with: + profile: minimal + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + - name: Build Android + run: ./epearl build + - name: Test Android + run: ./epearl test diff --git a/.gitignore b/.gitignore index b74fd02..8fb9b02 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ # Rust files /*.lock -target \ No newline at end of file +target + +# Python files +__pycache__ \ No newline at end of file diff --git a/epearl b/epearl index b851886..ba942b7 100644 --- a/epearl +++ b/epearl @@ -14,4 +14,4 @@ do done APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit -exec "python" "$APP_HOME/libs/scripts.py" "$APP_HOME" "$@" +exec "python" "$APP_HOME/epearl.py" "$APP_HOME" "$@" diff --git a/epearl.bat b/epearl.bat index 4d18ea4..f2cbd74 100644 --- a/epearl.bat +++ b/epearl.bat @@ -24,7 +24,7 @@ echo. echo Please install Python :execute -"%PYTHON_EXE%" "%APP_HOME%\libs\scripts.py" "%APP_HOME%" "%*%" +"%PYTHON_EXE%" %APP_HOME%/epearl.py %APP_HOME% %*% :end @REM End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd diff --git a/epearl.py b/epearl.py new file mode 100644 index 0000000..93ccf5e --- /dev/null +++ b/epearl.py @@ -0,0 +1,43 @@ +from libs.scripts import run_cmd, hlp + +# Parse command line arguments +def get_args() -> tuple[str, list[str]]: + # Import sys + import sys + # Get the directory path (This is always supplied via the './epearl' script files) + dir_path = sys.argv[1] + # Replace backslashes with forward slashes + if '\\' in dir_path: dir_path = dir_path.replace('\\', '/') + # Add a trailing slash if there isn't one + if dir_path[-1] != "/": dir_path += "/" + # Get the other arguments + other_args = sys.argv[2:] + # Return the directory path and the other arguments + return (dir_path, other_args) + +# Run the main function +def main() -> str | int | None: + # Get the command line arguments + (cd, args) = get_args() + # Try to get the command and its arguments + try: + # Get the command and its arguments + (cmd, args) = (args[0], args[1:]) + except IndexError: + # If there is no command, run the help command + return hlp() + # Run the command + return run_cmd(cmd, cd, args) + +# Run main() if this file is run directly +if __name__ == "__main__": + # Run main() and return its exit code + try: exit(main()) + # If we were interrupted by the user, exit with code -1 + except KeyboardInterrupt: + print("Interrupted by user") + exit(-1) + # If there was an error, print it and exit with code 1 + except Exception as e: + print("Error: {}".format(e)) + exit(1) diff --git a/libs/__init__.py b/libs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/libs/scripts.py b/libs/scripts.py index b3c6ca2..791e5a7 100644 --- a/libs/scripts.py +++ b/libs/scripts.py @@ -1,12 +1,28 @@ -def main(): - raise Exception("TODO!") - -if __name__ == "__main__": - try: main() - except KeyboardInterrupt: - print("Interrupted by user") - exit(1) - except Exception as e: - print("Error: {}".format(e)) - exit(1) +import subprocess + +def run_cmd(cmd: str, cwd: str, args: list[str]) -> str | int | None: + if cmd == "help" or cmd == "--help" or cmd == "-h": return hlp() + if cmd == "build": return build(cwd, args) + if cmd == "test": return test(cwd, args) + if cmd == "fmt": return fmt(cwd, args) + + return f"Unknown command: {cmd}" + +def fmt(cd: str, args: list[str]) -> str | int | None: + cmd = ["cargo", "fmt"] + if '--check' in args: cmd.extend(['--', '--check']) + subprocess.run(cmd, cwd=cd) + +def test(cd: str, args: list[str]) -> str | int | None: + cmd = ["cargo", "tarpaulin"] + cmd.extend(args) + subprocess.run(cmd, cwd=cd) + +def build(cd: str, args: list[str]) -> str | int | None: + cmd = ["cargo", "build"] + cmd.extend(args) + subprocess.run(cmd, cwd=cd) + +def hlp() -> None: + print("") exit(0) \ No newline at end of file From 3f14230820d4c946b67b42c1fe56b999083567fe Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 16:02:55 -0800 Subject: [PATCH 26/93] Minor CI fix --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e5acae..829ebf3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,8 @@ jobs: name: CI Pass needs: [style, android, linux] runs-on: ubuntu-latest + steps: + - run: echo "CI passed!" # Check style. style: From 8aaed6d28fd653014e3b829792575f5f37c16bff Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 16:06:13 -0800 Subject: [PATCH 27/93] Permission fix --- .github/workflows/ci.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 829ebf3..bd813f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,9 @@ name: CI +env: + RUST_BACKTRACE: 1 + CARGO_INCREMENTAL: 0 + on: push: branches: [ main ] @@ -28,6 +32,8 @@ jobs: uses: actions/setup-python@v4 with: python-version: 3.11 + - name: Give permission to run epearl + run: chmod +x epearl - name: Check style run: ./epearl fmt --check @@ -48,6 +54,8 @@ jobs: uses: actions/setup-python@v4 with: python-version: 3.11 + - name: Give permission to run epearl + run: chmod +x epearl - name: Build Android run: ./epearl build --target aarch64-linux-android - name: Test Android @@ -69,6 +77,8 @@ jobs: uses: actions/setup-python@v4 with: python-version: 3.11 + - name: Give permission to run epearl + run: chmod +x epearl - name: Build Android run: ./epearl build - name: Test Android From e93e13e1ce451ce967c01f1adc35c606a8ec11af Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 16:07:26 -0800 Subject: [PATCH 28/93] Bash ? --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd813f8..b99d971 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: - name: Give permission to run epearl run: chmod +x epearl - name: Check style - run: ./epearl fmt --check + run: bash ./epearl fmt --check # Check if the Android build works. android: @@ -57,9 +57,9 @@ jobs: - name: Give permission to run epearl run: chmod +x epearl - name: Build Android - run: ./epearl build --target aarch64-linux-android + run: bash ./epearl build --target aarch64-linux-android - name: Test Android - run: ./epearl test --target aarch64-linux-android + run: bash ./epearl test --target aarch64-linux-android # Check if the Linux build works. linux: @@ -80,6 +80,6 @@ jobs: - name: Give permission to run epearl run: chmod +x epearl - name: Build Android - run: ./epearl build + run: bash ./epearl build - name: Test Android - run: ./epearl test + run: bash ./epearl test From 5192a7c01f62e1d4fedbf6fdcbd9457394e94db8 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 16:08:21 -0800 Subject: [PATCH 29/93] Shell <- Bash ? --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b99d971..e5f77ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: - name: Give permission to run epearl run: chmod +x epearl - name: Check style - run: bash ./epearl fmt --check + run: sh ./epearl fmt --check # Check if the Android build works. android: @@ -57,9 +57,9 @@ jobs: - name: Give permission to run epearl run: chmod +x epearl - name: Build Android - run: bash ./epearl build --target aarch64-linux-android + run: sh ./epearl build --target aarch64-linux-android - name: Test Android - run: bash ./epearl test --target aarch64-linux-android + run: sh ./epearl test --target aarch64-linux-android # Check if the Linux build works. linux: @@ -78,8 +78,8 @@ jobs: with: python-version: 3.11 - name: Give permission to run epearl - run: chmod +x epearl + run: sh +x epearl - name: Build Android - run: bash ./epearl build + run: sh ./epearl build - name: Test Android - run: bash ./epearl test + run: sh ./epearl test From 0db4f5924a1238d45a3e3d4568256f33f3ecf9f0 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 16:10:04 -0800 Subject: [PATCH 30/93] Just chmod ? --- .github/workflows/ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5f77ea..1d6154c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,9 +33,9 @@ jobs: with: python-version: 3.11 - name: Give permission to run epearl - run: chmod +x epearl + run: chmod +x ./epearl.sh - name: Check style - run: sh ./epearl fmt --check + run: ./epearl.sh fmt --check # Check if the Android build works. android: @@ -55,11 +55,11 @@ jobs: with: python-version: 3.11 - name: Give permission to run epearl - run: chmod +x epearl + run: chmod +x ./epearl.sh - name: Build Android - run: sh ./epearl build --target aarch64-linux-android + run: ./epearl.sh build --target aarch64-linux-android - name: Test Android - run: sh ./epearl test --target aarch64-linux-android + run: ./epearl.sh test --target aarch64-linux-android # Check if the Linux build works. linux: @@ -78,8 +78,8 @@ jobs: with: python-version: 3.11 - name: Give permission to run epearl - run: sh +x epearl + run: chmod +x ./epearl.sh - name: Build Android - run: sh ./epearl build + run: ./epearl.sh build - name: Test Android - run: sh ./epearl test + run: ./epearl.sh test From 3229ccf62679945576b63e055615a7c71f1bd116 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 16:10:40 -0800 Subject: [PATCH 31/93] Rename --- epearl => epearl.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename epearl => epearl.sh (100%) diff --git a/epearl b/epearl.sh similarity index 100% rename from epearl rename to epearl.sh From 55c62719c6c3ffd47bea12ecbad19c68bd315c3a Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 16:12:11 -0800 Subject: [PATCH 32/93] Rename + CRLF -> LF --- .github/workflows/ci.yml | 16 ++++++++-------- epearl.sh => epearl | 34 +++++++++++++++++----------------- 2 files changed, 25 insertions(+), 25 deletions(-) rename epearl.sh => epearl (96%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d6154c..1523cc9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,9 +33,9 @@ jobs: with: python-version: 3.11 - name: Give permission to run epearl - run: chmod +x ./epearl.sh + run: chmod +x ./epearl - name: Check style - run: ./epearl.sh fmt --check + run: ./epearl fmt --check # Check if the Android build works. android: @@ -55,11 +55,11 @@ jobs: with: python-version: 3.11 - name: Give permission to run epearl - run: chmod +x ./epearl.sh + run: chmod +x ./epearl - name: Build Android - run: ./epearl.sh build --target aarch64-linux-android + run: ./epearl build --target aarch64-linux-android - name: Test Android - run: ./epearl.sh test --target aarch64-linux-android + run: ./epearl test --target aarch64-linux-android # Check if the Linux build works. linux: @@ -78,8 +78,8 @@ jobs: with: python-version: 3.11 - name: Give permission to run epearl - run: chmod +x ./epearl.sh + run: chmod +x ./epearl - name: Build Android - run: ./epearl.sh build + run: ./epearl build - name: Test Android - run: ./epearl.sh test + run: ./epearl test diff --git a/epearl.sh b/epearl similarity index 96% rename from epearl.sh rename to epearl index ba942b7..db711d1 100644 --- a/epearl.sh +++ b/epearl @@ -1,17 +1,17 @@ -#!/bin/sh - -app_path=$0 -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit -exec "python" "$APP_HOME/epearl.py" "$APP_HOME" "$@" +#!/bin/sh + +app_path=$0 +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +exec "python" "$APP_HOME/epearl.py" "$APP_HOME" "$@" From a5e4720c6e8e174136adf7576393b2a40485b11e Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 16:15:54 -0800 Subject: [PATCH 33/93] Added target installation --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1523cc9..69faf0f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: needs: [style, android, linux] runs-on: ubuntu-latest steps: - - run: echo "CI passed!" + - run: exit 0 # Check style. style: @@ -48,8 +48,9 @@ jobs: - name: Set up Rust uses: dtolnay/rust-toolchain@stable with: - profile: minimal target: aarch64-linux-android + - name: Install rustup target + run: rustup target add aarch64-linux-android - name: Set up Python uses: actions/setup-python@v4 with: From 27a15eb4ed3ccb29ecae527643ce6508aa5bb622 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 16:24:27 -0800 Subject: [PATCH 34/93] fmt + cli fix --- libs/macros-core/ffi/mod.rs | 156 ++--- libs/macros-core/lib.rs | 22 +- libs/macros-core/mass_impl/args.rs | 93 ++- libs/macros-core/mass_impl/mod.rs | 92 ++- libs/macros-core/mass_impl/variants.rs | 218 +++---- libs/macros/lib.rs | 33 +- libs/scripts.py | 9 +- libtrig/angle.rs | 850 ++++++++++++------------- libtrig/coords/coord2d.rs | 589 +++++++++-------- libtrig/coords/mod.rs | 10 +- libtrig/lib.rs | 46 +- libtrig/traits/mod.rs | 166 ++--- libtrig/traits/number.rs | 34 +- libtrig/types.rs | 32 +- llm/lib.rs | 104 ++- llm/math.rs | 321 +++++----- 16 files changed, 1396 insertions(+), 1379 deletions(-) diff --git a/libs/macros-core/ffi/mod.rs b/libs/macros-core/ffi/mod.rs index 74603b5..53de198 100644 --- a/libs/macros-core/ffi/mod.rs +++ b/libs/macros-core/ffi/mod.rs @@ -1,78 +1,78 @@ -use crate::TokenStream; - -/// Simplifies the creation of FFI functions -/// -/// # Example -/// ```rust,ignore,no_run -/// #[macros::ffi(type = "system")] -/// pub fn Java_Main_greet<'a>( -/// mut env: JNIEnv<'a>, _class: JClass<'a>, input: JString<'a> -/// ) -> jstring { -/// // First, we have to get the string out of Java. Check out the `strings` -/// // module for more info on how this works. -/// let input: String = env.get_string(&input).expect("Couldn't get java string!").into(); -/// -/// // Then we have to create a new Java string to return. Again, more info -/// // in the `strings` module. -/// let output = env.new_string( -/// format!("Hello, {}!", input) -/// ).expect("Couldn't create java string!"); -/// -/// // Finally, extract the raw pointer to return. -/// output.into_raw() -/// } -/// ``` -pub fn ffi>(cfg: T, input: T) -> TokenStream { - let res = parse_func(input.into()).to_string(); - let settings = parse_settings(cfg.into()); - let res = res.replace("__FFI_RAW_MODIFIERS__", &settings.0); - let res = res.replace("__FFI_EXTERN_MODIFIER__", &settings.1); - match syn::parse_str::(&res) { - Ok(res) => res, - Err(err) => err.to_compile_error(), - } -} - -/// parses the function it should be attached to -fn parse_func(item: TokenStream) -> TokenStream { - let input = match syn::parse2::(item) { - Ok(input) => input, - Err(err) => { - return err.to_compile_error(); - } - }; - let ret = &input.sig.output; - let inputs = &input.sig.inputs; - let name = &input.sig.ident; - let generics = &input.sig.generics; - let body = &input.block; - let attrs = &input.attrs; - let vis = &input.vis; - let result = quote::quote! { - #(#attrs)* - #[no_mangle] - #vis __FFI_RAW_MODIFIERS__ extern __FFI_EXTERN_MODIFIER__ fn #name #generics(#inputs) #ret { - #body - } - }; - result -} - -/// parses the settings (can be none, const, unsafe or both) -fn parse_settings(attr: TokenStream) -> (String, String) { - let modifiers_str = attr.to_string(); - let mut res = String::new(); - if modifiers_str.contains("const") { - res.push_str("const "); - } - if modifiers_str.contains("unsafe") { - res.push_str("unsafe "); - } - let t = if modifiers_str.contains("type=") { - let type_str = modifiers_str.split("type=").collect::>()[1]; - type_str.split(' ').collect::>()[0] - } else { - "C" - }; - (res, format!("\"{}\"",t)) -} +use crate::TokenStream; + +/// Simplifies the creation of FFI functions +/// +/// # Example +/// ```rust,ignore,no_run +/// #[macros::ffi(type = "system")] +/// pub fn Java_Main_greet<'a>( +/// mut env: JNIEnv<'a>, _class: JClass<'a>, input: JString<'a> +/// ) -> jstring { +/// // First, we have to get the string out of Java. Check out the `strings` +/// // module for more info on how this works. +/// let input: String = env.get_string(&input).expect("Couldn't get java string!").into(); +/// +/// // Then we have to create a new Java string to return. Again, more info +/// // in the `strings` module. +/// let output = env.new_string( +/// format!("Hello, {}!", input) +/// ).expect("Couldn't create java string!"); +/// +/// // Finally, extract the raw pointer to return. +/// output.into_raw() +/// } +/// ``` +pub fn ffi>(cfg: T, input: T) -> TokenStream { + let res = parse_func(input.into()).to_string(); + let settings = parse_settings(cfg.into()); + let res = res.replace("__FFI_RAW_MODIFIERS__", &settings.0); + let res = res.replace("__FFI_EXTERN_MODIFIER__", &settings.1); + match syn::parse_str::(&res) { + Ok(res) => res, + Err(err) => err.to_compile_error(), + } +} + +/// parses the function it should be attached to +fn parse_func(item: TokenStream) -> TokenStream { + let input = match syn::parse2::(item) { + Ok(input) => input, + Err(err) => { + return err.to_compile_error(); + } + }; + let ret = &input.sig.output; + let inputs = &input.sig.inputs; + let name = &input.sig.ident; + let generics = &input.sig.generics; + let body = &input.block; + let attrs = &input.attrs; + let vis = &input.vis; + let result = quote::quote! { + #(#attrs)* + #[no_mangle] + #vis __FFI_RAW_MODIFIERS__ extern __FFI_EXTERN_MODIFIER__ fn #name #generics(#inputs) #ret { + #body + } + }; + result +} + +/// parses the settings (can be none, const, unsafe or both) +fn parse_settings(attr: TokenStream) -> (String, String) { + let modifiers_str = attr.to_string(); + let mut res = String::new(); + if modifiers_str.contains("const") { + res.push_str("const "); + } + if modifiers_str.contains("unsafe") { + res.push_str("unsafe "); + } + let t = if modifiers_str.contains("type=") { + let type_str = modifiers_str.split("type=").collect::>()[1]; + type_str.split(' ').collect::>()[0] + } else { + "C" + }; + (res, format!("\"{}\"", t)) +} diff --git a/libs/macros-core/lib.rs b/libs/macros-core/lib.rs index 2f66cc6..ae0ecc9 100644 --- a/libs/macros-core/lib.rs +++ b/libs/macros-core/lib.rs @@ -1,11 +1,11 @@ -//! A collection of core functionality for the macros. - -#![warn(missing_docs, unused, clippy::all)] - -use proc_macro2::TokenStream; - -mod mass_impl; -mod ffi; - -pub use mass_impl::mass_impl; -pub use ffi::ffi; +//! A collection of core functionality for the macros. + +#![warn(missing_docs, unused, clippy::all)] + +use proc_macro2::TokenStream; + +mod ffi; +mod mass_impl; + +pub use ffi::ffi; +pub use mass_impl::mass_impl; diff --git a/libs/macros-core/mass_impl/args.rs b/libs/macros-core/mass_impl/args.rs index c41e1d5..82a031c 100644 --- a/libs/macros-core/mass_impl/args.rs +++ b/libs/macros-core/mass_impl/args.rs @@ -1,47 +1,46 @@ -//! Argument parsing for the `mass_impl` macro. - -pub use super::variants::TypeVariant; - -/// The configuration for the `mass_impl` macro. -pub struct MassImplMacroConfig { - /// The type variants to implement the trait for. - pub type_variants: Vec, -} - -impl std::fmt::Debug for MassImplMacroConfig { - /// Formats a `TypeVariant` - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("MassImplMacroConfig") - .field("type_variants", &self.type_variants) - .field("number_of_passthroughs", &self.number_of_passthroughs()) - .finish() - } -} - -impl MassImplMacroConfig { - /// Returns the number of passthroughs for this type variant. - pub fn number_of_passthroughs(&self) -> i32 { - let mut i = 1; - for variant in &self.type_variants { - i *= variant.number_of_passthroughs(); - } - i - } -} - -// parses this: -// $SELF = @R @M Vec2D, -// $OTHER = @R @M Vec2D -// -impl syn::parse::Parse for MassImplMacroConfig { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let mut type_variants = Vec::new(); - let vars = syn::punctuated::Punctuated::::parse_terminated(input)?; - for var in vars { - type_variants.push(var); - } - Ok(MassImplMacroConfig { - type_variants, - }) - } -} \ No newline at end of file +//! Argument parsing for the `mass_impl` macro. + +pub use super::variants::TypeVariant; + +/// The configuration for the `mass_impl` macro. +pub struct MassImplMacroConfig { + /// The type variants to implement the trait for. + pub type_variants: Vec, +} + +impl std::fmt::Debug for MassImplMacroConfig { + /// Formats a `TypeVariant` + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("MassImplMacroConfig") + .field("type_variants", &self.type_variants) + .field("number_of_passthroughs", &self.number_of_passthroughs()) + .finish() + } +} + +impl MassImplMacroConfig { + /// Returns the number of passthroughs for this type variant. + pub fn number_of_passthroughs(&self) -> i32 { + let mut i = 1; + for variant in &self.type_variants { + i *= variant.number_of_passthroughs(); + } + i + } +} + +// parses this: +// $SELF = @R @M Vec2D, +// $OTHER = @R @M Vec2D +// +impl syn::parse::Parse for MassImplMacroConfig { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let mut type_variants = Vec::new(); + let vars = + syn::punctuated::Punctuated::::parse_terminated(input)?; + for var in vars { + type_variants.push(var); + } + Ok(MassImplMacroConfig { type_variants }) + } +} diff --git a/libs/macros-core/mass_impl/mod.rs b/libs/macros-core/mass_impl/mod.rs index df384c6..e60835c 100644 --- a/libs/macros-core/mass_impl/mod.rs +++ b/libs/macros-core/mass_impl/mod.rs @@ -1,47 +1,45 @@ -use crate::TokenStream; - -mod variants; -mod args; - -/// A macro for implementing a trait for a list of types. -pub fn mass_impl>(cfg: T, input: T) -> TokenStream { - let cfg: TokenStream = cfg.into(); - let input: TokenStream = input.into(); - let config = match syn::parse2::(cfg) { - Ok(config) => config, - Err(err) => { - return err.to_compile_error(); - } - }; - let mut results = vec![input.to_string()]; - - for tv in &config.type_variants { - let mut temp_results = Vec::new(); - if tv.allow_owned { - for r in &results { - let new = r.replace(&tv.alias.to_string(), &tv.ty.to_string()); - temp_results.push(new); - } - } - if tv.allow_ref { - for r in &results { - let new = r.replace(&tv.alias.to_string(), &format!("&{}", tv.ty)); - temp_results.push(new); - } - } - if tv.allow_mut { - for r in &results { - let new = r.replace(&tv.alias.to_string(), &format!("&mut {}", tv.ty)); - temp_results.push(new); - } - } - results = temp_results; - } - let single_str = results.join("\n"); - match syn::parse_str::(&single_str) { - Ok(ts) => ts, - Err(err) => { - err.to_compile_error() - } - } -} \ No newline at end of file +use crate::TokenStream; + +mod args; +mod variants; + +/// A macro for implementing a trait for a list of types. +pub fn mass_impl>(cfg: T, input: T) -> TokenStream { + let cfg: TokenStream = cfg.into(); + let input: TokenStream = input.into(); + let config = match syn::parse2::(cfg) { + Ok(config) => config, + Err(err) => { + return err.to_compile_error(); + } + }; + let mut results = vec![input.to_string()]; + + for tv in &config.type_variants { + let mut temp_results = Vec::new(); + if tv.allow_owned { + for r in &results { + let new = r.replace(&tv.alias.to_string(), &tv.ty.to_string()); + temp_results.push(new); + } + } + if tv.allow_ref { + for r in &results { + let new = r.replace(&tv.alias.to_string(), &format!("&{}", tv.ty)); + temp_results.push(new); + } + } + if tv.allow_mut { + for r in &results { + let new = r.replace(&tv.alias.to_string(), &format!("&mut {}", tv.ty)); + temp_results.push(new); + } + } + results = temp_results; + } + let single_str = results.join("\n"); + match syn::parse_str::(&single_str) { + Ok(ts) => ts, + Err(err) => err.to_compile_error(), + } +} diff --git a/libs/macros-core/mass_impl/variants.rs b/libs/macros-core/mass_impl/variants.rs index 52ed5bc..a00c4f1 100644 --- a/libs/macros-core/mass_impl/variants.rs +++ b/libs/macros-core/mass_impl/variants.rs @@ -1,107 +1,111 @@ -/// A type variant, used in the `#[mass_impl(...)]` macro. -/// -/// Input generally looks like this: -/// -/// ```rust,ignore,no_run -/// $NAME = @RM SomeStruct -/// ``` -/// -/// Which essentially means: -/// - `$NAME` is the alias for `SomeStruct` -/// - `@R` means that `SomeStruct` can be passed by reference -/// - `@RM` means that `SomeStruct` can be passed by mutable reference -/// -/// So it will create 3 bodies for the macro: -/// - `impl SomeTrait for SomeStruct` -/// - `impl SomeTrait for &SomeStruct` -/// - `impl SomeTrait for &mut SomeStruct` -pub struct TypeVariant { - /// The alias for the type (e.g. `$NAME`) - pub alias: syn::Ident, - /// The type (e.g. `SomeStruct`) - pub ty: syn::Ident, - /// Whether or not the type can be passed by value - pub allow_owned: bool, - /// Whether or not the type can be passed by reference - pub allow_ref: bool, - /// Whether or not the type can be passed by mutable reference - pub allow_mut: bool, -} - -impl TypeVariant { - /// Returns the number of passthroughs for this type variant. - pub fn number_of_passthroughs(&self) -> i32 { - let mut i =if self.allow_owned { 1 } else { 0 }; - if self.allow_ref { i += 1 }; - if self.allow_mut { i += 1 }; - i - } -} - -impl std::fmt::Debug for TypeVariant { - /// Formats a `TypeVariant` - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("TypeVariant") - .field("alias", &self.alias) - .field("ty", &self.ty) - .field("allow_owned", &self.allow_owned) - .field("allow_ref", &self.allow_ref) - .field("allow_mut", &self.allow_mut) - .finish() - } -} - -impl syn::parse::Parse for TypeVariant { - /// Turns this: - /// - /// ```rust,ignore,no_run - /// $NAME = @RM SomeStruct, - /// ``` - /// - /// Into this: - /// - /// ```rust,ignore,no_run - /// TypeVariant { - /// alias: "NAME" - /// ty: SomeStruct, - /// allow_owned: true, - /// allow_ref: true, - /// allow_mut: true, - /// } - /// ``` - fn parse(input: syn::parse::ParseStream) -> syn::Result { - use syn::*; - let _ = input.parse::()?; - let alias = input.parse::()?; - input.parse::()?; - let mut allow_owned = false; - let mut allow_ref = false; - let mut allow_mut = false; - loop { - if input.peek(Token![@]) { - let _ = input.parse::()?; - let modifier = input.parse::()?; - let modifier = modifier.to_string(); - if modifier.contains('R') { - allow_ref = true; - } - if modifier.contains('M') { - allow_mut = true; - } - if modifier.contains('O') { - allow_owned = true; - } - } else { - break; - } - }; - let ty = input.parse::()?; - Ok(TypeVariant { - alias, - ty, - allow_owned, - allow_ref, - allow_mut, - }) - } -} +/// A type variant, used in the `#[mass_impl(...)]` macro. +/// +/// Input generally looks like this: +/// +/// ```rust,ignore,no_run +/// $NAME = @RM SomeStruct +/// ``` +/// +/// Which essentially means: +/// - `$NAME` is the alias for `SomeStruct` +/// - `@R` means that `SomeStruct` can be passed by reference +/// - `@RM` means that `SomeStruct` can be passed by mutable reference +/// +/// So it will create 3 bodies for the macro: +/// - `impl SomeTrait for SomeStruct` +/// - `impl SomeTrait for &SomeStruct` +/// - `impl SomeTrait for &mut SomeStruct` +pub struct TypeVariant { + /// The alias for the type (e.g. `$NAME`) + pub alias: syn::Ident, + /// The type (e.g. `SomeStruct`) + pub ty: syn::Ident, + /// Whether or not the type can be passed by value + pub allow_owned: bool, + /// Whether or not the type can be passed by reference + pub allow_ref: bool, + /// Whether or not the type can be passed by mutable reference + pub allow_mut: bool, +} + +impl TypeVariant { + /// Returns the number of passthroughs for this type variant. + pub fn number_of_passthroughs(&self) -> i32 { + let mut i = if self.allow_owned { 1 } else { 0 }; + if self.allow_ref { + i += 1 + }; + if self.allow_mut { + i += 1 + }; + i + } +} + +impl std::fmt::Debug for TypeVariant { + /// Formats a `TypeVariant` + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TypeVariant") + .field("alias", &self.alias) + .field("ty", &self.ty) + .field("allow_owned", &self.allow_owned) + .field("allow_ref", &self.allow_ref) + .field("allow_mut", &self.allow_mut) + .finish() + } +} + +impl syn::parse::Parse for TypeVariant { + /// Turns this: + /// + /// ```rust,ignore,no_run + /// $NAME = @RM SomeStruct, + /// ``` + /// + /// Into this: + /// + /// ```rust,ignore,no_run + /// TypeVariant { + /// alias: "NAME" + /// ty: SomeStruct, + /// allow_owned: true, + /// allow_ref: true, + /// allow_mut: true, + /// } + /// ``` + fn parse(input: syn::parse::ParseStream) -> syn::Result { + use syn::*; + let _ = input.parse::()?; + let alias = input.parse::()?; + input.parse::()?; + let mut allow_owned = false; + let mut allow_ref = false; + let mut allow_mut = false; + loop { + if input.peek(Token![@]) { + let _ = input.parse::()?; + let modifier = input.parse::()?; + let modifier = modifier.to_string(); + if modifier.contains('R') { + allow_ref = true; + } + if modifier.contains('M') { + allow_mut = true; + } + if modifier.contains('O') { + allow_owned = true; + } + } else { + break; + } + } + let ty = input.parse::()?; + Ok(TypeVariant { + alias, + ty, + allow_owned, + allow_ref, + allow_mut, + }) + } +} diff --git a/libs/macros/lib.rs b/libs/macros/lib.rs index 886ee0c..8c4053d 100644 --- a/libs/macros/lib.rs +++ b/libs/macros/lib.rs @@ -1,17 +1,16 @@ -#![doc = include_str!("./README.md")] - -#![warn(missing_docs, unused, clippy::all)] - -use proc_macro::TokenStream; - -/// A macro for implementing a trait for a list of types. -#[proc_macro_attribute] -pub fn mass_impl(cfg: TokenStream, input: TokenStream) -> TokenStream { - mc::mass_impl(cfg, input).into() -} - -/// A macro for generating FFI functions. -#[proc_macro_attribute] -pub fn ffi(cfg: TokenStream, input: TokenStream) -> TokenStream { - mc::ffi(cfg, input).into() -} +#![doc = include_str!("./README.md")] +#![warn(missing_docs, unused, clippy::all)] + +use proc_macro::TokenStream; + +/// A macro for implementing a trait for a list of types. +#[proc_macro_attribute] +pub fn mass_impl(cfg: TokenStream, input: TokenStream) -> TokenStream { + mc::mass_impl(cfg, input).into() +} + +/// A macro for generating FFI functions. +#[proc_macro_attribute] +pub fn ffi(cfg: TokenStream, input: TokenStream) -> TokenStream { + mc::ffi(cfg, input).into() +} diff --git a/libs/scripts.py b/libs/scripts.py index 791e5a7..fc84c8f 100644 --- a/libs/scripts.py +++ b/libs/scripts.py @@ -11,17 +11,20 @@ def run_cmd(cmd: str, cwd: str, args: list[str]) -> str | int | None: def fmt(cd: str, args: list[str]) -> str | int | None: cmd = ["cargo", "fmt"] if '--check' in args: cmd.extend(['--', '--check']) - subprocess.run(cmd, cwd=cd) + res = subprocess.run(cmd, cwd=cd) + if res.returncode != 0: exit(res.returncode) def test(cd: str, args: list[str]) -> str | int | None: cmd = ["cargo", "tarpaulin"] cmd.extend(args) - subprocess.run(cmd, cwd=cd) + res = subprocess.run(cmd, cwd=cd) + if res.returncode != 0: exit(res.returncode) def build(cd: str, args: list[str]) -> str | int | None: cmd = ["cargo", "build"] cmd.extend(args) - subprocess.run(cmd, cwd=cd) + res = subprocess.run(cmd, cwd=cd) + if res.returncode != 0: exit(res.returncode) def hlp() -> None: print("") diff --git a/libtrig/angle.rs b/libtrig/angle.rs index 719495d..9005943 100644 --- a/libtrig/angle.rs +++ b/libtrig/angle.rs @@ -1,425 +1,425 @@ -use crate::*; - -/// A wrapper around a `float` value that represents an angle. -/// -/// It can be created from either radians or degrees, and can be converted to either radians or degrees. -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Angle2D(RadianOrDegree64, bool); - -impl Angle2D { - /// Creates a new `Angle2D` from the given `value` and `is_radians` flag. - #[inline] - #[must_use] - pub const fn new(value: RadianOrDegree64, is_radians: bool) -> Self { - Self(value, is_radians) - } - /// Creates a new `Angle2D` from the given `value` in radians. - #[inline] - #[must_use] - pub const fn from_radians(value: Radian64) -> Self { - Self::new(value, true) - } - /// Creates a new `Angle2D` from the given `value` in degrees. - #[inline] - #[must_use] - pub const fn from_degrees(value: Degree64) -> Self { - Self::new(value, false) - } - /// Creates a new `Angle2D` with a value of `0.0` radians. - #[inline] - #[must_use] - pub const fn zero() -> Self { - Self::new(0.0, true) - } - /// Creates a new `Angle2D` with a value of `0.0` degrees. - #[inline] - #[must_use] - pub const fn zero_deg() -> Self { - Self::new(0.0, false) - } - /// Returns the value of the angle in radians. - #[inline] - #[must_use] - pub fn to_radians(&self) -> Radian64 { - if self.1 { - self.0 - } else { - self.0.to_radians() - } - } - /// Returns the value of the angle in degrees. - #[inline] - #[must_use] - pub fn to_degrees(&self) -> Degree64 { - if self.1 { - self.0.to_degrees() - } else { - self.0 - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::Add for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() + rhs.to_radians()) - } else { - Angle2D::from_degrees(self.to_degrees() + rhs.to_degrees()) - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::Add for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() + rhs) - } else { - Angle2D::from_degrees(self.to_degrees() + rhs) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() + rhs.to_radians(); - } else { - self.0 = self.to_degrees() + rhs.to_degrees(); - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() + rhs; - } else { - self.0 = self.to_degrees() + rhs; - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::Sub for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() - rhs.to_radians()) - } else { - Angle2D::from_degrees(self.to_degrees() - rhs.to_degrees()) - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::Sub for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() - rhs) - } else { - Angle2D::from_degrees(self.to_degrees() - rhs) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() - rhs.to_radians(); - } else { - self.0 = self.to_degrees() - rhs.to_degrees(); - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() - rhs; - } else { - self.0 = self.to_degrees() - rhs; - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::Mul for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() * rhs.to_radians()) - } else { - Angle2D::from_degrees(self.to_degrees() * rhs.to_degrees()) - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::Mul for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() * rhs) - } else { - Angle2D::from_degrees(self.to_degrees() * rhs) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() * rhs.to_radians(); - } else { - self.0 = self.to_degrees() * rhs.to_degrees(); - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() * rhs; - } else { - self.0 = self.to_degrees() * rhs; - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::Div for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() / rhs.to_radians()) - } else { - Angle2D::from_degrees(self.to_degrees() / rhs.to_degrees()) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::Div for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() / rhs) - } else { - Angle2D::from_degrees(self.to_degrees() / rhs) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() / rhs.to_radians(); - } else { - self.0 = self.to_degrees() / rhs.to_degrees(); - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() / rhs; - } else { - self.0 = self.to_degrees() / rhs; - } - } -} - -#[macros::mass_impl($THIS = @ORM Angle2D)] -impl core::ops::Neg for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn neg(self) -> Self::Output { - if self.1 { - Angle2D::from_radians(-self.to_radians()) - } else { - Angle2D::from_degrees(-self.to_degrees()) - } - } -} - -impl Default for Angle2D { - #[inline] - #[must_use] - fn default() -> Self { - Self::zero() - } -} - -impl core::fmt::Display for Angle2D { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - if self.1 { - return write!(f, "{}rad", self.to_radians()); - } - write!(f, "{}°", self.to_degrees()) - } -} - -impl> From<(F, bool)> for Angle2D { - #[inline] - #[must_use] - fn from((f, r): (F, bool)) -> Self { - if r { - Self::from_radians(f.into()) - } else { - Self::from_degrees(f.into()) - } - } -} - -impl crate::traits::Number for Angle2D {} - -macro_rules! i { - ($n:ident $($t:tt)*) => ( - #[inline] - #[must_use] - fn $n(&self) -> Float64 { - self.0.$n() - } - i!($($t)*); - ); - () => (); -} - -impl crate::traits::Float for Angle2D { - #[inline] - #[must_use] - fn mul_add(&self, a: Self, b: Self) -> Float64 { - self.0.mul_add(a.0, b.0) - } - #[inline] - #[must_use] - fn div_euclid(&self, rhs: Self) -> Float64 { - self.0.div_euclid(rhs.0) - } - #[inline] - #[must_use] - fn rem_euclid(&self, rhs: Self) -> Float64 { - self.0.rem_euclid(rhs.0) - } - #[inline] - #[must_use] - fn powi(&self, n: Int) -> Float64 { - self.0.powi(n) - } - #[inline] - #[must_use] - fn powf(&self, n: Self) -> Float64 { - self.0.powf(n.0) - } - #[inline] - #[must_use] - fn log(&self, base: Self) -> Float64 { - self.0.log(base.0) - } - #[inline] - #[must_use] - fn atan2(&self, other: Self) -> Float64 { - self.0.atan2(other.0) - } - #[inline] - #[must_use] - fn hypot(&self, other: Self) -> Float64 { - self.0.hypot(other.0) - } - #[inline] - #[must_use] - fn sin_cos(&self) -> (Float64, Float64) { - self.0.sin_cos() - } - - i!(floor ceil round trunc fract abs signum sqrt exp exp2 ln log2 log10 cbrt - sin cos tan asin acos atan exp_m1 ln_1p sinh cosh tanh asinh acosh atanh); -} +use crate::*; + +/// A wrapper around a `float` value that represents an angle. +/// +/// It can be created from either radians or degrees, and can be converted to either radians or degrees. +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +pub struct Angle2D(RadianOrDegree64, bool); + +impl Angle2D { + /// Creates a new `Angle2D` from the given `value` and `is_radians` flag. + #[inline] + #[must_use] + pub const fn new(value: RadianOrDegree64, is_radians: bool) -> Self { + Self(value, is_radians) + } + /// Creates a new `Angle2D` from the given `value` in radians. + #[inline] + #[must_use] + pub const fn from_radians(value: Radian64) -> Self { + Self::new(value, true) + } + /// Creates a new `Angle2D` from the given `value` in degrees. + #[inline] + #[must_use] + pub const fn from_degrees(value: Degree64) -> Self { + Self::new(value, false) + } + /// Creates a new `Angle2D` with a value of `0.0` radians. + #[inline] + #[must_use] + pub const fn zero() -> Self { + Self::new(0.0, true) + } + /// Creates a new `Angle2D` with a value of `0.0` degrees. + #[inline] + #[must_use] + pub const fn zero_deg() -> Self { + Self::new(0.0, false) + } + /// Returns the value of the angle in radians. + #[inline] + #[must_use] + pub fn to_radians(&self) -> Radian64 { + if self.1 { + self.0 + } else { + self.0.to_radians() + } + } + /// Returns the value of the angle in degrees. + #[inline] + #[must_use] + pub fn to_degrees(&self) -> Degree64 { + if self.1 { + self.0.to_degrees() + } else { + self.0 + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @ORM Angle2D +)] +impl core::ops::Add for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() + rhs.to_radians()) + } else { + Angle2D::from_degrees(self.to_degrees() + rhs.to_degrees()) + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::Add for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() + rhs) + } else { + Angle2D::from_degrees(self.to_degrees() + rhs) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @ORM Angle2D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() + rhs.to_radians(); + } else { + self.0 = self.to_degrees() + rhs.to_degrees(); + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() + rhs; + } else { + self.0 = self.to_degrees() + rhs; + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @ORM Angle2D +)] +impl core::ops::Sub for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() - rhs.to_radians()) + } else { + Angle2D::from_degrees(self.to_degrees() - rhs.to_degrees()) + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::Sub for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() - rhs) + } else { + Angle2D::from_degrees(self.to_degrees() - rhs) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Angle2D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() - rhs.to_radians(); + } else { + self.0 = self.to_degrees() - rhs.to_degrees(); + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() - rhs; + } else { + self.0 = self.to_degrees() - rhs; + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR Angle2D +)] +impl core::ops::Mul for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn mul(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() * rhs.to_radians()) + } else { + Angle2D::from_degrees(self.to_degrees() * rhs.to_degrees()) + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::Mul for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn mul(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() * rhs) + } else { + Angle2D::from_degrees(self.to_degrees() * rhs) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Angle2D +)] +impl core::ops::MulAssign for THIS { + #[inline] + fn mul_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() * rhs.to_radians(); + } else { + self.0 = self.to_degrees() * rhs.to_degrees(); + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::MulAssign for THIS { + #[inline] + fn mul_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() * rhs; + } else { + self.0 = self.to_degrees() * rhs; + } + } +} + +#[macros::mass_impl( + $THIS = @ORM Angle2D, + $OTHER = @OR Angle2D +)] +impl core::ops::Div for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn div(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() / rhs.to_radians()) + } else { + Angle2D::from_degrees(self.to_degrees() / rhs.to_degrees()) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::Div for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn div(self, rhs: OTHER) -> Self::Output { + if self.1 { + Angle2D::from_radians(self.to_radians() / rhs) + } else { + Angle2D::from_degrees(self.to_degrees() / rhs) + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Angle2D +)] +impl core::ops::DivAssign for THIS { + #[inline] + fn div_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() / rhs.to_radians(); + } else { + self.0 = self.to_degrees() / rhs.to_degrees(); + } + } +} + +#[macros::mass_impl( + $THIS = @OM Angle2D, + $OTHER = @OR Float64 +)] +impl core::ops::DivAssign for THIS { + #[inline] + fn div_assign(&mut self, rhs: OTHER) { + if self.1 { + self.0 = self.to_radians() / rhs; + } else { + self.0 = self.to_degrees() / rhs; + } + } +} + +#[macros::mass_impl($THIS = @ORM Angle2D)] +impl core::ops::Neg for THIS { + type Output = Angle2D; + #[inline] + #[must_use] + fn neg(self) -> Self::Output { + if self.1 { + Angle2D::from_radians(-self.to_radians()) + } else { + Angle2D::from_degrees(-self.to_degrees()) + } + } +} + +impl Default for Angle2D { + #[inline] + #[must_use] + fn default() -> Self { + Self::zero() + } +} + +impl core::fmt::Display for Angle2D { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if self.1 { + return write!(f, "{}rad", self.to_radians()); + } + write!(f, "{}°", self.to_degrees()) + } +} + +impl> From<(F, bool)> for Angle2D { + #[inline] + #[must_use] + fn from((f, r): (F, bool)) -> Self { + if r { + Self::from_radians(f.into()) + } else { + Self::from_degrees(f.into()) + } + } +} + +impl crate::traits::Number for Angle2D {} + +macro_rules! i { + ($n:ident $($t:tt)*) => ( + #[inline] + #[must_use] + fn $n(&self) -> Float64 { + self.0.$n() + } + i!($($t)*); + ); + () => (); +} + +impl crate::traits::Float for Angle2D { + #[inline] + #[must_use] + fn mul_add(&self, a: Self, b: Self) -> Float64 { + self.0.mul_add(a.0, b.0) + } + #[inline] + #[must_use] + fn div_euclid(&self, rhs: Self) -> Float64 { + self.0.div_euclid(rhs.0) + } + #[inline] + #[must_use] + fn rem_euclid(&self, rhs: Self) -> Float64 { + self.0.rem_euclid(rhs.0) + } + #[inline] + #[must_use] + fn powi(&self, n: Int) -> Float64 { + self.0.powi(n) + } + #[inline] + #[must_use] + fn powf(&self, n: Self) -> Float64 { + self.0.powf(n.0) + } + #[inline] + #[must_use] + fn log(&self, base: Self) -> Float64 { + self.0.log(base.0) + } + #[inline] + #[must_use] + fn atan2(&self, other: Self) -> Float64 { + self.0.atan2(other.0) + } + #[inline] + #[must_use] + fn hypot(&self, other: Self) -> Float64 { + self.0.hypot(other.0) + } + #[inline] + #[must_use] + fn sin_cos(&self) -> (Float64, Float64) { + self.0.sin_cos() + } + + i!(floor ceil round trunc fract abs signum sqrt exp exp2 ln log2 log10 cbrt + sin cos tan asin acos atan exp_m1 ln_1p sinh cosh tanh asinh acosh atanh); +} diff --git a/libtrig/coords/coord2d.rs b/libtrig/coords/coord2d.rs index 66358bd..81bac40 100644 --- a/libtrig/coords/coord2d.rs +++ b/libtrig/coords/coord2d.rs @@ -1,296 +1,293 @@ -use crate::*; - -/// A wrapper around a `float` value that represents a 2D coordinate. -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Coord2D { - /// The x coordinate. - pub x: Float64, - /// The y coordinate. - pub y: Float64, -} - -impl Coord2D { - /// Creates a new `Vec2D` from the given `x` and `y` values. - #[inline] - #[must_use] - pub const fn new(x: Float64, y: Float64) -> Self { - Self { x, y } - } - /// Creates a new `Vec2D` located at the origin. - #[inline] - #[must_use] - pub const fn origin() -> Self { - Self::new(0.0, 0.0) - } - /// Rotates the vector by the given angle in radians. - #[inline] - #[must_use] - pub fn rotate_by(&self, angle: Angle2D) -> Self { - #[allow(unused_imports)] - use crate::traits::Float; - let angle = angle.to_radians(); - let (sin, cos) = angle.sin_cos(); - Self::new( - self.x * cos - self.y * sin, - self.x * sin + self.y * cos, - ) - } - /// Returns the angle of the vector in radians. - #[inline] - #[must_use] - pub fn angle(&self) -> Angle2D { - #[allow(unused_imports)] - use crate::traits::Float; - Angle2D::from_radians(self.y.atan2(self.x)) - } - /// Returns the inverted position. - /// - /// Same as rotating the position by 180 degrees. - #[inline] - #[must_use] - pub fn inverse(&self) -> Self { - -self - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::Add for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x + rhs.x(), self.y + rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::Add for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x + rhs.x, self.y + rhs.y) - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.x += rhs.x(); - self.y += rhs.y(); - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.x += rhs.x; - self.y += rhs.y; - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::Sub for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x - rhs.x(), self.y - rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::Sub for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x - rhs.x, self.y - rhs.y) - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.x -= rhs.x(); - self.y -= rhs.y(); - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.x -= rhs.x; - self.y -= rhs.y; - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @OR Float64 -)] -impl core::ops::Mul for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x * rhs, self.y * rhs) - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @OR Vec2D -)] -impl core::ops::Mul for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x * rhs.x(), self.y * rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @OR Float64 -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - self.x *= rhs; - self.y *= rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @OR Vec2D -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - self.x *= rhs.x(); - self.y *= rhs.y(); - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @OR Float64 -)] -impl core::ops::Div for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x / rhs, self.y / rhs) - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @OR Vec2D -)] -impl core::ops::Div for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x / rhs.x(), self.y / rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @OR Float64 -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - self.x /= rhs; - self.y /= rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @OR Vec2D -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - self.x /= rhs.x(); - self.y /= rhs.y(); - } -} - -#[macros::mass_impl($THIS = @ORM Coord2D)] -impl core::ops::Neg for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn neg(self) -> Self::Output { - Coord2D::new(-self.x, -self.y) - } -} - -impl core::fmt::Display for Coord2D { - #[inline] - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "[{}, {}]", self.x, self.y) - } -} - -impl Default for Coord2D { - #[inline] - #[must_use] - fn default() -> Self { - Self::origin() - } -} - -impl> From<(F, F)> for Coord2D { - #[inline] - #[must_use] - fn from((x, y): (F, F)) -> Self { - Self::new(x.into(), y.into()) - } -} - -impl From for (Float64, Float64) { - #[inline] - #[must_use] - fn from(Coord2D {x, y}: Coord2D) -> Self { - (x, y) - } -} +use crate::*; + +/// A wrapper around a `float` value that represents a 2D coordinate. +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +pub struct Coord2D { + /// The x coordinate. + pub x: Float64, + /// The y coordinate. + pub y: Float64, +} + +impl Coord2D { + /// Creates a new `Vec2D` from the given `x` and `y` values. + #[inline] + #[must_use] + pub const fn new(x: Float64, y: Float64) -> Self { + Self { x, y } + } + /// Creates a new `Vec2D` located at the origin. + #[inline] + #[must_use] + pub const fn origin() -> Self { + Self::new(0.0, 0.0) + } + /// Rotates the vector by the given angle in radians. + #[inline] + #[must_use] + pub fn rotate_by(&self, angle: Angle2D) -> Self { + #[allow(unused_imports)] + use crate::traits::Float; + let angle = angle.to_radians(); + let (sin, cos) = angle.sin_cos(); + Self::new(self.x * cos - self.y * sin, self.x * sin + self.y * cos) + } + /// Returns the angle of the vector in radians. + #[inline] + #[must_use] + pub fn angle(&self) -> Angle2D { + #[allow(unused_imports)] + use crate::traits::Float; + Angle2D::from_radians(self.y.atan2(self.x)) + } + /// Returns the inverted position. + /// + /// Same as rotating the position by 180 degrees. + #[inline] + #[must_use] + pub fn inverse(&self) -> Self { + -self + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::Add for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x + rhs.x(), self.y + rhs.y()) + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::Add for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn add(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x + rhs.x, self.y + rhs.y) + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + self.x += rhs.x(); + self.y += rhs.y(); + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::AddAssign for THIS { + #[inline] + fn add_assign(&mut self, rhs: OTHER) { + self.x += rhs.x; + self.y += rhs.y; + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::Sub for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x - rhs.x(), self.y - rhs.y()) + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::Sub for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn sub(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x - rhs.x, self.y - rhs.y) + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @ORM Vec2D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + self.x -= rhs.x(); + self.y -= rhs.y(); + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @ORM Coord2D +)] +impl core::ops::SubAssign for THIS { + #[inline] + fn sub_assign(&mut self, rhs: OTHER) { + self.x -= rhs.x; + self.y -= rhs.y; + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @OR Float64 +)] +impl core::ops::Mul for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn mul(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x * rhs, self.y * rhs) + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @OR Vec2D +)] +impl core::ops::Mul for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn mul(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x * rhs.x(), self.y * rhs.y()) + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @OR Float64 +)] +impl core::ops::MulAssign for THIS { + #[inline] + fn mul_assign(&mut self, rhs: OTHER) { + self.x *= rhs; + self.y *= rhs; + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @OR Vec2D +)] +impl core::ops::MulAssign for THIS { + #[inline] + fn mul_assign(&mut self, rhs: OTHER) { + self.x *= rhs.x(); + self.y *= rhs.y(); + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @OR Float64 +)] +impl core::ops::Div for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn div(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x / rhs, self.y / rhs) + } +} + +#[macros::mass_impl( + $THIS = @ORM Coord2D, + $OTHER = @OR Vec2D +)] +impl core::ops::Div for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn div(self, rhs: OTHER) -> Self::Output { + Coord2D::new(self.x / rhs.x(), self.y / rhs.y()) + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @OR Float64 +)] +impl core::ops::DivAssign for THIS { + #[inline] + fn div_assign(&mut self, rhs: OTHER) { + self.x /= rhs; + self.y /= rhs; + } +} + +#[macros::mass_impl( + $THIS = @OM Coord2D, + $OTHER = @OR Vec2D +)] +impl core::ops::DivAssign for THIS { + #[inline] + fn div_assign(&mut self, rhs: OTHER) { + self.x /= rhs.x(); + self.y /= rhs.y(); + } +} + +#[macros::mass_impl($THIS = @ORM Coord2D)] +impl core::ops::Neg for THIS { + type Output = Coord2D; + #[inline] + #[must_use] + fn neg(self) -> Self::Output { + Coord2D::new(-self.x, -self.y) + } +} + +impl core::fmt::Display for Coord2D { + #[inline] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "[{}, {}]", self.x, self.y) + } +} + +impl Default for Coord2D { + #[inline] + #[must_use] + fn default() -> Self { + Self::origin() + } +} + +impl> From<(F, F)> for Coord2D { + #[inline] + #[must_use] + fn from((x, y): (F, F)) -> Self { + Self::new(x.into(), y.into()) + } +} + +impl From for (Float64, Float64) { + #[inline] + #[must_use] + fn from(Coord2D { x, y }: Coord2D) -> Self { + (x, y) + } +} diff --git a/libtrig/coords/mod.rs b/libtrig/coords/mod.rs index aad37f6..2589cb1 100644 --- a/libtrig/coords/mod.rs +++ b/libtrig/coords/mod.rs @@ -1,5 +1,5 @@ -mod coord2d; -// mod coord3d; - -pub use coord2d::Coord2D; -// pub use coord3d::Coord3D; \ No newline at end of file +mod coord2d; +// mod coord3d; + +pub use coord2d::Coord2D; +// pub use coord3d::Coord3D; diff --git a/libtrig/lib.rs b/libtrig/lib.rs index b4a993b..c3747a8 100644 --- a/libtrig/lib.rs +++ b/libtrig/lib.rs @@ -1,24 +1,22 @@ -#![feature(const_mut_refs)] - -#![no_std] - -#![warn(missing_docs, unused, clippy::all)] -#![doc = include_str!("./README.md")] - -pub(crate) mod vectors; -pub(crate) mod traits; -pub(crate) mod coords; -pub(crate) mod angle; -pub(crate) mod types; - -pub use llm; - -pub mod prelude { - //! Re-exports all the traits. - pub use super::traits::*; -} - -pub use vectors::*; -pub use coords::*; -pub use angle::*; -pub use types::*; +#![feature(const_mut_refs)] +#![no_std] +#![warn(missing_docs, unused, clippy::all)] +#![doc = include_str!("./README.md")] + +pub(crate) mod angle; +pub(crate) mod coords; +pub(crate) mod traits; +pub(crate) mod types; +pub(crate) mod vectors; + +pub use llm; + +pub mod prelude { + //! Re-exports all the traits. + pub use super::traits::*; +} + +pub use angle::*; +pub use coords::*; +pub use types::*; +pub use vectors::*; diff --git a/libtrig/traits/mod.rs b/libtrig/traits/mod.rs index 041f127..258f1df 100644 --- a/libtrig/traits/mod.rs +++ b/libtrig/traits/mod.rs @@ -1,83 +1,83 @@ -use crate::*; - -mod number; -mod float; - -pub use number::Number; -pub use float::Float; - -macro_rules! simpl { - ($n:ident => $m:ident $($t:tt)*) => ( - #[inline] - #[must_use] - fn $n(&self) -> Self { - llm::$m(*self) - } - simpl!($($t)*); - ); - ($n:ident $($t:tt)*) => (simpl!($n => $n $($t)*);); - () => (); -} - -#[allow(unused)] -impl Float for Float64 { - simpl!(floor ceil round trunc abs => fabs sqrt exp exp2 ln log2 log10 cbrt - sin cos tan asin acos atan exp_m1 => expm1 ln_1p => log1p - sinh cosh tanh asinh acosh atanh); - #[inline] - #[must_use] - fn mul_add(&self, a: Self, b: Self) -> Self { - llm::fma(*self, a, b) - } - #[inline] - #[must_use] - fn div_euclid(&self, rhs: Self) -> Self { - todo!("div_euclid") - } - #[inline] - #[must_use] - fn rem_euclid(&self, rhs: Self) -> Self { - todo!("rem_euclid") - } - #[inline] - #[must_use] - fn signum(&self) -> Self { - if *self > 0.0 { - 1.0 - } else if *self < 0.0 { - -1.0 - } else { - Float64::NAN - } - } - #[inline] - #[must_use] - fn powi(&self, n: Int) -> Self { - llm::pow(*self, n as Float64) - } - #[inline] - #[must_use] - fn powf(&self, n: Self) -> Self { - llm::pow(*self, n) - } - #[inline] - #[must_use] - fn log(&self, base: Self) -> Self { - llm::log(*self) / llm::log(base) - } - #[inline] - #[must_use] - fn hypot(&self, other: Self) -> Self { - llm::hypot(*self, other) - } - #[inline] - #[must_use] - fn atan2(&self, other: Self) -> Self { - llm::atan2(*self, other) - } - #[inline] - #[must_use] - fn fract(&self) -> Self { - *self - self.floor() - } -} \ No newline at end of file +use crate::*; + +mod float; +mod number; + +pub use float::Float; +pub use number::Number; + +macro_rules! simpl { + ($n:ident => $m:ident $($t:tt)*) => ( + #[inline] + #[must_use] + fn $n(&self) -> Self { + llm::$m(*self) + } + simpl!($($t)*); + ); + ($n:ident $($t:tt)*) => (simpl!($n => $n $($t)*);); + () => (); +} + +#[allow(unused)] +impl Float for Float64 { + simpl!(floor ceil round trunc abs => fabs sqrt exp exp2 ln log2 log10 cbrt + sin cos tan asin acos atan exp_m1 => expm1 ln_1p => log1p + sinh cosh tanh asinh acosh atanh); + #[inline] + #[must_use] + fn mul_add(&self, a: Self, b: Self) -> Self { + llm::fma(*self, a, b) + } + #[inline] + #[must_use] + fn div_euclid(&self, rhs: Self) -> Self { + todo!("div_euclid") + } + #[inline] + #[must_use] + fn rem_euclid(&self, rhs: Self) -> Self { + todo!("rem_euclid") + } + #[inline] + #[must_use] + fn signum(&self) -> Self { + if *self > 0.0 { + 1.0 + } else if *self < 0.0 { + -1.0 + } else { + Float64::NAN + } + } + #[inline] + #[must_use] + fn powi(&self, n: Int) -> Self { + llm::pow(*self, n as Float64) + } + #[inline] + #[must_use] + fn powf(&self, n: Self) -> Self { + llm::pow(*self, n) + } + #[inline] + #[must_use] + fn log(&self, base: Self) -> Self { + llm::log(*self) / llm::log(base) + } + #[inline] + #[must_use] + fn hypot(&self, other: Self) -> Self { + llm::hypot(*self, other) + } + #[inline] + #[must_use] + fn atan2(&self, other: Self) -> Self { + llm::atan2(*self, other) + } + #[inline] + #[must_use] + fn fract(&self) -> Self { + *self - self.floor() + } +} diff --git a/libtrig/traits/number.rs b/libtrig/traits/number.rs index 36de71b..833bd9d 100644 --- a/libtrig/traits/number.rs +++ b/libtrig/traits/number.rs @@ -1,13 +1,21 @@ -use core::ops; - -/// A trait for types that can be used as numbers. -pub trait Number: - core::fmt::Debug + Copy + Clone + PartialEq + - ops::Add + ops::AddAssign + - ops::Sub + ops::SubAssign + - ops::Mul + ops::MulAssign + - ops::Div + ops::DivAssign + -{ } - -impl Number for crate::Int { } -impl Number for crate::Float64 { } +use core::ops; + +/// A trait for types that can be used as numbers. +pub trait Number: + core::fmt::Debug + + Copy + + Clone + + PartialEq + + ops::Add + + ops::AddAssign + + ops::Sub + + ops::SubAssign + + ops::Mul + + ops::MulAssign + + ops::Div + + ops::DivAssign +{ +} + +impl Number for crate::Int {} +impl Number for crate::Float64 {} diff --git a/libtrig/types.rs b/libtrig/types.rs index 71e2971..e3b9261 100644 --- a/libtrig/types.rs +++ b/libtrig/types.rs @@ -1,16 +1,16 @@ -pub use llm::{Float64, Float32, Radian64, Radian32}; - -/// A degree. (64bit) -pub type Degree64 = f64; - -/// A degree. (32bit) -pub type Degree32 = f32; - -/// An integer. -pub type Int = i32; - -/// A radian or degree. (64bit) -pub type RadianOrDegree64 = Float64; - -/// A radian or degree. (32bit) -pub type RadianOrDegree32 = Float32; +pub use llm::{Float32, Float64, Radian32, Radian64}; + +/// A degree. (64bit) +pub type Degree64 = f64; + +/// A degree. (32bit) +pub type Degree32 = f32; + +/// An integer. +pub type Int = i32; + +/// A radian or degree. (64bit) +pub type RadianOrDegree64 = Float64; + +/// A radian or degree. (32bit) +pub type RadianOrDegree32 = Float32; diff --git a/llm/lib.rs b/llm/lib.rs index f31d77c..a4a6d75 100644 --- a/llm/lib.rs +++ b/llm/lib.rs @@ -1,53 +1,51 @@ -#![doc = include_str!("./README.md")] - -#![no_std] -#![feature(core_intrinsics)] - -#![allow(clippy::unreadable_literal)] -#![allow(clippy::many_single_char_names)] -#![allow(clippy::needless_return)] -#![allow(clippy::int_plus_one)] -#![allow(clippy::deprecated_cfg_attr)] -#![allow(clippy::mixed_case_hex_literals)] -#![allow(clippy::float_cmp)] -#![allow(clippy::eq_op)] -#![allow(clippy::assign_op_pattern)] - -mod types; -mod math; - -pub use self::math::*; -pub use self::types::*; - -/// Approximate equality with 1 ULP of tolerance -#[doc(hidden)] -#[inline] -pub fn _eqf(a: Float32, b: Float32) -> Result<(), u32> { - if a.is_nan() && b.is_nan() { - Ok(()) - } else { - let err = (a.to_bits() as i32).wrapping_sub(b.to_bits() as i32).abs(); - - if err <= 1 { - Ok(()) - } else { - Err(err as u32) - } - } -} - -#[doc(hidden)] -#[inline] -pub fn _eq(a: Float64, b: Float64) -> Result<(), u64> { - if a.is_nan() && b.is_nan() { - Ok(()) - } else { - let err = (a.to_bits() as i64).wrapping_sub(b.to_bits() as i64).abs(); - - if err <= 1 { - Ok(()) - } else { - Err(err as u64) - } - } -} +#![doc = include_str!("./README.md")] +#![no_std] +#![feature(core_intrinsics)] +#![allow(clippy::unreadable_literal)] +#![allow(clippy::many_single_char_names)] +#![allow(clippy::needless_return)] +#![allow(clippy::int_plus_one)] +#![allow(clippy::deprecated_cfg_attr)] +#![allow(clippy::mixed_case_hex_literals)] +#![allow(clippy::float_cmp)] +#![allow(clippy::eq_op)] +#![allow(clippy::assign_op_pattern)] + +mod math; +mod types; + +pub use self::math::*; +pub use self::types::*; + +/// Approximate equality with 1 ULP of tolerance +#[doc(hidden)] +#[inline] +pub fn _eqf(a: Float32, b: Float32) -> Result<(), u32> { + if a.is_nan() && b.is_nan() { + Ok(()) + } else { + let err = (a.to_bits() as i32).wrapping_sub(b.to_bits() as i32).abs(); + + if err <= 1 { + Ok(()) + } else { + Err(err as u32) + } + } +} + +#[doc(hidden)] +#[inline] +pub fn _eq(a: Float64, b: Float64) -> Result<(), u64> { + if a.is_nan() && b.is_nan() { + Ok(()) + } else { + let err = (a.to_bits() as i64).wrapping_sub(b.to_bits() as i64).abs(); + + if err <= 1 { + Ok(()) + } else { + Err(err as u64) + } + } +} diff --git a/llm/math.rs b/llm/math.rs index 84e9869..14eb550 100644 --- a/llm/math.rs +++ b/llm/math.rs @@ -1,154 +1,167 @@ -macro_rules! force_eval { - ($e:expr) => { - unsafe { ::core::ptr::read_volatile(&$e) } - }; -} - -#[cfg(not(debug_assertions))] -macro_rules! i { - ($array:expr, $index:expr) => { - unsafe { *$array.get_unchecked($index) } - }; - ($array:expr, $index:expr, = , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) = $rhs; - } - }; - ($array:expr, $index:expr, += , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) += $rhs; - } - }; - ($array:expr, $index:expr, -= , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) -= $rhs; - } - }; - ($array:expr, $index:expr, &= , $rhs:expr) => { - unsafe { - *$array.get_unchecked_mut($index) &= $rhs; - } - }; - ($array:expr, $index:expr, == , $rhs:expr) => { - unsafe { *$array.get_unchecked_mut($index) == $rhs } - }; -} - -#[cfg(debug_assertions)] -macro_rules! i { - ($array:expr, $index:expr) => { - *$array.get($index).unwrap() - }; - ($array:expr, $index:expr, = , $rhs:expr) => { - *$array.get_mut($index).unwrap() = $rhs; - }; - ($array:expr, $index:expr, -= , $rhs:expr) => { - *$array.get_mut($index).unwrap() -= $rhs; - }; - ($array:expr, $index:expr, += , $rhs:expr) => { - *$array.get_mut($index).unwrap() += $rhs; - }; - ($array:expr, $index:expr, &= , $rhs:expr) => { - *$array.get_mut($index).unwrap() &= $rhs; - }; - ($array:expr, $index:expr, == , $rhs:expr) => { - *$array.get_mut($index).unwrap() == $rhs - }; -} - -// Temporary macro to avoid panic codegen for division (in debug mode too). At -// the time of this writing this is only used in a few places, and once -// rust-lang/rust#72751 is fixed then this macro will no longer be necessary and -// the native `/` operator can be used and panics won't be codegen'd. -#[cfg(debug_assertions)] -macro_rules! div { - ($a:expr, $b:expr) => { - $a / $b - }; -} - -#[cfg(not(debug_assertions))] -macro_rules! div { - ($a:expr, $b:expr) => { - unsafe { core::intrinsics::unchecked_div($a, $b) } - }; -} - - -macro_rules! consts { - (const $name:ident: $ty:ty = $value:expr; $($t:tt)* ) => ( - #[allow(clippy::excessive_precision)] - #[deny(clippy::approx_constant)] - const $name: $ty = $value; - consts!($($t)*); - ); - () => (); -} - -macro_rules! llvm_intrinsically_optimized { - (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all($($clause)*))] - { $e } - }; -} - -macro_rules! import { - ($p:vis $n:ident) => ( - mod $n; #[allow(unused_imports)] $p use self::$n::*; - ); - ($p:vis $n:ident $(, $m:ident)*) => ( - import!($p $n); import!($p $($m),*); - ); -} - -// Public modules -import!(pub acos, acosf, acosh, acoshf, asin, asinf, asinh, asinhf, atan, atan2, atan2f, atanf, atanh, atanhf); -import!(pub cbrt, cbrtf, ceil, ceilf, copysign, copysignf, cos, cosf, cosh, coshf); -import!(pub erf, erff, exp, exp10, exp10f, exp2, exp2f, expf, expm1, expm1f); -import!(pub fabs, fabsf, fdim, fdimf, floor, floorf, fma, fmaf, fmax, fmaxf, fmin, fminf, fmod, fmodf, frexp, frexpf); -import!(pub hypot, hypotf); -import!(pub ilogb, ilogbf); -import!(pub j0, j0f, j1, j1f, jn, jnf); -import!(pub ldexp, ldexpf, lgamma, lgamma_r, lgammaf, lgammaf_r, ln, lnf, log, log10, log10f, log1p, log1pf, log2, log2f, logf); -import!(pub modf, modff); -import!(pub nextafter, nextafterf); -import!(pub pow, powf); -import!(pub remainder, remainderf, remquo, remquof, rint, rintf, round, roundf); -import!(pub scalbn, scalbnf, sin, sincos, sincosf, sinf, sinh, sinhf, sqrt, sqrtf); -import!(pub tan, tanf, tanh, tanhf, tgamma, tgammaf, trunc, truncf); - -// Private modules -import!(expo2, fenv, k_cos, k_cosf, k_expo2, k_expo2f, k_sin, k_sinf, k_tan, k_tanf, rem_pio2, rem_pio2_large, rem_pio2f); - -use crate::Float64; - -#[inline] -fn get_high_word(x: Float64) -> u32 { - (x.to_bits() >> 32) as u32 -} - -#[inline] -fn get_low_word(x: Float64) -> u32 { - x.to_bits() as u32 -} - -#[inline] -fn with_set_high_word(f: Float64, hi: u32) -> Float64 { - let mut tmp = f.to_bits(); - tmp &= 0x00000000_ffffffff; - tmp |= (hi as u64) << 32; - Float64::from_bits(tmp) -} - -#[inline] -fn with_set_low_word(f: Float64, lo: u32) -> Float64 { - let mut tmp = f.to_bits(); - tmp &= 0xffffffff_00000000; - tmp |= lo as u64; - Float64::from_bits(tmp) -} - -#[inline] -fn combine_words(hi: u32, lo: u32) -> Float64 { - Float64::from_bits((hi as u64) << 32 | lo as u64) -} +macro_rules! force_eval { + ($e:expr) => { + unsafe { ::core::ptr::read_volatile(&$e) } + }; +} + +#[cfg(not(debug_assertions))] +macro_rules! i { + ($array:expr, $index:expr) => { + unsafe { *$array.get_unchecked($index) } + }; + ($array:expr, $index:expr, = , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) = $rhs; + } + }; + ($array:expr, $index:expr, += , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) += $rhs; + } + }; + ($array:expr, $index:expr, -= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) -= $rhs; + } + }; + ($array:expr, $index:expr, &= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) &= $rhs; + } + }; + ($array:expr, $index:expr, == , $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) == $rhs } + }; +} + +#[cfg(debug_assertions)] +macro_rules! i { + ($array:expr, $index:expr) => { + *$array.get($index).unwrap() + }; + ($array:expr, $index:expr, = , $rhs:expr) => { + *$array.get_mut($index).unwrap() = $rhs; + }; + ($array:expr, $index:expr, -= , $rhs:expr) => { + *$array.get_mut($index).unwrap() -= $rhs; + }; + ($array:expr, $index:expr, += , $rhs:expr) => { + *$array.get_mut($index).unwrap() += $rhs; + }; + ($array:expr, $index:expr, &= , $rhs:expr) => { + *$array.get_mut($index).unwrap() &= $rhs; + }; + ($array:expr, $index:expr, == , $rhs:expr) => { + *$array.get_mut($index).unwrap() == $rhs + }; +} + +// Temporary macro to avoid panic codegen for division (in debug mode too). At +// the time of this writing this is only used in a few places, and once +// rust-lang/rust#72751 is fixed then this macro will no longer be necessary and +// the native `/` operator can be used and panics won't be codegen'd. +#[cfg(debug_assertions)] +macro_rules! div { + ($a:expr, $b:expr) => { + $a / $b + }; +} + +#[cfg(not(debug_assertions))] +macro_rules! div { + ($a:expr, $b:expr) => { + unsafe { core::intrinsics::unchecked_div($a, $b) } + }; +} + +macro_rules! consts { + (const $name:ident: $ty:ty = $value:expr; $($t:tt)* ) => ( + #[allow(clippy::excessive_precision)] + #[deny(clippy::approx_constant)] + const $name: $ty = $value; + consts!($($t)*); + ); + () => (); +} + +macro_rules! llvm_intrinsically_optimized { + (#[cfg($($clause:tt)*)] $e:expr) => { + #[cfg(all($($clause)*))] + { $e } + }; +} + +macro_rules! import { + ($p:vis $n:ident) => ( + mod $n; #[allow(unused_imports)] $p use self::$n::*; + ); + ($p:vis $n:ident $(, $m:ident)*) => ( + import!($p $n); import!($p $($m),*); + ); +} + +// Public modules +import!(pub acos, acosf, acosh, acoshf, asin, asinf, asinh, asinhf, atan, atan2, atan2f, atanf, atanh, atanhf); +import!(pub cbrt, cbrtf, ceil, ceilf, copysign, copysignf, cos, cosf, cosh, coshf); +import!(pub erf, erff, exp, exp10, exp10f, exp2, exp2f, expf, expm1, expm1f); +import!(pub fabs, fabsf, fdim, fdimf, floor, floorf, fma, fmaf, fmax, fmaxf, fmin, fminf, fmod, fmodf, frexp, frexpf); +import!(pub hypot, hypotf); +import!(pub ilogb, ilogbf); +import!(pub j0, j0f, j1, j1f, jn, jnf); +import!(pub ldexp, ldexpf, lgamma, lgamma_r, lgammaf, lgammaf_r, ln, lnf, log, log10, log10f, log1p, log1pf, log2, log2f, logf); +import!(pub modf, modff); +import!(pub nextafter, nextafterf); +import!(pub pow, powf); +import!(pub remainder, remainderf, remquo, remquof, rint, rintf, round, roundf); +import!(pub scalbn, scalbnf, sin, sincos, sincosf, sinf, sinh, sinhf, sqrt, sqrtf); +import!(pub tan, tanf, tanh, tanhf, tgamma, tgammaf, trunc, truncf); + +// Private modules +import!( + expo2, + fenv, + k_cos, + k_cosf, + k_expo2, + k_expo2f, + k_sin, + k_sinf, + k_tan, + k_tanf, + rem_pio2, + rem_pio2_large, + rem_pio2f +); + +use crate::Float64; + +#[inline] +fn get_high_word(x: Float64) -> u32 { + (x.to_bits() >> 32) as u32 +} + +#[inline] +fn get_low_word(x: Float64) -> u32 { + x.to_bits() as u32 +} + +#[inline] +fn with_set_high_word(f: Float64, hi: u32) -> Float64 { + let mut tmp = f.to_bits(); + tmp &= 0x00000000_ffffffff; + tmp |= (hi as u64) << 32; + Float64::from_bits(tmp) +} + +#[inline] +fn with_set_low_word(f: Float64, lo: u32) -> Float64 { + let mut tmp = f.to_bits(); + tmp &= 0xffffffff_00000000; + tmp |= lo as u64; + Float64::from_bits(tmp) +} + +#[inline] +fn combine_words(hi: u32, lo: u32) -> Float64 { + Float64::from_bits((hi as u64) << 32 | lo as u64) +} From e195ab4cdfef087eabaac64b1c1569ad4cf94d04 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Fri, 10 Nov 2023 16:26:52 -0800 Subject: [PATCH 35/93] added rustfmt --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 69faf0f..378dc23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,8 @@ jobs: uses: actions/checkout@v3 - name: Set up Rust uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt - name: Set up Python uses: actions/setup-python@v4 with: From c0bd037ffe7da326f0198d3ff7baa7f0ab69b2e6 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sat, 11 Nov 2023 07:13:38 -0800 Subject: [PATCH 36/93] + rustfmt --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 378dc23..e0746fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,8 @@ jobs: uses: dtolnay/rust-toolchain@stable with: components: rustfmt + - name: Install toolchain + run: rustup component add rustfmt - name: Set up Python uses: actions/setup-python@v4 with: From 3328826f17d98d4fd0879878555f005cfc5169d1 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sat, 11 Nov 2023 07:59:49 -0800 Subject: [PATCH 37/93] + cargo binstall --- .github/workflows/ci.yml | 4 ++++ libs/scripts.py | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0746fd..9870228 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,6 +53,8 @@ jobs: uses: dtolnay/rust-toolchain@stable with: target: aarch64-linux-android + - name: Set up Rust Part 2 + uses: cargo-bins/cargo-binstall@main - name: Install rustup target run: rustup target add aarch64-linux-android - name: Set up Python @@ -78,6 +80,8 @@ jobs: uses: dtolnay/rust-toolchain@stable with: profile: minimal + - name: Set up Rust Part 2 + uses: cargo-bins/cargo-binstall@main - name: Set up Python uses: actions/setup-python@v4 with: diff --git a/libs/scripts.py b/libs/scripts.py index fc84c8f..7a3569a 100644 --- a/libs/scripts.py +++ b/libs/scripts.py @@ -15,6 +15,20 @@ def fmt(cd: str, args: list[str]) -> str | int | None: if res.returncode != 0: exit(res.returncode) def test(cd: str, args: list[str]) -> str | int | None: + # Check if tarpaulin is installed + def is_tarpaulin_installed() -> bool: + res = subprocess.run(["cargo", "tarpaulin", "--version"], capture_output=True) + return res.returncode == 0 + + # Install tarpaulin + def install_tarpaulin() -> None: + res = subprocess.run(["cargo", "binstall", "cargo-tarpaulin"]) + if res.returncode != 0: exit(res.returncode) + + # Check if tarpaulin is installed and install it if it isn't + if not is_tarpaulin_installed(): install_tarpaulin() + + # Run tarpaulin cmd = ["cargo", "tarpaulin"] cmd.extend(args) res = subprocess.run(cmd, cwd=cd) From 2e232f4bbe60a72a4b8faf0614f31e50351f967d Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sat, 11 Nov 2023 08:02:16 -0800 Subject: [PATCH 38/93] fixeing binstall --- libs/scripts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/scripts.py b/libs/scripts.py index 7a3569a..79fb1bd 100644 --- a/libs/scripts.py +++ b/libs/scripts.py @@ -22,7 +22,7 @@ def is_tarpaulin_installed() -> bool: # Install tarpaulin def install_tarpaulin() -> None: - res = subprocess.run(["cargo", "binstall", "cargo-tarpaulin"]) + res = subprocess.run(["cargo", "binstall", "--no-confirm", "cargo-tarpaulin"]) if res.returncode != 0: exit(res.returncode) # Check if tarpaulin is installed and install it if it isn't From 1fac1b33ab83c51ca82701ef19107241bf40bd92 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sat, 11 Nov 2023 08:06:04 -0800 Subject: [PATCH 39/93] Fixed Linux (Android no work) --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9870228..89ab80c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,7 +88,7 @@ jobs: python-version: 3.11 - name: Give permission to run epearl run: chmod +x ./epearl - - name: Build Android + - name: Build run: ./epearl build - - name: Test Android + - name: Test run: ./epearl test From 1ab707e9f8bae2f79c2a19bf8fa7976be9c9c2ed Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sat, 11 Nov 2023 08:09:29 -0800 Subject: [PATCH 40/93] Tests now seperate --- .github/workflows/ci.yml | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89ab80c..3abecae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: # If anything fails, the whole workflow fails. ci-pass: name: CI Pass - needs: [style, android, linux] + needs: [style, android, linux, tests] runs-on: ubuntu-latest steps: - run: exit 0 @@ -53,8 +53,6 @@ jobs: uses: dtolnay/rust-toolchain@stable with: target: aarch64-linux-android - - name: Set up Rust Part 2 - uses: cargo-bins/cargo-binstall@main - name: Install rustup target run: rustup target add aarch64-linux-android - name: Set up Python @@ -65,8 +63,6 @@ jobs: run: chmod +x ./epearl - name: Build Android run: ./epearl build --target aarch64-linux-android - - name: Test Android - run: ./epearl test --target aarch64-linux-android # Check if the Linux build works. linux: @@ -80,8 +76,6 @@ jobs: uses: dtolnay/rust-toolchain@stable with: profile: minimal - - name: Set up Rust Part 2 - uses: cargo-bins/cargo-binstall@main - name: Set up Python uses: actions/setup-python@v4 with: @@ -90,5 +84,26 @@ jobs: run: chmod +x ./epearl - name: Build run: ./epearl build - - name: Test + + # Check if the tests pass. + tests: + name: Tests + needs: [style, linux] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Rust + uses: dtolnay/rust-toolchain@stable + with: + profile: minimal + - name: Set up Binstall + uses: cargo-bins/cargo-binstall@main + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + - name: Give permission to run epearl + run: chmod +x ./epearl + - name: Run tests run: ./epearl test From 00c45fd9d35ac7914ba092e6b1c577b8f5d6c342 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sat, 11 Nov 2023 08:34:44 -0800 Subject: [PATCH 41/93] Restructure --- Cargo.toml | 4 ++-- README.md | 4 ++-- {libtrig => libs/libtrig}/Cargo.toml | 2 +- {libtrig => libs/libtrig}/README.md | 0 {libtrig => libs/libtrig}/angle.rs | 0 {libtrig => libs/libtrig}/coords/coord2d.rs | 0 {libtrig => libs/libtrig}/coords/coord3d.rs | 0 {libtrig => libs/libtrig}/coords/mod.rs | 0 {libtrig => libs/libtrig}/lib.rs | 0 {libtrig => libs/libtrig}/traits/float.rs | 0 {libtrig => libs/libtrig}/traits/mod.rs | 0 {libtrig => libs/libtrig}/traits/number.rs | 0 {libtrig => libs/libtrig}/types.rs | 0 {libtrig => libs/libtrig}/vectors/mod.rs | 0 {libtrig => libs/libtrig}/vectors/vec2d.rs | 0 {libtrig => libs/libtrig}/vectors/vec3d.rs | 0 {llm => libs/llm}/Cargo.toml | 2 +- {llm => libs/llm}/README.md | 0 {llm => libs/llm}/lib.rs | 0 {llm => libs/llm}/math.rs | 0 {llm => libs/llm}/math/acos.rs | 0 {llm => libs/llm}/math/acosf.rs | 0 {llm => libs/llm}/math/acosh.rs | 0 {llm => libs/llm}/math/acoshf.rs | 0 {llm => libs/llm}/math/asin.rs | 0 {llm => libs/llm}/math/asinf.rs | 0 {llm => libs/llm}/math/asinh.rs | 0 {llm => libs/llm}/math/asinhf.rs | 0 {llm => libs/llm}/math/atan.rs | 0 {llm => libs/llm}/math/atan2.rs | 0 {llm => libs/llm}/math/atan2f.rs | 0 {llm => libs/llm}/math/atanf.rs | 0 {llm => libs/llm}/math/atanh.rs | 0 {llm => libs/llm}/math/atanhf.rs | 0 {llm => libs/llm}/math/cbrt.rs | 0 {llm => libs/llm}/math/cbrtf.rs | 0 {llm => libs/llm}/math/ceil.rs | 0 {llm => libs/llm}/math/ceilf.rs | 0 {llm => libs/llm}/math/copysign.rs | 0 {llm => libs/llm}/math/copysignf.rs | 0 {llm => libs/llm}/math/cos.rs | 0 {llm => libs/llm}/math/cosf.rs | 0 {llm => libs/llm}/math/cosh.rs | 0 {llm => libs/llm}/math/coshf.rs | 0 {llm => libs/llm}/math/erf.rs | 0 {llm => libs/llm}/math/erff.rs | 0 {llm => libs/llm}/math/exp.rs | 0 {llm => libs/llm}/math/exp10.rs | 0 {llm => libs/llm}/math/exp10f.rs | 0 {llm => libs/llm}/math/exp2.rs | 0 {llm => libs/llm}/math/exp2f.rs | 0 {llm => libs/llm}/math/expf.rs | 0 {llm => libs/llm}/math/expm1.rs | 0 {llm => libs/llm}/math/expm1f.rs | 0 {llm => libs/llm}/math/expo2.rs | 0 {llm => libs/llm}/math/fabs.rs | 0 {llm => libs/llm}/math/fabsf.rs | 0 {llm => libs/llm}/math/fdim.rs | 0 {llm => libs/llm}/math/fdimf.rs | 0 {llm => libs/llm}/math/fenv.rs | 0 {llm => libs/llm}/math/floor.rs | 0 {llm => libs/llm}/math/floorf.rs | 0 {llm => libs/llm}/math/fma.rs | 0 {llm => libs/llm}/math/fmaf.rs | 0 {llm => libs/llm}/math/fmax.rs | 0 {llm => libs/llm}/math/fmaxf.rs | 0 {llm => libs/llm}/math/fmin.rs | 0 {llm => libs/llm}/math/fminf.rs | 0 {llm => libs/llm}/math/fmod.rs | 0 {llm => libs/llm}/math/fmodf.rs | 0 {llm => libs/llm}/math/frexp.rs | 0 {llm => libs/llm}/math/frexpf.rs | 0 {llm => libs/llm}/math/hypot.rs | 0 {llm => libs/llm}/math/hypotf.rs | 0 {llm => libs/llm}/math/ilogb.rs | 0 {llm => libs/llm}/math/ilogbf.rs | 0 {llm => libs/llm}/math/j0.rs | 0 {llm => libs/llm}/math/j0f.rs | 0 {llm => libs/llm}/math/j1.rs | 0 {llm => libs/llm}/math/j1f.rs | 0 {llm => libs/llm}/math/jn.rs | 0 {llm => libs/llm}/math/jnf.rs | 0 {llm => libs/llm}/math/k_cos.rs | 0 {llm => libs/llm}/math/k_cosf.rs | 0 {llm => libs/llm}/math/k_expo2.rs | 0 {llm => libs/llm}/math/k_expo2f.rs | 0 {llm => libs/llm}/math/k_sin.rs | 0 {llm => libs/llm}/math/k_sinf.rs | 0 {llm => libs/llm}/math/k_tan.rs | 0 {llm => libs/llm}/math/k_tanf.rs | 0 {llm => libs/llm}/math/ldexp.rs | 0 {llm => libs/llm}/math/ldexpf.rs | 0 {llm => libs/llm}/math/lgamma.rs | 0 {llm => libs/llm}/math/lgamma_r.rs | 0 {llm => libs/llm}/math/lgammaf.rs | 0 {llm => libs/llm}/math/lgammaf_r.rs | 0 {llm => libs/llm}/math/ln.rs | 0 {llm => libs/llm}/math/lnf.rs | 0 {llm => libs/llm}/math/log.rs | 0 {llm => libs/llm}/math/log10.rs | 0 {llm => libs/llm}/math/log10f.rs | 0 {llm => libs/llm}/math/log1p.rs | 0 {llm => libs/llm}/math/log1pf.rs | 0 {llm => libs/llm}/math/log2.rs | 0 {llm => libs/llm}/math/log2f.rs | 0 {llm => libs/llm}/math/logf.rs | 0 {llm => libs/llm}/math/modf.rs | 0 {llm => libs/llm}/math/modff.rs | 0 {llm => libs/llm}/math/nextafter.rs | 0 {llm => libs/llm}/math/nextafterf.rs | 0 {llm => libs/llm}/math/pow.rs | 0 {llm => libs/llm}/math/powf.rs | 0 {llm => libs/llm}/math/rem_pio2.rs | 0 {llm => libs/llm}/math/rem_pio2_large.rs | 0 {llm => libs/llm}/math/rem_pio2f.rs | 0 {llm => libs/llm}/math/remainder.rs | 0 {llm => libs/llm}/math/remainderf.rs | 0 {llm => libs/llm}/math/remquo.rs | 0 {llm => libs/llm}/math/remquof.rs | 0 {llm => libs/llm}/math/rint.rs | 0 {llm => libs/llm}/math/rintf.rs | 0 {llm => libs/llm}/math/round.rs | 0 {llm => libs/llm}/math/roundf.rs | 0 {llm => libs/llm}/math/scalbn.rs | 0 {llm => libs/llm}/math/scalbnf.rs | 0 {llm => libs/llm}/math/sin.rs | 0 {llm => libs/llm}/math/sincos.rs | 0 {llm => libs/llm}/math/sincosf.rs | 0 {llm => libs/llm}/math/sinf.rs | 0 {llm => libs/llm}/math/sinh.rs | 0 {llm => libs/llm}/math/sinhf.rs | 0 {llm => libs/llm}/math/sqrt.rs | 0 {llm => libs/llm}/math/sqrtf.rs | 0 {llm => libs/llm}/math/tan.rs | 0 {llm => libs/llm}/math/tanf.rs | 0 {llm => libs/llm}/math/tanh.rs | 0 {llm => libs/llm}/math/tanhf.rs | 0 {llm => libs/llm}/math/tgamma.rs | 0 {llm => libs/llm}/math/tgammaf.rs | 0 {llm => libs/llm}/math/trunc.rs | 0 {llm => libs/llm}/math/truncf.rs | 0 {llm => libs/llm}/types.rs | 0 142 files changed, 6 insertions(+), 6 deletions(-) rename {libtrig => libs/libtrig}/Cargo.toml (92%) rename {libtrig => libs/libtrig}/README.md (100%) rename {libtrig => libs/libtrig}/angle.rs (100%) rename {libtrig => libs/libtrig}/coords/coord2d.rs (100%) rename {libtrig => libs/libtrig}/coords/coord3d.rs (100%) rename {libtrig => libs/libtrig}/coords/mod.rs (100%) rename {libtrig => libs/libtrig}/lib.rs (100%) rename {libtrig => libs/libtrig}/traits/float.rs (100%) rename {libtrig => libs/libtrig}/traits/mod.rs (100%) rename {libtrig => libs/libtrig}/traits/number.rs (100%) rename {libtrig => libs/libtrig}/types.rs (100%) rename {libtrig => libs/libtrig}/vectors/mod.rs (100%) rename {libtrig => libs/libtrig}/vectors/vec2d.rs (100%) rename {libtrig => libs/libtrig}/vectors/vec3d.rs (100%) rename {llm => libs/llm}/Cargo.toml (87%) rename {llm => libs/llm}/README.md (100%) rename {llm => libs/llm}/lib.rs (100%) rename {llm => libs/llm}/math.rs (100%) rename {llm => libs/llm}/math/acos.rs (100%) rename {llm => libs/llm}/math/acosf.rs (100%) rename {llm => libs/llm}/math/acosh.rs (100%) rename {llm => libs/llm}/math/acoshf.rs (100%) rename {llm => libs/llm}/math/asin.rs (100%) rename {llm => libs/llm}/math/asinf.rs (100%) rename {llm => libs/llm}/math/asinh.rs (100%) rename {llm => libs/llm}/math/asinhf.rs (100%) rename {llm => libs/llm}/math/atan.rs (100%) rename {llm => libs/llm}/math/atan2.rs (100%) rename {llm => libs/llm}/math/atan2f.rs (100%) rename {llm => libs/llm}/math/atanf.rs (100%) rename {llm => libs/llm}/math/atanh.rs (100%) rename {llm => libs/llm}/math/atanhf.rs (100%) rename {llm => libs/llm}/math/cbrt.rs (100%) rename {llm => libs/llm}/math/cbrtf.rs (100%) rename {llm => libs/llm}/math/ceil.rs (100%) rename {llm => libs/llm}/math/ceilf.rs (100%) rename {llm => libs/llm}/math/copysign.rs (100%) rename {llm => libs/llm}/math/copysignf.rs (100%) rename {llm => libs/llm}/math/cos.rs (100%) rename {llm => libs/llm}/math/cosf.rs (100%) rename {llm => libs/llm}/math/cosh.rs (100%) rename {llm => libs/llm}/math/coshf.rs (100%) rename {llm => libs/llm}/math/erf.rs (100%) rename {llm => libs/llm}/math/erff.rs (100%) rename {llm => libs/llm}/math/exp.rs (100%) rename {llm => libs/llm}/math/exp10.rs (100%) rename {llm => libs/llm}/math/exp10f.rs (100%) rename {llm => libs/llm}/math/exp2.rs (100%) rename {llm => libs/llm}/math/exp2f.rs (100%) rename {llm => libs/llm}/math/expf.rs (100%) rename {llm => libs/llm}/math/expm1.rs (100%) rename {llm => libs/llm}/math/expm1f.rs (100%) rename {llm => libs/llm}/math/expo2.rs (100%) rename {llm => libs/llm}/math/fabs.rs (100%) rename {llm => libs/llm}/math/fabsf.rs (100%) rename {llm => libs/llm}/math/fdim.rs (100%) rename {llm => libs/llm}/math/fdimf.rs (100%) rename {llm => libs/llm}/math/fenv.rs (100%) rename {llm => libs/llm}/math/floor.rs (100%) rename {llm => libs/llm}/math/floorf.rs (100%) rename {llm => libs/llm}/math/fma.rs (100%) rename {llm => libs/llm}/math/fmaf.rs (100%) rename {llm => libs/llm}/math/fmax.rs (100%) rename {llm => libs/llm}/math/fmaxf.rs (100%) rename {llm => libs/llm}/math/fmin.rs (100%) rename {llm => libs/llm}/math/fminf.rs (100%) rename {llm => libs/llm}/math/fmod.rs (100%) rename {llm => libs/llm}/math/fmodf.rs (100%) rename {llm => libs/llm}/math/frexp.rs (100%) rename {llm => libs/llm}/math/frexpf.rs (100%) rename {llm => libs/llm}/math/hypot.rs (100%) rename {llm => libs/llm}/math/hypotf.rs (100%) rename {llm => libs/llm}/math/ilogb.rs (100%) rename {llm => libs/llm}/math/ilogbf.rs (100%) rename {llm => libs/llm}/math/j0.rs (100%) rename {llm => libs/llm}/math/j0f.rs (100%) rename {llm => libs/llm}/math/j1.rs (100%) rename {llm => libs/llm}/math/j1f.rs (100%) rename {llm => libs/llm}/math/jn.rs (100%) rename {llm => libs/llm}/math/jnf.rs (100%) rename {llm => libs/llm}/math/k_cos.rs (100%) rename {llm => libs/llm}/math/k_cosf.rs (100%) rename {llm => libs/llm}/math/k_expo2.rs (100%) rename {llm => libs/llm}/math/k_expo2f.rs (100%) rename {llm => libs/llm}/math/k_sin.rs (100%) rename {llm => libs/llm}/math/k_sinf.rs (100%) rename {llm => libs/llm}/math/k_tan.rs (100%) rename {llm => libs/llm}/math/k_tanf.rs (100%) rename {llm => libs/llm}/math/ldexp.rs (100%) rename {llm => libs/llm}/math/ldexpf.rs (100%) rename {llm => libs/llm}/math/lgamma.rs (100%) rename {llm => libs/llm}/math/lgamma_r.rs (100%) rename {llm => libs/llm}/math/lgammaf.rs (100%) rename {llm => libs/llm}/math/lgammaf_r.rs (100%) rename {llm => libs/llm}/math/ln.rs (100%) rename {llm => libs/llm}/math/lnf.rs (100%) rename {llm => libs/llm}/math/log.rs (100%) rename {llm => libs/llm}/math/log10.rs (100%) rename {llm => libs/llm}/math/log10f.rs (100%) rename {llm => libs/llm}/math/log1p.rs (100%) rename {llm => libs/llm}/math/log1pf.rs (100%) rename {llm => libs/llm}/math/log2.rs (100%) rename {llm => libs/llm}/math/log2f.rs (100%) rename {llm => libs/llm}/math/logf.rs (100%) rename {llm => libs/llm}/math/modf.rs (100%) rename {llm => libs/llm}/math/modff.rs (100%) rename {llm => libs/llm}/math/nextafter.rs (100%) rename {llm => libs/llm}/math/nextafterf.rs (100%) rename {llm => libs/llm}/math/pow.rs (100%) rename {llm => libs/llm}/math/powf.rs (100%) rename {llm => libs/llm}/math/rem_pio2.rs (100%) rename {llm => libs/llm}/math/rem_pio2_large.rs (100%) rename {llm => libs/llm}/math/rem_pio2f.rs (100%) rename {llm => libs/llm}/math/remainder.rs (100%) rename {llm => libs/llm}/math/remainderf.rs (100%) rename {llm => libs/llm}/math/remquo.rs (100%) rename {llm => libs/llm}/math/remquof.rs (100%) rename {llm => libs/llm}/math/rint.rs (100%) rename {llm => libs/llm}/math/rintf.rs (100%) rename {llm => libs/llm}/math/round.rs (100%) rename {llm => libs/llm}/math/roundf.rs (100%) rename {llm => libs/llm}/math/scalbn.rs (100%) rename {llm => libs/llm}/math/scalbnf.rs (100%) rename {llm => libs/llm}/math/sin.rs (100%) rename {llm => libs/llm}/math/sincos.rs (100%) rename {llm => libs/llm}/math/sincosf.rs (100%) rename {llm => libs/llm}/math/sinf.rs (100%) rename {llm => libs/llm}/math/sinh.rs (100%) rename {llm => libs/llm}/math/sinhf.rs (100%) rename {llm => libs/llm}/math/sqrt.rs (100%) rename {llm => libs/llm}/math/sqrtf.rs (100%) rename {llm => libs/llm}/math/tan.rs (100%) rename {llm => libs/llm}/math/tanf.rs (100%) rename {llm => libs/llm}/math/tanh.rs (100%) rename {llm => libs/llm}/math/tanhf.rs (100%) rename {llm => libs/llm}/math/tgamma.rs (100%) rename {llm => libs/llm}/math/tgammaf.rs (100%) rename {llm => libs/llm}/math/trunc.rs (100%) rename {llm => libs/llm}/math/truncf.rs (100%) rename {llm => libs/llm}/types.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 259ae00..2325a23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,8 @@ members = [ "libs/macros", # Main crates - "libtrig", - "llm", + "libs/libtrig", + "libs/llm", ] [workspace.package] diff --git a/README.md b/README.md index c523ec0..16efcae 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ ### Features -- **[`libtrig`](./libtrig//)** - Trigonometry functionality (angles, vectors, etc.) -- **[`llm`](./llm/)** - Low Level Math - Fundamental math functions and types +- **[`libtrig`](./libs/libtrig//)** - Trigonometry functionality (angles, vectors, etc.) +- **[`llm`](./libs/llm/)** - Low Level Math - Fundamental math functions and types ### Documentation diff --git a/libtrig/Cargo.toml b/libs/libtrig/Cargo.toml similarity index 92% rename from libtrig/Cargo.toml rename to libs/libtrig/Cargo.toml index 27173ba..a415d88 100644 --- a/libtrig/Cargo.toml +++ b/libs/libtrig/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true [dependencies.macros] package = "macros" -path = "../libs/macros" +path = "../macros" [dependencies.llm] package = "llm" diff --git a/libtrig/README.md b/libs/libtrig/README.md similarity index 100% rename from libtrig/README.md rename to libs/libtrig/README.md diff --git a/libtrig/angle.rs b/libs/libtrig/angle.rs similarity index 100% rename from libtrig/angle.rs rename to libs/libtrig/angle.rs diff --git a/libtrig/coords/coord2d.rs b/libs/libtrig/coords/coord2d.rs similarity index 100% rename from libtrig/coords/coord2d.rs rename to libs/libtrig/coords/coord2d.rs diff --git a/libtrig/coords/coord3d.rs b/libs/libtrig/coords/coord3d.rs similarity index 100% rename from libtrig/coords/coord3d.rs rename to libs/libtrig/coords/coord3d.rs diff --git a/libtrig/coords/mod.rs b/libs/libtrig/coords/mod.rs similarity index 100% rename from libtrig/coords/mod.rs rename to libs/libtrig/coords/mod.rs diff --git a/libtrig/lib.rs b/libs/libtrig/lib.rs similarity index 100% rename from libtrig/lib.rs rename to libs/libtrig/lib.rs diff --git a/libtrig/traits/float.rs b/libs/libtrig/traits/float.rs similarity index 100% rename from libtrig/traits/float.rs rename to libs/libtrig/traits/float.rs diff --git a/libtrig/traits/mod.rs b/libs/libtrig/traits/mod.rs similarity index 100% rename from libtrig/traits/mod.rs rename to libs/libtrig/traits/mod.rs diff --git a/libtrig/traits/number.rs b/libs/libtrig/traits/number.rs similarity index 100% rename from libtrig/traits/number.rs rename to libs/libtrig/traits/number.rs diff --git a/libtrig/types.rs b/libs/libtrig/types.rs similarity index 100% rename from libtrig/types.rs rename to libs/libtrig/types.rs diff --git a/libtrig/vectors/mod.rs b/libs/libtrig/vectors/mod.rs similarity index 100% rename from libtrig/vectors/mod.rs rename to libs/libtrig/vectors/mod.rs diff --git a/libtrig/vectors/vec2d.rs b/libs/libtrig/vectors/vec2d.rs similarity index 100% rename from libtrig/vectors/vec2d.rs rename to libs/libtrig/vectors/vec2d.rs diff --git a/libtrig/vectors/vec3d.rs b/libs/libtrig/vectors/vec3d.rs similarity index 100% rename from libtrig/vectors/vec3d.rs rename to libs/libtrig/vectors/vec3d.rs diff --git a/llm/Cargo.toml b/libs/llm/Cargo.toml similarity index 87% rename from llm/Cargo.toml rename to libs/llm/Cargo.toml index acd533d..b6fe1fb 100644 --- a/llm/Cargo.toml +++ b/libs/llm/Cargo.toml @@ -12,7 +12,7 @@ path = "lib.rs" doctest = false [dependencies.macros] -path = "../libs/macros" +path = "../macros" [features] default = ["unstable"] diff --git a/llm/README.md b/libs/llm/README.md similarity index 100% rename from llm/README.md rename to libs/llm/README.md diff --git a/llm/lib.rs b/libs/llm/lib.rs similarity index 100% rename from llm/lib.rs rename to libs/llm/lib.rs diff --git a/llm/math.rs b/libs/llm/math.rs similarity index 100% rename from llm/math.rs rename to libs/llm/math.rs diff --git a/llm/math/acos.rs b/libs/llm/math/acos.rs similarity index 100% rename from llm/math/acos.rs rename to libs/llm/math/acos.rs diff --git a/llm/math/acosf.rs b/libs/llm/math/acosf.rs similarity index 100% rename from llm/math/acosf.rs rename to libs/llm/math/acosf.rs diff --git a/llm/math/acosh.rs b/libs/llm/math/acosh.rs similarity index 100% rename from llm/math/acosh.rs rename to libs/llm/math/acosh.rs diff --git a/llm/math/acoshf.rs b/libs/llm/math/acoshf.rs similarity index 100% rename from llm/math/acoshf.rs rename to libs/llm/math/acoshf.rs diff --git a/llm/math/asin.rs b/libs/llm/math/asin.rs similarity index 100% rename from llm/math/asin.rs rename to libs/llm/math/asin.rs diff --git a/llm/math/asinf.rs b/libs/llm/math/asinf.rs similarity index 100% rename from llm/math/asinf.rs rename to libs/llm/math/asinf.rs diff --git a/llm/math/asinh.rs b/libs/llm/math/asinh.rs similarity index 100% rename from llm/math/asinh.rs rename to libs/llm/math/asinh.rs diff --git a/llm/math/asinhf.rs b/libs/llm/math/asinhf.rs similarity index 100% rename from llm/math/asinhf.rs rename to libs/llm/math/asinhf.rs diff --git a/llm/math/atan.rs b/libs/llm/math/atan.rs similarity index 100% rename from llm/math/atan.rs rename to libs/llm/math/atan.rs diff --git a/llm/math/atan2.rs b/libs/llm/math/atan2.rs similarity index 100% rename from llm/math/atan2.rs rename to libs/llm/math/atan2.rs diff --git a/llm/math/atan2f.rs b/libs/llm/math/atan2f.rs similarity index 100% rename from llm/math/atan2f.rs rename to libs/llm/math/atan2f.rs diff --git a/llm/math/atanf.rs b/libs/llm/math/atanf.rs similarity index 100% rename from llm/math/atanf.rs rename to libs/llm/math/atanf.rs diff --git a/llm/math/atanh.rs b/libs/llm/math/atanh.rs similarity index 100% rename from llm/math/atanh.rs rename to libs/llm/math/atanh.rs diff --git a/llm/math/atanhf.rs b/libs/llm/math/atanhf.rs similarity index 100% rename from llm/math/atanhf.rs rename to libs/llm/math/atanhf.rs diff --git a/llm/math/cbrt.rs b/libs/llm/math/cbrt.rs similarity index 100% rename from llm/math/cbrt.rs rename to libs/llm/math/cbrt.rs diff --git a/llm/math/cbrtf.rs b/libs/llm/math/cbrtf.rs similarity index 100% rename from llm/math/cbrtf.rs rename to libs/llm/math/cbrtf.rs diff --git a/llm/math/ceil.rs b/libs/llm/math/ceil.rs similarity index 100% rename from llm/math/ceil.rs rename to libs/llm/math/ceil.rs diff --git a/llm/math/ceilf.rs b/libs/llm/math/ceilf.rs similarity index 100% rename from llm/math/ceilf.rs rename to libs/llm/math/ceilf.rs diff --git a/llm/math/copysign.rs b/libs/llm/math/copysign.rs similarity index 100% rename from llm/math/copysign.rs rename to libs/llm/math/copysign.rs diff --git a/llm/math/copysignf.rs b/libs/llm/math/copysignf.rs similarity index 100% rename from llm/math/copysignf.rs rename to libs/llm/math/copysignf.rs diff --git a/llm/math/cos.rs b/libs/llm/math/cos.rs similarity index 100% rename from llm/math/cos.rs rename to libs/llm/math/cos.rs diff --git a/llm/math/cosf.rs b/libs/llm/math/cosf.rs similarity index 100% rename from llm/math/cosf.rs rename to libs/llm/math/cosf.rs diff --git a/llm/math/cosh.rs b/libs/llm/math/cosh.rs similarity index 100% rename from llm/math/cosh.rs rename to libs/llm/math/cosh.rs diff --git a/llm/math/coshf.rs b/libs/llm/math/coshf.rs similarity index 100% rename from llm/math/coshf.rs rename to libs/llm/math/coshf.rs diff --git a/llm/math/erf.rs b/libs/llm/math/erf.rs similarity index 100% rename from llm/math/erf.rs rename to libs/llm/math/erf.rs diff --git a/llm/math/erff.rs b/libs/llm/math/erff.rs similarity index 100% rename from llm/math/erff.rs rename to libs/llm/math/erff.rs diff --git a/llm/math/exp.rs b/libs/llm/math/exp.rs similarity index 100% rename from llm/math/exp.rs rename to libs/llm/math/exp.rs diff --git a/llm/math/exp10.rs b/libs/llm/math/exp10.rs similarity index 100% rename from llm/math/exp10.rs rename to libs/llm/math/exp10.rs diff --git a/llm/math/exp10f.rs b/libs/llm/math/exp10f.rs similarity index 100% rename from llm/math/exp10f.rs rename to libs/llm/math/exp10f.rs diff --git a/llm/math/exp2.rs b/libs/llm/math/exp2.rs similarity index 100% rename from llm/math/exp2.rs rename to libs/llm/math/exp2.rs diff --git a/llm/math/exp2f.rs b/libs/llm/math/exp2f.rs similarity index 100% rename from llm/math/exp2f.rs rename to libs/llm/math/exp2f.rs diff --git a/llm/math/expf.rs b/libs/llm/math/expf.rs similarity index 100% rename from llm/math/expf.rs rename to libs/llm/math/expf.rs diff --git a/llm/math/expm1.rs b/libs/llm/math/expm1.rs similarity index 100% rename from llm/math/expm1.rs rename to libs/llm/math/expm1.rs diff --git a/llm/math/expm1f.rs b/libs/llm/math/expm1f.rs similarity index 100% rename from llm/math/expm1f.rs rename to libs/llm/math/expm1f.rs diff --git a/llm/math/expo2.rs b/libs/llm/math/expo2.rs similarity index 100% rename from llm/math/expo2.rs rename to libs/llm/math/expo2.rs diff --git a/llm/math/fabs.rs b/libs/llm/math/fabs.rs similarity index 100% rename from llm/math/fabs.rs rename to libs/llm/math/fabs.rs diff --git a/llm/math/fabsf.rs b/libs/llm/math/fabsf.rs similarity index 100% rename from llm/math/fabsf.rs rename to libs/llm/math/fabsf.rs diff --git a/llm/math/fdim.rs b/libs/llm/math/fdim.rs similarity index 100% rename from llm/math/fdim.rs rename to libs/llm/math/fdim.rs diff --git a/llm/math/fdimf.rs b/libs/llm/math/fdimf.rs similarity index 100% rename from llm/math/fdimf.rs rename to libs/llm/math/fdimf.rs diff --git a/llm/math/fenv.rs b/libs/llm/math/fenv.rs similarity index 100% rename from llm/math/fenv.rs rename to libs/llm/math/fenv.rs diff --git a/llm/math/floor.rs b/libs/llm/math/floor.rs similarity index 100% rename from llm/math/floor.rs rename to libs/llm/math/floor.rs diff --git a/llm/math/floorf.rs b/libs/llm/math/floorf.rs similarity index 100% rename from llm/math/floorf.rs rename to libs/llm/math/floorf.rs diff --git a/llm/math/fma.rs b/libs/llm/math/fma.rs similarity index 100% rename from llm/math/fma.rs rename to libs/llm/math/fma.rs diff --git a/llm/math/fmaf.rs b/libs/llm/math/fmaf.rs similarity index 100% rename from llm/math/fmaf.rs rename to libs/llm/math/fmaf.rs diff --git a/llm/math/fmax.rs b/libs/llm/math/fmax.rs similarity index 100% rename from llm/math/fmax.rs rename to libs/llm/math/fmax.rs diff --git a/llm/math/fmaxf.rs b/libs/llm/math/fmaxf.rs similarity index 100% rename from llm/math/fmaxf.rs rename to libs/llm/math/fmaxf.rs diff --git a/llm/math/fmin.rs b/libs/llm/math/fmin.rs similarity index 100% rename from llm/math/fmin.rs rename to libs/llm/math/fmin.rs diff --git a/llm/math/fminf.rs b/libs/llm/math/fminf.rs similarity index 100% rename from llm/math/fminf.rs rename to libs/llm/math/fminf.rs diff --git a/llm/math/fmod.rs b/libs/llm/math/fmod.rs similarity index 100% rename from llm/math/fmod.rs rename to libs/llm/math/fmod.rs diff --git a/llm/math/fmodf.rs b/libs/llm/math/fmodf.rs similarity index 100% rename from llm/math/fmodf.rs rename to libs/llm/math/fmodf.rs diff --git a/llm/math/frexp.rs b/libs/llm/math/frexp.rs similarity index 100% rename from llm/math/frexp.rs rename to libs/llm/math/frexp.rs diff --git a/llm/math/frexpf.rs b/libs/llm/math/frexpf.rs similarity index 100% rename from llm/math/frexpf.rs rename to libs/llm/math/frexpf.rs diff --git a/llm/math/hypot.rs b/libs/llm/math/hypot.rs similarity index 100% rename from llm/math/hypot.rs rename to libs/llm/math/hypot.rs diff --git a/llm/math/hypotf.rs b/libs/llm/math/hypotf.rs similarity index 100% rename from llm/math/hypotf.rs rename to libs/llm/math/hypotf.rs diff --git a/llm/math/ilogb.rs b/libs/llm/math/ilogb.rs similarity index 100% rename from llm/math/ilogb.rs rename to libs/llm/math/ilogb.rs diff --git a/llm/math/ilogbf.rs b/libs/llm/math/ilogbf.rs similarity index 100% rename from llm/math/ilogbf.rs rename to libs/llm/math/ilogbf.rs diff --git a/llm/math/j0.rs b/libs/llm/math/j0.rs similarity index 100% rename from llm/math/j0.rs rename to libs/llm/math/j0.rs diff --git a/llm/math/j0f.rs b/libs/llm/math/j0f.rs similarity index 100% rename from llm/math/j0f.rs rename to libs/llm/math/j0f.rs diff --git a/llm/math/j1.rs b/libs/llm/math/j1.rs similarity index 100% rename from llm/math/j1.rs rename to libs/llm/math/j1.rs diff --git a/llm/math/j1f.rs b/libs/llm/math/j1f.rs similarity index 100% rename from llm/math/j1f.rs rename to libs/llm/math/j1f.rs diff --git a/llm/math/jn.rs b/libs/llm/math/jn.rs similarity index 100% rename from llm/math/jn.rs rename to libs/llm/math/jn.rs diff --git a/llm/math/jnf.rs b/libs/llm/math/jnf.rs similarity index 100% rename from llm/math/jnf.rs rename to libs/llm/math/jnf.rs diff --git a/llm/math/k_cos.rs b/libs/llm/math/k_cos.rs similarity index 100% rename from llm/math/k_cos.rs rename to libs/llm/math/k_cos.rs diff --git a/llm/math/k_cosf.rs b/libs/llm/math/k_cosf.rs similarity index 100% rename from llm/math/k_cosf.rs rename to libs/llm/math/k_cosf.rs diff --git a/llm/math/k_expo2.rs b/libs/llm/math/k_expo2.rs similarity index 100% rename from llm/math/k_expo2.rs rename to libs/llm/math/k_expo2.rs diff --git a/llm/math/k_expo2f.rs b/libs/llm/math/k_expo2f.rs similarity index 100% rename from llm/math/k_expo2f.rs rename to libs/llm/math/k_expo2f.rs diff --git a/llm/math/k_sin.rs b/libs/llm/math/k_sin.rs similarity index 100% rename from llm/math/k_sin.rs rename to libs/llm/math/k_sin.rs diff --git a/llm/math/k_sinf.rs b/libs/llm/math/k_sinf.rs similarity index 100% rename from llm/math/k_sinf.rs rename to libs/llm/math/k_sinf.rs diff --git a/llm/math/k_tan.rs b/libs/llm/math/k_tan.rs similarity index 100% rename from llm/math/k_tan.rs rename to libs/llm/math/k_tan.rs diff --git a/llm/math/k_tanf.rs b/libs/llm/math/k_tanf.rs similarity index 100% rename from llm/math/k_tanf.rs rename to libs/llm/math/k_tanf.rs diff --git a/llm/math/ldexp.rs b/libs/llm/math/ldexp.rs similarity index 100% rename from llm/math/ldexp.rs rename to libs/llm/math/ldexp.rs diff --git a/llm/math/ldexpf.rs b/libs/llm/math/ldexpf.rs similarity index 100% rename from llm/math/ldexpf.rs rename to libs/llm/math/ldexpf.rs diff --git a/llm/math/lgamma.rs b/libs/llm/math/lgamma.rs similarity index 100% rename from llm/math/lgamma.rs rename to libs/llm/math/lgamma.rs diff --git a/llm/math/lgamma_r.rs b/libs/llm/math/lgamma_r.rs similarity index 100% rename from llm/math/lgamma_r.rs rename to libs/llm/math/lgamma_r.rs diff --git a/llm/math/lgammaf.rs b/libs/llm/math/lgammaf.rs similarity index 100% rename from llm/math/lgammaf.rs rename to libs/llm/math/lgammaf.rs diff --git a/llm/math/lgammaf_r.rs b/libs/llm/math/lgammaf_r.rs similarity index 100% rename from llm/math/lgammaf_r.rs rename to libs/llm/math/lgammaf_r.rs diff --git a/llm/math/ln.rs b/libs/llm/math/ln.rs similarity index 100% rename from llm/math/ln.rs rename to libs/llm/math/ln.rs diff --git a/llm/math/lnf.rs b/libs/llm/math/lnf.rs similarity index 100% rename from llm/math/lnf.rs rename to libs/llm/math/lnf.rs diff --git a/llm/math/log.rs b/libs/llm/math/log.rs similarity index 100% rename from llm/math/log.rs rename to libs/llm/math/log.rs diff --git a/llm/math/log10.rs b/libs/llm/math/log10.rs similarity index 100% rename from llm/math/log10.rs rename to libs/llm/math/log10.rs diff --git a/llm/math/log10f.rs b/libs/llm/math/log10f.rs similarity index 100% rename from llm/math/log10f.rs rename to libs/llm/math/log10f.rs diff --git a/llm/math/log1p.rs b/libs/llm/math/log1p.rs similarity index 100% rename from llm/math/log1p.rs rename to libs/llm/math/log1p.rs diff --git a/llm/math/log1pf.rs b/libs/llm/math/log1pf.rs similarity index 100% rename from llm/math/log1pf.rs rename to libs/llm/math/log1pf.rs diff --git a/llm/math/log2.rs b/libs/llm/math/log2.rs similarity index 100% rename from llm/math/log2.rs rename to libs/llm/math/log2.rs diff --git a/llm/math/log2f.rs b/libs/llm/math/log2f.rs similarity index 100% rename from llm/math/log2f.rs rename to libs/llm/math/log2f.rs diff --git a/llm/math/logf.rs b/libs/llm/math/logf.rs similarity index 100% rename from llm/math/logf.rs rename to libs/llm/math/logf.rs diff --git a/llm/math/modf.rs b/libs/llm/math/modf.rs similarity index 100% rename from llm/math/modf.rs rename to libs/llm/math/modf.rs diff --git a/llm/math/modff.rs b/libs/llm/math/modff.rs similarity index 100% rename from llm/math/modff.rs rename to libs/llm/math/modff.rs diff --git a/llm/math/nextafter.rs b/libs/llm/math/nextafter.rs similarity index 100% rename from llm/math/nextafter.rs rename to libs/llm/math/nextafter.rs diff --git a/llm/math/nextafterf.rs b/libs/llm/math/nextafterf.rs similarity index 100% rename from llm/math/nextafterf.rs rename to libs/llm/math/nextafterf.rs diff --git a/llm/math/pow.rs b/libs/llm/math/pow.rs similarity index 100% rename from llm/math/pow.rs rename to libs/llm/math/pow.rs diff --git a/llm/math/powf.rs b/libs/llm/math/powf.rs similarity index 100% rename from llm/math/powf.rs rename to libs/llm/math/powf.rs diff --git a/llm/math/rem_pio2.rs b/libs/llm/math/rem_pio2.rs similarity index 100% rename from llm/math/rem_pio2.rs rename to libs/llm/math/rem_pio2.rs diff --git a/llm/math/rem_pio2_large.rs b/libs/llm/math/rem_pio2_large.rs similarity index 100% rename from llm/math/rem_pio2_large.rs rename to libs/llm/math/rem_pio2_large.rs diff --git a/llm/math/rem_pio2f.rs b/libs/llm/math/rem_pio2f.rs similarity index 100% rename from llm/math/rem_pio2f.rs rename to libs/llm/math/rem_pio2f.rs diff --git a/llm/math/remainder.rs b/libs/llm/math/remainder.rs similarity index 100% rename from llm/math/remainder.rs rename to libs/llm/math/remainder.rs diff --git a/llm/math/remainderf.rs b/libs/llm/math/remainderf.rs similarity index 100% rename from llm/math/remainderf.rs rename to libs/llm/math/remainderf.rs diff --git a/llm/math/remquo.rs b/libs/llm/math/remquo.rs similarity index 100% rename from llm/math/remquo.rs rename to libs/llm/math/remquo.rs diff --git a/llm/math/remquof.rs b/libs/llm/math/remquof.rs similarity index 100% rename from llm/math/remquof.rs rename to libs/llm/math/remquof.rs diff --git a/llm/math/rint.rs b/libs/llm/math/rint.rs similarity index 100% rename from llm/math/rint.rs rename to libs/llm/math/rint.rs diff --git a/llm/math/rintf.rs b/libs/llm/math/rintf.rs similarity index 100% rename from llm/math/rintf.rs rename to libs/llm/math/rintf.rs diff --git a/llm/math/round.rs b/libs/llm/math/round.rs similarity index 100% rename from llm/math/round.rs rename to libs/llm/math/round.rs diff --git a/llm/math/roundf.rs b/libs/llm/math/roundf.rs similarity index 100% rename from llm/math/roundf.rs rename to libs/llm/math/roundf.rs diff --git a/llm/math/scalbn.rs b/libs/llm/math/scalbn.rs similarity index 100% rename from llm/math/scalbn.rs rename to libs/llm/math/scalbn.rs diff --git a/llm/math/scalbnf.rs b/libs/llm/math/scalbnf.rs similarity index 100% rename from llm/math/scalbnf.rs rename to libs/llm/math/scalbnf.rs diff --git a/llm/math/sin.rs b/libs/llm/math/sin.rs similarity index 100% rename from llm/math/sin.rs rename to libs/llm/math/sin.rs diff --git a/llm/math/sincos.rs b/libs/llm/math/sincos.rs similarity index 100% rename from llm/math/sincos.rs rename to libs/llm/math/sincos.rs diff --git a/llm/math/sincosf.rs b/libs/llm/math/sincosf.rs similarity index 100% rename from llm/math/sincosf.rs rename to libs/llm/math/sincosf.rs diff --git a/llm/math/sinf.rs b/libs/llm/math/sinf.rs similarity index 100% rename from llm/math/sinf.rs rename to libs/llm/math/sinf.rs diff --git a/llm/math/sinh.rs b/libs/llm/math/sinh.rs similarity index 100% rename from llm/math/sinh.rs rename to libs/llm/math/sinh.rs diff --git a/llm/math/sinhf.rs b/libs/llm/math/sinhf.rs similarity index 100% rename from llm/math/sinhf.rs rename to libs/llm/math/sinhf.rs diff --git a/llm/math/sqrt.rs b/libs/llm/math/sqrt.rs similarity index 100% rename from llm/math/sqrt.rs rename to libs/llm/math/sqrt.rs diff --git a/llm/math/sqrtf.rs b/libs/llm/math/sqrtf.rs similarity index 100% rename from llm/math/sqrtf.rs rename to libs/llm/math/sqrtf.rs diff --git a/llm/math/tan.rs b/libs/llm/math/tan.rs similarity index 100% rename from llm/math/tan.rs rename to libs/llm/math/tan.rs diff --git a/llm/math/tanf.rs b/libs/llm/math/tanf.rs similarity index 100% rename from llm/math/tanf.rs rename to libs/llm/math/tanf.rs diff --git a/llm/math/tanh.rs b/libs/llm/math/tanh.rs similarity index 100% rename from llm/math/tanh.rs rename to libs/llm/math/tanh.rs diff --git a/llm/math/tanhf.rs b/libs/llm/math/tanhf.rs similarity index 100% rename from llm/math/tanhf.rs rename to libs/llm/math/tanhf.rs diff --git a/llm/math/tgamma.rs b/libs/llm/math/tgamma.rs similarity index 100% rename from llm/math/tgamma.rs rename to libs/llm/math/tgamma.rs diff --git a/llm/math/tgammaf.rs b/libs/llm/math/tgammaf.rs similarity index 100% rename from llm/math/tgammaf.rs rename to libs/llm/math/tgammaf.rs diff --git a/llm/math/trunc.rs b/libs/llm/math/trunc.rs similarity index 100% rename from llm/math/trunc.rs rename to libs/llm/math/trunc.rs diff --git a/llm/math/truncf.rs b/libs/llm/math/truncf.rs similarity index 100% rename from llm/math/truncf.rs rename to libs/llm/math/truncf.rs diff --git a/llm/types.rs b/libs/llm/types.rs similarity index 100% rename from llm/types.rs rename to libs/llm/types.rs From 4bc9eeed11901ba1d1030b573119c29a27237c55 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sat, 11 Nov 2023 08:48:39 -0800 Subject: [PATCH 42/93] Lint in release mode --- libs/llm/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/llm/lib.rs b/libs/llm/lib.rs index a4a6d75..8fd78b2 100644 --- a/libs/llm/lib.rs +++ b/libs/llm/lib.rs @@ -1,6 +1,7 @@ #![doc = include_str!("./README.md")] #![no_std] #![feature(core_intrinsics)] +#![allow(unused_unsafe)] #![allow(clippy::unreadable_literal)] #![allow(clippy::many_single_char_names)] #![allow(clippy::needless_return)] From db9b444466895c9ed5f093073b352e6b16c542e1 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Tue, 14 Nov 2023 09:41:38 -0800 Subject: [PATCH 43/93] Started adding Java --- .gitignore | 12 +- README.md | 2 +- bindings/.gitignore | 3 + bindings/README.md | 0 bindings/java/build.gradle | 22 +++ .../matveit/librobotop/AccelConstraint.java | 6 + .../dev/matveit/librobotop/HeadingPath.java | 8 + .../java/dev/matveit/librobotop/Math.java | 180 ++++++++++++++++++ .../java/dev/matveit/librobotop/MinMax.java | 13 ++ gradle.properties | 1 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 58695 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 164 ++++++++++++++++ gradlew.bat | 90 +++++++++ settings.gradle | 1 + 15 files changed, 505 insertions(+), 2 deletions(-) create mode 100644 bindings/.gitignore create mode 100644 bindings/README.md create mode 100644 bindings/java/build.gradle create mode 100644 bindings/java/src/main/java/dev/matveit/librobotop/AccelConstraint.java create mode 100644 bindings/java/src/main/java/dev/matveit/librobotop/HeadingPath.java create mode 100644 bindings/java/src/main/java/dev/matveit/librobotop/Math.java create mode 100644 bindings/java/src/main/java/dev/matveit/librobotop/MinMax.java create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore index 8fb9b02..f5e2d2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,16 @@ +# IDE Files +.vscode +.idea + # Rust files /*.lock target # Python files -__pycache__ \ No newline at end of file +__pycache__ + +# Java / Kotlin files +.gradle +local.properties +build +out \ No newline at end of file diff --git a/README.md b/README.md index 16efcae..e996c1a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ### Features -- **[`libtrig`](./libs/libtrig//)** - Trigonometry functionality (angles, vectors, etc.) +- **[`libtrig`](./libs/libtrig/)** - Trigonometry functionality (angles, vectors, etc.) - **[`llm`](./libs/llm/)** - Low Level Math - Fundamental math functions and types ### Documentation diff --git a/bindings/.gitignore b/bindings/.gitignore new file mode 100644 index 0000000..8d951cb --- /dev/null +++ b/bindings/.gitignore @@ -0,0 +1,3 @@ +# I used this for dissassembly +dissassembly +/*.jar \ No newline at end of file diff --git a/bindings/README.md b/bindings/README.md new file mode 100644 index 0000000..e69de29 diff --git a/bindings/java/build.gradle b/bindings/java/build.gradle new file mode 100644 index 0000000..e3ddea7 --- /dev/null +++ b/bindings/java/build.gradle @@ -0,0 +1,22 @@ +plugins { + id 'java' +} + +repositories { + maven { + url = 'https://maven.brott.dev/' + } +} + +dependencies { + implementation "com.acmerobotics.roadrunner:core:1.0.0-beta3" + implementation "com.acmerobotics.roadrunner:actions:1.0.0-beta3" +} + +group "dev.matveit.librobotop" +version "2.0.0" + +tasks.withType(JavaCompile).configureEach { + it.options.encoding("UTF-8") + it.options.compilerArgs += ["-Xlint:none"] +} \ No newline at end of file diff --git a/bindings/java/src/main/java/dev/matveit/librobotop/AccelConstraint.java b/bindings/java/src/main/java/dev/matveit/librobotop/AccelConstraint.java new file mode 100644 index 0000000..5b4e297 --- /dev/null +++ b/bindings/java/src/main/java/dev/matveit/librobotop/AccelConstraint.java @@ -0,0 +1,6 @@ +package dev.matveit.librobotop; + +@FunctionalInterface +public interface AccelConstraint { + MinMax minMaxProfileAccel(Pose2dDual pose, PosePath path, double s); +} diff --git a/bindings/java/src/main/java/dev/matveit/librobotop/HeadingPath.java b/bindings/java/src/main/java/dev/matveit/librobotop/HeadingPath.java new file mode 100644 index 0000000..9f3147c --- /dev/null +++ b/bindings/java/src/main/java/dev/matveit/librobotop/HeadingPath.java @@ -0,0 +1,8 @@ +package dev.matveit.librobotop; + +public interface HeadingPath { + Rotation2dDual get(double s, int n); + Rotation2dDual begin(int n); + Rotation2dDual end(int n); + double length(); +} diff --git a/bindings/java/src/main/java/dev/matveit/librobotop/Math.java b/bindings/java/src/main/java/dev/matveit/librobotop/Math.java new file mode 100644 index 0000000..54a7cde --- /dev/null +++ b/bindings/java/src/main/java/dev/matveit/librobotop/Math.java @@ -0,0 +1,180 @@ +package dev.matveit.librobotop; + +public class Math { + // ~10 * machine epsilon + private static final double EPS = 2.2e-15; + + /** + * Function `snz(x)` from section VI.A of the [SymForce paper](https://arxiv.org/abs/2204.07889) for use in + * singularity handling. + */ + public static double snz(double x) { + if (x >= 0.0) return EPS; + return -EPS; + } + + public static double clamp(double x, double lo, double hi) { + if (x < lo) return lo; + if (x > hi) return hi; + return x; + } + + data class MinMax(@JvmField val min: Double, @JvmField val max: Double) + +/** + * @usesMathJax + * + * Partitions \([a, b]\) into \((n - 1)\) equal intervals and returns the endpoints. + * + * @param[begin] \(a\) + * @param[end] \(b\) + * @param[samples] \(n\) + */ +fun range(begin: Double, end: Double, samples: Int): List { + require(samples >= 2) + val dx = (end - begin) / (samples - 1) + return (0 until samples).map { begin + dx * it } + } + + /** + * @usesMathJax + * + * Partitions \([a, b]\) into \(n\) equal intervals and returns the center values. + * + * @param[begin] \(a\) + * @param[end] \(b\) + * @param[samples] \(n\) + */ + fun rangeCentered(begin: Double, end: Double, samples: Int): List { + require(samples >= 1) + val dx = (end - begin) / samples + return (0 until samples).map { begin + 0.5 * dx + dx * it } + } + + // TODO: is the branch here okay? would snz() on the denominator be better? + fun lerp(x: Double, fromLo: Double, fromHi: Double, toLo: Double, toHi: Double) = + if (fromLo == fromHi) 0.0 + else + toLo + (x - fromLo) * (toHi - toLo) / (fromHi - fromLo) + + data class IntegralScanResult( + @JvmField + val values: List, + @JvmField + val sums: List, + ) + +/** + * @usesMathJax + * + * Returns samples of \(g(t) = \int_a^t f(x) \, dx\) for various values \(a \leq t \leq b\). The sampling points are + * chosen adaptively using the algorithm `adaptsim` from [Gander and Gautschi](https://doi.org/10.1023/A:1022318402393) + * ([more accessible link](https://users.wpi.edu/~walker/MA510/HANDOUTS/w.gander,w.gautschi,Adaptive_Quadrature,BIT_40,2000,84-101.pdf)). + * + * @param[a] \(a\) + * @param[b] \(b\) + * @param[f] \(f(x)\) + * @param[eps] desired error in the length approximation \(g(b)\) + */ +fun integralScan(a: Double, b: Double, eps: Double, f: (Double) -> Double): IntegralScanResult { + val m = (a + b) / 2 + val fa = f(a) + val fm = f(m) + val fb = f(b) + + var i = (b - a) / 8 * ( + fa + fm + fb + + f(a + 0.9501 * (b - a)) + + f(a + 0.2311 * (b - a)) + + f(a + 0.6068 * (b - a)) + + f(a + 0.4860 * (b - a)) + + f(a + 0.8913 * (b - a)) + ) + if (i == 0.0) { + i = b - a + } + i *= eps / Math.ulp(1.0) + + val values = mutableListOf(0.0) + val sums = mutableListOf(0.0) + + fun helper(a: Double, m: Double, b: Double, fa: Double, fm: Double, fb: Double) { + val h = (b - a) / 4 + val ml = a + h + val mr = b - h + val fml = f(ml) + val fmr = f(mr) + var i1 = h / 1.5 * (fa + 4 * fm + fb) + val i2 = h / 3 * (fa + 4 * (fml + fmr) + 2 * fm + fb) + i1 = (16 * i2 - i1) / 15 + if (i + (i1 - i2) == i || m <= a || b <= m) { + values.add(b) + sums.add(sums.last() + i1) + } else { + helper(a, ml, m, fa, fml, fm) + helper(m, mr, b, fm, fmr, fb) + } + } + + helper(a, m, b, fa, fm, fb) + + return IntegralScanResult(values, sums) + } + + // precondition: source, target sorted and share the same length + fun lerpLookup(source: List, target: List, query: Double): Double { + require(source.size == target.size) + require(source.isNotEmpty()) + + val index = source.binarySearch(query) + return if (index >= 0) { + target[index] + } else { + val insIndex = -(index + 1) + when { + insIndex <= 0 -> target.first() + insIndex >= source.size -> target.last() + else -> { + val sLo = source[insIndex - 1] + val sHi = source[insIndex] + val tLo = target[insIndex - 1] + val tHi = target[insIndex] + lerp(query, sLo, sHi, tLo, tHi) + } + } + } + } + + // precondition: source, target sorted and share the same length; queries sorted + fun lerpLookupMap(source: List, target: List, queries: List): List { + require(source.size == target.size) + require(source.isNotEmpty()) + + val result = mutableListOf() + + var i = 0 + for (query in queries) { + if (query < source[0]) { + result.add(target[0]) + continue + } + + while (i + 1 < source.size && source[i + 1] < query) { + i++ + } + + if (i + 1 == source.size) { + result.add(target.last()) + continue + } + + val sLo = source[i] + val sHi = source[i + 1] + val tLo = target[i] + val tHi = target[i + 1] + result.add(lerp(query, sLo, sHi, tLo, tHi)) + } + + return result + } +} diff --git a/bindings/java/src/main/java/dev/matveit/librobotop/MinMax.java b/bindings/java/src/main/java/dev/matveit/librobotop/MinMax.java new file mode 100644 index 0000000..d97c360 --- /dev/null +++ b/bindings/java/src/main/java/dev/matveit/librobotop/MinMax.java @@ -0,0 +1,13 @@ +package dev.matveit.librobotop; + +public class MinMax { + public final double min; + public final double max; + public MinMax(double min, double max) { + this.min = min; + this.max = max; + } + public MinMax(MinMax other) { + this(other.min, other.max); + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..6924422 --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx8G diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..f3d88b1c2faf2fc91d853cd5d4242b5547257070 GIT binary patch literal 58695 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..aa991fc --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..91a7e26 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..0b66d0d --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':bindings:java' \ No newline at end of file From 22936ebaa840fb3320dfa62bace53c095dd530aa Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 16 Nov 2023 09:56:32 -0800 Subject: [PATCH 44/93] Removed Java + Preparing llm & libtrig --- bindings/java/build.gradle | 22 --- .../matveit/librobotop/AccelConstraint.java | 6 - .../dev/matveit/librobotop/HeadingPath.java | 8 - .../java/dev/matveit/librobotop/Math.java | 180 ------------------ .../java/dev/matveit/librobotop/MinMax.java | 13 -- libs/libtrig/Cargo.toml | 2 - libs/libtrig/angle.rs | 5 + libs/libtrig/traits/float.rs | 5 + libs/libtrig/traits/mod.rs | 5 + libs/llm/math.rs | 1 + libs/llm/math/fabs.rs | 2 - libs/llm/math/ulp.rs | 114 +++++++++++ 12 files changed, 130 insertions(+), 233 deletions(-) delete mode 100644 bindings/java/build.gradle delete mode 100644 bindings/java/src/main/java/dev/matveit/librobotop/AccelConstraint.java delete mode 100644 bindings/java/src/main/java/dev/matveit/librobotop/HeadingPath.java delete mode 100644 bindings/java/src/main/java/dev/matveit/librobotop/Math.java delete mode 100644 bindings/java/src/main/java/dev/matveit/librobotop/MinMax.java create mode 100644 libs/llm/math/ulp.rs diff --git a/bindings/java/build.gradle b/bindings/java/build.gradle deleted file mode 100644 index e3ddea7..0000000 --- a/bindings/java/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ -plugins { - id 'java' -} - -repositories { - maven { - url = 'https://maven.brott.dev/' - } -} - -dependencies { - implementation "com.acmerobotics.roadrunner:core:1.0.0-beta3" - implementation "com.acmerobotics.roadrunner:actions:1.0.0-beta3" -} - -group "dev.matveit.librobotop" -version "2.0.0" - -tasks.withType(JavaCompile).configureEach { - it.options.encoding("UTF-8") - it.options.compilerArgs += ["-Xlint:none"] -} \ No newline at end of file diff --git a/bindings/java/src/main/java/dev/matveit/librobotop/AccelConstraint.java b/bindings/java/src/main/java/dev/matveit/librobotop/AccelConstraint.java deleted file mode 100644 index 5b4e297..0000000 --- a/bindings/java/src/main/java/dev/matveit/librobotop/AccelConstraint.java +++ /dev/null @@ -1,6 +0,0 @@ -package dev.matveit.librobotop; - -@FunctionalInterface -public interface AccelConstraint { - MinMax minMaxProfileAccel(Pose2dDual pose, PosePath path, double s); -} diff --git a/bindings/java/src/main/java/dev/matveit/librobotop/HeadingPath.java b/bindings/java/src/main/java/dev/matveit/librobotop/HeadingPath.java deleted file mode 100644 index 9f3147c..0000000 --- a/bindings/java/src/main/java/dev/matveit/librobotop/HeadingPath.java +++ /dev/null @@ -1,8 +0,0 @@ -package dev.matveit.librobotop; - -public interface HeadingPath { - Rotation2dDual get(double s, int n); - Rotation2dDual begin(int n); - Rotation2dDual end(int n); - double length(); -} diff --git a/bindings/java/src/main/java/dev/matveit/librobotop/Math.java b/bindings/java/src/main/java/dev/matveit/librobotop/Math.java deleted file mode 100644 index 54a7cde..0000000 --- a/bindings/java/src/main/java/dev/matveit/librobotop/Math.java +++ /dev/null @@ -1,180 +0,0 @@ -package dev.matveit.librobotop; - -public class Math { - // ~10 * machine epsilon - private static final double EPS = 2.2e-15; - - /** - * Function `snz(x)` from section VI.A of the [SymForce paper](https://arxiv.org/abs/2204.07889) for use in - * singularity handling. - */ - public static double snz(double x) { - if (x >= 0.0) return EPS; - return -EPS; - } - - public static double clamp(double x, double lo, double hi) { - if (x < lo) return lo; - if (x > hi) return hi; - return x; - } - - data class MinMax(@JvmField val min: Double, @JvmField val max: Double) - -/** - * @usesMathJax - * - * Partitions \([a, b]\) into \((n - 1)\) equal intervals and returns the endpoints. - * - * @param[begin] \(a\) - * @param[end] \(b\) - * @param[samples] \(n\) - */ -fun range(begin: Double, end: Double, samples: Int): List { - require(samples >= 2) - val dx = (end - begin) / (samples - 1) - return (0 until samples).map { begin + dx * it } - } - - /** - * @usesMathJax - * - * Partitions \([a, b]\) into \(n\) equal intervals and returns the center values. - * - * @param[begin] \(a\) - * @param[end] \(b\) - * @param[samples] \(n\) - */ - fun rangeCentered(begin: Double, end: Double, samples: Int): List { - require(samples >= 1) - val dx = (end - begin) / samples - return (0 until samples).map { begin + 0.5 * dx + dx * it } - } - - // TODO: is the branch here okay? would snz() on the denominator be better? - fun lerp(x: Double, fromLo: Double, fromHi: Double, toLo: Double, toHi: Double) = - if (fromLo == fromHi) 0.0 - else - toLo + (x - fromLo) * (toHi - toLo) / (fromHi - fromLo) - - data class IntegralScanResult( - @JvmField - val values: List, - @JvmField - val sums: List, - ) - -/** - * @usesMathJax - * - * Returns samples of \(g(t) = \int_a^t f(x) \, dx\) for various values \(a \leq t \leq b\). The sampling points are - * chosen adaptively using the algorithm `adaptsim` from [Gander and Gautschi](https://doi.org/10.1023/A:1022318402393) - * ([more accessible link](https://users.wpi.edu/~walker/MA510/HANDOUTS/w.gander,w.gautschi,Adaptive_Quadrature,BIT_40,2000,84-101.pdf)). - * - * @param[a] \(a\) - * @param[b] \(b\) - * @param[f] \(f(x)\) - * @param[eps] desired error in the length approximation \(g(b)\) - */ -fun integralScan(a: Double, b: Double, eps: Double, f: (Double) -> Double): IntegralScanResult { - val m = (a + b) / 2 - val fa = f(a) - val fm = f(m) - val fb = f(b) - - var i = (b - a) / 8 * ( - fa + fm + fb + - f(a + 0.9501 * (b - a)) + - f(a + 0.2311 * (b - a)) + - f(a + 0.6068 * (b - a)) + - f(a + 0.4860 * (b - a)) + - f(a + 0.8913 * (b - a)) - ) - if (i == 0.0) { - i = b - a - } - i *= eps / Math.ulp(1.0) - - val values = mutableListOf(0.0) - val sums = mutableListOf(0.0) - - fun helper(a: Double, m: Double, b: Double, fa: Double, fm: Double, fb: Double) { - val h = (b - a) / 4 - val ml = a + h - val mr = b - h - val fml = f(ml) - val fmr = f(mr) - var i1 = h / 1.5 * (fa + 4 * fm + fb) - val i2 = h / 3 * (fa + 4 * (fml + fmr) + 2 * fm + fb) - i1 = (16 * i2 - i1) / 15 - if (i + (i1 - i2) == i || m <= a || b <= m) { - values.add(b) - sums.add(sums.last() + i1) - } else { - helper(a, ml, m, fa, fml, fm) - helper(m, mr, b, fm, fmr, fb) - } - } - - helper(a, m, b, fa, fm, fb) - - return IntegralScanResult(values, sums) - } - - // precondition: source, target sorted and share the same length - fun lerpLookup(source: List, target: List, query: Double): Double { - require(source.size == target.size) - require(source.isNotEmpty()) - - val index = source.binarySearch(query) - return if (index >= 0) { - target[index] - } else { - val insIndex = -(index + 1) - when { - insIndex <= 0 -> target.first() - insIndex >= source.size -> target.last() - else -> { - val sLo = source[insIndex - 1] - val sHi = source[insIndex] - val tLo = target[insIndex - 1] - val tHi = target[insIndex] - lerp(query, sLo, sHi, tLo, tHi) - } - } - } - } - - // precondition: source, target sorted and share the same length; queries sorted - fun lerpLookupMap(source: List, target: List, queries: List): List { - require(source.size == target.size) - require(source.isNotEmpty()) - - val result = mutableListOf() - - var i = 0 - for (query in queries) { - if (query < source[0]) { - result.add(target[0]) - continue - } - - while (i + 1 < source.size && source[i + 1] < query) { - i++ - } - - if (i + 1 == source.size) { - result.add(target.last()) - continue - } - - val sLo = source[i] - val sHi = source[i + 1] - val tLo = target[i] - val tHi = target[i + 1] - result.add(lerp(query, sLo, sHi, tLo, tHi)) - } - - return result - } -} diff --git a/bindings/java/src/main/java/dev/matveit/librobotop/MinMax.java b/bindings/java/src/main/java/dev/matveit/librobotop/MinMax.java deleted file mode 100644 index d97c360..0000000 --- a/bindings/java/src/main/java/dev/matveit/librobotop/MinMax.java +++ /dev/null @@ -1,13 +0,0 @@ -package dev.matveit.librobotop; - -public class MinMax { - public final double min; - public final double max; - public MinMax(double min, double max) { - this.min = min; - this.max = max; - } - public MinMax(MinMax other) { - this(other.min, other.max); - } -} diff --git a/libs/libtrig/Cargo.toml b/libs/libtrig/Cargo.toml index a415d88..fad8517 100644 --- a/libs/libtrig/Cargo.toml +++ b/libs/libtrig/Cargo.toml @@ -8,11 +8,9 @@ authors.workspace = true license.workspace = true [dependencies.macros] -package = "macros" path = "../macros" [dependencies.llm] -package = "llm" path = "../llm" [lib] diff --git a/libs/libtrig/angle.rs b/libs/libtrig/angle.rs index 9005943..0ce1c4a 100644 --- a/libs/libtrig/angle.rs +++ b/libs/libtrig/angle.rs @@ -419,6 +419,11 @@ impl crate::traits::Float for Angle2D { fn sin_cos(&self) -> (Float64, Float64) { self.0.sin_cos() } + #[inline] + #[must_use] + fn signof(&self, rhs: Self) -> Float64 { + self.0.signof(rhs.0) + } i!(floor ceil round trunc fract abs signum sqrt exp exp2 ln log2 log10 cbrt sin cos tan asin acos atan exp_m1 ln_1p sinh cosh tanh asinh acosh atanh); diff --git a/libs/libtrig/traits/float.rs b/libs/libtrig/traits/float.rs index c918a27..db3a671 100644 --- a/libs/libtrig/traits/float.rs +++ b/libs/libtrig/traits/float.rs @@ -125,6 +125,11 @@ pub trait Float: Number { #[must_use = "method returns a new number and does not mutate the original value"] fn signum(&self) -> Output; + /// Returns `self` with the sign of `rhs`. + /// This method computes `self.abs() * rhs.signum()`. + #[must_use] + fn signof(&self, rhs: Self) -> Output; + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error, yielding a more accurate result than an unfused multiply-add. /// diff --git a/libs/libtrig/traits/mod.rs b/libs/libtrig/traits/mod.rs index 258f1df..9f1b235 100644 --- a/libs/libtrig/traits/mod.rs +++ b/libs/libtrig/traits/mod.rs @@ -52,6 +52,11 @@ impl Float for Float64 { } #[inline] #[must_use] + fn signof(&self, rhs: Self) -> Self { + self.abs() * rhs.signum() + } + #[inline] + #[must_use] fn powi(&self, n: Int) -> Self { llm::pow(*self, n as Float64) } diff --git a/libs/llm/math.rs b/libs/llm/math.rs index 14eb550..f103e31 100644 --- a/libs/llm/math.rs +++ b/libs/llm/math.rs @@ -115,6 +115,7 @@ import!(pub pow, powf); import!(pub remainder, remainderf, remquo, remquof, rint, rintf, round, roundf); import!(pub scalbn, scalbnf, sin, sincos, sincosf, sinf, sinh, sinhf, sqrt, sqrtf); import!(pub tan, tanf, tanh, tanhf, tgamma, tgammaf, trunc, truncf); +import!(pub ulp); // Private modules import!( diff --git a/libs/llm/math/fabs.rs b/libs/llm/math/fabs.rs index 1c438d2..53b1728 100644 --- a/libs/llm/math/fabs.rs +++ b/libs/llm/math/fabs.rs @@ -1,7 +1,5 @@ use crate::Float64; -use core::u64; - /// Absolute value (magnitude) /// /// Calculates the absolute value (magnitude) of the argument `x`, diff --git a/libs/llm/math/ulp.rs b/libs/llm/math/ulp.rs new file mode 100644 index 0000000..bbdbf0b --- /dev/null +++ b/libs/llm/math/ulp.rs @@ -0,0 +1,114 @@ +use crate::Float64; + +const MANTISSA_BITS: u64 = 52; +const EXPONENT_BITS: u64 = 11; +const POS_ZERO_BITS: u64 = 0x0000000000000000; +const NEG_ZERO_BITS: u64 = 0x8000000000000000; + +/// Returns the value of the least significant bit of the given floating point number. +/// +/// Note: this function can technically be `const` but we need to wait for: +/// - [`const_fn_floating_point_arithmetic`](https://github.com/rust-lang/rust/issues/57241) +/// - [`const_float_classify`](https://github.com/rust-lang/rust/issues/72505) +/// - [`const_fn_floating_point_arithmetic`](https://github.com/rust-lang/rust/issues/57241) +#[inline] +#[allow(unused_variables)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[must_use = "This function returns the least significant bit of the argument."] +pub fn ulp(x: Float64) -> Float64 { + // SAFETY: x is a normal number, so it is finite and not zero. + if x.is_nan() { + return x; + } + if x.is_infinite() { + return Float64::INFINITY; + } + if x == Float64::MAX || x == -Float64::MAX || + x == Float64::MIN || x == -Float64::MIN || + x == Float64::MIN_POSITIVE || x == -Float64::MIN_POSITIVE { + return x; + } + + // Last sanity check + let bits = x.to_bits(); + + if bits == POS_ZERO_BITS { + return Float64::MIN_POSITIVE; + } + if bits == NEG_ZERO_BITS { + return -Float64::MIN_POSITIVE; + } + + // Actual code + let mant_mask = (1 << MANTISSA_BITS) - 1; + let mantissa = bits & mant_mask; + let exp_mask = (1 << EXPONENT_BITS) - 1; + let exponent = (bits >> MANTISSA_BITS) & exp_mask; + if exponent == 0 { + let result = (exponent << MANTISSA_BITS) | 1; + return Float64::from_bits(result); + }; + let mut new_exponent = exponent - MANTISSA_BITS; + let new_mantissa: u64; + if new_exponent > 0 { + new_mantissa = 0; + } else { + new_mantissa = 1 << -(new_exponent as i64 - 1); + new_exponent = 0; + }; + Float64::from_bits((new_exponent << MANTISSA_BITS) | new_mantissa) +} + +#[test] +fn zero_ulp() { + assert_eq!(ulp(0.0), Float64::MIN_POSITIVE); + assert_eq!(ulp(-0.0), -Float64::MIN_POSITIVE); +} + +#[test] +fn one_ulp() { + assert_eq!(ulp(1.0), Float64::EPSILON); + assert_eq!(ulp(-1.0), Float64::EPSILON); +} + +#[test] +fn two_ulp() { + assert_eq!(ulp(2.0), Float64::EPSILON * 2.0); + assert_eq!(ulp(-2.0), Float64::EPSILON * 2.0); +} + +#[test] +fn half_ulp() { + assert_eq!(ulp(0.5), Float64::EPSILON / 2.0); + assert_eq!(ulp(-0.5), Float64::EPSILON / 2.0); +} + +#[test] +fn max_value_ulp() { + assert_eq!(ulp(Float64::MAX), Float64::MAX); + assert_eq!(ulp(-Float64::MAX), -Float64::MAX); +} + +#[test] +fn min_value_ulp() { + assert_eq!(ulp(Float64::MIN), Float64::MIN); + assert_eq!(ulp(-Float64::MIN), -Float64::MIN); +} + +#[test] +fn infinity_ulp() { + assert_eq!(ulp(Float64::INFINITY), Float64::INFINITY); + assert_eq!(ulp(-Float64::INFINITY), Float64::INFINITY); +} + +#[test] +fn nan_ulp() { + assert!(ulp(Float64::NAN).is_nan()); + assert!(ulp(-Float64::NAN).is_nan()); +} + +#[test] +fn subnormal_ulp() { + assert_eq!(ulp(Float64::MIN_POSITIVE), Float64::MIN_POSITIVE); + assert_eq!(ulp(-Float64::MIN_POSITIVE), -Float64::MIN_POSITIVE); +} From 0b3afdbe09999e6a93d4dc2bf453bd045443cfa0 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 16 Nov 2023 15:47:24 -0800 Subject: [PATCH 45/93] Major upgrade... But Broken --- Cargo.toml | 3 + libs/libodo/Cargo.toml | 17 +++ libs/libodo/README.md | 0 libs/libodo/dualnum.rs | 2 + libs/libodo/lib.rs | 12 ++ libs/libodo/rotation2d.rs | 19 +++ libs/libpath/Cargo.toml | 20 +++ libs/libpath/README.md | 0 libs/libpath/control.rs | 110 ++++++++++++++ libs/libpath/lib.rs | 12 ++ libs/libpath/math.rs | 233 ++++++++++++++++++++++++++++ libs/libtrig/angle.rs | 128 ++++++++++++++-- libs/libtrig/lib.rs | 7 +- libs/libtrig/traits/float.rs | 2 +- libs/libtrig/traits/mod.rs | 72 +++++++++ libs/libtrig/traits/number.rs | 22 ++- libs/llm/bindings/Cargo.toml | 18 +++ libs/llm/bindings/lib.rs | 278 ++++++++++++++++++++++++++++++++++ libs/llm/bindings/llm.h | 266 ++++++++++++++++++++++++++++++++ libs/llm/lib.rs | 11 +- libs/llm/macros.rs | 23 +++ libs/macros-core/ffi/mod.rs | 30 +++- 22 files changed, 1255 insertions(+), 30 deletions(-) create mode 100644 libs/libodo/Cargo.toml create mode 100644 libs/libodo/README.md create mode 100644 libs/libodo/dualnum.rs create mode 100644 libs/libodo/lib.rs create mode 100644 libs/libodo/rotation2d.rs create mode 100644 libs/libpath/Cargo.toml create mode 100644 libs/libpath/README.md create mode 100644 libs/libpath/control.rs create mode 100644 libs/libpath/lib.rs create mode 100644 libs/libpath/math.rs create mode 100644 libs/llm/bindings/Cargo.toml create mode 100644 libs/llm/bindings/lib.rs create mode 100644 libs/llm/bindings/llm.h create mode 100644 libs/llm/macros.rs diff --git a/Cargo.toml b/Cargo.toml index 2325a23..2f89b26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,9 @@ members = [ # Main crates "libs/libtrig", + "libs/libpath", + "libs/libodo", + "libs/llm/bindings", "libs/llm", ] diff --git a/libs/libodo/Cargo.toml b/libs/libodo/Cargo.toml new file mode 100644 index 0000000..46ca200 --- /dev/null +++ b/libs/libodo/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "libodo" +description = "Core odometrix functionality, you probably shouldn't use this directly" +repository.workspace = true +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true + +[dependencies.libtrig] +path = "../libtrig" + +[dependencies.llm] +path = "../llm" + +[lib] +path = "lib.rs" diff --git a/libs/libodo/README.md b/libs/libodo/README.md new file mode 100644 index 0000000..e69de29 diff --git a/libs/libodo/dualnum.rs b/libs/libodo/dualnum.rs new file mode 100644 index 0000000..e99b378 --- /dev/null +++ b/libs/libodo/dualnum.rs @@ -0,0 +1,2 @@ +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] +pub struct DualNum(alloc::vec::Vec); \ No newline at end of file diff --git a/libs/libodo/lib.rs b/libs/libodo/lib.rs new file mode 100644 index 0000000..1b545c5 --- /dev/null +++ b/libs/libodo/lib.rs @@ -0,0 +1,12 @@ +#![no_std] +#![feature(core_intrinsics)] +#![warn(missing_docs, unused, clippy::all)] +#![doc = include_str!("./README.md")] + +extern crate alloc; + +mod rotation2d; +mod dualnum; + +pub use rotation2d::Rotation2D; +pub use dualnum::DualNum; diff --git a/libs/libodo/rotation2d.rs b/libs/libodo/rotation2d.rs new file mode 100644 index 0000000..8f13f36 --- /dev/null +++ b/libs/libodo/rotation2d.rs @@ -0,0 +1,19 @@ +use llm::Float64; + +pub struct Rotation2D { + pub real: Float64, + pub imag: Float64, +} + +impl Rotation2D { + pub const fn new(real: Float64, imag: Float64) -> Self { + Self { real, imag } + } +} + +impl From for Rotation2D { + fn from(angle: libtrig::Angle2D) -> Self { + use libtrig::prelude::*; + Self::new(angle.cos(), angle.sin()) + } +} diff --git a/libs/libpath/Cargo.toml b/libs/libpath/Cargo.toml new file mode 100644 index 0000000..070d8df --- /dev/null +++ b/libs/libpath/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "libpath" +description = "Pathing" +repository.workspace = true +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true + +[dependencies.libtrig] +path = "../libtrig" + +[dependencies.libodo] +path = "../libodo" + +[dependencies.llm] +path = "../llm" + +[lib] +path = "lib.rs" diff --git a/libs/libpath/README.md b/libs/libpath/README.md new file mode 100644 index 0000000..e69de29 diff --git a/libs/libpath/control.rs b/libs/libpath/control.rs new file mode 100644 index 0000000..f30ebea --- /dev/null +++ b/libs/libpath/control.rs @@ -0,0 +1,110 @@ +use llm::Float64; +use libtrig::{Vec2D}; + +/// Kinematic motor feedforward +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct MotorFeedforward { + /// The static gain, or the voltage required to overcome static friction. + pub k_s: Float64, + /// The velocity gain, or the voltage required to maintain a given velocity. + pub k_v: Float64, + /// The acceleration gain, or the voltage required to produce a given acceleration. + pub k_a: Float64, +} + +impl Eq for MotorFeedforward {} + +impl MotorFeedforward { + /// Creates a new motor feedforward. + pub const fn new(k_s: Float64, k_v: Float64, k_a: Float64) -> Self { + Self { k_s, k_v, k_a } + } + /// Computes the (normalized) voltage: + /// ```text,no_run,ignore + /// |kₛ| · (v / |v|) + kᵥ · v + kₐ · a + /// ``` + pub fn compute(&self, vel: Float64, accel: Float64) -> Float64 { + use libtrig::prelude::*; + self.k_s.signof(vel) + self.k_v * vel + self.k_a * accel + } +} + +/// Proportional position-velocity controller for a holonomic robot. +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct HolonomicController { + axial_pos_gain: Float64, + lateral_pos_gain: Float64, + heading_gain: Float64, + axial_vel_gain: Float64, + lateral_vel_gain: Float64, + heading_vel_gain: Float64, +} + +impl Eq for HolonomicController {} + +impl HolonomicController { + pub const fn new( + axial_pos_gain: Float64, + lateral_pos_gain: Float64, + heading_gain: Float64, + ) -> Self { + Self { + axial_pos_gain, + lateral_pos_gain, + heading_gain, + axial_vel_gain: 0.0, + lateral_vel_gain: 0.0, + heading_vel_gain: 0.0, + } + } + /* + fun compute( + targetPose: Pose2dDual

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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index aa991fc..0000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew deleted file mode 100644 index 91a7e26..0000000 --- a/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index 8a0b282..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/libs/eztest/EZtest b/libs/eztest/EZtest deleted file mode 100644 index b77b5ff..0000000 --- a/libs/eztest/EZtest +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#ifndef __EZTEST_H -#define __EZTEST_H - -#ifdef __cplusplus -#define ____EZTEST_BOOL bool -#define ____EZTEST_TRUE true -#define ____EZTEST_FALSE false -#else // __cplusplus -#define ____EZTEST_BOOL int -#define ____EZTEST_TRUE 1 -#define ____EZTEST_FALSE 0 -#endif // __cplusplus - -/// Return from a test with success. -#define OK return ____EZTEST_TRUE; -/// Return from a test with failure. -#define FAIL return ____EZTEST_FALSE; -/// Assert that a condition is true. -#define ASSERT(x) if ( !(x) ) { FAIL; } -/// Assert that two values are equal. -#define ASSERT_EQ(x, y) if ((x) != (y)) { FAIL; } -/// Assert that two values are not equal. -#define ASSERT_NE(x, y) if ((x) == (y)) { FAIL; } -/// Assert that a value is less than another. -#define ASSERT_LT(x, y) if ((x) >= (y)) { FAIL; } -/// Assert that a value is less than or equal to another. -#define ASSERT_LE(x, y) if ((x) > (y)) { FAIL; } -/// Assert that a value is greater than another. -#define ASSERT_GT(x, y) if ((x) <= (y)) { FAIL; } -/// Assert that a value is greater than or equal to another. -#define ASSERT_GE(x, y) if ((x) < (y)) { FAIL; } - -/// Register a test. -/// -/// You should not call this function directly. Instead, use the TEST macro. -/// -/// @param name The name of the test. -/// @param test The test function. -/// @return Whether the test was registered successfully. -____EZTEST_BOOL ____EZTEST_register_test(const char* name, ____EZTEST_BOOL(*test)()); -/// Runs all tests. -/// -/// You should not call this function directly. Instead, use the RUN_TESTS macro. -/// -/// @return The number of failed tests. -int ____EZTEST_run_tests(); - -/// Define a test. -/// -/// @param name The name of the test. -/// @return The test function. -#define TEST(name) \ - ____EZTEST_BOOL name(); \ - static ____EZTEST_BOOL name##_registered = \ - ____EZTEST_register_test(#name, name); \ - ____EZTEST_BOOL name() - -/// Runs all tests. -/// -/// @return The number of failed tests. -#define RUN_TESTS ____EZTEST_run_tests(); - -#endif // __EZTEST_H diff --git a/libs/eztest/eztest.cpp b/libs/eztest/eztest.cpp deleted file mode 100644 index 5dfc23e..0000000 --- a/libs/eztest/eztest.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "EZtest" -#include - -constexpr const int ____SIMPLETEST_MAX_TESTS = 1000; - -typedef struct Test { - const char* name; - ____EZTEST_BOOL(*func)(); -} Test; - -Test tests[____SIMPLETEST_MAX_TESTS]; - -____EZTEST_BOOL ____EZTEST_register_test(const char* name, ____EZTEST_BOOL(*func)()) { - for (int i = 0; i < ____SIMPLETEST_MAX_TESTS; i++) { - if (tests[i].name == NULL) { - tests[i].name = name; - tests[i].func = func; - return ____EZTEST_TRUE; - } - } - return ____EZTEST_FALSE; -} - -int ____EZTEST_run_tests() { - int failed = 0; - for (int i = 0; i < ____SIMPLETEST_MAX_TESTS; i++) { - if (tests[i].name == NULL) break; - printf("Running test %s...\n", tests[i].name); - if (!tests[i].func()) { - printf("Test %s failed!\n", tests[i].name); - failed++; - } else { - printf("Test %s passed!\n", tests[i].name); - } - } - return failed; -} diff --git a/libs/l2math/Cargo.toml b/libs/helper/l2math/Cargo.toml similarity index 100% rename from libs/l2math/Cargo.toml rename to libs/helper/l2math/Cargo.toml diff --git a/libs/l2math/README.md b/libs/helper/l2math/README.md similarity index 100% rename from libs/l2math/README.md rename to libs/helper/l2math/README.md diff --git a/libs/l2math/core.rs b/libs/helper/l2math/core.rs similarity index 100% rename from libs/l2math/core.rs rename to libs/helper/l2math/core.rs diff --git a/libs/l2math/core/acos.rs b/libs/helper/l2math/core/acos.rs similarity index 100% rename from libs/l2math/core/acos.rs rename to libs/helper/l2math/core/acos.rs diff --git a/libs/l2math/core/acosf.rs b/libs/helper/l2math/core/acosf.rs similarity index 100% rename from libs/l2math/core/acosf.rs rename to libs/helper/l2math/core/acosf.rs diff --git a/libs/l2math/core/acosh.rs b/libs/helper/l2math/core/acosh.rs similarity index 100% rename from libs/l2math/core/acosh.rs rename to libs/helper/l2math/core/acosh.rs diff --git a/libs/l2math/core/acoshf.rs b/libs/helper/l2math/core/acoshf.rs similarity index 100% rename from libs/l2math/core/acoshf.rs rename to libs/helper/l2math/core/acoshf.rs diff --git a/libs/l2math/core/asin.rs b/libs/helper/l2math/core/asin.rs similarity index 100% rename from libs/l2math/core/asin.rs rename to libs/helper/l2math/core/asin.rs diff --git a/libs/l2math/core/asinf.rs b/libs/helper/l2math/core/asinf.rs similarity index 100% rename from libs/l2math/core/asinf.rs rename to libs/helper/l2math/core/asinf.rs diff --git a/libs/l2math/core/asinh.rs b/libs/helper/l2math/core/asinh.rs similarity index 100% rename from libs/l2math/core/asinh.rs rename to libs/helper/l2math/core/asinh.rs diff --git a/libs/l2math/core/asinhf.rs b/libs/helper/l2math/core/asinhf.rs similarity index 100% rename from libs/l2math/core/asinhf.rs rename to libs/helper/l2math/core/asinhf.rs diff --git a/libs/l2math/core/atan.rs b/libs/helper/l2math/core/atan.rs similarity index 100% rename from libs/l2math/core/atan.rs rename to libs/helper/l2math/core/atan.rs diff --git a/libs/l2math/core/atan2.rs b/libs/helper/l2math/core/atan2.rs similarity index 100% rename from libs/l2math/core/atan2.rs rename to libs/helper/l2math/core/atan2.rs diff --git a/libs/l2math/core/atan2f.rs b/libs/helper/l2math/core/atan2f.rs similarity index 100% rename from libs/l2math/core/atan2f.rs rename to libs/helper/l2math/core/atan2f.rs diff --git a/libs/l2math/core/atanf.rs b/libs/helper/l2math/core/atanf.rs similarity index 100% rename from libs/l2math/core/atanf.rs rename to libs/helper/l2math/core/atanf.rs diff --git a/libs/l2math/core/atanh.rs b/libs/helper/l2math/core/atanh.rs similarity index 100% rename from libs/l2math/core/atanh.rs rename to libs/helper/l2math/core/atanh.rs diff --git a/libs/l2math/core/atanhf.rs b/libs/helper/l2math/core/atanhf.rs similarity index 100% rename from libs/l2math/core/atanhf.rs rename to libs/helper/l2math/core/atanhf.rs diff --git a/libs/l2math/core/cbrt.rs b/libs/helper/l2math/core/cbrt.rs similarity index 100% rename from libs/l2math/core/cbrt.rs rename to libs/helper/l2math/core/cbrt.rs diff --git a/libs/l2math/core/cbrtf.rs b/libs/helper/l2math/core/cbrtf.rs similarity index 100% rename from libs/l2math/core/cbrtf.rs rename to libs/helper/l2math/core/cbrtf.rs diff --git a/libs/l2math/core/ceil.rs b/libs/helper/l2math/core/ceil.rs similarity index 100% rename from libs/l2math/core/ceil.rs rename to libs/helper/l2math/core/ceil.rs diff --git a/libs/l2math/core/ceilf.rs b/libs/helper/l2math/core/ceilf.rs similarity index 100% rename from libs/l2math/core/ceilf.rs rename to libs/helper/l2math/core/ceilf.rs diff --git a/libs/l2math/core/copysign.rs b/libs/helper/l2math/core/copysign.rs similarity index 100% rename from libs/l2math/core/copysign.rs rename to libs/helper/l2math/core/copysign.rs diff --git a/libs/l2math/core/copysignf.rs b/libs/helper/l2math/core/copysignf.rs similarity index 100% rename from libs/l2math/core/copysignf.rs rename to libs/helper/l2math/core/copysignf.rs diff --git a/libs/l2math/core/cos.rs b/libs/helper/l2math/core/cos.rs similarity index 100% rename from libs/l2math/core/cos.rs rename to libs/helper/l2math/core/cos.rs diff --git a/libs/l2math/core/cosf.rs b/libs/helper/l2math/core/cosf.rs similarity index 100% rename from libs/l2math/core/cosf.rs rename to libs/helper/l2math/core/cosf.rs diff --git a/libs/l2math/core/cosh.rs b/libs/helper/l2math/core/cosh.rs similarity index 100% rename from libs/l2math/core/cosh.rs rename to libs/helper/l2math/core/cosh.rs diff --git a/libs/l2math/core/coshf.rs b/libs/helper/l2math/core/coshf.rs similarity index 100% rename from libs/l2math/core/coshf.rs rename to libs/helper/l2math/core/coshf.rs diff --git a/libs/l2math/core/erf.rs b/libs/helper/l2math/core/erf.rs similarity index 100% rename from libs/l2math/core/erf.rs rename to libs/helper/l2math/core/erf.rs diff --git a/libs/l2math/core/erff.rs b/libs/helper/l2math/core/erff.rs similarity index 100% rename from libs/l2math/core/erff.rs rename to libs/helper/l2math/core/erff.rs diff --git a/libs/l2math/core/exp.rs b/libs/helper/l2math/core/exp.rs similarity index 100% rename from libs/l2math/core/exp.rs rename to libs/helper/l2math/core/exp.rs diff --git a/libs/l2math/core/exp10.rs b/libs/helper/l2math/core/exp10.rs similarity index 100% rename from libs/l2math/core/exp10.rs rename to libs/helper/l2math/core/exp10.rs diff --git a/libs/l2math/core/exp10f.rs b/libs/helper/l2math/core/exp10f.rs similarity index 100% rename from libs/l2math/core/exp10f.rs rename to libs/helper/l2math/core/exp10f.rs diff --git a/libs/l2math/core/exp2.rs b/libs/helper/l2math/core/exp2.rs similarity index 100% rename from libs/l2math/core/exp2.rs rename to libs/helper/l2math/core/exp2.rs diff --git a/libs/l2math/core/exp2f.rs b/libs/helper/l2math/core/exp2f.rs similarity index 100% rename from libs/l2math/core/exp2f.rs rename to libs/helper/l2math/core/exp2f.rs diff --git a/libs/l2math/core/expf.rs b/libs/helper/l2math/core/expf.rs similarity index 100% rename from libs/l2math/core/expf.rs rename to libs/helper/l2math/core/expf.rs diff --git a/libs/l2math/core/expm1.rs b/libs/helper/l2math/core/expm1.rs similarity index 100% rename from libs/l2math/core/expm1.rs rename to libs/helper/l2math/core/expm1.rs diff --git a/libs/l2math/core/expm1f.rs b/libs/helper/l2math/core/expm1f.rs similarity index 100% rename from libs/l2math/core/expm1f.rs rename to libs/helper/l2math/core/expm1f.rs diff --git a/libs/l2math/core/expo2.rs b/libs/helper/l2math/core/expo2.rs similarity index 100% rename from libs/l2math/core/expo2.rs rename to libs/helper/l2math/core/expo2.rs diff --git a/libs/l2math/core/fabs.rs b/libs/helper/l2math/core/fabs.rs similarity index 100% rename from libs/l2math/core/fabs.rs rename to libs/helper/l2math/core/fabs.rs diff --git a/libs/l2math/core/fabsf.rs b/libs/helper/l2math/core/fabsf.rs similarity index 100% rename from libs/l2math/core/fabsf.rs rename to libs/helper/l2math/core/fabsf.rs diff --git a/libs/l2math/core/fdim.rs b/libs/helper/l2math/core/fdim.rs similarity index 100% rename from libs/l2math/core/fdim.rs rename to libs/helper/l2math/core/fdim.rs diff --git a/libs/l2math/core/fdimf.rs b/libs/helper/l2math/core/fdimf.rs similarity index 100% rename from libs/l2math/core/fdimf.rs rename to libs/helper/l2math/core/fdimf.rs diff --git a/libs/l2math/core/fenv.rs b/libs/helper/l2math/core/fenv.rs similarity index 100% rename from libs/l2math/core/fenv.rs rename to libs/helper/l2math/core/fenv.rs diff --git a/libs/l2math/core/floor.rs b/libs/helper/l2math/core/floor.rs similarity index 100% rename from libs/l2math/core/floor.rs rename to libs/helper/l2math/core/floor.rs diff --git a/libs/l2math/core/floorf.rs b/libs/helper/l2math/core/floorf.rs similarity index 100% rename from libs/l2math/core/floorf.rs rename to libs/helper/l2math/core/floorf.rs diff --git a/libs/l2math/core/fma.rs b/libs/helper/l2math/core/fma.rs similarity index 100% rename from libs/l2math/core/fma.rs rename to libs/helper/l2math/core/fma.rs diff --git a/libs/l2math/core/fmaf.rs b/libs/helper/l2math/core/fmaf.rs similarity index 100% rename from libs/l2math/core/fmaf.rs rename to libs/helper/l2math/core/fmaf.rs diff --git a/libs/l2math/core/fmax.rs b/libs/helper/l2math/core/fmax.rs similarity index 100% rename from libs/l2math/core/fmax.rs rename to libs/helper/l2math/core/fmax.rs diff --git a/libs/l2math/core/fmaxf.rs b/libs/helper/l2math/core/fmaxf.rs similarity index 100% rename from libs/l2math/core/fmaxf.rs rename to libs/helper/l2math/core/fmaxf.rs diff --git a/libs/l2math/core/fmin.rs b/libs/helper/l2math/core/fmin.rs similarity index 100% rename from libs/l2math/core/fmin.rs rename to libs/helper/l2math/core/fmin.rs diff --git a/libs/l2math/core/fminf.rs b/libs/helper/l2math/core/fminf.rs similarity index 100% rename from libs/l2math/core/fminf.rs rename to libs/helper/l2math/core/fminf.rs diff --git a/libs/l2math/core/fmod.rs b/libs/helper/l2math/core/fmod.rs similarity index 100% rename from libs/l2math/core/fmod.rs rename to libs/helper/l2math/core/fmod.rs diff --git a/libs/l2math/core/fmodf.rs b/libs/helper/l2math/core/fmodf.rs similarity index 100% rename from libs/l2math/core/fmodf.rs rename to libs/helper/l2math/core/fmodf.rs diff --git a/libs/l2math/core/frexp.rs b/libs/helper/l2math/core/frexp.rs similarity index 100% rename from libs/l2math/core/frexp.rs rename to libs/helper/l2math/core/frexp.rs diff --git a/libs/l2math/core/frexpf.rs b/libs/helper/l2math/core/frexpf.rs similarity index 100% rename from libs/l2math/core/frexpf.rs rename to libs/helper/l2math/core/frexpf.rs diff --git a/libs/l2math/core/hypot.rs b/libs/helper/l2math/core/hypot.rs similarity index 100% rename from libs/l2math/core/hypot.rs rename to libs/helper/l2math/core/hypot.rs diff --git a/libs/l2math/core/hypotf.rs b/libs/helper/l2math/core/hypotf.rs similarity index 100% rename from libs/l2math/core/hypotf.rs rename to libs/helper/l2math/core/hypotf.rs diff --git a/libs/l2math/core/ilogb.rs b/libs/helper/l2math/core/ilogb.rs similarity index 100% rename from libs/l2math/core/ilogb.rs rename to libs/helper/l2math/core/ilogb.rs diff --git a/libs/l2math/core/ilogbf.rs b/libs/helper/l2math/core/ilogbf.rs similarity index 100% rename from libs/l2math/core/ilogbf.rs rename to libs/helper/l2math/core/ilogbf.rs diff --git a/libs/l2math/core/j0.rs b/libs/helper/l2math/core/j0.rs similarity index 100% rename from libs/l2math/core/j0.rs rename to libs/helper/l2math/core/j0.rs diff --git a/libs/l2math/core/j0f.rs b/libs/helper/l2math/core/j0f.rs similarity index 100% rename from libs/l2math/core/j0f.rs rename to libs/helper/l2math/core/j0f.rs diff --git a/libs/l2math/core/j1.rs b/libs/helper/l2math/core/j1.rs similarity index 100% rename from libs/l2math/core/j1.rs rename to libs/helper/l2math/core/j1.rs diff --git a/libs/l2math/core/j1f.rs b/libs/helper/l2math/core/j1f.rs similarity index 100% rename from libs/l2math/core/j1f.rs rename to libs/helper/l2math/core/j1f.rs diff --git a/libs/l2math/core/jn.rs b/libs/helper/l2math/core/jn.rs similarity index 100% rename from libs/l2math/core/jn.rs rename to libs/helper/l2math/core/jn.rs diff --git a/libs/l2math/core/jnf.rs b/libs/helper/l2math/core/jnf.rs similarity index 100% rename from libs/l2math/core/jnf.rs rename to libs/helper/l2math/core/jnf.rs diff --git a/libs/l2math/core/k_cos.rs b/libs/helper/l2math/core/k_cos.rs similarity index 100% rename from libs/l2math/core/k_cos.rs rename to libs/helper/l2math/core/k_cos.rs diff --git a/libs/l2math/core/k_cosf.rs b/libs/helper/l2math/core/k_cosf.rs similarity index 100% rename from libs/l2math/core/k_cosf.rs rename to libs/helper/l2math/core/k_cosf.rs diff --git a/libs/l2math/core/k_expo2.rs b/libs/helper/l2math/core/k_expo2.rs similarity index 100% rename from libs/l2math/core/k_expo2.rs rename to libs/helper/l2math/core/k_expo2.rs diff --git a/libs/l2math/core/k_expo2f.rs b/libs/helper/l2math/core/k_expo2f.rs similarity index 100% rename from libs/l2math/core/k_expo2f.rs rename to libs/helper/l2math/core/k_expo2f.rs diff --git a/libs/l2math/core/k_sin.rs b/libs/helper/l2math/core/k_sin.rs similarity index 100% rename from libs/l2math/core/k_sin.rs rename to libs/helper/l2math/core/k_sin.rs diff --git a/libs/l2math/core/k_sinf.rs b/libs/helper/l2math/core/k_sinf.rs similarity index 100% rename from libs/l2math/core/k_sinf.rs rename to libs/helper/l2math/core/k_sinf.rs diff --git a/libs/l2math/core/k_tan.rs b/libs/helper/l2math/core/k_tan.rs similarity index 100% rename from libs/l2math/core/k_tan.rs rename to libs/helper/l2math/core/k_tan.rs diff --git a/libs/l2math/core/k_tanf.rs b/libs/helper/l2math/core/k_tanf.rs similarity index 100% rename from libs/l2math/core/k_tanf.rs rename to libs/helper/l2math/core/k_tanf.rs diff --git a/libs/l2math/core/ldexp.rs b/libs/helper/l2math/core/ldexp.rs similarity index 100% rename from libs/l2math/core/ldexp.rs rename to libs/helper/l2math/core/ldexp.rs diff --git a/libs/l2math/core/ldexpf.rs b/libs/helper/l2math/core/ldexpf.rs similarity index 100% rename from libs/l2math/core/ldexpf.rs rename to libs/helper/l2math/core/ldexpf.rs diff --git a/libs/l2math/core/lgamma.rs b/libs/helper/l2math/core/lgamma.rs similarity index 100% rename from libs/l2math/core/lgamma.rs rename to libs/helper/l2math/core/lgamma.rs diff --git a/libs/l2math/core/lgamma_r.rs b/libs/helper/l2math/core/lgamma_r.rs similarity index 100% rename from libs/l2math/core/lgamma_r.rs rename to libs/helper/l2math/core/lgamma_r.rs diff --git a/libs/l2math/core/lgammaf.rs b/libs/helper/l2math/core/lgammaf.rs similarity index 100% rename from libs/l2math/core/lgammaf.rs rename to libs/helper/l2math/core/lgammaf.rs diff --git a/libs/l2math/core/lgammaf_r.rs b/libs/helper/l2math/core/lgammaf_r.rs similarity index 100% rename from libs/l2math/core/lgammaf_r.rs rename to libs/helper/l2math/core/lgammaf_r.rs diff --git a/libs/l2math/core/ln.rs b/libs/helper/l2math/core/ln.rs similarity index 100% rename from libs/l2math/core/ln.rs rename to libs/helper/l2math/core/ln.rs diff --git a/libs/l2math/core/lnf.rs b/libs/helper/l2math/core/lnf.rs similarity index 100% rename from libs/l2math/core/lnf.rs rename to libs/helper/l2math/core/lnf.rs diff --git a/libs/l2math/core/log.rs b/libs/helper/l2math/core/log.rs similarity index 100% rename from libs/l2math/core/log.rs rename to libs/helper/l2math/core/log.rs diff --git a/libs/l2math/core/log10.rs b/libs/helper/l2math/core/log10.rs similarity index 100% rename from libs/l2math/core/log10.rs rename to libs/helper/l2math/core/log10.rs diff --git a/libs/l2math/core/log10f.rs b/libs/helper/l2math/core/log10f.rs similarity index 100% rename from libs/l2math/core/log10f.rs rename to libs/helper/l2math/core/log10f.rs diff --git a/libs/l2math/core/log1p.rs b/libs/helper/l2math/core/log1p.rs similarity index 100% rename from libs/l2math/core/log1p.rs rename to libs/helper/l2math/core/log1p.rs diff --git a/libs/l2math/core/log1pf.rs b/libs/helper/l2math/core/log1pf.rs similarity index 100% rename from libs/l2math/core/log1pf.rs rename to libs/helper/l2math/core/log1pf.rs diff --git a/libs/l2math/core/log2.rs b/libs/helper/l2math/core/log2.rs similarity index 100% rename from libs/l2math/core/log2.rs rename to libs/helper/l2math/core/log2.rs diff --git a/libs/l2math/core/log2f.rs b/libs/helper/l2math/core/log2f.rs similarity index 100% rename from libs/l2math/core/log2f.rs rename to libs/helper/l2math/core/log2f.rs diff --git a/libs/l2math/core/logf.rs b/libs/helper/l2math/core/logf.rs similarity index 100% rename from libs/l2math/core/logf.rs rename to libs/helper/l2math/core/logf.rs diff --git a/libs/l2math/core/modf.rs b/libs/helper/l2math/core/modf.rs similarity index 100% rename from libs/l2math/core/modf.rs rename to libs/helper/l2math/core/modf.rs diff --git a/libs/l2math/core/modff.rs b/libs/helper/l2math/core/modff.rs similarity index 100% rename from libs/l2math/core/modff.rs rename to libs/helper/l2math/core/modff.rs diff --git a/libs/l2math/core/nextafter.rs b/libs/helper/l2math/core/nextafter.rs similarity index 100% rename from libs/l2math/core/nextafter.rs rename to libs/helper/l2math/core/nextafter.rs diff --git a/libs/l2math/core/nextafterf.rs b/libs/helper/l2math/core/nextafterf.rs similarity index 100% rename from libs/l2math/core/nextafterf.rs rename to libs/helper/l2math/core/nextafterf.rs diff --git a/libs/l2math/core/pow.rs b/libs/helper/l2math/core/pow.rs similarity index 100% rename from libs/l2math/core/pow.rs rename to libs/helper/l2math/core/pow.rs diff --git a/libs/l2math/core/powf.rs b/libs/helper/l2math/core/powf.rs similarity index 100% rename from libs/l2math/core/powf.rs rename to libs/helper/l2math/core/powf.rs diff --git a/libs/l2math/core/rem_pio2.rs b/libs/helper/l2math/core/rem_pio2.rs similarity index 100% rename from libs/l2math/core/rem_pio2.rs rename to libs/helper/l2math/core/rem_pio2.rs diff --git a/libs/l2math/core/rem_pio2_large.rs b/libs/helper/l2math/core/rem_pio2_large.rs similarity index 100% rename from libs/l2math/core/rem_pio2_large.rs rename to libs/helper/l2math/core/rem_pio2_large.rs diff --git a/libs/l2math/core/rem_pio2f.rs b/libs/helper/l2math/core/rem_pio2f.rs similarity index 100% rename from libs/l2math/core/rem_pio2f.rs rename to libs/helper/l2math/core/rem_pio2f.rs diff --git a/libs/l2math/core/remainder.rs b/libs/helper/l2math/core/remainder.rs similarity index 100% rename from libs/l2math/core/remainder.rs rename to libs/helper/l2math/core/remainder.rs diff --git a/libs/l2math/core/remainderf.rs b/libs/helper/l2math/core/remainderf.rs similarity index 100% rename from libs/l2math/core/remainderf.rs rename to libs/helper/l2math/core/remainderf.rs diff --git a/libs/l2math/core/remquo.rs b/libs/helper/l2math/core/remquo.rs similarity index 100% rename from libs/l2math/core/remquo.rs rename to libs/helper/l2math/core/remquo.rs diff --git a/libs/l2math/core/remquof.rs b/libs/helper/l2math/core/remquof.rs similarity index 100% rename from libs/l2math/core/remquof.rs rename to libs/helper/l2math/core/remquof.rs diff --git a/libs/l2math/core/rint.rs b/libs/helper/l2math/core/rint.rs similarity index 100% rename from libs/l2math/core/rint.rs rename to libs/helper/l2math/core/rint.rs diff --git a/libs/l2math/core/rintf.rs b/libs/helper/l2math/core/rintf.rs similarity index 100% rename from libs/l2math/core/rintf.rs rename to libs/helper/l2math/core/rintf.rs diff --git a/libs/l2math/core/round.rs b/libs/helper/l2math/core/round.rs similarity index 100% rename from libs/l2math/core/round.rs rename to libs/helper/l2math/core/round.rs diff --git a/libs/l2math/core/roundf.rs b/libs/helper/l2math/core/roundf.rs similarity index 100% rename from libs/l2math/core/roundf.rs rename to libs/helper/l2math/core/roundf.rs diff --git a/libs/l2math/core/scalbn.rs b/libs/helper/l2math/core/scalbn.rs similarity index 100% rename from libs/l2math/core/scalbn.rs rename to libs/helper/l2math/core/scalbn.rs diff --git a/libs/l2math/core/scalbnf.rs b/libs/helper/l2math/core/scalbnf.rs similarity index 100% rename from libs/l2math/core/scalbnf.rs rename to libs/helper/l2math/core/scalbnf.rs diff --git a/libs/l2math/core/sin.rs b/libs/helper/l2math/core/sin.rs similarity index 100% rename from libs/l2math/core/sin.rs rename to libs/helper/l2math/core/sin.rs diff --git a/libs/l2math/core/sincos.rs b/libs/helper/l2math/core/sincos.rs similarity index 100% rename from libs/l2math/core/sincos.rs rename to libs/helper/l2math/core/sincos.rs diff --git a/libs/l2math/core/sincosf.rs b/libs/helper/l2math/core/sincosf.rs similarity index 100% rename from libs/l2math/core/sincosf.rs rename to libs/helper/l2math/core/sincosf.rs diff --git a/libs/l2math/core/sinf.rs b/libs/helper/l2math/core/sinf.rs similarity index 100% rename from libs/l2math/core/sinf.rs rename to libs/helper/l2math/core/sinf.rs diff --git a/libs/l2math/core/sinh.rs b/libs/helper/l2math/core/sinh.rs similarity index 100% rename from libs/l2math/core/sinh.rs rename to libs/helper/l2math/core/sinh.rs diff --git a/libs/l2math/core/sinhf.rs b/libs/helper/l2math/core/sinhf.rs similarity index 100% rename from libs/l2math/core/sinhf.rs rename to libs/helper/l2math/core/sinhf.rs diff --git a/libs/l2math/core/sqrt.rs b/libs/helper/l2math/core/sqrt.rs similarity index 100% rename from libs/l2math/core/sqrt.rs rename to libs/helper/l2math/core/sqrt.rs diff --git a/libs/l2math/core/sqrtf.rs b/libs/helper/l2math/core/sqrtf.rs similarity index 100% rename from libs/l2math/core/sqrtf.rs rename to libs/helper/l2math/core/sqrtf.rs diff --git a/libs/l2math/core/tan.rs b/libs/helper/l2math/core/tan.rs similarity index 100% rename from libs/l2math/core/tan.rs rename to libs/helper/l2math/core/tan.rs diff --git a/libs/l2math/core/tanf.rs b/libs/helper/l2math/core/tanf.rs similarity index 100% rename from libs/l2math/core/tanf.rs rename to libs/helper/l2math/core/tanf.rs diff --git a/libs/l2math/core/tanh.rs b/libs/helper/l2math/core/tanh.rs similarity index 100% rename from libs/l2math/core/tanh.rs rename to libs/helper/l2math/core/tanh.rs diff --git a/libs/l2math/core/tanhf.rs b/libs/helper/l2math/core/tanhf.rs similarity index 100% rename from libs/l2math/core/tanhf.rs rename to libs/helper/l2math/core/tanhf.rs diff --git a/libs/l2math/core/tgamma.rs b/libs/helper/l2math/core/tgamma.rs similarity index 100% rename from libs/l2math/core/tgamma.rs rename to libs/helper/l2math/core/tgamma.rs diff --git a/libs/l2math/core/tgammaf.rs b/libs/helper/l2math/core/tgammaf.rs similarity index 100% rename from libs/l2math/core/tgammaf.rs rename to libs/helper/l2math/core/tgammaf.rs diff --git a/libs/l2math/core/trunc.rs b/libs/helper/l2math/core/trunc.rs similarity index 100% rename from libs/l2math/core/trunc.rs rename to libs/helper/l2math/core/trunc.rs diff --git a/libs/l2math/core/truncf.rs b/libs/helper/l2math/core/truncf.rs similarity index 100% rename from libs/l2math/core/truncf.rs rename to libs/helper/l2math/core/truncf.rs diff --git a/libs/l2math/core/ulp.rs b/libs/helper/l2math/core/ulp.rs similarity index 100% rename from libs/l2math/core/ulp.rs rename to libs/helper/l2math/core/ulp.rs diff --git a/libs/l2math/lib.rs b/libs/helper/l2math/lib.rs similarity index 100% rename from libs/l2math/lib.rs rename to libs/helper/l2math/lib.rs diff --git a/libs/l2math/macros.rs b/libs/helper/l2math/macros.rs similarity index 100% rename from libs/l2math/macros.rs rename to libs/helper/l2math/macros.rs diff --git a/libs/l2math/types.rs b/libs/helper/l2math/types.rs similarity index 100% rename from libs/l2math/types.rs rename to libs/helper/l2math/types.rs diff --git a/libs/libtrig/Cargo.toml b/libs/helper/libtrig/Cargo.toml similarity index 100% rename from libs/libtrig/Cargo.toml rename to libs/helper/libtrig/Cargo.toml diff --git a/libs/libtrig/README.md b/libs/helper/libtrig/README.md similarity index 100% rename from libs/libtrig/README.md rename to libs/helper/libtrig/README.md diff --git a/libs/libtrig/angle.rs b/libs/helper/libtrig/angle.rs similarity index 100% rename from libs/libtrig/angle.rs rename to libs/helper/libtrig/angle.rs diff --git a/libs/libtrig/coords/coord2d.rs b/libs/helper/libtrig/coords/coord2d.rs similarity index 100% rename from libs/libtrig/coords/coord2d.rs rename to libs/helper/libtrig/coords/coord2d.rs diff --git a/libs/libtrig/coords/coord3d.rs b/libs/helper/libtrig/coords/coord3d.rs similarity index 100% rename from libs/libtrig/coords/coord3d.rs rename to libs/helper/libtrig/coords/coord3d.rs diff --git a/libs/libtrig/coords/mod.rs b/libs/helper/libtrig/coords/mod.rs similarity index 100% rename from libs/libtrig/coords/mod.rs rename to libs/helper/libtrig/coords/mod.rs diff --git a/libs/libtrig/lib.rs b/libs/helper/libtrig/lib.rs similarity index 100% rename from libs/libtrig/lib.rs rename to libs/helper/libtrig/lib.rs diff --git a/libs/libtrig/morenums/mod.rs b/libs/helper/libtrig/morenums/mod.rs similarity index 100% rename from libs/libtrig/morenums/mod.rs rename to libs/helper/libtrig/morenums/mod.rs diff --git a/libs/libtrig/morenums/u2/impls.rs b/libs/helper/libtrig/morenums/u2/impls.rs similarity index 100% rename from libs/libtrig/morenums/u2/impls.rs rename to libs/helper/libtrig/morenums/u2/impls.rs diff --git a/libs/libtrig/morenums/u2/mod.rs b/libs/helper/libtrig/morenums/u2/mod.rs similarity index 100% rename from libs/libtrig/morenums/u2/mod.rs rename to libs/helper/libtrig/morenums/u2/mod.rs diff --git a/libs/libtrig/morenums/u2/source.rs b/libs/helper/libtrig/morenums/u2/source.rs similarity index 100% rename from libs/libtrig/morenums/u2/source.rs rename to libs/helper/libtrig/morenums/u2/source.rs diff --git a/libs/libtrig/morenums/u2/tests.rs b/libs/helper/libtrig/morenums/u2/tests.rs similarity index 100% rename from libs/libtrig/morenums/u2/tests.rs rename to libs/helper/libtrig/morenums/u2/tests.rs diff --git a/libs/libtrig/morenums/u3/impls.rs b/libs/helper/libtrig/morenums/u3/impls.rs similarity index 100% rename from libs/libtrig/morenums/u3/impls.rs rename to libs/helper/libtrig/morenums/u3/impls.rs diff --git a/libs/libtrig/morenums/u3/mod.rs b/libs/helper/libtrig/morenums/u3/mod.rs similarity index 100% rename from libs/libtrig/morenums/u3/mod.rs rename to libs/helper/libtrig/morenums/u3/mod.rs diff --git a/libs/libtrig/morenums/u3/source.rs b/libs/helper/libtrig/morenums/u3/source.rs similarity index 100% rename from libs/libtrig/morenums/u3/source.rs rename to libs/helper/libtrig/morenums/u3/source.rs diff --git a/libs/libtrig/morenums/u3/tests.rs b/libs/helper/libtrig/morenums/u3/tests.rs similarity index 100% rename from libs/libtrig/morenums/u3/tests.rs rename to libs/helper/libtrig/morenums/u3/tests.rs diff --git a/libs/libtrig/traits/float.rs b/libs/helper/libtrig/traits/float.rs similarity index 100% rename from libs/libtrig/traits/float.rs rename to libs/helper/libtrig/traits/float.rs diff --git a/libs/libtrig/traits/impls.rs b/libs/helper/libtrig/traits/impls.rs similarity index 100% rename from libs/libtrig/traits/impls.rs rename to libs/helper/libtrig/traits/impls.rs diff --git a/libs/libtrig/traits/mod.rs b/libs/helper/libtrig/traits/mod.rs similarity index 100% rename from libs/libtrig/traits/mod.rs rename to libs/helper/libtrig/traits/mod.rs diff --git a/libs/libtrig/traits/number.rs b/libs/helper/libtrig/traits/number.rs similarity index 100% rename from libs/libtrig/traits/number.rs rename to libs/helper/libtrig/traits/number.rs diff --git a/libs/libtrig/types.rs b/libs/helper/libtrig/types.rs similarity index 100% rename from libs/libtrig/types.rs rename to libs/helper/libtrig/types.rs diff --git a/libs/libtrig/vectors/mod.rs b/libs/helper/libtrig/vectors/mod.rs similarity index 100% rename from libs/libtrig/vectors/mod.rs rename to libs/helper/libtrig/vectors/mod.rs diff --git a/libs/libtrig/vectors/vec2d.rs b/libs/helper/libtrig/vectors/vec2d.rs similarity index 100% rename from libs/libtrig/vectors/vec2d.rs rename to libs/helper/libtrig/vectors/vec2d.rs diff --git a/libs/libtrig/vectors/vec3d.rs b/libs/helper/libtrig/vectors/vec3d.rs similarity index 100% rename from libs/libtrig/vectors/vec3d.rs rename to libs/helper/libtrig/vectors/vec3d.rs diff --git a/libs/macros-core/Cargo.toml b/libs/helper/macros-core/Cargo.toml similarity index 100% rename from libs/macros-core/Cargo.toml rename to libs/helper/macros-core/Cargo.toml diff --git a/libs/macros-core/ffi/mod.rs b/libs/helper/macros-core/ffi/mod.rs similarity index 100% rename from libs/macros-core/ffi/mod.rs rename to libs/helper/macros-core/ffi/mod.rs diff --git a/libs/macros-core/func_mod/mod.rs b/libs/helper/macros-core/func_mod/mod.rs similarity index 100% rename from libs/macros-core/func_mod/mod.rs rename to libs/helper/macros-core/func_mod/mod.rs diff --git a/libs/macros-core/lib.rs b/libs/helper/macros-core/lib.rs similarity index 100% rename from libs/macros-core/lib.rs rename to libs/helper/macros-core/lib.rs diff --git a/libs/macros-core/mass_impl/args.rs b/libs/helper/macros-core/mass_impl/args.rs similarity index 100% rename from libs/macros-core/mass_impl/args.rs rename to libs/helper/macros-core/mass_impl/args.rs diff --git a/libs/macros-core/mass_impl/mod.rs b/libs/helper/macros-core/mass_impl/mod.rs similarity index 100% rename from libs/macros-core/mass_impl/mod.rs rename to libs/helper/macros-core/mass_impl/mod.rs diff --git a/libs/macros-core/mass_impl/variants.rs b/libs/helper/macros-core/mass_impl/variants.rs similarity index 100% rename from libs/macros-core/mass_impl/variants.rs rename to libs/helper/macros-core/mass_impl/variants.rs diff --git a/libs/macros/Cargo.toml b/libs/helper/macros/Cargo.toml similarity index 100% rename from libs/macros/Cargo.toml rename to libs/helper/macros/Cargo.toml diff --git a/libs/libodo/README.md b/libs/helper/macros/README.md similarity index 100% rename from libs/libodo/README.md rename to libs/helper/macros/README.md diff --git a/libs/macros/lib.rs b/libs/helper/macros/lib.rs similarity index 100% rename from libs/macros/lib.rs rename to libs/helper/macros/lib.rs diff --git a/libs/l2math/bindings/.gitignore b/libs/l2math/bindings/.gitignore deleted file mode 100644 index a40651e..0000000 --- a/libs/l2math/bindings/.gitignore +++ /dev/null @@ -1 +0,0 @@ -l2mathtestbin* \ No newline at end of file diff --git a/libs/l2math/bindings/Cargo.toml b/libs/l2math/bindings/Cargo.toml deleted file mode 100644 index 3f961e5..0000000 --- a/libs/l2math/bindings/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "l2math-bindings" -description = "Low Level Math Bindings" -repository.workspace = true -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true - -[lib] -path = "lib.rs" -crate-type = ["cdylib", "staticlib"] - -[features] -no_std = [] -__android__ = [] - -[dependencies.l2math] -path = ".." diff --git a/libs/l2math/bindings/bindings.py b/libs/l2math/bindings/bindings.py deleted file mode 100644 index 958bb0d..0000000 --- a/libs/l2math/bindings/bindings.py +++ /dev/null @@ -1,165 +0,0 @@ -class BindingsTargetsConfig: - __targets: dict[str, list[str]] - def __init__(self, cd: str): - self.__targets = { } - - import tomllib - - cd = f"{cd}/libs/l2math/bindings" - - try: - with open(f"{cd}/bindings.targets.config.toml", "rb") as f: - data = tomllib.load(f) - for target in data: - self.add(target, data[target]) - except Exception as e: - print(f"Failed to load bindings.targets.config.toml: {e}") - exit(1) - - def add(self, name: str, deps: list[str]): - self.__targets[name] = deps - def get(self, name: str) -> list[str]: - if name not in self.__targets: return [] - return self.__targets[name] - def get_all_registries(self) -> list[str]: - return list(self.__targets.keys()) - def get_all_targets(self) -> list[str]: - out: list[str] = [] - for registry in self.get_all_registries(): - out.extend(self.get(registry)) - return out - -# "windows", "linux", "macos", "android", "ios", "unknown" -def get_current_platform() -> str: - import platform - - if platform.system() == "Windows": - return "windows" - elif platform.system() == "Linux": - return "linux" - elif platform.system() == "Darwin": - return "macos" - elif platform.system() == "Android": - return "android" - elif platform.system() == "iOS": - return "ios" - else: - return "unknown" - -def build_l2math_bindings(cd: str, args: list[str]) -> str | int | None: - architecture = args[0] if len(args) > 0 else get_current_platform() - - print(f"Building L2Math bindings for {architecture}...") - - config = BindingsTargetsConfig(cd) - targets = config.get(architecture) - - if len(targets) == 0: return f"No targets found for {architecture}!" - - if architecture == "windows": - return build_l2math_bindings_windows(cd, targets) - elif architecture == "linux": - return build_l2math_bindings_linux(cd, targets) - elif architecture == "macos": - return build_l2math_bindings_macos(cd, targets) - elif architecture == "android": - return build_l2math_bindings_android(cd, targets) - else: - return build_l2math_bindings_unknown(cd, targets) - -from typing import Callable - -def common_build_l2math_bindings( - cd: str, targets: list[str], - to_f: Callable[[str], list[str]], - from_f: Callable[[str], list[str]] -) -> int | str | None: - import subprocess, shutil, os - - for target in targets: - print(f"Building L2Math bindings for {target}...") - - cmd = ["cargo", "build", "--target", target, "-r", "-p", "l2math-bindings"] - res = subprocess.run(cmd, cwd=cd) - if res.returncode != 0: return res.returncode - - print("Copying L2Math bindings...") - - TO_DIR = f"{cd}/libs/l2math/bindings/.build" - if not os.path.exists(TO_DIR): - os.mkdir(TO_DIR) - to_f_res = to_f(target) - from_f_res = from_f(target) - - for i in range(len(to_f_res)): - TO = f"{TO_DIR}/{to_f_res[i]}" - if os.path.exists(TO): - print(f"Removing {TO}...") - os.remove(TO) - FROM = f"{cd}/target/{target}/release/{from_f_res[i]}" - if os.path.exists(FROM) and not os.path.exists(TO): - shutil.move(FROM, TO) - print("Done!") - return - return "Could not find the L2Math bindings library!" - -def build_l2math_bindings_windows(cd: str, targets: list[str]) -> int | str | None: - return common_build_l2math_bindings( - cd, targets, - lambda t: [f"l2math-{t}.dll", f"l2math-{t}.lib"], - lambda _: ["l2math_bindings.dll", "l2math_bindings.lib"] - ) - -def build_l2math_bindings_linux(cd: str, targets: list[str]) -> int | str | None: - return common_build_l2math_bindings( - cd, targets, - lambda t: [f"libl2math-{t}.so"], - lambda _: ["libl2math_bindings.so"] - ) - -def build_l2math_bindings_macos(cd: str, targets: list[str]) -> int | str | None: - return common_build_l2math_bindings( - cd, targets, - lambda t: [f"libl2math-{t}.dylib"], - lambda _: ["libl2math_bindings.dylib"] - ) - -def build_l2math_bindings_android(cd: str, targets: list[str]) -> int | str | None: - import shutil, os - - TO_DIR = f"{cd}/libs/l2math/bindings/.build" - if not os.path.exists(TO_DIR): os.mkdir(TO_DIR) - - for target in targets: - import subprocess - - print(f"Building L2Math bindings for {target}...") - - cmd = ["cargo", "ndk", "-t", target, "-o", f"{cd}/target/ndk/", "build", "--release", "-p", "l2math-bindings"] - res = subprocess.run(cmd, cwd = cd) - if res.returncode != 0: return res.returncode - - print(f"Copying L2Math bindings for {target}...") - - TO = f"{TO_DIR}/libl2math-{target}.so" - if os.path.exists(TO): - print(f"Removing {TO}...") - os.remove(TO) - FROM = f"{cd}/target/ndk/{target}/libl2math_bindings.so" - if os.path.exists(FROM) and not os.path.exists(TO): - shutil.move(FROM, TO) - - print("Copying libc++_shared.so...") - - TO = f"{TO_DIR}/libc++_shared.so" - if os.path.exists(TO): - print(f"Removing {TO}...") - os.remove(TO) - FROM = f"{cd}/target/ndk/libc++_shared.so" - if os.path.exists(FROM) and not os.path.exists(TO): - shutil.move(FROM, TO) - - print("Done!") - -def build_l2math_bindings_unknown(cd: str, targets: list[str]) -> str | None: - return "Unknown platform!" diff --git a/libs/l2math/bindings/bindings.targets.config.toml b/libs/l2math/bindings/bindings.targets.config.toml deleted file mode 100644 index 9feeec7..0000000 --- a/libs/l2math/bindings/bindings.targets.config.toml +++ /dev/null @@ -1,26 +0,0 @@ -linux = [ - "x86_64-unknown-linux-gnu", - # You may add more targets below, as long as they are supported by the Rust. - # ALL target triples will be built and copied to the output directory. -] - -windows = [ - "x86_64-pc-windows-msvc", -] - -macos = [ - "x86_64-apple-darwin", -] - -android = [ - "armeabi-v7a", - "arm64-v8a", - - # These also work, but are not needed for me. - # "x86_64-linux-android", - # "i686-linux-android", -] - -# You may add more targets below, as long as they are supported by the Rust. -# As an example: -# wasm = [ "wasm32-unknown-unknown" ] diff --git a/libs/l2math/bindings/build.rs b/libs/l2math/bindings/build.rs deleted file mode 100644 index 3639dba..0000000 --- a/libs/l2math/bindings/build.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![allow(unused)] - -use std::env; -use std::path::{Path, PathBuf}; - -type Res> = Result; - -fn main() -> Res { - if env::var("CARGO_CFG_TARGET_OS")? == "android" { - android()?; - }; - Ok(()) -} - -#[rustfmt::skip] -#[cfg(feature = "__android__")] -fn android() -> Res { Ok(()) } - -#[cfg(not(feature = "__android__"))] -fn android() -> Res { - println!("cargo:rustc-link-lib=c++_shared"); - let output_path = env::var("CARGO_NDK_OUTPUT_PATH")?; - let ndk_sysroot_libs_path = - env::var_os("CARGO_NDK_SYSROOT_LIBS_PATH").ok_or("CARGO_NDK_SYSROOT_LIBS_PATH not set")?; - let sysroot_libs_path: PathBuf = ndk_sysroot_libs_path.into(); - let lib_path = sysroot_libs_path.join("libc++_shared.so"); - let new_lib_path = Path::new(&output_path).join("libc++_shared.so"); - std::fs::copy(lib_path, new_lib_path)?; - Ok(()) -} diff --git a/libs/l2math/bindings/l2math.h b/libs/l2math/bindings/l2math.h deleted file mode 100644 index f0b9169..0000000 --- a/libs/l2math/bindings/l2math.h +++ /dev/null @@ -1,783 +0,0 @@ -/** - * @file l2math.h - * @author Матвей Т - * @brief C bindings for l2math - * @version 0.1.0-dev - * @date 2023-11-22 -*/ - -#ifndef __L2MATH_H -#define __L2MATH_H - -#ifdef __cplusplus -namespace l2math { - extern "C" { -#endif // __cplusplus - -// C binding for rust's f64 -typedef double ____l2math_f64; -// C binding for rust's f32 -typedef float ____l2math_f32; -// C binding for rust's i32 -typedef int ____l2math_i32; - -/// High precision floating point number -typedef ____l2math_f64 __l2math_Float64; -/// Low precision floating point number -typedef ____l2math_f32 __l2math_Float32; -/// High precision floating point number representing an angle -typedef ____l2math_f64 __l2math_Radian64; -/// Low precision floating point number representing an angle -typedef ____l2math_f32 __l2math_Radian32; -/// High precision floating point number representing an angle in degrees -typedef ____l2math_f64 __l2math_Degree64; -/// Low precision floating point number representing an angle in degrees -typedef ____l2math_f32 __l2math_Degree32; -/// A standard signed integer -typedef ____l2math_i32 __l2math_Int; - -/// A structure representing a tuple of a `__l2math_Float64` and an `__l2math_Int` -typedef struct __l2math_Tuple_Float64_Int { - __l2math_Float64 f; - __l2math_Int i; -} __l2math_Tuple_Float64_Int; - -/// A structure representing a tuple of a `__l2math_Float32` and an `__l2math_Int` -typedef struct __l2math_Tuple_Float32_Int { - __l2math_Float32 f; - __l2math_Int i; -} __l2math_Tuple_Float32_Int; - -/// A structure representing a tuple of two `__l2math_Float64`s -typedef struct __l2math_Tuple_Float64_Float64 { - __l2math_Float64 f1; - __l2math_Float64 f2; -} __l2math_Tuple_Float64_Float64; - -/// A structure representing a tuple of two `__l2math_Float32`s -typedef struct __l2math_Tuple_Float32_Float32 { - __l2math_Float32 f1; - __l2math_Float32 f2; -} __l2math_Tuple_Float32_Float32; - -/// Arccosine -__l2math_Radian64 __l2math_acos(__l2math_Float64 x); -/// Arccosine (__l2math_Float32) -__l2math_Radian32 __l2math_acosf(__l2math_Float32 x); -/// Inverse hyperbolic cosine -__l2math_Float64 __l2math_acosh(__l2math_Float64 x); -/// Inverse hyperbolic cosine (__l2math_Float32) -__l2math_Float32 __l2math_acoshf(__l2math_Float32 x); -/// Arcsine -__l2math_Radian64 __l2math_asin(__l2math_Float64 x); -/// Arcsine (__l2math_Float32) -__l2math_Radian32 __l2math_asinf(__l2math_Float32 x); -/// Inverse hyperbolic sine -__l2math_Float64 __l2math_asinh(__l2math_Float64 x); -/// Inverse hyperbolic sine (__l2math_Float32) -__l2math_Float32 __l2math_asinhf(__l2math_Float32 x); -/// Arctangent -__l2math_Radian64 __l2math_atan(__l2math_Float64 x); -/// Arctangent of y/x -__l2math_Radian64 __l2math_atan2(__l2math_Float64 y, __l2math_Float64 x); -/// Arctangent of y/x (__l2math_Float32) -__l2math_Radian32 __l2math_atan2f(__l2math_Float32 y, __l2math_Float32 x); -/// Arctangent (__l2math_Float32) -__l2math_Radian32 __l2math_atanf(__l2math_Float32 x); -/// Inverse hyperbolic tangent -__l2math_Float64 __l2math_atanh(__l2math_Float64 x); -/// Inverse hyperbolic tangent (__l2math_Float32) -__l2math_Float32 __l2math_atanhf(__l2math_Float32 x); -/// Computes the cube root of the argument. -__l2math_Float64 __l2math_cbrt(__l2math_Float64 x); -/// Cube root (__l2math_Float32) -__l2math_Float32 __l2math_cbrtf(__l2math_Float32 x); -/// Ceil -__l2math_Float64 __l2math_ceil(__l2math_Float64 x); -/// Ceil (__l2math_Float32) -__l2math_Float32 __l2math_ceilf(__l2math_Float32 x); -/// Sign of Y, magnitude of X -__l2math_Float64 __l2math_copysign(__l2math_Float64 x, __l2math_Float64 y); -/// Sign of Y, magnitude of X (__l2math_Float32) -__l2math_Float32 __l2math_copysignf(__l2math_Float32 x, __l2math_Float32 y); -/// Cosine -__l2math_Float64 __l2math_cos(__l2math_Radian64 x); -/// Cosine (__l2math_Float32) -__l2math_Float32 __l2math_cosf(__l2math_Radian32 x); -/// Hyperbolic cosine -__l2math_Float64 __l2math_cosh(__l2math_Float64 x); -/// Hyperbolic cosine (__l2math_Float32) -__l2math_Float32 __l2math_coshf(__l2math_Float32 x); -/// Computes the exponential function of x. -__l2math_Float64 __l2math_exp(__l2math_Float64 x); -/// Computes the exponential function of x (__l2math_Float32). -__l2math_Float32 __l2math_expf(__l2math_Float32 x); -/// Computes the exponential minus one function of x. -__l2math_Float64 __l2math_expm1(__l2math_Float64 x); -/// Computes the exponential minus one function of x (__l2math_Float32). -__l2math_Float32 __l2math_expm1f(__l2math_Float32 x); -/// Absolute value -__l2math_Float64 __l2math_fabs(__l2math_Float64 x); -/// Absolute value (__l2math_Float32) -__l2math_Float32 __l2math_fabsf(__l2math_Float32 x); -/// Factorial -__l2math_Float64 __l2math_factorial(__l2math_Float64 x); -/// Factorial (__l2math_Float32) -__l2math_Float32 __l2math_factorialf(__l2math_Float32 x); -/// Floor -__l2math_Float64 __l2math_floor(__l2math_Float64 x); -/// Floor (__l2math_Float32) -__l2math_Float32 __l2math_floorf(__l2math_Float32 x); -/// Computes the fused multiply-add of x, y and z. -__l2math_Float64 __l2math_fma(__l2math_Float64 x, __l2math_Float64 y, __l2math_Float64 z); -/// Computes the fused multiply-add of x, y and z (__l2math_Float32). -__l2math_Float32 __l2math_fmaf(__l2math_Float32 x, __l2math_Float32 y, __l2math_Float32 z); -/// Returns the maximum of the two arguments, signaling NaNs if either argument is a signaling NaN. -__l2math_Float64 __l2math_fmax(__l2math_Float64 x, __l2math_Float64 y); -/// Returns the maximum of the two arguments, signaling NaNs if either argument is a signaling NaN (__l2math_Float32). -__l2math_Float32 __l2math_fmaxf(__l2math_Float32 x, __l2math_Float32 y); -/// Returns the minimum of the two arguments, signaling NaNs if either argument is a signaling NaN. -__l2math_Float64 __l2math_fmin(__l2math_Float64 x, __l2math_Float64 y); -/// Returns the minimum of the two arguments, signaling NaNs if either argument is a signaling NaN (__l2math_Float32). -__l2math_Float32 __l2math_fminf(__l2math_Float32 x, __l2math_Float32 y); -/// Computes the floating-point remainder of dividing x by y. -__l2math_Float64 __l2math_fmod(__l2math_Float64 x, __l2math_Float64 y); -/// Computes the floating-point remainder of dividing x by y (__l2math_Float32). -__l2math_Float32 __l2math_fmodf(__l2math_Float32 x, __l2math_Float32 y); -/// Breaks the number into a normalized fraction and a base-2 exponent -__l2math_Tuple_Float64_Int __l2math_frexp(__l2math_Float64 x); -/// Breaks the number into a normalized fraction and a base-2 exponent (__l2math_Float32) -__l2math_Tuple_Float32_Int __l2math_frexpf(__l2math_Float32 x); -/// Calculate the length of the hypotenuse of a right-angle triangle given legs of length x and y. -__l2math_Float64 __l2math_hypot(__l2math_Float64 x, __l2math_Float64 y); -/// Calculate the length of the hypotenuse of a right-angle triangle given legs of length x and y (__l2math_Float32). -__l2math_Float32 __l2math_hypotf(__l2math_Float32 x, __l2math_Float32 y); -/// Get exponent of floating point value -__l2math_Int __l2math_ilogb(__l2math_Float64 x); -/// Get exponent of floating point value (__l2math_Float32) -__l2math_Int __l2math_ilogbf(__l2math_Float32 x); -/// Bessel function of the first kind of order zero -__l2math_Float64 __l2math_j0(__l2math_Float64 x); -/// Bessel function of the first kind of order zero (__l2math_Float32) -__l2math_Float32 __l2math_j0f(__l2math_Float32 x); -/// Bessel function of the first kind of order one -__l2math_Float64 __l2math_j1(__l2math_Float64 x); -/// Bessel function of the first kind of order one (__l2math_Float32) -__l2math_Float32 __l2math_j1f(__l2math_Float32 x); -/// Bessel function of the first kind of order n -__l2math_Float64 __l2math_jn(__l2math_Int n, __l2math_Float64 x); -/// Bessel function of the first kind of order n (__l2math_Float32) -__l2math_Float32 __l2math_jnf(__l2math_Int n, __l2math_Float32 x); -/// Returns x * 2^n. -__l2math_Float64 __l2math_ldexp(__l2math_Float64 x, __l2math_Int n); -/// Returns x * 2^n (__l2math_Float32). -__l2math_Float32 __l2math_ldexpf(__l2math_Float32 x, __l2math_Int n); -/// Natural logarithm of gamma function -__l2math_Float64 __l2math_lgamma(__l2math_Float64 x); -/// Natural logarithm of gamma function (__l2math_Float32) -__l2math_Float32 __l2math_lgammaf(__l2math_Float32 x); -/// Natural logarithm of gamma function -__l2math_Tuple_Float64_Int __l2math_lgamma_r(__l2math_Float64 x); -/// Natural logarithm of gamma function (__l2math_Float32) -__l2math_Tuple_Float32_Int __l2math_lgammaf_r(__l2math_Float32 x); -/// Return the natural logarithm of x. -__l2math_Float64 __l2math_ln(__l2math_Float64 x); -/// Return the natural logarithm of x (__l2math_Float32). -__l2math_Float32 __l2math_lnf(__l2math_Float32 x); -/// Return logarithm of x. -__l2math_Float64 __l2math_log(__l2math_Float64 x); -/// Return logarithm of x (__l2math_Float32). -__l2math_Float32 __l2math_logf(__l2math_Float32 x); -/// Return logarithm of x to base 10. -__l2math_Float64 __l2math_log10(__l2math_Float64 x); -/// Return logarithm of x to base 10 (__l2math_Float32). -__l2math_Float32 __l2math_log10f(__l2math_Float32 x); -/// Return logarithm of x to base 2. -__l2math_Float64 __l2math_log2(__l2math_Float64 x); -/// Return logarithm of x to base 2 (__l2math_Float32). -__l2math_Float32 __l2math_log2f(__l2math_Float32 x); -/// Return the natural logarithm of one plus x. -__l2math_Float64 __l2math_log1p(__l2math_Float64 x); -/// Return the natural logarithm of one plus x (__l2math_Float32). -__l2math_Float32 __l2math_log1pf(__l2math_Float32 x); -/// Breaks the given number into an integral and a fractional part. -__l2math_Tuple_Float64_Float64 __l2math_modf(__l2math_Float64 x); -/// Breaks the given number into an integral and a fractional part (__l2math_Float32). -__l2math_Tuple_Float32_Float32 __l2math_modff(__l2math_Float32 x); -/// Returns the next representable floating-point value following x in the direction of y. -__l2math_Float64 __l2math_nextafter(__l2math_Float64 x, __l2math_Float64 y); -/// Returns the next representable floating-point value following x in the direction of y. (__l2math_Float32) -__l2math_Float32 __l2math_nextafterf(__l2math_Float32 x, __l2math_Float32 y); -/// Returns x raised to the power y. -__l2math_Float64 __l2math_pow(__l2math_Float64 x, __l2math_Float64 y); -/// Returns x raised to the power y. (__l2math_Float32) -__l2math_Float32 __l2math_powf(__l2math_Float32 x, __l2math_Float32 y); -/// Returns the remainder of x/y. -__l2math_Float64 __l2math_remainder(__l2math_Float64 x, __l2math_Float64 y); -/// Returns the remainder of x/y. (__l2math_Float32) -__l2math_Float32 __l2math_remainderf(__l2math_Float32 x, __l2math_Float32 y); -/// Return the remainder and part of the quotient of x and y. -__l2math_Tuple_Float64_Int __l2math_remquo(__l2math_Float64 x, __l2math_Float64 y); -/// Return the remainder and part of the quotient of x and y. (__l2math_Float32) -__l2math_Tuple_Float32_Int __l2math_remquof(__l2math_Float32 x, __l2math_Float32 y); -/// Round to nearest integer, rounding halfway cases away from zero. -__l2math_Float64 __l2math_rint(__l2math_Float64 x); -/// Round to nearest integer, rounding halfway cases away from zero. (__l2math_Float32) -__l2math_Float32 __l2math_rintf(__l2math_Float32 x); -/// Rounds x to the nearest integer in the direction of the current rounding mode. -__l2math_Float64 __l2math_round(__l2math_Float64 x); -/// Rounds x to the nearest integer in the direction of the current rounding mode. (__l2math_Float32) -__l2math_Float32 __l2math_roundf(__l2math_Float32 x); -/// Returns x * 2^n -__l2math_Float64 __l2math_scalbn(__l2math_Float64 x, __l2math_Int n); -/// Returns x * 2^n (__l2math_Float32) -__l2math_Float32 __l2math_scalbnf(__l2math_Float32 x, __l2math_Int n); -/// Returns the sine function of x. -__l2math_Float64 __l2math_sin(__l2math_Radian64 x); -/// Simultaneously computes the sine and cosine of the argument x. -__l2math_Tuple_Float64_Float64 __l2math_sincos(__l2math_Radian64 x); -/// Simultaneously computes the sine and cosine of the argument x. (__l2math_Float32) -__l2math_Tuple_Float32_Float32 __l2math_sincosf(__l2math_Radian32 x); -/// Returns the sine of the argument x. -__l2math_Float64 __l2math_sinf(__l2math_Float64 x); -/// Returns the hyperbolic sine of x. -__l2math_Float64 __l2math_sinh(__l2math_Float64 x); -/// Returns the hyperbolic sine of x. (__l2math_Float32) -__l2math_Float32 __l2math_sinhf(__l2math_Float32 x); -/// Returns the square root of x. -__l2math_Float64 __l2math_sqrt(__l2math_Float64 x); -/// Returns the square root of x. (__l2math_Float32) -__l2math_Float32 __l2math_sqrtf(__l2math_Float32 x); -/// Returns tangent of x. -__l2math_Float64 __l2math_tan(__l2math_Radian64 x); -/// Returns tangent of x. (__l2math_Float32) -__l2math_Float32 __l2math_tanf(__l2math_Radian32 x); -/// Returns the hyperbolic tangent of x. -__l2math_Float64 __l2math_tanh(__l2math_Float64 x); -/// Returns the hyperbolic tangent of x. (__l2math_Float32) -__l2math_Float32 __l2math_tanhf(__l2math_Float32 x); -/// Returns the gamma function of x. -__l2math_Float64 __l2math_tgamma(__l2math_Float64 x); -/// Returns the gamma function of x. (__l2math_Float32) -__l2math_Float32 __l2math_tgammaf(__l2math_Float32 x); -/// Returns the integer part of self. This means that non-integer numbers are always truncated towards zero. -__l2math_Float64 __l2math_trunc(__l2math_Float64 x); -/// Returns the integer part of self. This means that non-integer numbers are always truncated towards zero. (__l2math_Float32) -__l2math_Float32 __l2math_truncf(__l2math_Float32 x); -/// Returns the value of the least significant bit of the given floating point number. -__l2math_Float64 __l2math_ulp(__l2math_Float64 x); -/// Bessel function of the second kind of order zero -__l2math_Float64 __l2math_y0(__l2math_Float64 x); -/// Bessel function of the second kind of order zero (__l2math_Float32) -__l2math_Float32 __l2math_y0f(__l2math_Float32 x); -/// Bessel function of the second kind of order one -__l2math_Float64 __l2math_y1(__l2math_Float64 x); -/// Bessel function of the second kind of order one (__l2math_Float32) -__l2math_Float32 __l2math_y1f(__l2math_Float32 x); -/// Bessel function of the second kind of order n -__l2math_Float64 __l2math_yn(__l2math_Int n, __l2math_Float64 x); -/// Bessel function of the second kind of order n (__l2math_Float32) -__l2math_Float32 __l2math_ynf(__l2math_Int n, __l2math_Float32 x); - -#ifdef __cplusplus - } - - /// High precision floating point number - typedef __l2math_Float64 Float64; - /// Low precision floating point number - typedef __l2math_Float32 Float32; - /// High precision floating point number representing an angle - typedef __l2math_Radian64 Radian64; - /// Low precision floating point number representing an angle - typedef __l2math_Radian32 Radian32; - /// High precision floating point number representing an angle in degrees - typedef __l2math_Degree64 Degree64; - /// Low precision floating point number representing an angle in degrees - typedef __l2math_Degree32 Degree32; - /// A standard signed integer - typedef __l2math_Int Int; - - constexpr const Float64 PI = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679; - constexpr const Float64 _PI_OVER_180 = 0.0174532925199432957692369076848861271344287188854172545609719144017100911460344944368224156963450948221230449250737905924838546922752810123984742189340471173191682450150107695616975535812386053051687886912711720870329635896026424901877043509181733439396980475940192241589469684813789632978181124952292984699278144795310454160084495609046069671761964687105143908889518362808267803695632452608441195089412947626131431088441838454784298996256210728062141559692354442374975963993652929160623774343500663840546315186802258; - constexpr const Float64 _180_OVER_PI = 57.295779513082320876798154814105170332405472466564321549160243861202847148321552632440968995851110944186223381632864893281448264601248315036068267863411942122526388097467267926307988702893110767938261442638263158209610460487020506444259656841120171912057738566280431284962624203376187937297623870790340315980719624089522045186205459923396314841906966220115126609691801514787637366923164107126774038514690165499594192515711986479435210661624389035202306756177796757113315683506205731313360156501348898018788709917776439; - - constexpr const Radian64 DEG2RAD(Degree64 deg) { - return deg * _PI_OVER_180; - } - - constexpr const Degree64 RAD2DEG(Radian64 rad) { - return rad * _180_OVER_PI; - } - - template - class Tuple { - private: - L _l; - R _r; - public: - constexpr Tuple(L l, R r) : _l(l), _r(r) {} - constexpr const inline L l() const { - return this->_l; - } - constexpr const inline R r() const { - return this->_r; - } - }; - /// Arccosine - constexpr const inline Radian64 acos(Float64 x) { - return __l2math_acos(x); - } - /// Arccosine (Float32) - constexpr const inline Radian32 acos(Float32 x) { - return __l2math_acosf(x); - } - /// Inverse hyperbolic cosine - constexpr const inline Float64 acosh(Float64 x) { - return __l2math_acosh(x); - } - /// Inverse hyperbolic cosine (Float32) - constexpr const inline Float32 acosh(Float32 x) { - return __l2math_acoshf(x); - } - /// Arcsine - constexpr const inline Radian64 asin(Float64 x) { - return __l2math_asin(x); - } - /// Arcsine (Float32) - constexpr const inline Radian32 asin(Float32 x) { - return __l2math_asinf(x); - } - /// Inverse hyperbolic sine - constexpr const inline Float64 asinh(Float64 x) { - return __l2math_asinh(x); - } - /// Inverse hyperbolic sine (Float32) - constexpr const inline Float32 asinh(Float32 x) { - return __l2math_asinhf(x); - } - /// Arctangent - constexpr const inline Radian64 atan(Float64 x) { - return __l2math_atan(x); - } - /// Arctangent of y/x - constexpr const inline Radian64 atan2(Float64 y, Float64 x) { - return __l2math_atan2(y, x); - } - /// Arctangent of y/x (Float32) - constexpr const inline Radian32 atan2(Float32 y, Float32 x) { - return __l2math_atan2f(y, x); - } - /// Arctangent (Float32) - constexpr const inline Radian32 atan(Float32 x) { - return __l2math_atanf(x); - } - /// Inverse hyperbolic tangent - constexpr const inline Float64 atanh(Float64 x) { - return __l2math_atanh(x); - } - /// Inverse hyperbolic tangent (Float32) - constexpr const inline Float32 atanh(Float32 x) { - return __l2math_atanhf(x); - } - /// Computes the cube root of the argument. - constexpr const inline Float64 cbrt(Float64 x) { - return __l2math_cbrt(x); - } - /// Cube root (Float32) - constexpr const inline Float32 cbrt(Float32 x) { - return __l2math_cbrtf(x); - } - /// Ceil - constexpr const inline Float64 ceil(Float64 x) { - return __l2math_ceil(x); - } - /// Ceil (Float32) - constexpr const inline Float32 ceil(Float32 x) { - return __l2math_ceilf(x); - } - /// Sign of Y, magnitude of X - constexpr const inline Float64 copysign(Float64 x, Float64 y) { - return __l2math_copysign(x, y); - } - /// Sign of Y, magnitude of X (Float32) - constexpr const inline Float32 copysign(Float32 x, Float32 y) { - return __l2math_copysignf(x, y); - } - /// Cosine - constexpr const inline Float64 cos(Radian64 x) { - return __l2math_cos(x); - } - /// Cosine (Float32) - constexpr const inline Float32 cos(Radian32 x) { - return __l2math_cosf(x); - } - /// Hyperbolic cosine - constexpr const inline Float64 cosh(Float64 x) { - return __l2math_cosh(x); - } - /// Hyperbolic cosine (Float32) - constexpr const inline Float32 cosh(Float32 x) { - return __l2math_coshf(x); - } - /// Computes the exponential function of x. - constexpr const inline Float64 exp(Float64 x) { - return __l2math_exp(x); - } - /// Computes the exponential function of x (Float32). - constexpr const inline Float32 exp(Float32 x) { - return __l2math_expf(x); - } - /// Computes the exponential minus one function of x. - constexpr const inline Float64 expm1(Float64 x) { - return __l2math_expm1(x); - } - /// Computes the exponential minus one function of x (Float32). - constexpr const inline Float32 expm1(Float32 x) { - return __l2math_expm1f(x); - } - /// Absolute value - constexpr const inline Float64 abs(Float64 x) { - return __l2math_fabs(x); - } - /// Absolute value (Float32) - constexpr const inline Float32 abs(Float32 x) { - return __l2math_fabsf(x); - } - /// Factorial - constexpr const inline Float64 factorial(Float64 x) { - return __l2math_factorial(x); - } - /// Factorial (Float32) - constexpr const inline Float32 factorial(Float32 x) { - return __l2math_factorialf(x); - } - /// Floor - constexpr const inline Float64 floor(Float64 x) { - return __l2math_floor(x); - } - /// Floor (Float32) - constexpr const inline Float32 floor(Float32 x) { - return __l2math_floorf(x); - } - /// Computes the fused multiply-add of x, y and z. - constexpr const inline Float64 fma(Float64 x, Float64 y, Float64 z) { - return __l2math_fma(x, y, z); - } - /// Computes the fused multiply-add of x, y and z (Float32). - constexpr const inline Float32 fma(Float32 x, Float32 y, Float32 z) { - return __l2math_fmaf(x, y, z); - } - /// Returns the maximum of the two arguments, signaling NaNs if either argument is a signaling NaN. - constexpr const inline Float64 max(Float64 x, Float64 y) { - return __l2math_fmax(x, y); - } - /// Returns the maximum of the two arguments, signaling NaNs if either argument is a signaling NaN (Float32). - constexpr const inline Float32 max(Float32 x, Float32 y) { - return __l2math_fmaxf(x, y); - } - /// Returns the minimum of the two arguments, signaling NaNs if either argument is a signaling NaN. - constexpr const inline Float64 min(Float64 x, Float64 y) { - return __l2math_fmin(x, y); - } - /// Returns the minimum of the two arguments, signaling NaNs if either argument is a signaling NaN (Float32). - constexpr const inline Float32 min(Float32 x, Float32 y) { - return __l2math_fminf(x, y); - } - /// Computes the floating-point remainder of dividing x by y. - constexpr const inline Float64 mod(Float64 x, Float64 y) { - return __l2math_fmod(x, y); - } - /// Computes the floating-point remainder of dividing x by y (Float32). - constexpr const inline Float32 mod(Float32 x, Float32 y) { - return __l2math_fmodf(x, y); - } - /// Breaks the number into a normalized fraction and a base-2 exponent - constexpr const inline Tuple frexp(Float64 x) { - __l2math_Tuple_Float64_Int res = __l2math_frexp(x); - return Tuple(res.f, res.i); - } - /// Breaks the number into a normalized fraction and a base-2 exponent (Float32) - constexpr const inline Tuple frexp(Float32 x) { - __l2math_Tuple_Float32_Int res = __l2math_frexpf(x); - return Tuple(res.f, res.i); - } - /// Calculate the length of the hypotenuse of a right-angle triangle given legs of length x and y. - constexpr const inline Float64 hypot(Float64 x, Float64 y) { - return __l2math_hypot(x, y); - } - /// Calculate the length of the hypotenuse of a right-angle triangle given legs of length x and y (Float32). - constexpr const inline Float32 hypot(Float32 x, Float32 y) { - return __l2math_hypotf(x, y); - } - /// Get exponent of floating point value - constexpr const inline Int ilogb(Float64 x) { - return __l2math_ilogb(x); - } - /// Get exponent of floating point value (Float32) - constexpr const inline Int ilogb(Float32 x) { - return __l2math_ilogbf(x); - } - /// Bessel function of the first kind of order zero - constexpr const inline Float64 j0(Float64 x) { - return __l2math_j0(x); - } - /// Bessel function of the first kind of order zero (Float32) - constexpr const inline Float32 j0(Float32 x) { - return __l2math_j0f(x); - } - /// Bessel function of the first kind of order one - constexpr const inline Float64 j1(Float64 x) { - return __l2math_j1(x); - } - /// Bessel function of the first kind of order one (Float32) - constexpr const inline Float32 j1(Float32 x) { - return __l2math_j1f(x); - } - /// Bessel function of the first kind of order n - constexpr const inline Float64 jn(Int n, Float64 x) { - return __l2math_jn(n, x); - } - /// Bessel function of the first kind of order n (Float32) - constexpr const inline Float32 jn(Int n, Float32 x) { - return __l2math_jnf(n, x); - } - /// Returns x * 2^n. - constexpr const inline Float64 ldexp(Float64 x, Int n) { - return __l2math_ldexp(x, n); - } - /// Returns x * 2^n (Float32). - constexpr const inline Float32 ldexp(Float32 x, Int n) { - return __l2math_ldexpf(x, n); - } - /// Natural logarithm of gamma function - constexpr const inline Float64 lgamma(Float64 x) { - return __l2math_lgamma(x); - } - /// Natural logarithm of gamma function (Float32) - constexpr const inline Float32 lgamma(Float32 x) { - return __l2math_lgammaf(x); - } - /// Natural logarithm of gamma function - constexpr const inline Tuple lgamma_r(Float64 x) { - __l2math_Tuple_Float64_Int res = __l2math_lgamma_r(x); - return Tuple(res.f, res.i); - } - /// Natural logarithm of gamma function (Float32) - constexpr const inline Tuple lgamma_r(Float32 x) { - __l2math_Tuple_Float32_Int res = __l2math_lgammaf_r(x); - return Tuple(res.f, res.i); - } - /// Return the natural logarithm of x. - constexpr const inline Float64 ln(Float64 x) { - return __l2math_ln(x); - } - /// Return the natural logarithm of x (Float32). - constexpr const inline Float32 ln(Float32 x) { - return __l2math_lnf(x); - } - /// Return logarithm of x. - constexpr const inline Float64 log(Float64 x) { - return __l2math_log(x); - } - /// Return logarithm of x (Float32). - constexpr const inline Float32 log(Float32 x) { - return __l2math_logf(x); - } - /// Return logarithm of x to base 10. - constexpr const inline Float64 log10(Float64 x) { - return __l2math_log10(x); - } - /// Return logarithm of x to base 10 (Float32). - constexpr const inline Float32 log10(Float32 x) { - return __l2math_log10f(x); - } - /// Return logarithm of x to base 2. - constexpr const inline Float64 log2(Float64 x) { - return __l2math_log2(x); - } - /// Return logarithm of x to base 2 (Float32). - constexpr const inline Float32 log2(Float32 x) { - return __l2math_log2f(x); - } - /// Return the natural logarithm of one plus x. - constexpr const inline Float64 log1p(Float64 x) { - return __l2math_log1p(x); - } - /// Return the natural logarithm of one plus x (Float32). - constexpr const inline Float32 log1p(Float32 x) { - return __l2math_log1pf(x); - } - /// Breaks the given number into an integral and a fractional part. - constexpr const inline Tuple mod(Float64 x) { - __l2math_Tuple_Float64_Float64 res = __l2math_modf(x); - return Tuple(res.f1, res.f2); - } - /// Breaks the given number into an integral and a fractional part (Float32). - constexpr const inline Tuple mod(Float32 x) { - __l2math_Tuple_Float32_Float32 res = __l2math_modff(x); - return Tuple(res.f1, res.f2); - } - /// Returns the next representable floating-point value following x in the direction of y. - constexpr const inline Float64 nextafter(Float64 x, Float64 y) { - return __l2math_nextafter(x, y); - } - /// Returns the next representable floating-point value following x in the direction of y. (Float32) - constexpr const inline Float32 nextafter(Float32 x, Float32 y) { - return __l2math_nextafterf(x, y); - } - /// Returns x raised to the power y. - constexpr const inline Float64 pow(Float64 x, Float64 y) { - return __l2math_pow(x, y); - } - /// Returns x raised to the power y. (Float32) - constexpr const inline Float32 pow(Float32 x, Float32 y) { - return __l2math_powf(x, y); - } - /// Returns the remainder of x/y. - constexpr const inline Float64 remainder(Float64 x, Float64 y) { - return __l2math_remainder(x, y); - } - /// Returns the remainder of x/y. (Float32) - constexpr const inline Float32 remainder(Float32 x, Float32 y) { - return __l2math_remainderf(x, y); - } - /// Return the remainder and part of the quotient of x and y. - constexpr const inline Tuple remquo(Float64 x, Float64 y) { - __l2math_Tuple_Float64_Int res = __l2math_remquo(x, y); - return Tuple(res.f, res.i); - } - /// Return the remainder and part of the quotient of x and y. (Float32) - constexpr const inline Tuple remquo(Float32 x, Float32 y) { - __l2math_Tuple_Float32_Int res = __l2math_remquof(x, y); - return Tuple(res.f, res.i); - } - /// Round to nearest integer, rounding halfway cases away from zero. - constexpr const inline Float64 rint(Float64 x) { - return __l2math_rint(x); - } - /// Round to nearest integer, rounding halfway cases away from zero. (Float32) - constexpr const inline Float32 rint(Float32 x) { - return __l2math_rintf(x); - } - /// Rounds x to the nearest integer in the direction of the current rounding mode. - constexpr const inline Float64 round(Float64 x) { - return __l2math_round(x); - } - /// Rounds x to the nearest integer in the direction of the current rounding mode. (Float32) - constexpr const inline Float32 round(Float32 x) { - return __l2math_roundf(x); - } - /// Rounds x to a number of digits after the decimal point. - constexpr const inline Float64 round(Float64 x, Float64 to) { - return round(x / to) * to; - } - /// Rounds x to a number of digits after the decimal point. (Float32) - constexpr const inline Float32 round(Float32 x, Float32 to) { - return round(x / to) * to; - } - /// Returns x * 2^n - constexpr const inline Float64 scalbn(Float64 x, Int n) { - return __l2math_scalbn(x, n); - } - /// Returns x * 2^n (Float32) - constexpr const inline Float32 scalbn(Float32 x, Int n) { - return __l2math_scalbnf(x, n); - } - /// Returns the sine function of x. - constexpr const inline Float64 sin(Radian64 x) { - return __l2math_sin(x); - } - /// Simultaneously computes the sine and cosine of the argument x. - constexpr const inline Tuple sincos(Radian64 x) { - __l2math_Tuple_Float64_Float64 res = __l2math_sincos(x); - return Tuple(res.f1, res.f2); - } - /// Simultaneously computes the sine and cosine of the argument x. (Float32) - constexpr const inline Tuple sincos(Radian32 x) { - __l2math_Tuple_Float32_Float32 res = __l2math_sincosf(x); - return Tuple(res.f1, res.f2); - } - /// Returns the sine of the argument x. - constexpr const inline Float32 sin(Radian32 x) { - return __l2math_sinf(x); - } - /// Returns the hyperbolic sine of x. - constexpr const inline Float64 sinh(Float64 x) { - return __l2math_sinh(x); - } - /// Returns the hyperbolic sine of x. (Float32) - constexpr const inline Float32 sinh(Float32 x) { - return __l2math_sinhf(x); - } - /// Returns the square root of x. - constexpr const inline Float64 sqrt(Float64 x) { - return __l2math_sqrt(x); - } - /// Returns the square root of x. (Float32) - constexpr const inline Float32 sqrt(Float32 x) { - return __l2math_sqrtf(x); - } - /// Returns tangent of x. - constexpr const inline Float64 tan(Radian64 x) { - return __l2math_tan(x); - } - /// Returns tangent of x. (Float32) - constexpr const inline Float32 tan(Radian32 x) { - return __l2math_tanf(x); - } - /// Returns the hyperbolic tangent of x. - constexpr const inline Float64 tanh(Float64 x) { - return __l2math_tanh(x); - } - /// Returns the hyperbolic tangent of x. (Float32) - constexpr const inline Float32 tanh(Float32 x) { - return __l2math_tanhf(x); - } - /// Returns the gamma function of x. - constexpr const inline Float64 tgamma(Float64 x) { - return __l2math_tgamma(x); - } - /// Returns the gamma function of x. (Float32) - constexpr const inline Float32 tgamma(Float32 x) { - return __l2math_tgammaf(x); - } - /// Returns the integer part of self. This means that non-integer numbers are always truncated towards zero. - constexpr const inline Float64 trunc(Float64 x) { - return __l2math_trunc(x); - } - /// Returns the integer part of self. This means that non-integer numbers are always truncated towards zero. (Float32) - constexpr const inline Float32 trunc(Float32 x) { - return __l2math_truncf(x); - } - /// Returns the value of the least significant bit of the given floating point number. - constexpr const inline Float64 ulp(Float64 x) { - return __l2math_ulp(x); - } - /// Bessel function of the second kind of order zero - constexpr const inline Float64 y0(Float64 x) { - return __l2math_y0(x); - } - /// Bessel function of the second kind of order zero (Float32) - constexpr const inline Float32 y0(Float32 x) { - return __l2math_y0f(x); - } - /// Bessel function of the second kind of order one - constexpr const inline Float64 y1(Float64 x) { - return __l2math_y1(x); - } - /// Bessel function of the second kind of order one (Float32) - constexpr const inline Float32 y1(Float32 x) { - return __l2math_y1f(x); - } - /// Bessel function of the second kind of order n - constexpr const inline Float64 yn(Int n, Float64 x) { - return __l2math_yn(n, x); - } - /// Bessel function of the second kind of order n (Float32) - constexpr const inline Float32 yn(Int n, Float32 x) { - return __l2math_ynf(n, x); - } -} -#endif // __cplusplus - -#endif // __L2MATH_BINDINGS_H diff --git a/libs/l2math/bindings/l2math_test.cpp b/libs/l2math/bindings/l2math_test.cpp deleted file mode 100644 index 3a138a8..0000000 --- a/libs/l2math/bindings/l2math_test.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "l2math.h" -#include "EZtest" - -#include - -using namespace l2math; - -constexpr const Float64 THIRTY_DEGREES = 0.5235987756; -constexpr const Float64 SIXTY_DEGREES = 1.0471975512; - -TEST(main_test) { - Float64 thirty = DEG2RAD(30.0); - Float64 sixty = DEG2RAD(60.0); - - ASSERT_EQ( - round(thirty, 10), - round(THIRTY_DEGREES, 10) - ); - ASSERT_EQ( - round(sixty, 10), - round(SIXTY_DEGREES, 10) - ); - - Float64 one_half_1 = l2math::sin(thirty); - Float64 one_half_2 = l2math::cos(sixty); - one_half_1 = round(one_half_1, 10); - one_half_2 = round(one_half_2, 10); - - ASSERT_EQ(one_half_1, one_half_2); - OK -} - -int main(int argc, char** argv) { - return RUN_TESTS; -} diff --git a/libs/l2math/bindings/lib.rs b/libs/l2math/bindings/lib.rs deleted file mode 100644 index 1424675..0000000 --- a/libs/l2math/bindings/lib.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! For Documentation please refer [L2Math](../l2math) - -#![cfg_attr(feature = "no_std", no_std)] - -#[doc(hidden)] -pub use l2math::*; - -#[no_mangle] -#[panic_handler] -#[rustfmt::skip] -#[cfg(feature = "no_std")] -pub extern "C" fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/libs/l2math/bindings/tests.py b/libs/l2math/bindings/tests.py deleted file mode 100644 index 43cea41..0000000 --- a/libs/l2math/bindings/tests.py +++ /dev/null @@ -1,104 +0,0 @@ -from libs.l2math.bindings.bindings import build_l2math_bindings - -def get_current_target_triplet() -> str | None: - target_triplet = "" - import subprocess - res = subprocess.run(["rustc", "-vV"], capture_output = True) - if res.returncode != 0: return - for line in res.stdout.decode().split("\n"): - if line.startswith("host:"): - target_triplet = line.split(" ")[1] - break - return target_triplet - -def test_with_clang(cd: str, args: list[str]) -> str | int | None: - import subprocess, os - - target_triplet = get_current_target_triplet() - if target_triplet is None: - return "Failed to get target triplet" - - # Build bindings for current target triplet just in case - res = build_l2math_bindings(cd, []) - if res != None: return res - - bin_name = "l2mathtestbin" - if "windows" in target_triplet: - bin_name += ".exe" - - BIN_PATH = f"{cd}/libs/l2math/bindings/{bin_name}" - LIBS_PATH = f"{cd}/libs/l2math/bindings/.build/" - - cmd = [ - "clang++", # Compiler - "-I", f"{cd}/libs/eztest/", # Include eztest headers - "-Wall", # Enable all warnings - "-std=c++14", # Use c++14 - "-L", LIBS_PATH, # Include build directory during linking - f"-ll2math-{target_triplet}", # Link to l2math-{target_triplet} - "-o", BIN_PATH, # Output binary - f"{cd}/libs/l2math/bindings/l2math_test.cpp", # Include test source - f"{cd}/libs/eztest/eztest.cpp", # Include eztest source - ] - - #print("cmd:", " ".join(cmd)) - - print("Compiling test binary") - - res = subprocess.run(cmd, cwd = cd) - if res.returncode != 0: - if res.returncode == 1: - print("Compilation failed") - print(res.stderr.decode()) - else: - print("Compilation failed with error code", res.returncode) - return res.returncode - - print("Running test binary") - - res = os.system(BIN_PATH) - if res != 0: return res - - os.remove(BIN_PATH) - - print("Done!") - -def test_with_gcc(cd: str, args: list[str]) -> str | int | None: - return "GCC is not supported yet" - -def test_with_msvc(cd: str, args: list[str]) -> str | int | None: - return "MSVC is not supported yet" - -def bindings_test(cd: str, args: list[str]) -> str | int | None: - import subprocess - - print("Identifying c++ compiler") - # Identify the c++ compiler - res = subprocess.run( - ["clang++", "--version"], - capture_output = True - ) - - if res.returncode == 0: - print("Found clang++") - return test_with_clang(cd, args) - - res = subprocess.run( - ["g++", "--version"], - capture_output = True - ) - - if res.returncode == 0: - print("Found g++") - return test_with_gcc(cd, args) - - res = subprocess.run( - ["cl", "/?"], - capture_output = True - ) - - if res.returncode == 0: - print("Found cl") - return test_with_msvc(cd, args) - - return "No supported c++ compiler found" diff --git a/libs/libodo/Geometry.kt b/libs/libodo/Geometry.kt deleted file mode 100644 index a137c69..0000000 --- a/libs/libodo/Geometry.kt +++ /dev/null @@ -1,297 +0,0 @@ -/* -MIT License - -Copyright (c) 2018 ACME Robotics - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -@file:JvmName("Geometry") - -package com.acmerobotics.roadrunner - -import kotlin.math.atan2 -import kotlin.math.cos -import kotlin.math.sin -import kotlin.math.sqrt -import kotlin.math.tan - -/** - * @usesMathJax - * - * Vector \((x, y)\) - */ -data class Vector2d(@JvmField val x: Double, @JvmField val y: Double) { - operator fun plus(v: Vector2d) = Vector2d(x + v.x, y + v.y) - operator fun minus(v: Vector2d) = Vector2d(x - v.x, y - v.y) - operator fun unaryMinus() = Vector2d(-x, -y) - - operator fun times(z: Double) = Vector2d(x * z, y * z) - operator fun div(z: Double) = Vector2d(x / z, y / z) - - infix fun dot(v: Vector2d) = x * v.x + y * v.y - fun sqrNorm() = this dot this - fun norm() = sqrt(sqrNorm()) - - // precondition: this is normalized - fun angleCast() = Rotation2d(x, y) -} - -/** - * Dual version of [Vector2d]. - */ -data class Vector2dDual(@JvmField val x: DualNum, @JvmField val y: DualNum) { - companion object { - @JvmStatic - fun constant(v: Vector2d, n: Int) = - Vector2dDual(DualNum.constant(v.x, n), DualNum.constant(v.y, n)) - } - - operator fun plus(v: Vector2d) = Vector2dDual(x + v.x, y + v.y) - operator fun plus(v: Vector2dDual) = Vector2dDual(x + v.x, y + v.y) - operator fun minus(v: Vector2dDual) = Vector2dDual(x - v.x, y - v.y) - operator fun unaryMinus() = Vector2dDual(-x, -y) - - operator fun div(z: Double) = Vector2dDual(x / z, y / z) - - infix fun dot(v: Vector2dDual) = x * v.x + y * v.y - fun sqrNorm() = this dot this - fun norm() = sqrNorm().sqrt() - - fun bind() = Vector2dDual(x, y) - - fun reparam(oldParam: DualNum) = - Vector2dDual(x.reparam(oldParam), y.reparam(oldParam)) - - fun drop(n: Int) = Vector2dDual(x.drop(n), y.drop(n)) - fun value() = Vector2d(x.value(), y.value()) - - // precondition: this is normalized - fun angleCast() = Rotation2dDual(x, y) -} - -/** - * @usesMathJax - * - * Rotation \(\theta\) represented by the unit circle point \((\cos \theta, \sin \theta)\) or unit-modulus complex - * number \(\cos \theta + i \sin \theta\). - * - * Advanced: Rotations in two dimensions comprise a Lie group referred to as SO(2). The terminology [exp] and [log] - * comes from the Lie theory, and [this paper](https://arxiv.org/abs/1812.01537) gives a targeted exposition of the key - * fundamentals. - */ -data class Rotation2d(@JvmField val real: Double, @JvmField val imag: Double) { - companion object { - /** - * Turns an unnormalized angle into a rotation. - */ - @JvmStatic - fun exp(theta: Double) = Rotation2d(cos(theta), sin(theta)) - } - - operator fun plus(x: Double) = this * exp(x) - operator fun minus(r: Rotation2d) = (r.inverse() * this).log() - - operator fun times(v: Vector2d) = Vector2d(real * v.x - imag * v.y, imag * v.x + real * v.y) - operator fun times(pv: PoseVelocity2d) = PoseVelocity2d(this * pv.linearVel, pv.angVel) - operator fun times(r: Rotation2d) = - Rotation2d(real * r.real - imag * r.imag, real * r.imag + imag * r.real) - - fun vec() = Vector2d(real, imag) - - fun inverse() = Rotation2d(real, -imag) - - /** - * Get the rotation as a normalized [Double]. - */ - fun log() = atan2(imag, real) -} - -/** - * Dual version of [Rotation2d]. - */ -data class Rotation2dDual(@JvmField val real: DualNum, @JvmField val imag: DualNum) { - init { - require(real.size() == imag.size()) - require(real.size() <= 3) - } - - companion object { - @JvmStatic - fun exp(theta: DualNum) = Rotation2dDual(theta.cos(), theta.sin()) - - @JvmStatic - fun constant(r: Rotation2d, n: Int) = - Rotation2dDual(DualNum.constant(r.real, n), DualNum.constant(r.imag, n)) - } - - fun size() = real.size() - - operator fun plus(x: Double) = this * Rotation2d.exp(x) - operator fun plus(d: DualNum) = this * exp(d) - - operator fun times(pv: PoseVelocity2dDual) = PoseVelocity2dDual(this * pv.linearVel, pv.angVel) - operator fun times(v: Vector2dDual) = Vector2dDual(real * v.x - imag * v.y, imag * v.x + real * v.y) - operator fun times(v: Vector2d) = Vector2dDual(real * v.x - imag * v.y, imag * v.x + real * v.y) - operator fun times(r: Rotation2dDual) = - Rotation2dDual(real * r.real - imag * r.imag, real * r.imag + imag * r.real) - operator fun times(r: Rotation2d) = - Rotation2dDual(real * r.real - imag * r.imag, real * r.imag + imag * r.real) - operator fun times(p: Pose2d) = Pose2dDual(this * p.position, this * p.heading) - - fun inverse() = Rotation2dDual(real, -imag) - - fun reparam(oldParam: DualNum) = - Rotation2dDual(real.reparam(oldParam), imag.reparam(oldParam)) - - // derivative of atan2 under unit norm assumption - fun velocity() = real * imag.drop(1) - imag * real.drop(1) - fun value() = Rotation2d(real.value(), imag.value()) -} - -/** - * @usesMathJax - * - * 2D rigid transform comprised of [heading] followed by [position]. - * - * The pose `destPoseSource` denotes the transform from frame `Source` into frame `Dest`. It can be applied with - * `times()` to change the coordinates of `xSource` into `xDest` where `x` is a vector, twist, or even another pose: - * `xDest = destPoseSource * xSource`. The awkward names take some getting used to, but they avoid many routine errors. - * - * Transforms into the world frame are common enough to warrant a shorthand. The pose `worldPoseSource` can be shortened - * to `poseSource` for any frame `Source`. - * - * Advanced: Transforms in two dimensions comprise a Lie group referred to as SE(2). The terminology [exp] and [log] - * comes from the Lie theory, and [this paper](https://arxiv.org/abs/1812.01537) gives a targeted exposition of the key - * fundamentals. - */ -data class Pose2d( - @JvmField - val position: Vector2d, - @JvmField - val heading: Rotation2d, -) { - constructor(position: Vector2d, heading: Double) : this(position, Rotation2d.exp(heading)) - constructor(positionX: Double, positionY: Double, heading: Double) : this(Vector2d(positionX, positionY), heading) - - companion object { - @JvmStatic - fun exp(t: Twist2d): Pose2d { - val heading = Rotation2d.exp(t.angle) - - val u = t.angle + snz(t.angle) - val c = 1 - cos(u) - val s = sin(u) - val translation = Vector2d( - (s * t.line.x - c * t.line.y) / u, - (c * t.line.x + s * t.line.y) / u - ) - - return Pose2d(translation, heading) - } - } - - operator fun plus(t: Twist2d) = this * exp(t) - fun minusExp(t: Pose2d) = t.inverse() * this - operator fun minus(t: Pose2d) = minusExp(t).log() - - operator fun times(p: Pose2d) = Pose2d(heading * p.position + position, heading * p.heading) - operator fun times(v: Vector2d) = heading * v + position - operator fun times(pv: PoseVelocity2d) = PoseVelocity2d(heading * pv.linearVel, pv.angVel) - - fun inverse() = Pose2d(heading.inverse() * -position, heading.inverse()) - - fun log(): Twist2d { - val theta = heading.log() - - val halfu = 0.5 * theta + snz(theta) - val v = halfu / tan(halfu) - return Twist2d( - Vector2d( - v * position.x + halfu * position.y, - -halfu * position.x + v * position.y, - ), - theta, - ) - } -} - -/** - * Dual version of [Pose2d]. - */ -data class Pose2dDual( - @JvmField - val position: Vector2dDual, - @JvmField - val heading: Rotation2dDual, -) { - companion object { - @JvmStatic - fun constant(p: Pose2d, n: Int) = - Pose2dDual(Vector2dDual.constant(p.position, n), Rotation2dDual.constant(p.heading, n)) - } - - operator fun plus(t: Twist2d) = this * Pose2d.exp(t) - - operator fun times(p: Pose2d) = Pose2dDual(heading * p.position + position, heading * p.heading) - operator fun times(p: Pose2dDual) = Pose2dDual(heading * p.position + position, heading * p.heading) - operator fun times(pv: PoseVelocity2dDual) = PoseVelocity2dDual(heading * pv.linearVel, pv.angVel) - - fun inverse() = heading.inverse().let { - Pose2dDual(it * -position, it) - } - - fun reparam(oldParam: DualNum) = - Pose2dDual(position.reparam(oldParam), heading.reparam(oldParam)) - - fun value() = Pose2d(position.value(), heading.value()) - fun velocity() = PoseVelocity2dDual(position.drop(1), heading.velocity()) -} - -data class PoseVelocity2d(@JvmField val linearVel: Vector2d, @JvmField val angVel: Double) { - operator fun minus(pv: PoseVelocity2d) = PoseVelocity2d(linearVel - pv.linearVel, angVel - pv.angVel) -} - -/** - * Dual version of [PoseVelocity2d]. - */ -data class PoseVelocity2dDual( - @JvmField val linearVel: Vector2dDual, - @JvmField val angVel: DualNum -) { - companion object { - @JvmStatic - fun constant(pv: PoseVelocity2d, n: Int) = - PoseVelocity2dDual(Vector2dDual.constant(pv.linearVel, n), DualNum.constant(pv.angVel, n)) - } - - operator fun plus(other: PoseVelocity2d) = PoseVelocity2dDual(linearVel + other.linearVel, angVel + other.angVel) - - fun value() = PoseVelocity2d(linearVel.value(), angVel.value()) -} - -data class Twist2d(@JvmField val line: Vector2d, @JvmField val angle: Double) - -data class Twist2dDual( - @JvmField val line: Vector2dDual, - @JvmField val angle: DualNum -) { - fun value() = Twist2d(line.value(), angle.value()) - fun velocity() = PoseVelocity2dDual(line.drop(1), angle.drop(1)) -} diff --git a/libs/libodo/dualnum.rs b/libs/libodo/dualnum.rs deleted file mode 100644 index 4345907..0000000 --- a/libs/libodo/dualnum.rs +++ /dev/null @@ -1,475 +0,0 @@ -use core::marker::PhantomData; -use libtrig::prelude::*; -use libtrig::*; - -type Array = alloc::vec::Vec; - -/// [Dual number](https://en.wikipedia.org/wiki/Dual_number) -/// to implement forward autodifferentiation. -#[derive(Debug, Clone, PartialEq, PartialOrd, Default)] -pub struct DualNum(Array, PhantomData); - -impl DualNum { - #[inline(always)] - #[must_use = "this returns the dual number (new)"] - pub(crate) const fn constructor(array: Array) -> Self { - Self(array, PhantomData) - } - - /// Makes dual number (c, 0, ..., 0) with size [n] representing a constant function (c). - pub fn constant(c: Float64, n: usize) -> Self { - let mut array = Array::with_capacity(n); - for i in 0..n { - array.push(if i == 0 { c } else { 0.0 }); - } - debug_assert!(array.len() <= 4); - Self::constructor(array) - } - - /// Makes dual number (x0, 1, 0, ..., 0) with size [n] representing a variable function (x) at (x = x0). - pub fn variable(x0: Float64, n: usize) -> Self { - let mut array = Array::with_capacity(n); - for i in 0..n { - array.push(if i == 0 { - x0 - } else if i == 1 { - 1.0 - } else { - 0.0 - }); - } - debug_assert!(array.len() <= 4); - Self::constructor(array) - } - - /// Constructs a dual number (x, d[0], d[1], ..., d[n-1]) with size [n] representing a constant function (x). - pub fn cons(x: Float64, d: Self) -> Self { - let mut array = Array::with_capacity(d.size() + 1); - for i in 0..array.capacity() { - array.push(if i == 0 { x } else { d.values()[i - 1] }); - } - debug_assert!(array.len() <= 4); - Self::constructor(array) - } - - /// Returns the size of the dual number. - #[inline(always)] - pub fn size(&self) -> usize { - self.0.len() as usize - } - - /// Returns the values of the dual number. - #[inline(always)] - pub fn values(&self) -> &[Float64] { - &self.0 - } - - /// Returns the value of the dual number. - #[inline(always)] - #[must_use = "this returns the first component of the dual number"] - pub fn value(&self) -> Float64 { - self.0[0] - } - - /// Drops the first [n] components of the dual number. - /// - /// # Panics - /// - /// Panics if [n] is greater than the size of the dual number. - #[must_use = "this returns a new dual number"] - pub fn drop(&self, n: usize) -> Self { - let mut array = Array::with_capacity(self.size() - n); - for i in 0..array.capacity() { - array[i] = self.0[i + n]; - } - debug_assert!(array.len() <= 4); - Self::constructor(array) - } - - /// Calculates the reciprocal of the dual number. - #[must_use = "this returns the reciprocal of the dual number (new)"] - pub fn recip(&self) -> Self { - let mut array = Array::with_capacity(self.size()); - if array.capacity() == 0 { - return Self::constructor(array); - } - - let recip = 1.0 / self.0[0]; - array[0] = recip; - if array.capacity() == 1 { - return Self::constructor(array); - } - - let neg_recip = -recip; - let neg_recip2 = recip * neg_recip; - let deriv = neg_recip2 * self.0[1]; - array[1] = deriv; - if array.capacity() == 2 { - return Self::constructor(array); - } - - let int1 = 2.0 * neg_recip * deriv; - let deriv2 = int1 * self.0[1] + neg_recip2 * self.0[2]; - array[2] = deriv2; - if array.capacity() == 3 { - return Self::constructor(array); - } - - let int2 = int1 * self.0[2]; - array[3] = - int2 + neg_recip2 * self.0[3] + - int2 - 2.0 * (deriv * deriv + recip * deriv2) * self.0[1]; - Self::constructor(array) - } - - /// Reparameterizes (x, dx/du, d^2x/du^2, ..., d^(n - 1) x/du^(n - 1)) into - /// (x, dx/dt, d^2x/dt^2, ..., d^(n - 1) x/dt^(n - 1)) using [old_param] and - /// the chain rule. - pub fn reparam(&self, old_param: DualNum) -> DualNum { - let mut array = Array::with_capacity(self.size().min(old_param.size())); - if array.capacity() == 0 { - return DualNum::::constructor(array); - } - - array[0] = self[0]; - if array.capacity() == 1 { - return DualNum::::constructor(array); - } - - array[1] = self[1] * old_param[1]; - if array.capacity() == 2 { - return DualNum::::constructor(array); - } - - let old_deriv2 = old_param[1] * old_param[1]; - array[2] = old_deriv2 * self[2] + old_param[2] * self[1]; - if array.capacity() == 3 { - return DualNum::::constructor(array); - } - - array[3] = self[1] * old_param[3] + - (3.0 * self[2] * old_param[2] + self[3] * old_deriv2) * old_param[1]; - DualNum::::constructor(array) - } -} - -impl Sqrt for DualNum { - /// Calculates the square root of the dual number. - #[must_use = "this returns the square root of the dual number (new)"] - fn sqrt(&self) -> Self { - let mut array = Array::with_capacity(self.size()); - if array.capacity() == 0 { - return Self::constructor(array); - } - - let sqrt = l2math::sqrt(self.0[0]); - array[0] = sqrt; - if array.capacity() == 1 { - return Self::constructor(array); - } - - let recip = 1.0 / (2.0 * sqrt); - let deriv = recip * self.0[1]; - array[1] = deriv; - if array.capacity() == 2 { - return Self::constructor(array); - } - - let neg_recip = -2.0 * recip; - let neg_recip2 = recip * neg_recip; - let int1 = neg_recip2 * deriv; - let second_deriv = int1 * self.0[1] + recip * self.0[2]; - array[2] = second_deriv; - if array.capacity() == 3 { - return Self::constructor(array); - } - - let int2 = 2.0 * int1; - array[3] = recip * self.0[3] + int2 * self.0[2] + - (deriv * neg_recip * int2 + neg_recip2 * second_deriv) * self.0[1]; - Self::constructor(array) - } -} - -impl Sin for DualNum { - /// Calculates the sine of the dual number. - #[must_use = "this returns the sine of the dual number (new)"] - fn sin(&self) -> Self { - let mut array = Array::with_capacity(self.size()); - if array.capacity() == 0 { - return Self::constructor(array); - } - - let sin = l2math::sin(self.0[0]); - array[0] = sin; - if array.capacity() == 1 { - return Self::constructor(array); - } - - let cos = l2math::cos(self.0[0]); - let deriv = cos * self.0[1]; - array[1] = deriv; - if array.capacity() == 2 { - return Self::constructor(array); - } - - let deriv2 = self.0[1] * self.0[1]; - array[2] = cos * self.0[2] - sin * deriv2; - if array.capacity() == 3 { - return Self::constructor(array); - } - - array[3] = cos * self.0[3] - - 3.0 * sin * self.0[1] * self.0[2] - - deriv * deriv2; - Self::constructor(array) - } -} - -impl Cos for DualNum { - /// Calculates the cosine of the dual number. - #[must_use = "this returns the cosine of the dual number (new)"] - fn cos(&self) -> Self { - let mut array = Array::with_capacity(self.size()); - if array.capacity() == 0 { - return Self::constructor(array); - } - - let cos = l2math::cos(self.0[0]); - array[0] = cos; - if array.capacity() == 1 { - return Self::constructor(array); - } - - let sin = l2math::sin(self.0[0]); - let neg_in_eriv = -self.0[1]; - let deriv = sin * neg_in_eriv; - array[1] = deriv; - if array.capacity() == 2 { - return Self::constructor(array); - } - - let int = cos * neg_in_eriv; - array[2] = int * self.0[1] - sin * self.0[2]; - if array.capacity() == 3 { - return Self::constructor(array); - } - - array[3] = deriv * neg_in_eriv * self.0[1] + - 3.0 * int * self.0[2] - - sin * self.0[3]; - Self::constructor(array) - } -} - -impl core::ops::Add for DualNum { - type Output = Self; - #[must_use = "this returns the sum of the dual numbers (new)"] - fn add(self, rhs: Self) -> Self::Output { - let mut array = Array::with_capacity(self.size().min(rhs.size())); - for i in 0..array.capacity() { - array[i] = self.0[i] + rhs.0[i]; - } - debug_assert!(array.len() <= 4); - Self::constructor(array) - } -} - -impl core::ops::Add for DualNum { - type Output = Self; - #[must_use = "this returns the sum of the dual numbers (new)"] - fn add(self, rhs: Float64) -> Self::Output { - let mut array = Array::with_capacity(self.size()); - for i in 0..array.capacity() { - array[i] = self.0[i] + rhs; - } - debug_assert!(array.len() <= 4); - Self::constructor(array) - } -} - -impl core::ops::AddAssign for DualNum { - fn add_assign(&mut self, rhs: Self) { - for i in 0..self.size().min(rhs.size()) { - self.0[i] += rhs.0[i]; - } - } -} - -impl core::ops::Sub for DualNum { - type Output = Self; - #[must_use = "this returns the difference of the dual numbers (new)"] - fn sub(self, rhs: Self) -> Self::Output { - let mut array = Array::with_capacity(self.size().min(rhs.size())); - for i in 0..array.capacity() { - array[i] = self.0[i] - rhs.0[i]; - } - debug_assert!(array.len() <= 4); - Self::constructor(array) - } -} - -impl core::ops::Sub for DualNum { - type Output = Self; - #[must_use = "this returns the difference of the dual numbers (new)"] - fn sub(self, rhs: Float64) -> Self::Output { - let mut array = Array::with_capacity(self.size()); - for i in 0..array.capacity() { - array[i] = self.0[i] - rhs; - } - debug_assert!(array.len() <= 4); - Self::constructor(array) - } -} - -impl core::ops::SubAssign for DualNum { - fn sub_assign(&mut self, rhs: Self) { - for i in 0..self.size().min(rhs.size()) { - self.0[i] -= rhs.0[i]; - } - } -} - -impl core::ops::Mul for DualNum { - type Output = Self; - #[rustfmt::skip] - #[must_use = "this returns the product of the dual numbers (new)"] - fn mul(self, rhs: Self) -> Self::Output { - let mut array = Array::with_capacity(self.size().min(rhs.size())); - if array.capacity() == 0 { - return Self::constructor(array); - } - - array[0] = self[0] * rhs[0]; - if array.capacity() == 1 { - return Self::constructor(array); - } - - array[1] = self[0] * rhs[1] + self[1] * rhs[0]; - if array.capacity() == 2 { - return Self::constructor(array); - } - - array[2] = self[0] * rhs[2] + self[2] * rhs[0] + 2.0 * self[1] * rhs[1]; - if array.capacity() == 3 { - return Self::constructor(array); - } - - array[3] = self[0] * rhs[3] + self[3] * rhs[0] + - 3.0 * (self[2] * rhs[1] + self[1] * rhs[2]); - - return Self::constructor(array); - } -} - -impl core::ops::Mul for DualNum { - type Output = Self; - #[must_use = "this returns the product of the dual numbers (new)"] - fn mul(self, rhs: Float64) -> Self::Output { - let mut array = Array::with_capacity(self.size()); - for i in 0..array.capacity() { - array[i] = self.0[i] * rhs; - } - debug_assert!(array.len() <= 4); - Self::constructor(array) - } -} - -impl core::ops::Neg for DualNum { - type Output = Self; - - #[must_use = "this returns the negation of the dual number (new)"] - fn neg(self) -> Self::Output { - let mut array = Array::with_capacity(self.size()); - for i in 0..array.capacity() { - array[i] = -self.0[i]; - } - debug_assert!(array.len() <= 4); - Self::constructor(array) - } -} - -impl core::ops::Div for DualNum { - type Output = Self; - #[inline] - #[must_use = "this returns the quotient of the dual numbers (new)"] - fn div(self, rhs: Self) -> Self::Output { - self * rhs.recip() - } -} - -impl core::ops::Div for DualNum { - type Output = Self; - #[inline] - #[must_use = "this returns the quotient of the dual numbers (new)"] - fn div(self, rhs: Float64) -> Self::Output { - let mut array = Array::with_capacity(self.size()); - for i in 0..array.capacity() { - array[i] = self.0[i] / rhs; - } - debug_assert!(array.len() <= 4); - Self::constructor(array) - } -} - -impl core::ops::Index for DualNum { - type Output = Float64; - #[inline(always)] - #[must_use = "this returns the first component of the dual number"] - fn index(&self, i: usize) -> &Self::Output { - &self.0[i] - } -} - -impl core::ops::Index for &DualNum { - type Output = Float64; - #[inline(always)] - #[must_use = "this returns the first component of the dual number"] - fn index(&self, i: usize) -> &Self::Output { - &self.0[i] - } -} - -impl core::ops::Index for &mut DualNum { - type Output = Float64; - #[inline(always)] - #[must_use = "this returns the first component of the dual number"] - fn index(&self, i: usize) -> &Self::Output { - &self.0[i] - } -} - -impl core::ops::IndexMut for DualNum { - #[inline(always)] - #[must_use = "this returns the first component of the dual number"] - fn index_mut(&mut self, i: usize) -> &mut Self::Output { - &mut self.0[i] - } -} - -impl core::ops::IndexMut for &mut DualNum { - #[inline(always)] - #[must_use = "this returns the first component of the dual number"] - fn index_mut(&mut self, i: usize) -> &mut Self::Output { - &mut self.0[i] - } -} - -impl core::ops::Mul for DualNum { - type Output = crate::Vec2DDual; - #[inline] - fn mul(self, rhs: Vec2D) -> Self::Output { - let size = self.size(); - let mut x_array = Array::with_capacity(size); - let mut y_array = Array::with_capacity(size); - for i in 0..size { - x_array[i] = self.0[i] * rhs.x(); - y_array[i] = self.0[i] * rhs.y(); - } - debug_assert!(x_array.len() <= 4); - debug_assert!(y_array.len() <= 4); - let x = Self::constructor(x_array); - let y = Self::constructor(y_array); - crate::Vec2DDual::new(x, y) - } -} diff --git a/libs/libodo/lib.rs b/libs/libodo/lib.rs deleted file mode 100644 index 09af16d..0000000 --- a/libs/libodo/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![no_std] -#![feature(core_intrinsics)] -#![warn(missing_docs, unused, clippy::all)] -#![doc = include_str!("./README.md")] - -extern crate alloc; - -mod dualnum; -// mod rotation2d; -mod vec2ddual; - -pub use dualnum::DualNum; -// pub use rotation2d::Rotation2D; -pub use vec2ddual::Vec2DDual; diff --git a/libs/libodo/rotation2d.rs b/libs/libodo/rotation2d.rs deleted file mode 100644 index 23c607a..0000000 --- a/libs/libodo/rotation2d.rs +++ /dev/null @@ -1,69 +0,0 @@ -use l2math::{Float64, Radian64}; - -pub struct Rotation2D { - pub real: Float64, - pub imag: Float64, -} - -impl Rotation2D { - pub const fn new(real: Float64, imag: Float64) -> Self { - Self { real, imag } - } - pub fn log(self) -> Float64 { - l2math::atan2(self.imag, self.real) - } -} - -impl From for Rotation2D { - fn from(angle: libtrig::Angle2D) -> Self { - use libtrig::prelude::*; - Self::new(angle.cos(), angle.sin()) - } -} - -impl From for Rotation2D { - fn from(angle: Radian64) -> Self { - use libtrig::prelude::*; - Self::new(angle.cos(), angle.sin()) - } -} - -impl core::ops::Neg for Rotation2D { - type Output = Self; - fn neg(self) -> Self::Output { - Self::new(self.real, -self.imag) - } -} - -impl From for libtrig::Vec2D { - fn from(rot: Rotation2D) -> Self { - Self::new(rot.real, rot.imag) - } -} - -impl core::ops::Mul for Rotation2D { - type Output = Rotation2D; - fn mul(self, rhs: Rotation2D) -> Self::Output { - Self::new( - self.real * rhs.real - self.imag * rhs.imag, - self.real * rhs.imag + self.imag * rhs.real, - ) - } -} - -impl core::ops::Mul for Rotation2D { - type Output = libtrig::Vec2D; - fn mul(self, rhs: libtrig::Vec2D) -> Self::Output { - libtrig::Vec2D::new( - self.real * rhs.x() - self.imag * rhs.y(), - self.real * rhs.y() + self.imag * rhs.x(), - ) - } -} - -impl core::ops::Add for Rotation2D { - type Output = Self; - fn add(self, rhs: Float64) -> Self::Output { - self * Self::from(rhs) - } -} diff --git a/libs/libodo/vec2ddual.rs b/libs/libodo/vec2ddual.rs deleted file mode 100644 index 95e6712..0000000 --- a/libs/libodo/vec2ddual.rs +++ /dev/null @@ -1,84 +0,0 @@ -#[allow(unused_imports)] -use libtrig::prelude::*; -use libtrig::*; - -use crate::DualNum; - -/// Dual version of a 2D vector. -pub struct Vec2DDual { - /// The x component of the vector. - pub x: DualNum, - /// The y component of the vector. - pub y: DualNum, -} - -impl Vec2DDual { - /// Construct a new Vec2DDual. - #[inline] - #[must_use = "This function creates a new Vec2DDual"] - pub const fn new(x: DualNum, y: DualNum) -> Self { - Self { x, y } - } - /// Construct a new Vec2DDual from a Vec2D. - #[inline] - #[must_use = "This function creates a new Vec2DDual"] - pub fn constant(v: Vec2D, n: usize) -> Self { - Self::new(DualNum::constant(v.x(), n), DualNum::constant(v.y(), n)) - } -} - -impl core::ops::Add for Vec2DDual { - type Output = Self; - #[inline] - #[must_use = "This function creates a new Vec2DDual"] - fn add(self, rhs: Vec2D) -> Self::Output { - Self::new(self.x + rhs.x(), self.y + rhs.y()) - } -} - -impl core::ops::Add> for Vec2DDual { - type Output = Self; - #[inline] - #[must_use = "This function creates a new Vec2DDual"] - fn add(self, rhs: Vec2DDual) -> Self::Output { - Self::new(self.x + rhs.x, self.y + rhs.y) - } -} - -impl core::ops::Sub for Vec2DDual { - type Output = Self; - #[inline] - #[must_use = "This function creates a new Vec2DDual"] - fn sub(self, rhs: Vec2D) -> Self::Output { - Self::new(self.x - rhs.x(), self.y - rhs.y()) - } -} - -impl core::ops::Sub> for Vec2DDual { - type Output = Self; - #[inline] - #[must_use = "This function creates a new Vec2DDual"] - fn sub(self, rhs: Vec2DDual) -> Self::Output { - Self::new(self.x - rhs.x, self.y - rhs.y) - } -} - -impl core::ops::Neg for Vec2DDual { - type Output = Self; - #[inline] - #[must_use = "This function creates a new Vec2DDual"] - fn neg(self) -> Self::Output { - Self::new(-self.x, -self.y) - } -} - -impl core::ops::Div for Vec2DDual { - type Output = Self; - #[inline] - #[must_use = "This function creates a new Vec2DDual"] - fn div(self, rhs: Float64) -> Self::Output { - Self::new(self.x / rhs, self.y / rhs) - } -} - -// impl Dot for diff --git a/libs/libpath/Cargo.toml b/libs/libpath/Cargo.toml deleted file mode 100644 index b47a8ad..0000000 --- a/libs/libpath/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "libpath" -description = "Pathing" -repository.workspace = true -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true - -[dependencies.libtrig] -path = "../libtrig" - -[dependencies.libodo] -path = "../libodo" - -[dependencies.l2math] -path = "../l2math" - -[lib] -path = "lib.rs" diff --git a/libs/libpath/control.rs b/libs/libpath/control.rs deleted file mode 100644 index d9f23c4..0000000 --- a/libs/libpath/control.rs +++ /dev/null @@ -1,110 +0,0 @@ -use l2math::Float64; -use libtrig::Vec2D; - -/// Kinematic motor feedforward -#[derive(Debug, Clone, Copy, PartialEq, Default)] -pub struct MotorFeedforward { - /// The static gain, or the voltage required to overcome static friction. - pub k_s: Float64, - /// The velocity gain, or the voltage required to maintain a given velocity. - pub k_v: Float64, - /// The acceleration gain, or the voltage required to produce a given acceleration. - pub k_a: Float64, -} - -impl Eq for MotorFeedforward {} - -impl MotorFeedforward { - /// Creates a new motor feedforward. - pub const fn new(k_s: Float64, k_v: Float64, k_a: Float64) -> Self { - Self { k_s, k_v, k_a } - } - /// Computes the (normalized) voltage: - /// ```text,no_run,ignore - /// |kₛ| · (v / |v|) + kᵥ · v + kₐ · a - /// ``` - pub fn compute(&self, vel: Float64, accel: Float64) -> Float64 { - use libtrig::prelude::*; - self.k_s.signof(vel) + self.k_v * vel + self.k_a * accel - } -} - -/// Proportional position-velocity controller for a holonomic robot. -#[derive(Debug, Clone, Copy, PartialEq, Default)] -pub struct HolonomicController { - axial_pos_gain: Float64, - lateral_pos_gain: Float64, - heading_gain: Float64, - axial_vel_gain: Float64, - lateral_vel_gain: Float64, - heading_vel_gain: Float64, -} - -impl Eq for HolonomicController {} - -impl HolonomicController { - pub const fn new( - axial_pos_gain: Float64, - lateral_pos_gain: Float64, - heading_gain: Float64, - ) -> Self { - Self { - axial_pos_gain, - lateral_pos_gain, - heading_gain, - axial_vel_gain: 0.0, - lateral_vel_gain: 0.0, - heading_vel_gain: 0.0, - } - } - /* - fun compute( - targetPose: Pose2dDual

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 z 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 literal 0 HcmV?d00001 diff --git a/docs/logo_white.png b/docs/logo_white.png new file mode 100644 index 0000000000000000000000000000000000000000..821a899c05647a9d0ee6423c06475a056694dfe4 GIT binary patch literal 14084 zcmaL83tWv^7cjn_b55Pp{Y2=dPAX!kC@Q2!QH&zjDT7X;nu>1dN>8~Iy3q_NQwKB2 zV2WG{ak@xGsc00Eqo|OSk|LdN?bFQr&ivp1_dUO#dV2P{?X}ikd+oKC{jN)$R1~!p z0YGK(q6I4eIQYr|o;?1F8UM|00BX+<4i2u19UKHfA%WgM1Z)N{IkfYT?V>VT_qNB% zUl&dpe@@VndSdqDg$s3;j5#PgacRuj?dC;&N*R_$lTDN3{7XtwZvVFXV8QRIzsCs% zsFpV^zjRD69yXhNDWOMFsQPOPg zoW6L_COkPWYG5F8T&sI?`>^irZ|gQO%Z!pOp5-T4CHPoP`?+^s@SfF1dk2n(KM*O6 zvI|+iV=yW7v1hE0W8ymRENlCzN21)iJl9NL)uPpsd(!VmvzP1FSO*5L@mG0NG%3b2 zH~0LeqNSnAi>DgwwOml?D>|S(wcPj5Mbi(R__`-ProQL&UE{Q~ijK*0^(X8@h9oiF z*S{~Yw0$*k?+}BZpdR&Ni=^e+ z*}GBVSE}Y8ep#~b<)U2~_GdUZvg@qIFeknj3aj6pFGzXF6*#S*_8hqJ;swVpHrO_g z?|k>}xy8@JyI|>XNP6lv!`WyS`Hf4Q7T|Au1|6=);4g)sMed;hrV{dxQd4bsfgics z7P~CuwkwZeD_Nf#r9m*2wk>qq<`B4L%jT`yVEzh+!v~aZ0|;R8g88e$pL9N3l5BM6 zki4XFL6!r*@Ep6(of9QZJ`Y>%$d-1 zuT!lz_aO^b1s89~`@MAD>4&dhP67HwcAhB(zC(Kf_|G33BY&XC4?a^j8%!z(VqVza zo{r8`L0k@au$K6YHX*F zz^~e~ZX2+0+Wk?CuPy}|aqx?DP{4y3`E^vraFot38&m(N(R?(qKL&xs0+(YG_!Np| z$A*(Z9B}QX#A(^nNv|C!%d>SD2 zm)9#g4S)|q+ep3GV}tS_%4ahyyVD#>+!3&Xsff9kbEeQs(r&Su@|xD-BS)xIP44VI zt_b<6wx@vww83eSL$4V}yteNg3)Lxie4{GGY){zUaZC*Z`Cz9Odu(7P!+2|f-Ll!zoz5JX*60g+pVTF-s%tB%cvAMHcO4rU9LiBI zDM-2;f4Tj!yrYB%BAU(2kI7PGF^2<8n2KBV`+i&0d(P{b=d*}M6a^xam7*8N?qrl@ z^j5KLZCL1AAiS7;D-MKeI$TkYS@DG_f1IPvS)H@;$C-oTbUCd@@JQ!T=1k&s3)AD2 z{VD(IwFQsP$%z!7184|=-_d?W0EKtj(0~26UOZs#&wi`?w(1FLk~z7A+BY+9=DwNU zNpRj8*%gAIq$XlM2uH)h*tT1@z0Y=BT$5jsUvX{>s@&v~#(FmkH;+f-9x1zK8iJ^j z1&1H8Kz-0>ObEmjL};zHEPFGMO=U#d|FJw$ANyoa51Ac~W#jncp zGW`?-5}$dgoAiSeATUrP=n*qh_)hrFjg5R<#U~Pak9)azx*AqsioiwJkL}+56To>@la7?D_dgNQxkSrAGWj{0PeC!N zT^c*-A5kztoX*cb;00hFv^;P~->n2~_gC;`c!`SCSsUE>*<<@Eq_IE!0}TbnXJya^ zUSoL}N+sIZJQyQn|4XVFoPaizO4+p%rJ6P4zj0c?@^TQHCR0G)nb167m%kh1I8g_A zPz^{<@xCf`eNYu(n~CISDR;-ekXs$Z1_ZgR<=KE;5c3aYbxi}7YN#>>9gQv&c=!L0 zz{xz5QWRLUv94>#&h_8O#;gOuh&)B36Orxzft(<=R(JgomE@Z5W;Lv)u}LPSOj8Vz z7t-S_7Shx2OWE|^xMxTn-Kd8P^NE#fhu91sXu!Zh(R_6N+Qz|>xHf(CEN73i5li`y zf968L4k81zQu~fVh}>3nNX;!Ohz*|wNX{=Dhkxh}5M-$U&11CnDA=z( zH#4D~1$>TZmlMz@C)PN&6cM-0eMV64790yV1u%d&I|$_u0VY`rK=YZ5@f0l9w$(Y{ zgQzT#H$io*$!R$zLv0|abp;o~^<-SP6V!nK(=0il*YDFt)cxA?G826$a7{aNcdil- z7Cq>GylE~Mm}}1K+iYkgmQ&-{Y6DQe$!|st#ez{Ych1tOLAB_uOo>qCBl*__FT&Ba zKBh-jS>Uo-kd*Cm#{wYtcKyaITxmu>32LMuUJ+CDi3I`ltO=j= zfd2aHaL9W(Xk-E$yXFA%S;+v6q;p8+t}PepH~5)-!d-Wkp-x(qD&$_TU*CoMN5G<4 zlRoK!Yv`HlO`#lUObyw(w95uWZ7V{H+Ie6pHo*W|;2jF`AUVV4DnuB`aJsAfa}agz_wTYkL~ zlC2KD!wNU{7u^By`{t7-l6&4ZCfYDGg@XFkUDI(o8%wM#K8*v~<<;;65Ic^IUKtvL zgDZKc_r|KYK))_C6kd@iCeyt;srsuNxGpik2qyr1@GyW=#us~h%^>Nf0j}C=I{=2y z)ZE7u51@R~mLDpg;uy2c<;-M28T0`?mbOX8L7-VHj>zBmiu+XfgX0;v0r?Ii(w-5z z7Q@|x!@Ug~2J>PH1xQj9dvFQRZ*x3))$V<0ef2b6`XyWX#bcZtbM0gL64&^vQn;GA zi-IOKibFw613w3TGp9s@T;C^s?6(e-C!`jg9>u~qU)#6a9H75Gz;wQQ^DsMO_@^(w z_QVW4c$sIc3=isca^S#>5yS!Zo#K7+aUgI=F(!ds^qM=LF+|OsdA%+!1OtP%REAsl zv{K)g2c>@+PJ{!~Dc6A#4HjhV5=~l3W=xTF->SB_3|Fpb&e7-958G{7xl2n-{rg$yaL;jyu=6Aw0R9ZHgxU6GH*M3U~+k5^zS z)UNQM^3ec0)Pi`59H1CUb^?q`Lp9r~*T>D<19VQs^8vd~|0_-tiK%<1Q?)&@<5*Cq z6C*GkjZ%4_U2rb!IDl$tLc??8j%7SpAY*l*B61dCWoJ4Xc2DJCYI(kg8#05iy0d+U z!c-pJtLFL*a(k=1&1_vP*SleSEMShC1u9=ws+| z6lxNMw3J@DHp#RkeGh6hdzZe&u-d}RHed4BY1`4jHq$g9arWd4mH!V`eW9Ic$$$)N z>+>1IYO6C|cF3?$%(SUSBUly$>&@)zoUt0{Kbq5d&^JZn=69wg>zrAb2@mZ21Eow* z`irl$ae0!8;e-&PYmtbfh2aPA}yuH9SKEMW;NBZkS}V=Ou<8RrCXX6w?3H}P54 zqfjeHZgUtp<&2ndl)xRO8jlBvO3|PXw_SR|Ht^zJfGA9SQS*zmSiBXI^*dkw>Zv#p zruyQ{QfKp^IBo-OhI>^oT%gvS1oyx0Q25Z3N!1Rm46s8%Ec51Dt762#4Qm=*`rD3KAUvoYy1hF)o;{U zIHesoDMp2b;q07X)BG(d7_EBM(A$MWpC21b#yX+Mp`n51!)h5Tk8BRsWfc631EobJ zxZNmYP|QD+FL!w^ilmFKKt#d~yOAEDP~X)T9IW70aA;s6u}HWsYrqsWyDw(xI@Y66 z$a>jL?f?j!|4e)k&&Qb?;#Q-hgc>th0K3ViJ4+L_i9zJD&CYDCql~RC7b8hPH6~Xo zCYd%weRb&|-nScL?G%2wXsi=3Nn8{P*NzIt-P$3Gv8_^b{ZsAsBtdzVIZMF^spIb7 z?+A4CJoyA!Qj%M&j=9RPkC|nnwCs{Do6iCsm^5fE65#HOikOLp4wx$%jHkZd=~<50 z$Oo5S`_5p`A&=ggzP~W6A89Po{R;!PP_jQ@prIfw&GO`6Jm|_{u=2wh3U|-%t+{9| zRXa4GN~oi={0BDL$Q^U6%d_#|Zg%5qc430~uzp&o^o)(X`M8ysTQR$;nFZ=H%B}^5 zWQJvXoHQHmj4gZodId+>fQbT~pnV|3&Km`I|hCQMTxcF6RM1U$%BLqLraFypKyl72n@oF_dl@l<;cR8 zJ6mvfq@8o1cC>)Z*F8ouM_OZ;!(H)VJdzWDVB-t3*KB}3c@_xt1EmIH-jIXTLKv{U-o{VqH-i&b| z{C*ftuS4tavw-8oyREi?(%3(BCovk%ln9N8ONK5}m8lO35XJ2t=Gz>oa_iQ4@gfi< zhm>>{t!6+Zr@fQM$V_NH@9y~SEBcz!hTJm8WQy5Px*92^_4MmQV<{0KJ+WLB9ZA5U zm&F1I9;yYlN_Ag_&tHoN4IZAG!oR3#Z(|IdDOA0J=AXomFq(Xi`l;-5c#6l6R4;ON zah%p~yzOWaKo;G2Q%atJqJAccG#UO{>sHl1FBDWX`{!Cqgj}^&?=~8{}GQD zaBvpTw{a+YN;Fq6^A4F*;)+h4yNj!z#?+>=F9{Xtnio?L7$3|f7q^7;qWHddHJIiy zoXymR@#`Wnp1$A~^h)brHqQ6ENsO!5uw{H?$CCYa+wMu5zwZs5eFis-1U5X=9(W|Z zd1_~OMBBmQquk`jC^YnKQlua1yn285eBO<4-!My$95rN?^ZwmMn6*mVp;Q68B&zg=U zpFO_V4rz-O0t*)&IeJyfr~%7xy8218VB@w4014d=jRSVm6bx2ad`RNMD0z6G=X;N& zkCH`ZTUlsGfcSJ4V}p~Q=rd%ee(IBQ>2y3ZP)tvZ@13VH!bPP#$>^0(d%roW3AG4d zBmgEh;!BMMp5!*@vL$0zqT&IPwS!+aV~sIkJYdM#f>wp9N)5Pl;k1<%Mer1OAf%gz z3-A;(8v26|rXbk@PFd#-h6J?&ay`}(~xM+dq)EJT^q5k?icCRRP&4m9Bo=Ptjw z9M>y#jWE!b`WUxL?^gBqOT%8-?{F-RC||Cg+qCld(q&3q*)cnn!6Hv@e>MqCj_oRD zDd~JlHV1Qi!nnTmon25vqKEX8juJD;nWAm|Bf}8UBA^3xve;T4%rRBp*7D8{QV&gr zkrh|Wf_5qO*c75!d2;kUsDM{*|VZg)XP+;MO^Aq|z#Kc~3(N&JN_=7} zkt54O4mLk~^UeiTdc}Q?RE^V$f_Nc2G4EvZy*YT=WI?5Pzz)Qb7z1#btF%h#Rk*^H z#{%xWIHmILqC4maKcRSQ4(?jo90rVvE}Myz`4j;lt5WPzA$?rNh1ia0Ug~8W{(~Y8 z4Sx=hf<@2G2I5NEULZhoXm}50+oI6!*79PEC5(*3h^|?XTQy)8r72xjH5hX^M42I^ z6e;F8!mOIq4UFlAs9pcDwBq#P8a*`JIbF7J+8vp@gj%R#6aon8?$7>_qkqFo@h>m> zQ5A;d!TSDS3?Ad6xsZH)L*92t$##~oRa&IAJKhTCe8~{`JQ>9hpY`5^mKDt#AuFr? zRJ0Dogj76#p@haD;x1RfbQhfm11^Zh<3}t$V}dZL{k&DvE14Y;$V45EFP)S}2n+Hb zzTP(b*6?lt%rX_APbCK%u^LOlKp533eeym#@GG|zm=DLL4V|nMEcDQibEKhxF%f+p zZbvp3p}0p$TD{0q`gzm9o-<6}%?4+ITozr*}we6nNrelIwO9+#hI zcdPU3xZ*LFb8yp1Qv%B$KBo+QGW&HH;s~;4UQf(+(?M>?0`#_4DLlm$;ClMbyoRCO z*EYj1K10uEvY7dwUxyyFD>P?Zl^$?$j@Nn(=n1pFUXE&Ca_?5{#ep@1(vA0N-`ji| zP|8q*i$TNsYtVGdP|FETeV^X!H!GI5+}k(>z-1cnZ}q(Y>SLV}V&E(Xbr@`d5+{Se z{-NE9yePeotcX>bA=DT2JFz)BQk{;pZg^dLomsj$z~P`xECx@9mA0J`IZCe&vAjKp z^hL_J3cmW;9DQus`F-%avRD#10)Y3duV$eAX4S3|IkNnHhqC856;jE(+L!LV6ukxy zJKXf+68Sq2ULFs1p}&Xi-{E!S_9`-y&7bcrGOY{z(H!%G8@J_=A#-1AtEiQtzrj-q zP>NQlqz;{w>zl5f2$Z{a22q$kmzXQJdX0ON#^QCu@v9AZNYJmh`H~d2fLUF0;5mpD zE2PvL)JYWHiuCPbG3(X#d_w`-d@;q$%PTy%r28Wk@zuwPEUC74uLmkQ;xz7^GWIz# zLlrW^r@JP?nt6)?7v4mMUDL0q!n4SkSr$}&E7hAy(QMWj=-a&T7+80Ui-!wjLhZ2C z{E`kPeS%0$_H&P0tkg-zrCeXk3<_`OvFZbRjw>*wYHb(O$?j?Lr^oVS1^itSvAtmo zu4f3w$kb7W+XB%a+5;HH#4{urVhR(b4u-6;T|vsk`|-i;q4?paY*SWu`qhU}Hqi5- zdLg3G?l|cR$;d)TDE|dd)d2KLMM4Z84!l~Q*KqbMlr$7!oOI|J54GPL{51qY7(0Kr zAsG1Jx++K6HPhbzRfWYbO<|vhA1;Kgp<~Aj-Rw5pEaD0Nf`w(cjj_#lmauQK|Kde4 zOUNJ#fMoj`Xm;_)%zWpORSV)(oaqGA1drU}b-L`4$j{)U^KN`?XM44qtE`lv3lw9O ziBR8m_v;I{Vw(G(Ah^|htEx=g+3Hm!eBgsIV(v>e1Jeii0`ldNh4)_|qiYF>Pz{&d z1@tBX4$2gruW7~|A<5wIxA&!Gzc~AK@A-S$G(w$;I4hH&1rthsrq_R2fpf_r6&X*j zA^mEjm#BCF!v7^AgD*nmiJv0^a4y0Uv5$)`1Fnn=`)8B6%c#h z#lT-#J^eq%2EkOHJI|I7fbxw)`pjmm592#NxRaFVY+O`PX-)HTX43%Oj)m;SyzRB- zq|}6z@!#X{l`{D^qWt1%7<17mxNCLc{OM_@A1?kC%^|vq#U0H0^cg3#1qU^GOg;FM z=6^La0X@qNof8RWIO1jRBr)0Lo7w^ju|kLhWvtBAooq0Z)wB^Hhee5duDAbJA)^U* zJ>;&weqCH#QpLx}?PFkK&-H0K;N6k8^mLlVy1iuW2>pg}?F6P$u+PWO;nrRdeRk-W zzbCfgOt(C!7+PR=D6Hbxp(H1VUHC!SfzTB0 zd;FVN@PCY3kYYD_`@@ABS(0ZCEf^S~{B5tZ+|aAzUp-TmFT8Q@nWY6nw}~@rznl-f z8`(PzXUE+5Dy%regyv*U?TIyd`>b3ZR+DpE*j_5s@B=;w8sK`tz+l!W|l`jTk`(k zi$jPkaL~-3x-*4)JZk9I;&c@|wfs=p(#*cZ(}t)HRb{fQn0-r$|l`Z86rK;$nehXi)k%ubZ9I*o3)_Ih^Vc z=gt?OZyp{Rw%c}$W-EgEj1x+oO6((>-S2D1AhiU2&hho~!fVy{`s9G!-@wopQMU3QS|eA!4Jrb-jZ zTf*zh?U=X8X{`=(L5Rfj*OSdBqAUJ43U}{4w7p>z9JxJk?JZZf@I*c!ksTZ8sqdq9 zjt1A*y6p{ogwVYHR^CgUATwwaJit;3T)}Pt^VHMnQy`8f!C0`b#`Y%eMK~`U z9b+Re$)Lm+HT}bW#y|0qg%W1P)?Iz?Ba1hz*ET7vy(!(Mz6R@0^fuW}5T+@OFSV^q zN*T%|2n+{{%#77jfKPa!!{fQS0oMQ4GpdyMd;t+!JRr-gMe2ct6x^IKhI;pRxcYIE zqIf$6fj4BQh|~k-9C-zZ<`E;beaJnE6HU?z3$q1rW?%zE%51}+kCl8M2m*^hsizpo z2?;~5YE5MLXrQeo8sKT+`ykOwZ2G_geTI58!sFAS1(+$f}efyzG?{Q4b=o`Ji^6poJhSPE(r88%qnL+Z6gY>4Gq3O^9ZnPQF( zh<=d&s%xGGCA#A%)Gy**a%UW#8U?+E`Or_C9NY$BgWI zb(y<}SYBV`n=j+?jQnKb6s2S9@^r(8Aj6EFeMyJ6xli3cZunDnnN-W=8=$q&X;cQ= zKlFQy{!KsQ{S%M5`N(Y3+qX01dF{sn`#0!?d$+%v4Yg@kr5Rl&F-HS-zA9>9r}k`g z7|T+G+5m@b=f6B2wX?gZ!K0~_l@S2Kc`SwWtMNAr`+DuH=gFtf;iSLV&2(4ZlD>~w z$0_~Ndev?{$5Ohd!*<=?qMz53x$(iATD)%Ssqu0_mK6M<^P>9tRcWN^cf^#}$te+? zODFs-`pC<7c0ABbIHc={cT?(c_1F&2wu$R{Q#LptC|MpI^Jm0cbpyS)dHB>FM2j|v z#*-#)gCYZk@!G-OFPts2A~ZAesbY*bM6t4~^-V@W;C4p?GD2yzvg7vJAK4J4pjo>T z*Mb3Pv`#a@>l;3}CX^?y*`o}iJxUa97O0fi+U&pq*L4H%k&w!r3@Qc^g_hr#;Yq7UIUnNg85`jyR9 z1EqBqGS;NNhqbJ4PdY7TahO);a?vrTJO){pv(XilQCikv+da_ta?2!?kd)ViC;7B5 z9ygStdq@(XOTz z6+0-$IzS}KD{kY{*5Dd%IHTTgU?#z}I&61kABc*mbTgi;+)ksUM2qy;Q8eC&f58xY zIO=DXxeB-*Jv9Su;%h&uG6QdKW`d~AiSWU1>9GrtW&LNw6xq5d03#DYQ&P&B+pU{0n^Wzlo&XVOW@ z=y=K)SZ0mL9c?^){OLrN-L5Z~hu@qPf)%2_n-;`dMj^24K|>H%u#GU0 zgL(ucJn8zvpAc z0T*)p%kFU=hsqtUs8RRND)PZ z;v}Sq7<39T`&_RwV)iL%i3lHwu>jA|z+`ceDjpyX8QL<<_$~(`cT@+>g1G}oBGP~Y zy>NW7t^0AQX)Jdi9wp4OPF4$9yK)f4mBl>O>NMhxQa$QOy zl+atDvSHyg$t=8n|r1~LX{Qf zQJJfsW8WBFKyWCgLZ8nP;4KTA$EF{u2{<$eFsO3yJ9(pVg391x$KV^o$0ieU%QbQ< zjo&T5V$h%%09q4#Kcl;_Fw!#S35Rx>}1+r#qhr!M2YJ_YuSQRcBPN~M(LXKarkQ_Ea? zxVq}A+zZf-rfv60t0_z-Rch4V9XUJ* zSTIZQ&yJjgfO%cEz-T+Gv^Aqv6ds2+MFDpAXp@c{L1r=*>vPNMJ-h741>`K<8uatA zD-TAc9^Vy>Ny!M^)STVRICx*)3oq>8ol@iNt%_SgSEQ`+ZorP)>O}0o|=~+mZBDSxQNO z=7&36*iTxrlI%!J7N^-6ySbDwqf2=rLmibF-!4PlMNnPJ+g?0I)Zwa?rz2){Lw*GN zLNMtCL&o6*n-0*HwTf8|lU6Z)cyGQZIyV`{?UB=L888+DAIg=1v0uVHh>L(E1h{B1 zWxze0tPlhi;Lb_`S>L3qhpg~`Z97PeKnQ%ub_R@=^-7LLE1slRnKbU?f=M~j_0qZ{jn^;61nbb6=Vjtsz zXIC+O`-T@Tv407?iRVUmD!bLF|-pIE%G7-Q-;>9WtLNmOj? za%{E4T9^5JPn4>A&tH+2jHzpmX6a!$7DkWxgyk5uf1nA-IOIqY`9VjqKxpn6`yMqh z{$EnfyWYOzuQhz&vk@KOEw72f~2wO(QIJiCmP8 z-X_oDwRz!Ph$_l8^z>|ZFaLaLUe8n(dgXGb2XXg%_kZ-YZ5hO4D-*YLdV7)F+nOh3 z7E0%Wf)yZPRjr?MttBP?Iosb9-Q&TJ;rB1(oSW?bN2n?awoq5m+8_M6{&%#|stil@ zcINij%Nx%N*Mo)ib&e<~bPR}VqGGV?6qWyl~C?q+LQ&po0=?KNkteer$fIveg#Dzh|K<~!0y~B8x=!8jYDEARL(DG(WCri{b5G@&kD|B6A?%|Aq)Gie%0k!e-KgY$Tf0oVU=1U{_^OM^ zR+3$+r(KW&Q^TPSn4VMlPk;La<-JE|#$Mic+1mw1hj1W#Ep1XxI@_w=V>`dUqT<56 z6O_ezZ!)N~_hU>;q*ucNtyIg*`4HRZ(Kj4*yZG+vL^Sp3^uDi z;8>gsuF~_a(dMf5jsuZVuC)=x?6wPf+>FpaZ7^Z&v3#pt5dXN~cS;V#A8IG&y4R%J zRb_uvc7B1$f`5K+5DTeGYO^q6P6|NyS#QT#BxqgQC4(1CDs(T%inA%#U3(Sz2_w=+ zH@iam!m5*(6-@y2c-!K1zlG2Qn@dY&@WM$|C&2t*`og!PT>+-5g|Wsf0(WZFsqG5R zZQ8VORc%-YOVajyGIRFRHz|;wd!5JcvM!dNo;I)^5QCMS8qcCBz^gtDU}`6IoZtiv z+*!9a3~o{|buQofM@mww*1g%Im&cqxxsZ`Kebg=s*eK;9uCD6tQmpjJLH|x>%a9y| zzY$Bs@~DjN&a8HI$osrnp0|5J179@&|91(dqer<5PVkMHGQ0k8L_+N&4Y8Yk3gAPs zRa`{mCw|3;R1h%}H+#*ZQ!^pM{-6$kpd5b?MDqL(hD)@|I2cu^AhOQK;u4hJkcC7U z9h@LOs6Tv=Gww0vr7e7no0KTlI&zF%S4hTO9@4c zB+53V?EGHS`}6((Up;#0alP)n=RD7P&$+K2SeO~mQgKlM06>c}ykrFcWZ*x^015>7 zBbHb49soe%eD(A!PUD=-xUe#1daQHY;i_i^MbOoF(6kO@U#Ziod?t z*z%YSC<0Es2}Wy&YtpWpk9NK6lKCKuHwoWfRu4wvm+548%8e7g8^+}6R*`iUO{lP9 zN*rBX-*415r+*|DFmRGy0LT;ZmvWn?HRpNPH#Qa&o}9)2W~aAu9)<|1fnq_p8yj2# z&PacXyDA@nBa~=EhhP9WPayq;(9=yXf`jBCC{um%6&h9;mGBfjsuUce4$-#{(F?qJ z(=#9hxM-z^OQP-v0097X>7sS`m-VkG}XceTGXH^E9bi-^{otTb4cO zdXx1`{4G)>uPD!bGCUB+eZ_RW^lqMy`vc2HZY4oM!4GZ?7zzmr8ri;)+y#FBbU~}9 z1xNB3YRG@UVL4%Ckt@GZ0gXCUpQR(6>*c#U_H#A1a(Oy5RtANW*O1LXqH;fxtCG)18ST8%?`b`bX>P&& znG~r*`UUiVYPXdm^o7Pm)9(ur>)LQg6b>mqO1HF>8(QD$LW?h%zl=kA+CDh<5GlTt zz>qax9c_dyNw|nZQUf?-|H)Uik+2%MOynRGgG9x@|GYMWW{pRp*Z?FdsYRX|;FMEL zsz9Qe00ESh)SsmDp(cS#VkjIOK;gcP{Oe;f1*0nK&* zQB3E56mcu*#P&T5f??|ZKLq+2ihE_RU%Svy>-O+J6oMA5{;Z?@{||-KOgN^74M{}@?*A_`nD`u|ZvR*sr^7wNP8NA-0Go+O-qBDie>xksZnb(6XO z>i_l*eBdkE_b~KH!?@sosP4S0_}O7eMI%S^?~U>_E$UaWd~PZS;C?8?HOI|DeHTy; zo|8mrQ3$iPQMrl|vhk95+V%na4PztC!t+NO0hSwBBHkrzD`lak;1U z5PC=`sK|&ZV8tWI`lj)D=afzU`gIqXyv{0GD}0BJUdUNF)&?Jpzn~LXvv*Wwoe#tDObTlv-4Gyk_q;0o;6v>2Uw=I2Mpy-4j=UMnjsAPgP zZf8Q(V2O}0*s$-{8)pf1Y6OP9=cet??(OB;&DJTR8{3{JFXC5u$1{#@z==S~JG<0W zEnyVSy@X{|&u4y5-lFLBbq|U0F$RC3y?IlSBWx|E2nhCxG*~flPG|6nC}(p?VgerR%!xV~gdh1zKf#dy4mVeZ1_E}# zy+(6TGp+J78UOB`v4$6ghd2ZxL-@lI45Yi$MS<^YNDOt?35z%+Mn@xU$ppp^Ofw&n zg{KrFQ6DZ_14Xd6Olhu3j<^1tYiQ$tR9e1NFS2y!Rb8KZ!ClSLa`k{cA6_&)8nE~| z0D`yMC_z9I&VB2tjDR+D@HEKU&2qs)lz|C)fb0{ zK+K?pLVKwvYPVP>w(1r9rf`QC1 z3ZLe~77!xL>CyQcKXqd=VeO^L_t7jlgW)lCkK?@jC7fN1R>K+?a}WjmUDVO(hPd*( zrpJ+x1(;VxfkQs6Q!oY_Q=`9Tp#c$CXs$|(;AX2m#gD`-^qJ~NqZ!8sbV1A{%HQ;; z5X;1T%_6?_+-_UxaSN_=|MLX;GW$`UM)dS-gP0BAAy&Ywnuk%r8e^p!IzTUMg#Na` z-j3v&V{vbq1PT%rRQjKi?U$j#=j*j|rC66Emv2x7|1o850QN7);v*e#NMZ2{zsQf{ z#*ww--Y9m6`cWhM<68tvW@4wy60zWqdozq^hFzHc`HTV0>Xx4y54v?0V`+s`?R11s z{|k*n@#43R#Xcd>AGw&7lL%P4jiiVZMl@;l)C@+Al|<`y* zvv=nA8d3MVe{R?lBOvt=J+Z&`@msL`f3JVGh84g}Dpa%GTfM4&{F%wA8K-vb`Qx1a zK9qJd_5Af^d<)BHMr`hRvXK-joKu$#D0&eahzrD7etY4&4Sm7=X8HJnhsVQ58p_jp zY;#mEXKwQ}d^w6LvlEiN5V1AGas`JBHH4!Xh^p~-HgC1owPDW9Yr(6S-PV%#?r79~ z7SV+J%NDjyOcipBK@;`20zj^9C1JP8H~T+l|8=I%%V8<+)_JlQcB4+MxTwwZbrtmV zf$`bwE2@o)gyxA?*KkPRdqxxr(<)3azo_ThTEJojIaRm9t{S6HqzAMiZ zz7VPIG0j9!!2|22LMR-?lan6P8GqkzMF(p=aURSz9Pv$Oe+tvS{_$tdzdJ!2J|C$j zDLUC{YX5lZ{j3SD{F^m|2m9nCSWfT2e=ga9VhD58S?Lk>HBl78a@UIRYc=<0^ph@T zm@_PmT%v0k)c3-RQ=4&RBXh$A`ToM__BQ8lHjpb_MIK?M$y(gPvn4aG3fZCvjk~E( zVU$F;BP^6;0T|P{r)v3?stxX$(n;M?hnNmz+tR)#+5g`vhH(;wtoe!GgA$<5|l63(9yS zXm-wkBj;Zq!=aVkE3V#pjQQJmnmz$A-?5&l*&i^VQe{@9QqLJU32qv^*4d)yyBo=} zwKc(r|D2}nv1ECTQH=B|F^_THW|nqQ}VXi8seM(de(=NHrJ{z9=d+`DS7? z?rp5{M9MUWYk>zq!v5P1()Mi0E4X(8!v+E`^76l=b1isHmB3Qu*r-HjcS_3QS!;jz$TqyScw+@88u#*rEGHTdJ?fX{J~->X zmRc?QZD?Mbl&rgJ+=it!$KV6Ec@CpQ6qO$vr)51&9qKZ}pFvJ&^>0WE761Yy2nAc2 z#$ai$?qRm}M@Ajxe_H+cPDEmkQ$>4VJnmxd8z|R!w}(-##u5Rhal%;B1i`5XtLa!x zTK&Uzq~*xawgRUw8Ph)fauaJ3)SuCIM)@47u&Cysx$faS zIow1d#4KRejA|cW;e^y9fLOAZ+)4J;eV<}*QJh9enXo-rB3F{Vu>ov@A4p9obK2_s z(86>gP071N4xI%YnbR`34OM$O6%PZ%?o2UwsjXoTbfjge!#$o7FV5`R?YzE8f!q%ACfwtF(|?tcNZTtldLklKYqb0766&O(rLH7y=|rMb z+wNDi3wo%mI;kPT>(%OliosxvaS*|@w_~*#(-HT3!W(K_s{L_w??xFNZ1ndLbL7ue z-oPE1K~?~#)ubtVj!RZ@{s%yQY0$XQAGQ06DQk_M98v#xmp+B*M1HQQ##9uQYKhx5 zv!=;`n7FK6AC-EPer*ZX0kcaDT1n+^Uq-WybXC0H!XOlZWNZTRT9 zCo0C=m0WkiFVb~IY_UFtDcW1;acZv)tYlT0Gn_VuP1t&?#)d^K>l5@bUK+ohCd}+6 z-(X-(@zDDF98{o6U(@XY;XK_cQw9w`Z2{diyJD1qL*_bt%I09!^;m;qm)%&&-_AC4 znGCiW)(ovoH`s-{P2)a6w;)$a-SO86kDpnL>$v@8Gt?g|tlvK|P6?Vg5kqOU3rF`t z@I7VNx^IDU#CWlvh7osd%x0=jI9;d3e)4k)A9>n0*vh}CAq%GuzaW7y5xh|!QIwv~ zEb=+cQup&fx;o<&L*7}c0t-oNuiDYNiTF$EWpJ3o3>f~3h%R?sp$ZWhS>0k2W)Y%% ze{eNx`zXfhoR6=Xy}4?rE0kzu%@fXRuiw;47jjNf;Oj!VvfK}Yu`l$r@g#GdvZ0#O zv7fKH?gOnOJ1<(OkSyN29;4)D8yo0q9rEXm=8=S!v?e@@$(Ev%;#ft3F3K>cG1cQ@ zF-tp5I}5j;$l%6=de@)@DI)krn~_~!!mS}4AUyi3?|2jUjNlENZnw{x@tbiKCr+jA zm@U4a9`7wL7N<2x5PI;`_;6QCYX-vs!d3^r+uxqI=~8le7zNBM%|F_d%VlI)R|CYD zJgG|f@vrWLr@!FoYf~>tf3rfF`az;B&c$k0kx8x99Dd5|Bm?k2EMkRrVFxH?Lo<1X zDTdD$l>b5Y<>4)Y7C}}oL+m|16|Yi8b}oO2!uT)@u0_7Cuj=tKnX)Id<*p8INeLm? z@*+WBcPsry?7}cs8(2Wk<)|)E&;rvOR49M?Z%E&p{uBcczPpjlkC5**r6<#h*^LxzL zBVk@vfQvT1Jd}SO_o8lt^2u{`&ZIYY^2bXeZznLNjWM>e@lenRu5ayqJ=brbu$Z#f zh8ZZki~kta=~OJ#ntB=uqY3_2gZL|OF!08R6pzWDQw*DgDX~1*6+rVW-fx_ecz`>4 zZP^>ElX)E0|H<77r^v*0ubV=HlNIhP%A-G%^$B8wcfw~RC}xNlz%ic^bU%FInM7SJ zis)6wjJcM`KA?k-!s;Fj1v-=cKS=U?#=ngGX7*ne z*z@;L{jRh`J~tbDU)=IZ^1-gww&lcGSK>M2^_3{q5`qxPp|=>(F8XxT(&)Q)8LGZ_ zgEzq463#4ocTP9ksZ1oiO!0~MX3)T{Z{I9dATlh5&b0yH{!fdpRxN^r#(P6ZZY;-EXA(dzv-wvqu|5c>3nVt5^SNah0^$eFW1ei!qKR)-=w8 zJ5YrMH#P99t~~Wlk}NlPDEn5QhCaMUs*6l|ZNX$X5GWkeVh>)h?_ad|YY)@VogGcf z0@L?w5yjwZ9%BDqbzZ_m^nn$n8YLi|3qfKl^bL>ebFcy50%^B$ry*} zkTw{~QNjz&xY^^%+YOns&LXYSN%YAF@K}Jmp_1YgR=-M-nDCstMhGSGB{c$g{cklr zm|K-wa|yUbeO_5uljQGzI=z!f&77cHdQ@n_}(x9f|5BM7WAm(Un*pMwf#azVTf`;ck^xkf-;D{TrGa#zRTGn@K_6a{rU*a-Ret z=--eAt(-eztgIIFW`Lx8)n~B*ZL}G28!b7}UfSKJstK z90>j2(1%O*r88i1hZhzArRvOxB5^6qeAx!XUH@JK@n6+n@AzKQ)m@`ENn zRQ)6W*Taxqvp;dXB-Hw+RCV>h>f~e$?S#4wiG!rtJ9rinXo)7|UjKpC@4!sNflO8D zIrna!;pA&384QPt1MvM|*(QDw9RJ!1dkK?)RnsJrbmZHv)Ms)I+5!q|E+!OCt(<2D zrkc{gN|3(MBuN5IW0t0!W}jD5_qG400_iIQ-S~|O{2PZ@ z6t2l*;}g(~RS8nUfQt`3gv6D3gRWZHHJBiZSHkNQ{K-a&&t9V~ZhZzlgbvfjPyG-F zu1?qCKjQoFkhrAg$x@aX`f#3hhG)u1P)Du339sB(?0Ai9E7Yc6)4VsyC?#5`<{o z!26+F8G~_`-{YEJLVIJH)G6P4PE}IPFso`sG@8I|xm!yuD5H4Wb1iIcyMoGp%!G&F z?J!DsQ{d9)$?4(aJXy9%45r|GxJkFSxJ*f%NvQ?2k3uc|BLjnaQkjke32Z2JTM2xuVI z(^H|;rWepW#LL`Ndd~kn+a2>sBK|yOtXcA|^*%dwCA@q3T>Ip1%V1)D1wJ=E`aO07 zJY92_ble~AdsHt>75SE|967j6-(@=P>>HsFboDzIxq0`H?1& zbmamXjt)Rp2rI&SEQTpR&rb|1V?2-iIy+Y;8x_e z^Vq$6;k?m#R+kfu+>1c|-0XjkT@x4Cys4_3&bAGN2a+OsG$2zCH5<6uY4zF`LyyS% zPSgj{q*}jcJhb#Qa~!`NdSiEGne^C5*>UASc;Y0nOHXNLc=y@eSZ~&CKB$OeMbrV( zrAVEAH>6u^*cQ)%%RMY}sf#zjPdIIkTBA7z_L;{Q$h*N3qmaHTVslk&u|UV3v-nsX z(h8}A#_0LfJQ?PxrBY=GFGNSgB@xaQ_o}3%kHx*u{vmd7CP_4KEs4i;&PXJku{Q!> z43P7O@*%ouM-+JO4E9Ap7n17U|1QXXk4QuAZd*YVAYxG`6h~dRlV0o9DG)CZswa%S zx!m$GP4#3m^zF1o{{Vl<_@G$_ zj1GW>d?+kHbp3VuuwOdMVmtmGRu8j>xvFs&nJSIfby%e$M`LZf$ld!t!;4)YKuO-2fu$~!iXF= zlQsA;r2Sz7R1Yj+MK8UDVQx}JzP97QrL0^lg2d2YgVLn@+}D8LFwK!YRN>?Fh3Gs0 zk6|3D+K{3kakqodlyL~Lj|cnZ(9m^AH#M5QGWCNxQ^)rw zgwMc2cgx@cTO4a%^1*()Yl~)@CYBn*jftkLmcnJ4uS28&k;OL!aG?LtEtml=*udt1)j$PS6cfmh zr|jQ1ggwC)F?fv)Q+;2_Ggsw9m-07)#2Clw4vapbCVKk=e5q6r<_7hR!|s7s%vm`% zxAwq>kmpPY;YP0?kbN)KO1wb`Exu^jKLkDIbV-hBRXJ&=UP`dpY2n#x3&V=UR>XC! zi!yn2RKkp-ArStpJ$}>GFMd0umSe3bnuU1&FWe_Xu;yh~0eWZZJj-a!*~3&em2dTu4@>*=``SmNcu)K%9lIW|{4PGcl-5@&Hxr9h(l6K# zysUb2?Q-w-gU9+rg+SWfb2o-VmFnQY^7ii|K4LUg+qd>^atn6dE4VUBn|GZ0`%GV; z?S&0I^}Y3AZ*T}J?<&)a+w;aQ>;L^7CTMc$E7QqUz3rNA6aAti2?G4u1AmClodYI5 z%45D~5+90UgLQ=usqwRTN0u0Ud3Y3}J%8Ni>6?FRl`y$-pk;}I4Gk1AKW-6pdcP01 zQ7SA}37)L)A)Yd}ewQd2jKlp@hM+KYbA*$t zs&GAGb9cd5xvCS+ATCc;MZZq1IO$%&Qzi)Js7U)iHpX2}WQzh7d2ZnOETl-dfPr{X_jG<4AA@(nP*X%_@r1R+)SPe< zGzp#>oC0$Ec{n$10)Lz*%C9Jb00C*D+P=w>1O1D<@rPq`Km`U5zA|XvOn0Caec7Z02HTHK>~!=tF64O z8NFuGg`88N!x#mue;Iov$d{E3EYX0{?V1_Is*!3dF`{>3=*e-8{8RD8wpplFFd7pJW3Qx6I@%s2rGe2E$NY(_ZUP_23{`dF5BTwNH zx!w11USIMrw2mg#Qa;K~ce|oP4fxsJji6dwRmm3iR2l6m6~uRcue5YkB61UsCX%f{ zr}J_O}HeKSPjVU;5>Q3B%Ymh`Zj_l-f=ybofl$vB|bOlEd|{u-LQ3gyvPr3F3wBoz#k zNJ+bv$!|=#fPoE+%W>3^CEiEtV z>%%=g-KOn_>!qhoSF#pVlw;=pUf)=#KN(9+O;uD>93LOYKewp{?7O2nUT04-)-y(2 zGaV$vHcJwfdb5VGY4z@MX)zS4e9shk*nk%?6>&nS^Zm<&pbsov#dTzxl^#z_uf#F) zz6I{l)FLtSU6CIvjM;~VhMqltUfR@z`}NE3@XwmTSfS?6i8Au9FGI_oK2139^m4o- z*!%hO=g*!!EAH$p*xA`JKklxnNx|WmjEs#@6;|a|;zq`O{+=5Pl^=aS{2bpYuc~_R zS65e8)zv)>UKzEvwZ$1#Xc>K(-aCr&7w4$i+WYh8 zPtCOs++#^QD?7UZ65WmNaQ>M6b0pfgzx8(>{Kz*c(t6@KoYffd$IrIj`Te*4WG6QP z)^vDW-LZLV8HEL6{bG)WItCq)_03xtEm+c)YYLGDe5Ca-2AG>*^|BUvYWB=$v^-Q4 zkqNjUZwRk?QdIO#;NFG({1C4dec15POug~Xlw)&0n`6Ugul$KxN0pbiH;kt1oJfRs zb{>}@waf;i>XH%Cc4|+&mWLioIku*dNDBFBH6OX9IUl{}^y7X0fPa10+fx1HXVujn zpPM{8PyWu%hgiAYp;x62Z=m&fev@)QvS!7*EYEANlu&bIgG!n~d|whYDk- z3j)HkiFg%CNw<7uT-$Ei>D-;TM@>=hL;lw@COb3bQjh<1-Hndrto7E}02*GkOb84yUTI#G&UBLHaExP0e>9pH zqIP0gf0u+)__jOS`D^cv4}MqG)-FG`b9NgoxIj|Fj^Gt8S#i!^rQ1Z>sEB+|cHJHf zHKk@|)V>ID!Zb(m)&17Mvd3`D-J~-+ipbt-8iP_LMzt@_7wvm(&1aJT^6LK9(RLB{ zB7tDE+V5E9o^O|CZO(j9k*bc-59hQAvp;GB)X}ZyW==`qw`< z=PLR#JrXg!)q-IOti~2GiI`0RtoUe z!&%ZxU&9tWPmd2qaupKUox>N)_+Wq89=a=K9kLQ-2u!{6K?7Ft9*~k}3jLsu6I1?5 z@l|$Djs;#-2=?KOS~AI%l$3TiX0uOEj(&e0i^+NtHlKU(9%7>2MLS}5^`ftDRr4Vm z+{e$)eGn%+Qlwp^vJmx1{K`|}dh?i-qvNppR_BrgL_9W+V)%_Dt^UP`LiFKhD?K+z zv3(|^*ZrQv$Q-1&2jy9VTi;CBLbSHg{?XqJV}1R2g`+R!SsO4~T3V7mefe_LYb59O z6?4u0Oz|t>Yqf1s6oyt_<=6#?_J2qre;7bKf?V2>E$WN>vaW#o#tY`7%~vu)ms4B` zcq|DYe&J)QM1yBP6+v$#<=mMAF8b8$$x!o{*6^DL%+lb312qUU_~vU8^i*@M1UXlK zuufE~;xjIQpywO8NY4AF?$zcHsC&i>-O=Kbk_wABgrqu>iX_q zzW~&ihNoiMFC`AUz_n6NFh^J}kWu~>Q=Ps$D^Kh?&Q6b-`{>jgK>u{b!Qp39jPO-s zz1Ii7R}?~jSrCQA6F({2|c^o z;QHFLE8fp#^X;mq5 z0zv+ePH?mkx@kMh`pt*9v>s-x0Vc8CV{D7-xR~p{K?QVZUO` z*kDN3MlZs7LP#$X3$CEt?G402hG-MZ1*3B75zdfJ&$CB`gmp;~tDQk*F*d-u=Eu!8 z^`Aey=KbuWKgR@DMgcsqbzeChtBk9#DC%}dI^qTJ&|(&n4s!%s1p1k~DnLDK4{}CG z>v%M6dT4rDVFB1XzU;^qm$WOmHJSghjVuj%8!o|HkCG7FVoF0qeFaU*FwYNkwyt{T zswfnJ7Q8lw9AqSz+vrdlFyuZDec|I5;5GY``L;+6m1>e~m4(|IBrA5HY{mIWNdxeZ zMHrusktDv;M#WcCf<;h<_ItA{8kcM*UtkGWU9#E`5xS>ntRBglq=e@o1VqpstM^3u$qVzY zS$gfrv~*F73z{k{Wp&1mcToH9k(rStxc0fB;ynf3)c+iT@kZy`V@MBlbYQa!hpXqb zr_?~q4c%Vn^v6bI9j)>yws1miMGL%Uw5SBfgTTl z_}?${BiQN=ID1Hn``SXxA!VGJ{!+`I{Z#{YWIQV=#@$VW74$02_o>hbG%!Bc_@F$_ z7qLlh2G8QAqXvRL!8oXSu15(A>u}jak9pfO)cpp+LIQi>fcP04liovkPgAJu#!iqT zgcpkj&_B#f`Fp$7w!yI9FY2wQ{e1Sspx}{bJ53%ZZ!!9JY zXF;}0Hy{Jh6=)Gm;)D#@|IV7=t3ofDt#P;QWlK%C^twa9pu z<&*f$1^K0d;0eAm8@l$4XpQl&a;4=O;q0nx;Zr0sz+(!1n#!7;Q|rQieuEfT ze5QIz0iLc5iigmKL&Wgtb7+`KSByiQ`k^E6kg6JJXnkD5Ks>_)V<4o7_L@XZf?Dw) z8Vq`ho_IL^F{$=EdC`}^ONa<4JXDZSA5h*_ImpI2k^%OQ&6>ZaWXmK`K^(!`SeX!i zOcAt4kjGq#8h}^v?8AvLjaWM?^7a(Yja12}ZN8igM;Ro&n zjcbeoRVR6v1!y)ynphT?VAz7UNuzkhlz4Do9`5(h&%L3o=j9&IJY@sQd(Q(e?zbYY znb|Xr&&pMlD;vVvn9>BCJi&uBOR^u~a<3)3?U?XQiES6e-0QQn$S0?IrN*$`ND9dZ(n-y0EU@TlFJiPEcOR-N*4us`m4q; zS-SQlxt6gEqrbZ6{%`VU`n5qBvQFUMmv8-6w-bD&Y2IUb;5ip>-@@O#|{=UH*( zkRK<_dbt=o+_0(jwbBf#t3E@dT*9n#mZl3`urSN1)&3ABb{^Dn&ZQ*9m!8)7j3)$5iv=coe>D!b1l<{Vd!w#rrZ!TlTnpISwdyI6E3+;U~H_*E&zTFx4`ba6}WAf0{B zy&v6a;zP0T$*3Ba1?NDR0#Rb9oHm z-b$brJNGPXFHvFkCE%mvbqEQXL~90_KK1s+7TB}Rm!@*Z_|a42TuYy7V5+sW>H)8} zStr{**Z601N25+9yf8ixd%2HM+f1_`>?s%!VvlzWA7p{yGR@s&!=WE{Y;5HpA};MY zdf##dVgQ__zSYLzsu=gR30%Lk_iw>96&zI`kBG?z8Q*Lv@By zbe$m$txE6T(>&2yOvI;CRKg97(nLVbohtkU`gV-kQw20HTCncRLngU2I3M)9$4KX3 z{LEKSg_|fIKK3RjuHyFS)WY00F5olTX|0UzDiXs8Qo6sj!MZ3S1QtL}w-@}#UGsJ{ zb9|heY!7IW?ktDe4nPl)dGS*TilBm7!uW=l=dg&@Lo4%+MU$J~4Jz{Ni^`5z7~W~& zYLCyad}92#(hltAHdWi(L85l?rj?v>OUwS4KtcxAsv9hjL!WXbT@Qlm$eWUziL5JS zWhU}ugKY%Xx089G9O$ecXUclNc}9(qfz>bi0pc!fmpbkbg06Xa{8DdByMBW1P*nuM zE1*z0voY{EIWyf7H3Z%Zz5V8yK_%_%O#{MM_*_n={}#*z<}42e_Dsk3cm>dtCMM_& z4Tf#f60F}&7XGX`L)`to6D#iDTBtTJaH;eYumCj^sCjow36mK;jID>IA3ZTX9|<5` zC>Li^*U;JpnbQ84*jpQMA}{yUUV{$x;ZDWO5l~|uVufFQ#$n-hsl3J>9>v`bH{?#c zE}CxCs)!av%enbBm5*GdDCpyD86dHDY@MAY@4f%-BSp2~3OA$p5*Nl8<7j&NXp9wz zFQeI)LvvaLsFu_DLkr>OUDvrE(F{Dja3r&wPz@-rA1oWEs~v1OEFkCrqtyG8ZmHmD zX*rHH!${Q*V42GP9ZNwQlt+^|c}@~r-Es48jK~=-lP7XIq$hBSm_ZKFCb#8atkTQF z^g!)$jvWCD4J8I!$Xvp3aQR;!kpllnDUTmcy1B`|NO9jGEAby`9HAHZi!1}0<*PP6 zfcGrY(fL6agQ#`fei_Y_1!opDPWq+dyXJNegF=3}D}H$`4Oj)V!;AmeKK&Q()iF!x z9V}+SRc2@%p>^;yz`1{r z(bvNnVg_g9OzQo$)Ftupvn^~ERTp(Ic~cZ*x+=#nFJldRiF z^&;xSfEUC7`jJ+D5w!E5s0?$mADmP_g(NXWw~lxo#e!Mx6Jw)X&8Y8`;1>b(srPp? z+AxnyPN|C|fusR%Y$Qf2L03P3j%fOJBr+~D9dCmE>oP=d2MHl`z-hn$0RaoCC6_Ph z2gso{h%5ma;^B3G7~dGo+ZD#cTCYe{TsT_mNQv(I?t)9Qr+UUK_v^v-?4|}|I7_;@ z?el)wc=Y zn1kb>^ec3gxmEMzexI5Q4LB*cpScVb)mEmdP;hcHROYC=Ptwjn zoci5p(Za+PF_njKfVKTHVH&SAu~l(**cj{G{v+3s^XM(}=3X}PrqLuj;qwE%+YV$Y zeGZnaPelk<34XsZ-=e3g!fhb2NJa7&9Ob$b6e-J7oRwCVo{CNHKF5lmX;2ENbLD-c z$v@pm#ZP18g-W3rhye0YxGiVex9cD5=4@f?z@GaOJ?p4uG;7$1(m}R0%N*h%FKZQ( z7d`(SHnez&WnN~;dpryuW$sS7pnc(C5g2SdVN~? zqw^Q)b~uNZVy2D^WB>@{rs{y|NV5T=uq!n2xXeW8QpfdmdXrOO)MqOYIBIj+FN?Pc z+U@REgYwc`OZmstXgEd-^j!RSSG|%PV;Ft#?-w#wpFaD1f7pCxrO`npaAaHgF(qev zrwgAQBxt(5CxT{?9kh5BPk+94O^Lul;MFVP@FxpcY;^!lzPzAHLfq{KF=GIjW*oK3 z{`Tvuj|q5-ksA0?&W`ccL{)YUHB_}@ophnkppg1F1$~&pqGF6~ zrf{?^H%C)rly3*}z~*QsIq3S|P!SALs!kNd*Rl@?pzoXqp;q^GCBDcWC98wHYBMPhWLf0 z#=bH+^@QkbWFRiXvKh0Sj1P9`&`^&bUrmSN!M;tnA*2PIK+luzH1*iUA2SU0!$tbQ zB+Re=G9e5fSh`@`VM`tLxG_+}9qfc9EhqcEc_vEXC<@+qSiZ_B6*CwtRIvOO#P7TOU5^#H?PM3wQZv)VVz>UBwZQC(V+bNZKq|O7y!?hA z;_dIArOOJgt3@;hCR!}qfYAe2A^h>x51@)Wd7DbW{@$vo%ET7fBj%p+`%1DORkFM`LH1AO=318+NzWQL#P&Y3`& zcg$zd16z;iV>tW5)cN*b=>shn;Y0=3U_DURh6cKRo4Ok4mDu_r_}q6*UY!^pgcuBQ z7zVxjZY4az(LEc4*9Q5by$mcUr#}Ldl`jkg=+?QGa|f|^9lfIlziVIQ&l^57J$)P= z0J|T{=z7@jH4Vbo|0BRJ`t-Jz?3~3rDCSm0!T5fCWr>Ak7ykW6y7JN?Lqpt)tRWoJ zQ@Ys=3xYVvY6ag6g9QkO9y#c0%!I3yoEKlBQmsRknZR#I3@X7_X}*TW;)S{WYK5>e zTnJDwt)cK3NPC)Ntz7EX$sdEs8-MTUo$J5v2q~YbIxoFkbx~b|qSH%pl1iEu^6H-` zTg$-)+7sINt0ioz8DHsny~S_?CudfR4fHyC zqsJq&|D__7@+u7%12KFpLn*J>^oyeQ7Wlccw7R zXAqm)pLzBfExg2DKW$iB1ifz3m^FIV~rSqfY`4Rq6qAG-+*PIZ)LK2i%)Cx52I^<{jTM|E1m9BdKV zo?rv-r2D|M$VR=^x$C*81_d$Ya~-z`;}7thB>cJGZH*?s-2v~|wH$Wu(~VDC_-KN` zR@Q4?h$N~xlBlYDYFdYUd^8V%1*K_F%Y%l}Z)k&}WWT-jJKD8yVqEPdz^?BR z1zxk$@{}PM_7#Upk&iCYkC}kCuaW&@ZHEDW1krS7MO{a9&DBzSTBlzlji?@uU(yNJ zWBTBmK*pF+Dk!na_=?i?!mq~SQo;KSnqp!Gmn_n#_{gwG3>5`iUPx6gneQO-9Q;0+ z?>WkHlg~#d9%}BvI2#=B(PX{L#jlxVL{##3F~zOQ|Qae|`|J*7Yk+4iboWCVWWdHA)AWccb~$ zsZ4g>d#dTT#&HU^$75jP-ROs?T;3t#(K}%FOgI!xBhd9L z_yQld`oTTC`$vn_4g9N=*HBE8H^W8vc;sEGyPU7<8{gkfEN2g%{pZgpC1UQS3jS7xE?lp_SEmC0F9sh1-xQzIChMlF zQAr))CW~T4vxAYtDnN#C^7i2!I6=@$=IEZKq4*MAce%4vuIwKKA$zd})3gzd*Lv#; z(fMgZ9tG#{W69l<&6Ymqy08FkdiysPr5Qvcpw50qJ+KwaM1a+mEPg2-B~_%J{3X-U zMYE+e`O^}WxSl{WkmAW)_h>Qouxb;b-&!;&N(gGeXvO11-?iQH`c-wba&z{AKMOA6 zI|nv1!dTQKnn9J>MH7A_HeD=q8-nK+k^d&;}R>2z8rS8k1bxj7PuVSSq6 zI}0lczUc!p)+kLBpF0_AvUNqc>~Cw7fuEo9(tYuoUBiCt^@n?2p;Oh8A|qi%ynD*= zngY|bRzGs}F!rrL)%7%H!`#N}$C<-mlepCP`c&Ow-fI=GNNCi44!^Sfm(Ss^l=nQ* zU`Gp%WM9WkzP~Gwy;P#P2M>R%C|^yt51l_h2gNXLIpOEuK6I$X?{Ri*nUuX#UO5wf zJQNHx{iLN$EdtC2EHP5~6rHmiAg&!;*fS_sieU4NlWZhP*g-yKXjzr&q38eO>Mg^f z+`|3gXJ#0>rCS80yBn338Yuw*K}u4Pk{U#DiZb%|^IJk2!+x-8U2dZc>mCEuMP|?5 z+a|bQdzuGpbzsW`L7q4dEwE_99qhYc?r$RZNCuq$?CHc^bvS9~#RY4+C=w@mxhAkE z(;Vpqdlh*0!iGOxMT3*V65!e_*Dink8QbalV*k-?zbG-i(F%w;KF^POC*S?<_bu!R zL4+2nUgSH!o)wUC<@6Ogm~Ga=@R?U#oG?*929L@}y{0~rk?0|Cq6rNK$NlKWcpIiR;C6<1;C%Xe&d#;EVOhdB%!j7rRskp}!x|T&{gs<*d3m#MG z$c&C53S#;T8@$Jsxj*k44-9*3rtJ|tJlgc`z)Zib-#barQEnaL2Y3jkLsjcaf^%x> z09^S_`oDaw?rs?yJEYO;0cmbffU`M*B!Le=V;S1ZW6u*nez8l@npHvYpdTl>F(+lbS_h7x9)}7Cz<$jEqUzjSRmZt4PCI^xCTz ztf7dTQK4~;&+B~?zP_B!iM&nYd2O()O;nS)v)cE*I>&_A=}H3L=Z9E3*YwYoTtk!K zH}^O>v|#x!94;5P+#8hpts?wAK+=A7Z-Z)vfyR#FIr*E93!28APh{`F3S07CzFN@C zbvT^Uw+(ztJiwQZFEs_Ek7^VCmt1b;<){J-mqZt z=fCIYA4OQn<7Xuv&74)Lx9_W`FRFrw@%t!Ho+S+&QJmtmp_;V% zvaLkGne~q~{DuJATmDt;Re{S4^d=e;2@dD>lO{xBF8^c@!$(yotrM3cAKH=4jd+by zxMvYYd!)7#*3Yzi%=Lk0&H2TL+fB0^1IshVUdm^ooD@g7v52#oghqJ@dbdisxA(%4 zM_O?E-)-^CbwejdABA&b$z~W?ty_+dNAl6WD!zJ0pUwWNek$1ya^11GT(C7al8yhC z5XA+{*kZ6t6U_@oUvx_jcoKM7G`ms6HbdZSima<$yle>mVdHAcyD#wY;Pk4BiD{QP z8+KJyk)>pro0gCfkyz>SQ?nniL5;!Kq|dSTm5ERM%N8kS80p?8h`)u6J#F9e2)iR% z#cjX(H)p3)Vx}|Fg#o?K+B({-4bWm1cw0qr-_ZMQVqYICJ(5IcY8bo*NIvPvKeT_n zi?&tR=PcR7#~n2-mO%2Hf=n)(q!_AJ-D#jy+f`Pdd>>l$#wDykRfOjOr|Ig^!I$|% z03tFME#*X)F7CH0-iv_vI|qOpWG_(}vgJf1+Na+RYRW%qt@=7_cr$H%QWjk$q05u| zTde#aZVUQGWd_4ZJj(Gix6oKE^LO-c=(amQNq7Nwt*9xWQg|Ap*)B_d@cB>V!JAu( z-H?=L;xUaPalWX`@*boP6XVa4?qcwXM*G_)QvT=lQTE6@^&EYVt6B*+^Pz|2`Yf}} ztJCC61KU#&5t*=7iRfd*awPkz7G{-SVd7IPI46 zr6Z0cU#@)QAMH{mrB?rS2*;jd2bRT0M`rr1AI3|T$~WL$|J%pMK2u#*zf1Zs=SsJ6 zGpuQbuQ=QiVshj@z(j9y90OwHn&_vel9bsB0BF5 zGulj88F4cD9x@qy7LED)K)5z-#+?#F|H&WXJ8%FeJY2X1p(v*B3wsJ4E~*y*d4!Fy6pNh6{` z@%?H&aM}^}ly3-ICOd>)>_EqSmTCVznXep|Z zwx3Biwo4nw>lc!oG}6X5FcM0QE>?TIP2Ub1dl|!!sf5F##(tH&Rb%_aeOXWm?=V&q z$r7#ae9~TA>`SQ;PVm~Iu{q!z>l*prY@Vm02s}QlQqofgV@?h_1ZBg{#%c=qRmc2M znc|)};=uSqXoo2qpI%s(EzD#OIEhd24HNK$sCJ6=bYHkrj&GSWLVH9NLC}V^)1w2Jn%59n6mo6i)GgXI_{t?ad*%tvsd50 zC_-(FPz-dEmB;W**7kIQjG#5@O1is^&XLu9e8sxI5R?_gkOUozcLa*h+huj^QoQC* z;1{931HFl&tayVsdI|QJOUiYU>!Bdb$$il4n3S7988^;O)g#^L7b%9 zK&2G;OO_(2gS7jd$>Z$N#W!|2AU$U*ph@S@otH0~i*i@~+~^a8WCjgJHBh~=Sng85 z+Np=1-<{2A)uzxVz)Beo2>X9JZiFeXRafO8nz#wWQDFuAlgk@&IdyEk05$d6T6|Yt z9Kx!A9M_v-jeasfml4tZhUHUjr>6rt@tUa1lS4dZlscY`pDM7bVBHEy+u?LGsAuR) zKe`yhi1z3WO^E>%wBPHvkB%go0?JHZwWHv?8AT3pz9zPANH4F=GFZV+v6zX0_eDwk z3RG%l9QX3n2FIA3R4$k4y|q4m8G9uo}kd+A?JQ$vwtA~<6_FrqEYD7K@w11#7*&b2%slR+|2Jp-5 z-)C>8Z_k79YO@87&2OMhU&wT7Wl5Dp1I79=D9$5_X*j8T@BP=aN+g=t!N(s{z9$0S z(aFH4<}-I0IueW|$(1B4TZe00^Fg9#qH_B6%KPF+6tw^fj#=5?{Nz1taP*o>JNSpf z5D*0O*NjKCoA~m_B#^$oG7a3U?4xj*`qOa>jL`mjI(%6AcqXXGQu=nkbD^CrnlAvb zFs850?KI^jK`EJ=LlaMpNMM0t(8$nNFF0T7&&%sU!sz zp+V?|40oAh1O5&8$DohA8!{{3iCq_0Am%Z5ax_MwH=}NU)hVB#u>EjE>;xX9v0dQW z@Kjdr^r+6jiwcxG0Z262gJvysam}<*n>cW4ic4jd_Mk?{F}H)IVk8Ewu?U@MIe!kMMeR(Y&~_1+Jkc0xf~XdfwP7;mMtnitVg+lFXvO zli&lnl?OdatHEj`NaSc^7t$zWqmgp^PY~R$mZz^8jc=ZwF5`~}v<^D3d^#3aF_acL zR&>cT-}D$ftWwMY=bIfn(Bjf|vJ6niT~9pD4UuR%tc3pyq3`q&pcQV-^J#i9CZ}$b zog0$NdTjQ>3$3ce3^g>#=NH$=NPDamb>;gtpH$tb*(osk1ve@C(6qlr12@h9KQ+9B z=R~6K2a`Z$sK&{2(8*+`9MF-Ic23P;cufe;PZYN;0FA($CLg3z={dV0w|@Tt@j*S= zAm&+Wlk)4-6BkN11fV#{3uU|>&7SjlKtf)rgPB3In3vr8LPS zVM7lsUo>BWv9TFyV*2jDuA`7_dy422!>i>zxf<8FCgO2s8hSqk;X#Uc!d61(H=*s% zKVbT)6KoTr+!k;Z$VABA;OHV~qAxzbZy8K=xlAPho1roL#sPl`Esim$k4G>8G}n&*Uy^`{MIms$17|9e8K$4Kf!5}c@~>-+__ zxcB%Fkz$qx_swg>C-dp8&oNT^iVu3Tp(eY6vVj+)BKk|=<4renxgU7xf!jW1It0?F z&)#p;3Z_PzJyYGsT1LHz8VxRdWd^cXktan2l{(U{Rr@<;XyR6SmSs^9`2te!cYve%IFvk8m)xqUD+U8o9#;3WBY0 zU$JZ03!L~UKI@M(oMo*+cUSPYf9bEM5){`{dCG{MgJ*Sm9!)*!mu!DWs))c_*(!JC zdk^=nDZPge5YJv6Wb~z~CT@YJczu)d?^TZnPMo{LsmpJ>M9BE%W2v`Jjd<&a6Pw#c z;m_2YiiB}Yk80s+up1;@3%6i>xr$5sMFhXk-Qn>H)K4~k36)ky?>X}Aa>k~;eszdF zCM>i4R?ux&E@QrkAl$$Ar{UF~s`mlozh7~C{2o~O64E)vEZb;-YaU6tE+;?wjx`U= zPhr2vO_=IqxaBZQyp|Z^v1#AkVK)Z--KnB|Z@g5w$_a0*SO36m7zv!avl1#9R}!-c zZXu{Ms<+GcPv#7LdooilhvzP-4BTh)K*D8+ zRv?vo^!m?ojrQyf(vwdYQP66CEj-1-zjv}vxQwy^|MEp~Ru9Se-2@k*-h1zV%;o%z zIHCx#Kz}dfbgLoYZ!)lRu0SK~Pw0!Og2^-VBvjWxBQrvvl-UaivEY-(0(dk`uST>u2Hv~TZfhL z;y->E$hWx>Pkr2bM#A#w;i!d()T`z-L5Iig0+q%$ajZBY2a8DYqn5sIp14X^q^*Gj z$sJ4d!t(vSkef+M3-%aC-aLw`q2k~*1s=RH5y{fF&JF6GZ`}g<34#A5B2E@Ki5S!q zF||;>)a(TCs*B5m<)MSNj9nurHZ`|vcAPeuYU^*t(?1kA6I?K^4LkPvwOfIwI|-LG zh!7V~gizAJN3eqM4Rj009J7-J;+-ak?6~)N+M>}5g;a08V9ac4{c;gJWuBM(j=S@O zm_#5qo-vYlnVaI~-(xQLV@<%R@u9iGxzo=cZWs}K=c&4U^AHdeXXhd=wX?j_p@|lb zx_#qX{fEy^UuMo<>P{R79FS2?S3*>ekC!$ArHJ*!&iMuHK1M@%Al$;HzvLa+Se5=* zom7>x8uurvP#jun%>eI(*q640Bd3q`1RTp$O4af(B(L^GnO?!?x|K-oGwHlWimfF)es~W{gjWU*?9LB-hxCj=$dNuqMhTJB<_lMm`a_($*258G*O!28+qsX)r{wxoiPOX#1L8qnb9Z~8_Y2BT-F~nx<%<6#!lDa~fEfbiL zDlTs2>1FC{fFqCE|^qyN;gPC7ShQ5Ze|c+Gii9Gkc&StWgpi)p1RS zEn5H1Njn3KLSQ|{30nV}AI61KOg0fr_wa1Kb?SnW_+elEH%@iX<5MTz9{mF7ANTnx zK#7MnNnx|*IlyhW@gxXtMH(kXb-*Kg<=FDTx_32tj!g|0h%Bvxqq}uI(^*AMW;XNSVKhE8KCt}9R}yZ+ zrfi|3=}GXu0^a)U7DxSf6cZ#>_B#1=9H+gtVPz+-`nn=22-f{%u2HW2hE*q{vA0f} z>-F-W2E50GpvofYnGLxBpX1L6O3f;JB-8UackhRE6GJlJBiE2`5nFIE5^vs#&jCcm zGzZ!ydl%kra1yTyBhZ)05H!#D1C^{x6?Ecp zsAQV@euLaiD($nd1LG}z-*bD+-}FX=nRwbfM=+bpjp}#rxwpVQ{kN}#&KJfRV-a01 zf;Wl$?*a>8IiNA}N%ZAo>>@)LluzNQWnYd7kaBFAKS2IcFt;OOR-@ ziP`#cB$}^xeyzxTaKM>@TaNgEkZ@pQ0me(YolAC&?$P9Z{vQdI=Asavs3ir|dngr< z`xD?5r!W9d0J4*KX2t+{!fGK9`aD~=pM{&C^gM5-7b}Q*pF7i+2|!I2!1-jM!Zv_C ze6xm3e1P`;`wYo+fR%*WjC?m;U_8e$h-i@V(Lj09Oep7u3I8H=;p$H>bip9Pm_rt9(GML@+W9)80cUsB1`A_l z-rf|2KuLHUXTKaH61@T}ljBDt3cZq0m@@Re+GwT&MEdzU8x&M>W8mnL5H#8_7W^~z5l0D2VPRq6+u0|v>RM+j1+fYt<|U`=lr&$*8x6R3^mpYs{v zBrKOpSWdhv8r((pCD1TLzn{BEs=qwF9;bj;g4p`F21=k^d z!SiuHeWh>U>XJwkKoR8-4He<{%n*53l3O6*(jF6I*?U0jn=Ow8yebjjwkQrh`a>fn zkcmvpbq~sM3(z6y5&aI8`Tz;wQ3$}&GWmX3S`e_N4Z0T3v-=BxI_v32z_4`aB?4>k z{P{&7l#Ci78?f*R1UEiPLIFb11T4w(e-^w5c3*`}xMT+`gP0n>V5Zn~$WkB^Bm#k? z5E4pV{w;j|iIz{WOXRcedgqTAub?+b2;?aVd{-hMbxNf!L+thNDnX|_1CIcZQ4|3O zNkXE}g&=`7B>KJ5O~RH+l_;Rfio39U?!4kah|fkjgaRUOI;j$!2o&RwxeZM+eX#M7 zdG=X7E}D?`KtiKa4=*JZ6IJtEDht|((L-=o?7(z|&=Ia?! zKEaD3{knTu1NEsQ5amwt$QwF!5x^}n8h&=eB|q=f5iXF9fShRZF$BuzD~Tq7Jv6*R zAObGgEIiC=;`7C_3qSe^z(2M&pt#o;LopBe9YLna1xQKB zb0^4dSn!1k0t?r0B!~7s0ni0KyW!sYRKSrSfcD4lAF8%$_4kZ03pRkv-1;inLzn^* zTGO+ZAyyYjxdGUM%=vZ9Uyud?UkXWgCXkA+1mgLhttT1iRISVr zgbYv%RclLA`b3@$N`~N$765oNmjvQZz;mZH~ zeff=e?IhI({Flz+6siPRFyTI!prvH99IAp$@Jv8A!NjOO9*t+0^S4x>N^9ueaFRG8>8?2|RkB;Ro z{j*3G5TF1$lL1QcRGb1GR3K_;9_pK$?7>N(h>1UYHG=0Dz@3TrOT>7Bgg2(9R}B5Y zgMu7t@aI33`U7ln_ZwU!az#wdcgfHGjf7Sc{Z~<)Mb4G#W=0k5KV;I8R7{c3MNOh*& z*VDHFNz#VP1P;)6I|;)*jafM7tv|ExBYv(V^uh^RYhgLG7L!FnK}&#b7F4^b(Mvx% z4%z=lZv{#``|M8yc#~HFo44$YZY5Vljm5tL4tR=$ zXeS&?o2;ucZU#>B>7F^89eZAmOef3tPQafiP++P1RF7h1b3^IMF8PGH7mP>K4uEdP zj>ptGp_nFkx12--y=I}KkH&J{<$$I741yiBz&DhEXP}4T1^UJxQvtQQ0mi~CfFx~M zu-7j~$~EAM@s%+E%6$~m$dTmx0PSFaO#w>s9D|r$$|0Bw`V~WP{s&qF-I>HAj_~SA zilLza4KC%1>|0Kvg61DNn`UnC?oNG@1)78JsxWYN^&i5p)If%dmq;sTX7AEIJ0!=c zHiK=&JhcFca5`X87*)(>2zu_IWz#(fb4_2==3{t2e~D3Ob;x2x zcJj7Xb|uE`%IN06%};X<%Fn2@n47#z#V! zpd4^e?*p9;VjoxrwKxdxQN3{*>VsX23WAfc=qvzSdY0%E)bOTAN-+Z)Xi{T*1>Yv| zM%aD24>(-1|9%ke0``G}$e@GBvvd+|5CqagImUeyTalUIK0;J8G)bLWYx_3Jnm1!j zo&B&D*w83p^wTKmDB#N9bmr4)NyGq|(nHAt(xqMPu7CNx5XM3h#tkqii4$NAWaEzI zXig~AdFz)Z=MkVeis1ZQIRPgNR~G`hl&_X2oHt6i618zc%##EHnsH=mFiRek$B z6A|EsRKunk&$u!4E}VkmT%j*l9{RuLV`+96XhE~zSCOwxkHo&2U>p>FbIHbKNb*M{ zNA+tTF5ag2ez$+&thS+G3arS+G~-T$16hY6%yRw~j0sXw)tlb5^x4BU;dnIIT?hy8 z%pTt*mxUIi@We(RE7ASTkV>z;b3_KieMd0sLNJ%S`N%R4iN4ywK>zs|+ zxX-tK+6|LV75BdlI}kiQiG$Rr!{~!f7~_?)1wk+-wsseE(>~dH4|kz^fE2l+bsKh^ zqGDwO)4A~L&$rH*2rax4tMQP{f0v^`Xr$O0ls!%CQ$w-(gog%Jny-JZ^rm$2yFfRH}90Y3h z>KnoqU@^4PdEtBS!nfUKc6cNvWJVIL^&BiUvXvn~q-i_h6BYvZw@weezr)J~m7b^f zfNf@+XA=JJ2(b0w>?Lgg^Z^P8vcP)cgd8UrlM+qcZ0LUNeFGR+10R!585?QR9Xl8t z|H(w;jyJSR&jmF#>Iqy1oOjNiae)b*a8WymwluM0d)vDm<0wv!EcGV`B_4uINOXSh z6e$0=OhSoJBM(br2|zB92*g#OivU)AqkZo?M0<|pB+EiK$o8NjYbbcs(!8w>8FBHK z3s?Z-4HDTJN(famA_f@;0gpU%;PWNl0r*TiWDW{kzg`2F!tIPrRTskOhlQS>`}Q9V zuk&A9sfAaEXkHHiL=pKcfUYlX<_rjJ+v_X_II^g;UBW>qG>xL&j z0Fd!FTi>n|jXWWM5hV+f&p*iII7(#JrWt)j>GBv&>^r&pCL^3p5e->j^hPJ(x4w^4 zm%i7+`)*e&|EPNV1$J^%B;z_Ih=l90>Ey~a!E34G+39?+VNbh877zG--sb>yF}F~pju0D^B9DGUZQ;uo8Kh_^j+ z(h0=@RrVcfUTt=rg~v&dIa^V)5QoJ{ZSf>+FF&Q^&sb}R2eT+pObEY~(S4+i<8flK z0uge|0#*_owL5HizWMk1)LVZ`jhj}W9dSa*cF_klw|25cqz!C*^P<=$UP82{qX*0fO!>uekr!Kar?GnyifXc~k=kVMDWI8s*m!n!-TWVD4>5{2C~&*}g6+ z!mTsBi+=*gYJyaM=LdzMzm- z$8ulGjjQEW9w5n+j&>y^dDs;r`iBV43q$<7uZG*OKv}XfN8u>u7VyUlnrM_P8~RY0 zn3nV38p|visf0C(K6!}frQXsAh8#e#h4N0uv95Ut&1M1^zQkuP?1_&Axf%12y4Rqo zcmpq3=Go#mopJcjT?y!tljnr}asip7sgJS|?^@sx_7Z3mE>|F?r6a82j$_ey@^6hO zZIE9Rg9bsqk`;#}q}S}GDvE&aFfUh~xSvwxDx)^A{CbZk8mP&@#U|A`FUnMZ z@U%#|90*JCx#2&o3==0UURPnN+zl0h>geKNy5+Wror~QBIp|}y)8vfa#G~r%g1YQK zyc~Z?0@EK2RreAl(8cW4nB&E!G>ln%!q+oLA0&AF=)MTP)SY-%N(hOky4vnfJD~}c zA^|X5z~b2qBb3XlAfkc#xgM2BYgTPe3?dPF?x0SV-;RW6PL0FPK(Bn-0J{fLqJS&4 z7D?s2C6GW_(t8QiAvi#8ZIlaPtuF}G!Ti^xgh6Qc({cY}@qcE{oxlLB4xxlpX}Y)e z2_O!`r^x1+{^Ifx822l1Wn~2BE&=k>CQNja$W2{Uz-M0BZFm+&gYQsrC~DR-SI&5D z{L=GZwl~yaa~%&+14`c$ozKceQ9$C5!B>#(HQCBI(}=ZC}%fVuB|K}V+F zgxvVuSd+|hICdnbtPKlk2x_qgsKu>%#^+ETX;luNxvO{6D{+urq?UnEiyMrxf4v{d z_0LV2VIQ7;z$Y;V2*$Yj^G17^IQ~weIYQ6b9eQP2mkXkNBj&;SlQQ{3GR5Tq9FT4^ z5`Bzi+fU}*wUc`*O}HbmG3F^)f)tq`y+_m)AwlRZ374e0ApNJ~U&R;V3qrx88&mVy zA8H^tL{-p_mya2qb)y4P8K5b&;_?+OUK$RaP>^=V@I9G|{)A81aJtP~_P~GDIiQJAQ0Uh~C$1tk)NqPCxyL9va7iK>-P0*a3<$~cq-mqxg4 zXYgEmX(5mYCq9l#;(bTAdhoRb6fArpdJ5Bz?J`xt_frzC@>XL*n-}X23=}ogLcs-D za1CKiil|~Y%Eiyu{0OVnc+Y9k*n?U|demL6;`C!YU=Sn-V8x=S71A1*lEF7JN0;X# zQ6p1PC!kKD6A6))lU7<3uf{DjNpeg7oq%QgPsoyQH>|MP&zwR-k0X$)B?{jmd{999EZE z!BBSlc%-R69!7|7eRsLViePE?-CBW(!;9VOpCZv1Z^<z~F^PQQR>e#KR#Ps4AX5^BAOSrUBwOMu>H>{W zHF<{X0Lrj6XRT;9bGbbq)b#Qlh{WH9ieA11y%O_9!lR!*VGZhmVuJ_K#vycL$9QmW z7$^vz12Mx_Gx!crZBt1)ZN$2d2eP0Pk<7H8c5gxT2K(_Jvk%vrPXLwjzKFp zVTaVpQHEx9ig{Hy`G-VS?z1REO5zXB1RCkr_#Wb4VoipV?k&s_U4op;Kusd7=}T)# zRtU|oHkTt%D}rU(;%-W$!R?^X&7ZltQk@*yByxhdEX78(*WW_~i79)a$BkI6J5m3v zbF=(e;G;kIn(?J$^2kpuq~404+%4hmRL?bn`Qn`N zqGIkcj)Jr+UzuNMf8>8ZFVOsVmRBn~ai)%R+cEv}I39aQMqR*8?TMg7Hc;W4_Yd!A za3)cVi#HqDbK>8AZzG>J-TYX{CXP6S>$pmsUX`afO4#0j%%HM!Itmf?PtD@$8a%igL>!+CI`74>PO{S-z%t(h}p+Fa0P_tj^my1 z0%%9HN=Ld#)i%2BcXj3ZfHiK?F2W^<;xu9V+DAu??(u3dd@GerASWdS1tn+a6HQfy z%b1C96Ue)uPkC2sH=T>5pCX#;KV+CO#j$0mRd$t&zjC;-@^6oiSAv4n)s6PWl;Md` z%U`<`GA-Qee!Fuozum}okkiBzyL}Fz%qNYrmRNa;b-(K`FZcYM>en@2`f!d1-@hx@ebxbH}T zB8M*@n4PauAF0?YKj0Q?Ix$@Y>Ikv6&TPR&X}i6kezWq5Lb8b1-*q*s@$S6F*F#TK zG%XDn7AaKExPCIxa*?E2uv;+za2tT7{8d#17iv>nwY8k5+&DA-K3;8&oJdpwuQxbb z`1?m1bDmPXBg`*i4A=%x46b_6$!HHXfF7L*P{kK}Vb!U0qI>Rj*6tHcPcEI+seo$E zm&#NR+3Z(sHF}ANZZ6(VXbceNP@&&MC#V)5m$P*w?YiBY2&(iq2=EMIBfAh6mEiG905}3d8 z%pF`iH*L0d(K*!Wz>w+BGOQD>#AJLGe6GwUutk6zp-5cq>OU-l z)8&5BA3}DdI{Og>G9A}KaETu@q+i1_I<#qsQuy?Se$aB99)_zNi9fF_A#N-Ly^vZ( zMOvCsf#N$kk9366oTBZAr)U_rmgAr?{R{ zPaq$Gcst*yZDb;hAPYR;t8cbQxCrs_*hVHCs?|`3$qRW(<5h9F;JWW+Yqgby5qA0o8LoS(y0yeKneQWyW6CKQ3#dYQFT*2@oMtzY@1)>v`h2#qAY z)x;Ukp2A#AIeqC}BLnBoPYr;z# ze@NkU=IbBVxFUS%X8(QzjaF-PI3uT?x3?ANu`?XVq~hRr2<`jk0!))ZL!S;|7KgPP zVh*{4rY5O+TC<&2aa*~cXc`4_;34WuzHfGC+ZoznyE-|{R>^4{2Qn6z4GWwk_#QEi zq@E24A_J+uhc_{WbU#_JZ#Fk+>(1q~JYBw$cuN8r=rBaR6I+bg5?g|WH=kdjM(`1=?cDpT=I&Uz znji>46qirZ6_uL#QDaMy{;!}p#JZux@EE+k3-Jjsa4HibQYNPV2h)*a1v_vFiz)93 zGC>irU!ZF&NVIy8(CwBp6=e^vV%1tUoIiTEf_gAwaMnFzq{kMlI+%qwuO-pE z62O;j!J29e6x&kJ_Mf*ffxn<^Ml}6kx$f(MP0noSexVHpPy8haFDJHa-u1%+@tvT5 z-vx~i&r{Wr4RA4svp2xCM8&p_%~E&V&To*UdNO{#65{~_3D~Y_*t9bxdHj5BviItm z3Za9wOpfD)X^K)J3~cvTz1u7|diQeCpt|qj902$JA_fJdArclQhSUXqszAM+@qC?@ z3Wt$OzLW!J!h`Trh9Ep3)9@B$J0GbFqWx=~s@h%9*vvl;sF}c>z47)SoS`6+4qFX&jdyTxc0v`v%e{I};qEEhQ_Dt*iNT#JDF>;5{YYyX?N56}89 z>Z*N^(Y{>|xgyv>$FdAZ;KUt#i|3>ic-RSc390hh^RKT5$aK?RFxf zD-i~qxyZ{;?CGH|>EbJ+mi9k!(KIfrg9XHe7?4RyUCA|<_w5PfmLN^_8Z9@^zTd@a z8-6evQ&3rn7$C`BV*u%=h7s~pnw@gf(pm$t=EwGD>y~fr+h-*}Wc&pcyPWTk7W4i2 zC(LXy?;pyxHu%UA&@ha-V3kB1f5(^x6jwMR@F#P_V`DBXAY7{v8mb)mcQ{XByLF%P z+HJIjTC<}a7CWpZjuPxZOxg#Rrz?QE+roP|G z*(o*4_hj!fqm?{-d{(|io=d;ZeJCXU;ixdG^ol<^847X%O|y(1$a7>ELn%1v!IVdp zBmrX9D7&ZU#ice?hb}-5Edst9137Z*!-=<%%I@_vQ5zSY^M4Pd zWB^3#zwqqJ-scO(Rzyj~LX(D<&;W7z-&aERmsw*T))FgRu)zbFpnJ&CMC9xInoD&D zi^vY!>unIw$C#A>-pJaHIBc2r|E3yKFv}2S5Tz3jAmSNH0&%WHD==Nv_q$!}nUYS# z!j_dXlzJGUozwkq{#~rDzW=EAcTdFEJGesZp!XVNo=~p=Q-D9$S?>f4*#%J76~S7p zN)Jk-?mia%f~r#?m3V1UVcmJlHK(&G^33CtiTzX*H`K`T1Qa`f!ijBUpd|Uht3?fL z+0EBd!8;C!UdRW3MGKz=Q1C?GSXM1xQ9mYAKU*`Vx>gd*aHLe-K>&!TH~Bjx{(rat zHFQ?6Fcu$*QnhISqfE&r^B(|VmH@!Th<9K(>J28SX0d+UZt)R?7%onFK!P&$q2al6 z_L*g-=b{C_H>~m#0%rbbe?U3W{(LX}txe+q;GcEES(oGPo6e){XR|@U7HFPk7$Hhk%jfFU_fEAN7XLSdo=)$UDEwK-}-vk zRB;sWG?9>b!;w1RLEF?du|+sr2L1+6!qZib@60qA0fm7E}#h0o8JU?}WN zWZ9o8$>-48(AZcPH~vWH!+y?owck&DgsGx86hT?X{zT~KZOE*G2}g-zEHWv}jXVz_ zXrapY>q6ExHdNO!DP^7b-Ya?iv5dl$*MC}3o#Ov&soW@EAHW~ASpG5BY~Zs5NWJHO^?eZ z!(q_8vz_Q4%16Yox?UdoX0~dj**JQDl;5v6v$bqJZm_lAd{Q-Xr@WBV-0mv z?f@Wk!b||5$NT`&HW)(XZR*$$pnn3JsdyCSd}jMq52rr?81vFnUyOxeAqkku!cpBx zIIm#=|4utrewT<$_73UJ-WTzkDAY%66vBPBwOQ-guETXyAS?9Q-r1QSAbl$XK=;=* zHQyhVmNC%%^*w;)b}z!5fhXlbJWZax8D8Z17`kx9h%d*;f8x&5p&Dm{=Z+9hFU0dl zNJyv&0CuxVIzEn$bQUI3pj{#|r=a4a`z#UN3*sw3whQ6641R=RkN8yRgE+CBz>~ z982C=YiEC#D!sq*ZKdsScCq>swNq8wpTg3f^W5YQGENaOz(- zs@exSneF?BjZZR5tpt!p#IrCaHn^M4ucgWys&ix57V&g&#YBe09XOC-E^wp8A3n@J z(#7}{f{7LY!{2{4WM%gwg}4=Mr=ADS$U%Z@vVzkWi4I(1!QFA-HYjMiRez5WTx1a# zI6*+j$Iz>H`E@V?pvSq$N_bBWK$p)A|8q;Mb?2&G1JZBOW(N6>TKdcZ#VLZFMA2{LO z8~d}^fQ_+RwEUVRSDmo$G@krSf}tBmkw?nDDJ3Q-Fg!rw{=)V0H*Z+MAPuh{4fO(s z{gaWsP(E!qFvioti}ALRX9wVCROVR(bLAsbT z7)S76eWdpSJc|I*7dHDm1~L@SF{%ag7{H8#E`WRQrI}(j0}6VEH0pl}c;>=+l%EKR zs~j&SQ?g1u1}6!pJOg=;nOK0a!nwdmvj=AVudRm zz>p25>&HxRNG{`|tiM}*-N4PG`U@VjVm z52v%qF;HebFbD(*i#Yi)hcdl0{NQJam+gpU~N!;hcZ;+U{yravpd#)0$J z3uZ=WwMU$-elK}`5e-A902z_Gl&Zh`ccaRG(m7qyZ%J4A>7Ab0@7n0V70&E#BgQ(|q^ye{=)~q_EUPHt{Mt6Mb8p3QD;`P0R&Ta}_jOb@`gr z2}XLX&9unRv;@6wYMLknD(smHR2@oS7+{6cZwIm#X~+Auw-Z$q(K^uY6cDyj6V4SJ z=ezZq&tdI*$&Fl<%s-nyYQdm`n*>cxxDhnGI%MC4EBv>q*oPxWaP{t*#m03ABcd)C z_bqA=rN1eUyMyyJxOi3@8%uuqMh3Pko_%euUEOP{?!E!m2mpafK|LhEPgw|RKj9p= z3l#Xfef|1`oC@27nx^0R9_X3B+Yv69tp!Qz-X24Z!E3RYoNWa3aKnMT!fFier*|MHlf9J9W(}ONtzL8&A`X7Q?0SzoIlc%UBB)|&s z^#aAgqUgt$ZtF(|EJhac1>5V4K^h+9jl_sPNJBD&Gm?B-*9yr~_JZJ3OuTct)$GR~ ze)7i|yavU3h@-%*_J&k3`H?2+msnLhzzEclpAEjmEGZ zNN>`M(u*KXM4BMd1bh&XrU8-OLJ{dC5-gyAG*OWvO#~^@YhqAPK#E9_8c>STrT2G( zzxRK>a9xM&p4r*inc3Odxqk)`dqHjZISe$b0amfK-G(qg{84EeQD!g+H3h&vH`f!`k(&T_wVHq0PxjJ97X^v<5X~_ z(|N!!4gAQ;-ppjaub6At>(oUsU~{BZ>4GTcyd`oM$dF8qt&b;v#%s=C5DZyhbiobW z1S(7-Olvf^&rM^Sgz#=yRKCwB&^6+NUyMEDbY04xNse+Q%oqVV8K6jKNo%Rv?agEz z1#npay3FtIg{%Pfrn93TBJ(0n5TZB}0&i1>LCGh!Qkm#LfCVitm83-YH z|5c8j)JENw*xH20A#Oq%)x1=YJNGLL5-ZEZ4H>qV1FFcIZBf&VD{XOnzx#_$PEYUn zau>ibz}@ozDoE{Ue~kd5-~U^0wk|yG@fEsX*yVoEIWo#5F^*@Z(h%noqZ_gqFDKem?iMbuC)x zXX_J3pe+`F1N!K^e9!a|5CrACKDSg^R2P8!`2xU`zC7kq0O+`h1!?Fj!Dr>@^~u(A z@z7(%nq}x5O~58uDW<-CE7|&(t3~9Q9Wi`stPLp6 z@YUSg51=-93PD=X%YY85ocGBPfa8%bY#AhWEKBUZq@8uN0t$hQTm}Tae2l{$5)?s= z?m^%C`&Yrf?(fTq{rkYp%eXrp+;-BqJ#%&X5lEnFCL2i&TV^x|`drVjpZ*RR_v|_< zJZ1G~+cgUdT>yyYSSLe(wAvYc=^(R0HZn*OIm!X#&T)Tx71WdbYsv+Rax+=o2Ksva zchr$AERs^yhCxEp!rYwfBayW&@Uh5vMUHoDz~^p5J#5OJLj;9xwHBvmH(C$2CQJc@ zk!)fz{spW6?hor;RfKv>cxm?e=G-N6_iNnyCCU2W9_5K4m&|Zr+E3)=)h%whA+&(H z?5p-3YX{7(oq6F=yI4IEv^91&+&7olBToyV)4j*)dke3L#l*(?|DE+c=6y0iVH*!yGd^5-pt(Z!0<9~Y>qb$MYF?n~>ng#f z1N4{WqPQ(!FOf?$x3C}sRB@g2=1oaSS)c2T0+!lIof_;C3ADErXcJ)(S96 ziR35>m{}B4A^Hx53DgQ-Iyei72kn8>19o=yD=!oukv#_hOBK(r?h2xa1G@-d zu6It4h{1rO8F**gMh=<)2%vTZqZ$DO9KwZ!l^zGj!84G`!0KYO`}u<~Jt7sK{q)_* zn+~#14OWuQOJy&>H>0F;v;jx>ef6`18&w&5M3cPu66wc zTc8|ZOF8t+Ow6xeR{#rgseb+p*%L(`CI(uZ1<;nVnCw~>!TEHcN99S}q-UH2{b2-f zCMM@mN2+A6SC8)wn~Y7R>w07#DAjwoduJJcJAkAKVr`e>c)yUP4OkTEvRw85kfXGA z^xtjb7Rr%YoAU=JNW)-B=8jojyVe4HB`)<4#n_Xw`M@raG4tNPS3j~U-^onI%l9Jf zf&6!7sJ{fNRW58B4My(l5^3<{zbmfynkmz0a-|=Et5V~?Tv!uJW>R&`9D(*c>oeYX zbOJtH<*^lck+8J+PdWl~9SV7h$?yrB!_4R^w_Y@yu!ss>vK_<~?dPDU)-TgFf19VWgQ z7A4t{&f3w~LkVI^8k9ktLmi+GcQUU!6}o@5X&#;11~@rBNe)Jvs7z9*-uZLM z*SDO!s8>vZdLRq&OXVj|PwUA$5GfjVjoPCbu|5b{>zI7Ule_s!P*BeYe6HP_;^JQb z&&shqS%U1}f+h0oLlm+vM~~6a&=Yo=y?%E$1Q64LqhYND{xWb=s{w=RzEg5ihOq{H z^;4uL?^O;kkq|;AI=7Y#W~g(YZnCn^B*$l>d4Dr1)0(Xi@@#--m6XH*TO;q>$w>~H z&2+u;zzTo*!h<_>Gm?%5Q1byo(tDa+X8JKX029)Gz}jVXZ{p}MrfBwPyXLD+>dq6v z=?X==(T(`V!`*qcjqlgg4!3^-IJBX9{g|TXxJ5{c+|B46h#ziJ(VWO42yWtnlh~%o z#mr6_$;}+2_Lshql3zbwnB`ZPtPVa}20`x0X~(v>s`AX-OJQNKpV(#CyvzfbmR%M6 zGRwEOw>pF*98i@nvAzVvV3X3XM~U*9t+}~|{du)Bn5QUM1U#KtJ!gAVOv0^O)D)U! zila@2X)W-cR9CC1WJ_cz<_JOt%@vqt?0Cn+UR|z})G{O_`KcOzol*7X+$Kx|1Pf5Z zJmqP!{Yz{g)-9C?3C0;>ZLvp0b|~?$z1l_n(Kh($Qk3GaA5&(U!@0Ev{ROqoM^6hN zO{y-6;XU3{5~dkCOVAnkA89hxi@H{n=(N0qWIcCmG$BXl@~gA>t+QhpeioSImVzns z7sm5N0?pGy4`!ev240F}TP}m(+x&8AJw;$sULL5n!rKGb-(KU3bT~iGMw;|EnI0bL z7EGh78}Um2N6=P(|A0c{MEHb|Vyh~!#%3^U zouTpd`aC&E-#xrrB%pMiliwhklM2LpVDYG(zgzgBkW!8b1-gVlmANCH?5LwhI1AiT z!BcZrcXDO>*Dln+uQxl77Ra`a-$*roV>W_=Iqs%^pN_6r-fj2rX1$utu=@;OzWE^X za7KYI=i*U0!>$PXuHNYt@ky1wcd0Fq;O~0oYWR8uTjC||A$TK|+6lGLgQ?6;sWWH( z+8P8)x&J!Hv@H*Sy%ZgS@lg>5_jGaNZUR;S1~%;M!ybu-CwU3Ek+g_vxDjTRFf@6h zE4Vthn6rjfy!Tw7s&Tki%;dq+1*MQT>XbY?2H)b$nP0q$t74;qc5-oOMG{(#`)Xof zKF5%j%GTY5>AvRBt1r9W-LJRMdc?V2@a?;2$@G1l!w?3cZ2^h^QBP#D@Ig@siHd|@ z{j7<=sC|zqtC{Xd)lSs7M*Bw8lRXW7r7rNpj~t^8Lp#2#A-e7Pc{94@yAy&$x+4Ps z4w-jw{~&SwM=Oi-Q4x8CHvci2L-zEU>3=JUufnL>pU!?tx^3Tn$A><+ur~LzmX6>%K|HH&Iw4n`fx;cbh<#4* zBu&qctGc-RJ~}`o*TEtsQ)Y(cNSX{P89n8A4@FW9HdA=<`8xni*9L&;fF-<2`xuIt zY>5(fl4g2CsR5sX`ar4plj#bDxy5O(PnmM|l+bVIh#a6|sCM=AuDc-j6O+$MfUEOP zxc+c?NSu0+rVYjCBk|Xa-r=YqR4Z?k3T{EL#d#qrkT?A1M#K)*%bx3g^5#L8Wr~96 zV0(^F`08&|_Z$r`Eia6YVt6t!LShi{QPnf+d8spmqLd`_C;L2S5VkD&>P|LC8pY_P zp}v4R)J-$b?|RFkkZJWw~lMe?Ce~$zqafJ-k$S*<=6L=G45e=BoeL% zSAYGX8T*bc)1}ZBJBulz`KlD2+AbgfFF>r3xtBd~bb)X%#3(30#c=}5gB8Qd^dhFO z5_?6Po6YFjqH$dL_2O(nQRpdxHtEUyIJbO3t*|Gbxa8k?d1jC|Nbjbf_f1VHtbNj7 zz~KO!(wlf~Y&^CGtJ~XMgS}f4>hW1E3cF3W zJ}5JW{*c)f^f#PDa7~DWCO^Ik>~%pu>b_uh%2TvBy)ia&?BqCyide|arQe~dPt6Dd z7%B7w9)@u}p?1+qzU0>sG>X_aWrHtBf02eYBS-nw6ATSWX$rIevciz`N}MT3zzWtF zzEioJ@uU7)N4Bo6E*tw~;JsE3HJfTvRpZ5h5VGF()mnB%;{{fB<_5i9cU!w`Sg(h&0hy^tdHWq%F0MRYR=0cWKBj1JL_>P)6KM$YVLRx{P|Xl+FYfK zRQ>rSSW7JH^rTAD8Ju81=3GUYRJN(1uVSritBkK%wiRVMedFh)Wg1zL^!z(Y0DKt# zV5)$7`z}eKc6kEQI(kh}o7yw?kt=T7)pg}AtHTVw{^@d^BlSg7StBWl#NiJXIzy}t z*q(U%kxU+paqn#J=3wfa%Z>F3eMDgkexiVy^d|DcTvqif8-B_%-^H096#~|v;`fq{ z5#TVYSuLd2o1yYy$qWutzoU%z(NP(wzOh~rzTRzf`N(qw7T&9@De}9?)m|m%DWb)h zVErExI-$F#JoJ9^bGhJ|=18z{yd*_(ApS^e)~M_6AuVs=^7eS-w4l$OF(O8LEO8jM-mTZd29gOECj&@rgm0qUBLRprr`FkB zeZKh5$dKr?E9^c!G`c)Ep~rMK(IlQdgQ{4EiD*YJv%P{s>`;jlP+KOhly_N#Om+1 zU8ir(_KMj;1KC5{;L_#vtp9*MNz-lkOA3{nc2d6!MgrGgr5={w6~j%E_uO@Xveb7; zAyGX_JL2hl-jWjbXVD^ZkIU>NQl>R^=;h*i#HUrXf69Ps3t?PLhaB4?4pXN`x`USy z@l4#R0@Mr9tY?g^mo-_rkNU~+!o?piT~*P-4$o`l#f(+%%{!A^2ptQDe+kwz~rR1Gsrw&nu*9;Z%F|i`A<39ANiBO+rjfB>zH?C`o9N zf9)k>kW_+tA=h%qN9w28w;qH{bt7kPYTaF6ENgJ58BsfoGd=<#*;U5ELF%^WyweZ* z&KSU!Aw1O?F-33>O($^!w^X&q{9<7H1t>0C`&KL<;)vN{O46V^)`)rp&cRwuxe%Qs z+hEhsfSq8<^x_Ahj)rqT6p6mR;Rp7^h4(LQSrUtn6#Yhm^3N(Gx|zF5)rYr=L2^vC z4KRPvIQAj~b7UjKzRd20^|s5{%#B8MhHVMu0|n@6(p#Z)7gf%oHoyH?N#gm6S?1IL zi|H@V{@m7n<9n*7^O-dm+(%I&%gRfdgVaQtr#uu8#BXVE>7u#!i4~TWAVo{n&n~5W zHc*&mh(-zw^J3^SF=MlW`b)01+}|+8m7^05J7F4&I_@e$Bqfq?))Uz}a8aV15i3N9 z`ZZCv%!4T>xMs0V>U;B0QhB`oaP*SQ@*f9;@RQrz(c#Wv>T<|hsP<9WtTc)zA(uv- zUX-O85%9su4Wz}N>lXHbCPa$OI%i!<8EKm6ote2Q19QsuHST2#P7|ceFA`f`d}MKRFjyp5nMB!w#Xh@XN4S zxannq#^~bg^CUA8ZteuQ-cu+MMzIgyR^RDeC_Vd@rr?UY;ZRJd;Le0N+H9S!`Ad!V z`?^S#$gnuH-ROtl?Yl*=o5Ja5K^`jC7$_jkN%Si|Y%T@W&hIzrx>oM9>@-Y7nx-&W zPTfR=J>OsWx1&(J^f{(AOp=mPme=87Rjy_44>Rqn0%uYd>}bwSN|5gyT0&Ku)Z_0~HNAah14lK+2wP^|MO2>t!CJzDt-uyG zH&Q_{rFpoYhF$t3NX~c&wTUDZ;C?QpZ%iD>&adL2>Dd1`K^|%4g#l(!hs#Wx4IYF2 z@KP3TO3SCCm$9}qVqWU^Ml|Rkw!Mq%JiVl&pu`Hc#uwViVx2uF?W zB9R4|3j(!#R#6g;`NgL^X@(x4Z@yc;3kXuUgEL4IU`~Bsw90K+qrv!?vYs_W`P0sG zY2CEshIFEu`v|1<=#VM%N*XNg=PG6chudKx-aNXS!^rDoX|bMH0aJHzA-Pr@qRh{kX>3zwbZ{ z9Eze2hx?tsSV6JPAjFgi!?1Ys$(`7i6!Pt?cGpJs`sXm#KWP>|--k9QIg?yRSwO<8 z&@ja)o!yl=eD3I*Q_^*ja93liJnPgb%{F)KpKW!`!e)o!@a8LN(WWlH-wN?g-}Q^r z=&bY?AqbL;iGKLXXUEU=ag>BTvmB=w{AYeL8n?FAs}NAV^ymq}x>nu1-RKkU;PT6t z+flh1+*XH>tM?DbcNbQ!rs7>2|2^*``&le+M|8DiT6s`~y_DlY4Sw9Zq?A3GIih{S zljCaiX+HYS8n~F!hxrNMFPtM#5*Fs7j8-jZ)QqeSwh(y{R$4oDp6$p#+7LZLfzKT3yIi`zU;FcyFhW=b#FF z?p_B0sKIBm&4ZXoB!4_rxZ(YGy$XA$aqoDL%$5VrQ(W)(Yx!!&LxD1k7SdJW%0i;` zPiyK|Gj%DdGX}}g!jn6ZICh+<;vzQcAPnSR_PPUnbs>W7(6nZuB#oY;2A_J)MxJj| zl^L#|^5jq4D|7TP(>Id38~i#?G<5->ChQtj*vTLP9*U4)@*}cp!?6F^rLr;X@&zn9 zeKTX-#}IZT=qZt4o~6o?y0H95t5n1AY2@R*Pixl9Jv>43w4q^Xe~%x-%Q<)#48r#U zO2dO8>_J(R<8>a&d<+d?Jk`|fr2X!hFxO)Eecfy3|0p#fnyicxP44(@Tb|g@uGfl z#Gj+I|1nQm%`$6!GFf^$h}B3n{ITr;?*%dI^3&XE?cH*$e73XgQph0eZHsN4*>Ki^%K-_3ZsKI z42zde*k_7UtWfKNGd=f87UF-3H7p?%waZt5tw=iM+26>8Bv3nWvQOblYW$|K1mB1JSVwB28r^rl#LhDHZpM)hl%nlJ!cG_ z^p|mydgr!Es1k$=ec#el9M0+qVZeXEq4TG94(-7oCAhVRA_m_w>I7;zhi*#Pa zh&b8MOsW_F{WTj$_@Zh+1ts3{Mv?40z>3XTM`-wP36oDED?VuXAHPaQ6j)P{e>L@% zPGzi{0}%2zT|;HpI|ZEe8=-K@P5!L!)uon4!Uo2#AEJ5f6^w+){qe5DsjNWb7nd}%O8@o8K*jn3 z0=I)YrQ(}CM94ofQCcuwU%Le6A=J5MFpk{U`N4lf_?{a_srqlIe!q?W4I#;$KK=GF zL)ueVh>0J~j6e=~Qsis~|3Najtu?^+>L(AMJqlx)dJ*WwTsyGVow>+YL%Rt7{d?sp zb&A*Ew%#ppT{dU(*Q-SiGGuQz6L@vBAHlszdP?S)bSEGpmj5>o^1p%mc>Kx+AqKi6 z|0)kxwvYdArk}{xusqk7lbJ~VWbgk*aO?N&|1V3daTN77WGV_3(3Ss2P##m(QYLKR zJAgJbefp2qv+dz;z$XW|iM!4qWCrH1b&h_$1~Bc@@c&JKqe>2-eqX70=$QJ@+{ft3 zgiLnuo1?lz#f2ZIfnvZaN3_Llh|z%UYx7Ar2stZdztKyj+Qjk!9Mkf=m_3l@gULLql}(fl|n91idN0s zAc_hgCNId1KBc{`F2ote#YwNmD2=eu6(T%M6)#U^HCg`QDnVYq!xmz!&hZ^Gx~IZ< z={H?Gx4Jv1oA^wqnmGOITK=~Ml%$TUdVx!Cx`uZm8(rJ zV|S&K;~HX$hFwsQ+NG;wewHZqAD6?4iS0Rl5DyLc{494-36YP`vx>RIjR<>LR&e(^ zyIyIiCh5C4-8S4o>Y+n2E`Ja+w7wi0GbhQOlH=%7nj=yX~4bjnYk<7BB^Wb*xtV z(zr;7*G$h(lFv1U|SI6REA(Gcsm<*!^B*_e$N#y${01!Rt4?LD)ERyGPV5 z)QNBnN9AWYkVVoU73_QHlwOJSNoG-v7T}}&jh$d4Y8)7H zYj)tJCTNaM(5=>;^=)N&(KKK~OP2S*{1atN4Vq$KwTa^gDd)HOB@n7CAykSKa3qs+ z79BzZ#}VT{{Fh?+}<@Mhh# z#V=J;;!HzGm6$T*hAZi+hP4psZv6VA07X(M6$d1XsL09e$N}+Ls>rTu*hnVJBXO=j zSbxlasoG`;ffW(2A{;s(A(Q^gQ~05N+N;=(Oc$v#>H3U^aO@^d2GPc(dQE_)vV|Wm z*$Io35vqNumo}EkcVpgBku))Wi4=)JG2hb=nZ0lzBtOEVZFX;`N5sw63v-ToY&?ao zkESia>q^g-i4G&k<7=V$N*PZPqKCy4Q6!uGd42JKmiSweesEu$;`67(L-l@+pwzOj zdSA-!mECd7IbPCkp<=9E2{j}BK%aCjHNIHE>lrAnOz^0rmE9p-CB|US^x~yfr!C>% z^$@!oy-*~-95T&F#Ue+UmLhTCDlss}qN~6j zJNWl@kGbj4a$`D^b_&zIHyZyj^=Q^J44+|>`)qkeabcwNG=*<$HP;HBw$Vr>wIc3U z=hE`qLCid6VvqNEn#(~SwVrOi^aEjmbYUe|6DyO5+C2S_q@Mx=M(Wv!lkHm;ZUJ`? zRF@nGT3IMIHpN(N*p`@7l3A}kp2|vBC1zQP^lol&nc3NT{)8*0|8bAi(ujtUDA5Bq zE@cahqh_Uu(wwQQc0bYV=aj9rfk#a;II3b0juw9AZQw4KCRdabG(u}PS7c8TIS}CRRVfz(ci{J;>EAMG6y9sf092g1%4M6YMpVZ z5b6@^{3RT|k{TAS0}rESK9E1nm9uD}vT?JI zhEnzkP9WPvm_3e#$U@#6x z3ZrvG@{fGi)K>7dr~z!=X7WX2wLDA%X146v<#al@jV%?~v2;-39%_^S*eXxDg_JF~ zU~Kf_y4C%Td$o$PR&lrZnp!|y1|``rxBKhj@*)GFxCieDDJm_zTaf)zCyoXBB=QiHwBF@CZ2C0xQM&8T3I#^^%@d8an>B3ZWsv~}Ktz(;Ojw3h!XD?Z8NOByjd&m}}pOGW^7R&;rgqVC{5)386eyh=UPdv$OJ2{LI<-b2YBQ zM&avRDqqZgjh@A^!j74sBlfcnUsp|4%k&H{>Pxr#m{<&>jIK!)oXYx` zt%snD?vZRc+xfm8XrA8asY(U~6Nrp=HJa#{r5gxi8~?0^xT03;xWR6zzTsg0nV=&ADBPQSVg$F`-`INkt#;(FW0Hm zrq%fx=DF;e(-{qE+HwX$P0#(_>U~LIr27im*m+^IasHLpGz6XYU(g4vD|ejG#Z`1P zmHxal7Sr);O*hm&e=DH1l&uV2tM;~B*uc+T=PvQeo#=~NttGUi6XQ37r^C{-ACEkq zi43xxNpZx)H`XWwdO;D43m#WR4HB!b!+9wlf4q!+()5SALMEd+5!H-qQkV+xqBQwi z-6{2nkcZ2GHMQ{!l9n%$nAE0B6NSU?n~_{e2KKRxW}yM@0Bo zM(wgPz_n~_+mdDrWl-S{bp+wVF>{7=sw<)a^qZ6JgC*01!*Pw^3v$72p=!#5iE~Q- z9sV|&GyWOg>~UQtJCb;g+BgDK3*=Us+kwe3n$iuW{CFlXd9x$Tg6i?6Mtr{^kIVVB zYs@R*qka`qBVWfUx>_w7WmY0jkB1C#sqtx*n4Qn&5sXTEPjTT*r(H(PtjIP6Djzv9LTDC_pi+|fk&AssIx-f6~w4mBnTl(Vsq7{=NW?rK6or{D$I~vjR z6$|jwVy-duD23=-8#^riNH?5|&m#8RE29{^801~*6a?22azk8^EW;jglV-%{-VcJy z!7+Kah;+Z{an`Y6DCRN_mG94*vXWt-%+c(A2s4j2#|xd;7k!%<_pgH*d`*1YV9>&p zup3wpYK1#HoD|<#xQTVb6)Q`NBYdDmeanacK1je1llB)rJcV1bR3~k$kEaS77)035 z!|6`*S|`h1)S?aIbzL&DOSpgQXNTR^SncPLGC?K8p~<1ALXp^dcOA#v((&lQNN8%= ztP+t?1$VJGn~N#uJAzoWN=%{cm>P!P)zi>EVwu%14Zs;!_tvm4LF;xUTcWeOi1s)T}4nM6=)$rMx1bAf)cWs>apmdf~r5Y z6sP%6yF~HnFH?cWaW@g{)o}!=v-s;Z@N1Z5_&Z*}E#ZT;tUnasCJyVW$KUm{E4nCA zX6`#<(^_gSgJVO|#ve{%=+8Fl6=B4vnEJ$A3LDW(H{694t~e3= zt@O{E&2O8_ZJy_5iiH$6_s(bM;H5r-Ci2CU4yMzZ)S=QZLudl&(G1Go-|+5~#erHG z8y@sM!y~3667UH9K=_n9F(%4~$x>kZ00i2?mWj7ncl_oj^Y^$_Ijj|(u; z$avr`od_;&zo9{?IId@XL)l)C|0h5uOBVk`xJfVtN1?684f3{oEInO+-A>XGlA!lM z*glL04pVwz-5P>WULX%v^OHA_8iU|$F0}AUsQvj1DE2aqU3^lY?#sChUv$PRk8s7Z zq`*&;1l2%|ks~2A5^cB62deqxs$HX7pr?a@yYoeGcWk!GUe1j{y0mG6n#Z6t(tY@A z_ukP|l9#Fk(eo&P=o#rU`UfaIbGdfxX$&*&Cd?EjBOM#4Ljzs}50w1JFjV>S1uPye zg&D!h+CK#IY2FiqWxz$izAe>ro5DX2&_IJh4Q`AJlmQ?6ZzNtS6iE;^(~5TL;kUUm zr@VC6z3*+jyUb$AMyggKJn1Ts2UZB&mrEr3G>LzQ%(NZPD!r2-G=Kob@hiVPRa)5h z%GAqMKmh>%LwFiz)K}5+jw6w5vJ;cn{&^}1!ob~0%-v57L=XSs)=sSi-tqApI~%(1 z*7rrPJs1IX>VZiXmY_<7lv1<5e7~gh|9doNUukx7m0#BTzcYKb`D-1z17`m|IMr@F-}weP{(tn%LWJ=7CoY-=jQaGrlm;+MSn=aYt@TGjFYm7bNjoPo-o0au1h*QeC6d4+2_rT_`yn1rEF9+y&{ zoD8Pdzz)+%R#AXh;wUdDUUE|_G;1tSa|AA;#Vqt#7GwzA{{70X&?};eatI3JJ@DKH z=5<%+U^feB;Kb> zY%-$4t9jNa=jf~HHRN}1g`kQ0ubLAq2NCmu`0>rHenP%i$y=`yW5SHr;aFR*Ma>QI gvIA4FDlZ-hNLtkfu$*>7L*OycHMvxxZGZ3o0WKqub^rhX literal 0 HcmV?d00001 diff --git a/docs/logo_white_gear.png b/docs/logo_white_gear.png new file mode 100644 index 0000000000000000000000000000000000000000..f75d5016f18fbe1399e10b45a154bffe03091c32 GIT binary patch literal 14766 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 tuple[str, list[str]]: diff --git a/examples/auto.py b/examples/auto.py index c8a97d5..a5a610f 100644 --- a/examples/auto.py +++ b/examples/auto.py @@ -8,16 +8,17 @@ def main(op: Op): print("Starting...") - holding_a = False + # holding_a = False while op.running: if op.gamepad.a: - if not holding_a: - print("A pressed!") - holding_a = True - else: - if holding_a: - print("A released!") - holding_a = False + print("A pressed!") + # if not holding_a: + # print("A pressed!") + # holding_a = True + # else: + # if holding_a: + # print("A released!") + # holding_a = False print("Done!") diff --git a/libs/helper/l2math/Cargo.toml b/helpers/l2math/Cargo.toml similarity index 100% rename from libs/helper/l2math/Cargo.toml rename to helpers/l2math/Cargo.toml diff --git a/libs/helper/l2math/README.md b/helpers/l2math/README.md similarity index 59% rename from libs/helper/l2math/README.md rename to helpers/l2math/README.md index 25892dc..6e98005 100644 --- a/libs/helper/l2math/README.md +++ b/helpers/l2math/README.md @@ -2,4 +2,8 @@

A port of MUSL's Math library to Rust for no_std environments.

-### It is exceptionally rare that you should use this library directly. It is intended to be used by other libraries that require math functionality. If you are looking for a math library, you should probably be using [`libtrig`](../libtrig/). +### Disclaimer + +It is exceptionally rare that you should use this library directly. +It is intended to be used by other libraries that require low level math functionality. +If you are looking for a math library, you should probably be using [`libtrig`](../libtrig/). diff --git a/libs/helper/l2math/core.rs b/helpers/l2math/core.rs similarity index 100% rename from libs/helper/l2math/core.rs rename to helpers/l2math/core.rs diff --git a/libs/helper/l2math/core/acos.rs b/helpers/l2math/core/acos.rs similarity index 100% rename from libs/helper/l2math/core/acos.rs rename to helpers/l2math/core/acos.rs diff --git a/libs/helper/l2math/core/acosf.rs b/helpers/l2math/core/acosf.rs similarity index 100% rename from libs/helper/l2math/core/acosf.rs rename to helpers/l2math/core/acosf.rs diff --git a/libs/helper/l2math/core/acosh.rs b/helpers/l2math/core/acosh.rs similarity index 100% rename from libs/helper/l2math/core/acosh.rs rename to helpers/l2math/core/acosh.rs diff --git a/libs/helper/l2math/core/acoshf.rs b/helpers/l2math/core/acoshf.rs similarity index 100% rename from libs/helper/l2math/core/acoshf.rs rename to helpers/l2math/core/acoshf.rs diff --git a/libs/helper/l2math/core/asin.rs b/helpers/l2math/core/asin.rs similarity index 100% rename from libs/helper/l2math/core/asin.rs rename to helpers/l2math/core/asin.rs diff --git a/libs/helper/l2math/core/asinf.rs b/helpers/l2math/core/asinf.rs similarity index 100% rename from libs/helper/l2math/core/asinf.rs rename to helpers/l2math/core/asinf.rs diff --git a/libs/helper/l2math/core/asinh.rs b/helpers/l2math/core/asinh.rs similarity index 100% rename from libs/helper/l2math/core/asinh.rs rename to helpers/l2math/core/asinh.rs diff --git a/libs/helper/l2math/core/asinhf.rs b/helpers/l2math/core/asinhf.rs similarity index 100% rename from libs/helper/l2math/core/asinhf.rs rename to helpers/l2math/core/asinhf.rs diff --git a/libs/helper/l2math/core/atan.rs b/helpers/l2math/core/atan.rs similarity index 100% rename from libs/helper/l2math/core/atan.rs rename to helpers/l2math/core/atan.rs diff --git a/libs/helper/l2math/core/atan2.rs b/helpers/l2math/core/atan2.rs similarity index 100% rename from libs/helper/l2math/core/atan2.rs rename to helpers/l2math/core/atan2.rs diff --git a/libs/helper/l2math/core/atan2f.rs b/helpers/l2math/core/atan2f.rs similarity index 100% rename from libs/helper/l2math/core/atan2f.rs rename to helpers/l2math/core/atan2f.rs diff --git a/libs/helper/l2math/core/atanf.rs b/helpers/l2math/core/atanf.rs similarity index 100% rename from libs/helper/l2math/core/atanf.rs rename to helpers/l2math/core/atanf.rs diff --git a/libs/helper/l2math/core/atanh.rs b/helpers/l2math/core/atanh.rs similarity index 100% rename from libs/helper/l2math/core/atanh.rs rename to helpers/l2math/core/atanh.rs diff --git a/libs/helper/l2math/core/atanhf.rs b/helpers/l2math/core/atanhf.rs similarity index 100% rename from libs/helper/l2math/core/atanhf.rs rename to helpers/l2math/core/atanhf.rs diff --git a/libs/helper/l2math/core/cbrt.rs b/helpers/l2math/core/cbrt.rs similarity index 100% rename from libs/helper/l2math/core/cbrt.rs rename to helpers/l2math/core/cbrt.rs diff --git a/libs/helper/l2math/core/cbrtf.rs b/helpers/l2math/core/cbrtf.rs similarity index 100% rename from libs/helper/l2math/core/cbrtf.rs rename to helpers/l2math/core/cbrtf.rs diff --git a/libs/helper/l2math/core/ceil.rs b/helpers/l2math/core/ceil.rs similarity index 100% rename from libs/helper/l2math/core/ceil.rs rename to helpers/l2math/core/ceil.rs diff --git a/libs/helper/l2math/core/ceilf.rs b/helpers/l2math/core/ceilf.rs similarity index 100% rename from libs/helper/l2math/core/ceilf.rs rename to helpers/l2math/core/ceilf.rs diff --git a/libs/helper/l2math/core/copysign.rs b/helpers/l2math/core/copysign.rs similarity index 100% rename from libs/helper/l2math/core/copysign.rs rename to helpers/l2math/core/copysign.rs diff --git a/libs/helper/l2math/core/copysignf.rs b/helpers/l2math/core/copysignf.rs similarity index 100% rename from libs/helper/l2math/core/copysignf.rs rename to helpers/l2math/core/copysignf.rs diff --git a/libs/helper/l2math/core/cos.rs b/helpers/l2math/core/cos.rs similarity index 100% rename from libs/helper/l2math/core/cos.rs rename to helpers/l2math/core/cos.rs diff --git a/libs/helper/l2math/core/cosf.rs b/helpers/l2math/core/cosf.rs similarity index 100% rename from libs/helper/l2math/core/cosf.rs rename to helpers/l2math/core/cosf.rs diff --git a/libs/helper/l2math/core/cosh.rs b/helpers/l2math/core/cosh.rs similarity index 100% rename from libs/helper/l2math/core/cosh.rs rename to helpers/l2math/core/cosh.rs diff --git a/libs/helper/l2math/core/coshf.rs b/helpers/l2math/core/coshf.rs similarity index 100% rename from libs/helper/l2math/core/coshf.rs rename to helpers/l2math/core/coshf.rs diff --git a/libs/helper/l2math/core/erf.rs b/helpers/l2math/core/erf.rs similarity index 100% rename from libs/helper/l2math/core/erf.rs rename to helpers/l2math/core/erf.rs diff --git a/libs/helper/l2math/core/erff.rs b/helpers/l2math/core/erff.rs similarity index 100% rename from libs/helper/l2math/core/erff.rs rename to helpers/l2math/core/erff.rs diff --git a/libs/helper/l2math/core/exp.rs b/helpers/l2math/core/exp.rs similarity index 100% rename from libs/helper/l2math/core/exp.rs rename to helpers/l2math/core/exp.rs diff --git a/libs/helper/l2math/core/exp10.rs b/helpers/l2math/core/exp10.rs similarity index 100% rename from libs/helper/l2math/core/exp10.rs rename to helpers/l2math/core/exp10.rs diff --git a/libs/helper/l2math/core/exp10f.rs b/helpers/l2math/core/exp10f.rs similarity index 100% rename from libs/helper/l2math/core/exp10f.rs rename to helpers/l2math/core/exp10f.rs diff --git a/libs/helper/l2math/core/exp2.rs b/helpers/l2math/core/exp2.rs similarity index 100% rename from libs/helper/l2math/core/exp2.rs rename to helpers/l2math/core/exp2.rs diff --git a/libs/helper/l2math/core/exp2f.rs b/helpers/l2math/core/exp2f.rs similarity index 100% rename from libs/helper/l2math/core/exp2f.rs rename to helpers/l2math/core/exp2f.rs diff --git a/libs/helper/l2math/core/expf.rs b/helpers/l2math/core/expf.rs similarity index 100% rename from libs/helper/l2math/core/expf.rs rename to helpers/l2math/core/expf.rs diff --git a/libs/helper/l2math/core/expm1.rs b/helpers/l2math/core/expm1.rs similarity index 100% rename from libs/helper/l2math/core/expm1.rs rename to helpers/l2math/core/expm1.rs diff --git a/libs/helper/l2math/core/expm1f.rs b/helpers/l2math/core/expm1f.rs similarity index 100% rename from libs/helper/l2math/core/expm1f.rs rename to helpers/l2math/core/expm1f.rs diff --git a/libs/helper/l2math/core/expo2.rs b/helpers/l2math/core/expo2.rs similarity index 100% rename from libs/helper/l2math/core/expo2.rs rename to helpers/l2math/core/expo2.rs diff --git a/libs/helper/l2math/core/fabs.rs b/helpers/l2math/core/fabs.rs similarity index 100% rename from libs/helper/l2math/core/fabs.rs rename to helpers/l2math/core/fabs.rs diff --git a/libs/helper/l2math/core/fabsf.rs b/helpers/l2math/core/fabsf.rs similarity index 100% rename from libs/helper/l2math/core/fabsf.rs rename to helpers/l2math/core/fabsf.rs diff --git a/libs/helper/l2math/core/fdim.rs b/helpers/l2math/core/fdim.rs similarity index 100% rename from libs/helper/l2math/core/fdim.rs rename to helpers/l2math/core/fdim.rs diff --git a/libs/helper/l2math/core/fdimf.rs b/helpers/l2math/core/fdimf.rs similarity index 100% rename from libs/helper/l2math/core/fdimf.rs rename to helpers/l2math/core/fdimf.rs diff --git a/libs/helper/l2math/core/fenv.rs b/helpers/l2math/core/fenv.rs similarity index 100% rename from libs/helper/l2math/core/fenv.rs rename to helpers/l2math/core/fenv.rs diff --git a/libs/helper/l2math/core/floor.rs b/helpers/l2math/core/floor.rs similarity index 100% rename from libs/helper/l2math/core/floor.rs rename to helpers/l2math/core/floor.rs diff --git a/libs/helper/l2math/core/floorf.rs b/helpers/l2math/core/floorf.rs similarity index 100% rename from libs/helper/l2math/core/floorf.rs rename to helpers/l2math/core/floorf.rs diff --git a/libs/helper/l2math/core/fma.rs b/helpers/l2math/core/fma.rs similarity index 100% rename from libs/helper/l2math/core/fma.rs rename to helpers/l2math/core/fma.rs diff --git a/libs/helper/l2math/core/fmaf.rs b/helpers/l2math/core/fmaf.rs similarity index 100% rename from libs/helper/l2math/core/fmaf.rs rename to helpers/l2math/core/fmaf.rs diff --git a/libs/helper/l2math/core/fmax.rs b/helpers/l2math/core/fmax.rs similarity index 100% rename from libs/helper/l2math/core/fmax.rs rename to helpers/l2math/core/fmax.rs diff --git a/libs/helper/l2math/core/fmaxf.rs b/helpers/l2math/core/fmaxf.rs similarity index 100% rename from libs/helper/l2math/core/fmaxf.rs rename to helpers/l2math/core/fmaxf.rs diff --git a/libs/helper/l2math/core/fmin.rs b/helpers/l2math/core/fmin.rs similarity index 100% rename from libs/helper/l2math/core/fmin.rs rename to helpers/l2math/core/fmin.rs diff --git a/libs/helper/l2math/core/fminf.rs b/helpers/l2math/core/fminf.rs similarity index 100% rename from libs/helper/l2math/core/fminf.rs rename to helpers/l2math/core/fminf.rs diff --git a/libs/helper/l2math/core/fmod.rs b/helpers/l2math/core/fmod.rs similarity index 100% rename from libs/helper/l2math/core/fmod.rs rename to helpers/l2math/core/fmod.rs diff --git a/libs/helper/l2math/core/fmodf.rs b/helpers/l2math/core/fmodf.rs similarity index 100% rename from libs/helper/l2math/core/fmodf.rs rename to helpers/l2math/core/fmodf.rs diff --git a/libs/helper/l2math/core/frexp.rs b/helpers/l2math/core/frexp.rs similarity index 100% rename from libs/helper/l2math/core/frexp.rs rename to helpers/l2math/core/frexp.rs diff --git a/libs/helper/l2math/core/frexpf.rs b/helpers/l2math/core/frexpf.rs similarity index 100% rename from libs/helper/l2math/core/frexpf.rs rename to helpers/l2math/core/frexpf.rs diff --git a/libs/helper/l2math/core/hypot.rs b/helpers/l2math/core/hypot.rs similarity index 100% rename from libs/helper/l2math/core/hypot.rs rename to helpers/l2math/core/hypot.rs diff --git a/libs/helper/l2math/core/hypotf.rs b/helpers/l2math/core/hypotf.rs similarity index 100% rename from libs/helper/l2math/core/hypotf.rs rename to helpers/l2math/core/hypotf.rs diff --git a/libs/helper/l2math/core/ilogb.rs b/helpers/l2math/core/ilogb.rs similarity index 100% rename from libs/helper/l2math/core/ilogb.rs rename to helpers/l2math/core/ilogb.rs diff --git a/libs/helper/l2math/core/ilogbf.rs b/helpers/l2math/core/ilogbf.rs similarity index 100% rename from libs/helper/l2math/core/ilogbf.rs rename to helpers/l2math/core/ilogbf.rs diff --git a/libs/helper/l2math/core/j0.rs b/helpers/l2math/core/j0.rs similarity index 100% rename from libs/helper/l2math/core/j0.rs rename to helpers/l2math/core/j0.rs diff --git a/libs/helper/l2math/core/j0f.rs b/helpers/l2math/core/j0f.rs similarity index 100% rename from libs/helper/l2math/core/j0f.rs rename to helpers/l2math/core/j0f.rs diff --git a/libs/helper/l2math/core/j1.rs b/helpers/l2math/core/j1.rs similarity index 100% rename from libs/helper/l2math/core/j1.rs rename to helpers/l2math/core/j1.rs diff --git a/libs/helper/l2math/core/j1f.rs b/helpers/l2math/core/j1f.rs similarity index 100% rename from libs/helper/l2math/core/j1f.rs rename to helpers/l2math/core/j1f.rs diff --git a/libs/helper/l2math/core/jn.rs b/helpers/l2math/core/jn.rs similarity index 100% rename from libs/helper/l2math/core/jn.rs rename to helpers/l2math/core/jn.rs diff --git a/libs/helper/l2math/core/jnf.rs b/helpers/l2math/core/jnf.rs similarity index 100% rename from libs/helper/l2math/core/jnf.rs rename to helpers/l2math/core/jnf.rs diff --git a/libs/helper/l2math/core/k_cos.rs b/helpers/l2math/core/k_cos.rs similarity index 100% rename from libs/helper/l2math/core/k_cos.rs rename to helpers/l2math/core/k_cos.rs diff --git a/libs/helper/l2math/core/k_cosf.rs b/helpers/l2math/core/k_cosf.rs similarity index 100% rename from libs/helper/l2math/core/k_cosf.rs rename to helpers/l2math/core/k_cosf.rs diff --git a/libs/helper/l2math/core/k_expo2.rs b/helpers/l2math/core/k_expo2.rs similarity index 100% rename from libs/helper/l2math/core/k_expo2.rs rename to helpers/l2math/core/k_expo2.rs diff --git a/libs/helper/l2math/core/k_expo2f.rs b/helpers/l2math/core/k_expo2f.rs similarity index 100% rename from libs/helper/l2math/core/k_expo2f.rs rename to helpers/l2math/core/k_expo2f.rs diff --git a/libs/helper/l2math/core/k_sin.rs b/helpers/l2math/core/k_sin.rs similarity index 100% rename from libs/helper/l2math/core/k_sin.rs rename to helpers/l2math/core/k_sin.rs diff --git a/libs/helper/l2math/core/k_sinf.rs b/helpers/l2math/core/k_sinf.rs similarity index 100% rename from libs/helper/l2math/core/k_sinf.rs rename to helpers/l2math/core/k_sinf.rs diff --git a/libs/helper/l2math/core/k_tan.rs b/helpers/l2math/core/k_tan.rs similarity index 100% rename from libs/helper/l2math/core/k_tan.rs rename to helpers/l2math/core/k_tan.rs diff --git a/libs/helper/l2math/core/k_tanf.rs b/helpers/l2math/core/k_tanf.rs similarity index 100% rename from libs/helper/l2math/core/k_tanf.rs rename to helpers/l2math/core/k_tanf.rs diff --git a/libs/helper/l2math/core/ldexp.rs b/helpers/l2math/core/ldexp.rs similarity index 100% rename from libs/helper/l2math/core/ldexp.rs rename to helpers/l2math/core/ldexp.rs diff --git a/libs/helper/l2math/core/ldexpf.rs b/helpers/l2math/core/ldexpf.rs similarity index 100% rename from libs/helper/l2math/core/ldexpf.rs rename to helpers/l2math/core/ldexpf.rs diff --git a/libs/helper/l2math/core/lgamma.rs b/helpers/l2math/core/lgamma.rs similarity index 100% rename from libs/helper/l2math/core/lgamma.rs rename to helpers/l2math/core/lgamma.rs diff --git a/libs/helper/l2math/core/lgamma_r.rs b/helpers/l2math/core/lgamma_r.rs similarity index 100% rename from libs/helper/l2math/core/lgamma_r.rs rename to helpers/l2math/core/lgamma_r.rs diff --git a/libs/helper/l2math/core/lgammaf.rs b/helpers/l2math/core/lgammaf.rs similarity index 100% rename from libs/helper/l2math/core/lgammaf.rs rename to helpers/l2math/core/lgammaf.rs diff --git a/libs/helper/l2math/core/lgammaf_r.rs b/helpers/l2math/core/lgammaf_r.rs similarity index 100% rename from libs/helper/l2math/core/lgammaf_r.rs rename to helpers/l2math/core/lgammaf_r.rs diff --git a/libs/helper/l2math/core/ln.rs b/helpers/l2math/core/ln.rs similarity index 100% rename from libs/helper/l2math/core/ln.rs rename to helpers/l2math/core/ln.rs diff --git a/libs/helper/l2math/core/lnf.rs b/helpers/l2math/core/lnf.rs similarity index 100% rename from libs/helper/l2math/core/lnf.rs rename to helpers/l2math/core/lnf.rs diff --git a/libs/helper/l2math/core/log.rs b/helpers/l2math/core/log.rs similarity index 100% rename from libs/helper/l2math/core/log.rs rename to helpers/l2math/core/log.rs diff --git a/libs/helper/l2math/core/log10.rs b/helpers/l2math/core/log10.rs similarity index 100% rename from libs/helper/l2math/core/log10.rs rename to helpers/l2math/core/log10.rs diff --git a/libs/helper/l2math/core/log10f.rs b/helpers/l2math/core/log10f.rs similarity index 100% rename from libs/helper/l2math/core/log10f.rs rename to helpers/l2math/core/log10f.rs diff --git a/libs/helper/l2math/core/log1p.rs b/helpers/l2math/core/log1p.rs similarity index 100% rename from libs/helper/l2math/core/log1p.rs rename to helpers/l2math/core/log1p.rs diff --git a/libs/helper/l2math/core/log1pf.rs b/helpers/l2math/core/log1pf.rs similarity index 100% rename from libs/helper/l2math/core/log1pf.rs rename to helpers/l2math/core/log1pf.rs diff --git a/libs/helper/l2math/core/log2.rs b/helpers/l2math/core/log2.rs similarity index 100% rename from libs/helper/l2math/core/log2.rs rename to helpers/l2math/core/log2.rs diff --git a/libs/helper/l2math/core/log2f.rs b/helpers/l2math/core/log2f.rs similarity index 100% rename from libs/helper/l2math/core/log2f.rs rename to helpers/l2math/core/log2f.rs diff --git a/libs/helper/l2math/core/logf.rs b/helpers/l2math/core/logf.rs similarity index 100% rename from libs/helper/l2math/core/logf.rs rename to helpers/l2math/core/logf.rs diff --git a/libs/helper/l2math/core/modf.rs b/helpers/l2math/core/modf.rs similarity index 100% rename from libs/helper/l2math/core/modf.rs rename to helpers/l2math/core/modf.rs diff --git a/libs/helper/l2math/core/modff.rs b/helpers/l2math/core/modff.rs similarity index 100% rename from libs/helper/l2math/core/modff.rs rename to helpers/l2math/core/modff.rs diff --git a/libs/helper/l2math/core/nextafter.rs b/helpers/l2math/core/nextafter.rs similarity index 100% rename from libs/helper/l2math/core/nextafter.rs rename to helpers/l2math/core/nextafter.rs diff --git a/libs/helper/l2math/core/nextafterf.rs b/helpers/l2math/core/nextafterf.rs similarity index 100% rename from libs/helper/l2math/core/nextafterf.rs rename to helpers/l2math/core/nextafterf.rs diff --git a/libs/helper/l2math/core/pow.rs b/helpers/l2math/core/pow.rs similarity index 100% rename from libs/helper/l2math/core/pow.rs rename to helpers/l2math/core/pow.rs diff --git a/libs/helper/l2math/core/powf.rs b/helpers/l2math/core/powf.rs similarity index 100% rename from libs/helper/l2math/core/powf.rs rename to helpers/l2math/core/powf.rs diff --git a/libs/helper/l2math/core/rem_pio2.rs b/helpers/l2math/core/rem_pio2.rs similarity index 100% rename from libs/helper/l2math/core/rem_pio2.rs rename to helpers/l2math/core/rem_pio2.rs diff --git a/libs/helper/l2math/core/rem_pio2_large.rs b/helpers/l2math/core/rem_pio2_large.rs similarity index 100% rename from libs/helper/l2math/core/rem_pio2_large.rs rename to helpers/l2math/core/rem_pio2_large.rs diff --git a/libs/helper/l2math/core/rem_pio2f.rs b/helpers/l2math/core/rem_pio2f.rs similarity index 100% rename from libs/helper/l2math/core/rem_pio2f.rs rename to helpers/l2math/core/rem_pio2f.rs diff --git a/libs/helper/l2math/core/remainder.rs b/helpers/l2math/core/remainder.rs similarity index 100% rename from libs/helper/l2math/core/remainder.rs rename to helpers/l2math/core/remainder.rs diff --git a/libs/helper/l2math/core/remainderf.rs b/helpers/l2math/core/remainderf.rs similarity index 100% rename from libs/helper/l2math/core/remainderf.rs rename to helpers/l2math/core/remainderf.rs diff --git a/libs/helper/l2math/core/remquo.rs b/helpers/l2math/core/remquo.rs similarity index 100% rename from libs/helper/l2math/core/remquo.rs rename to helpers/l2math/core/remquo.rs diff --git a/libs/helper/l2math/core/remquof.rs b/helpers/l2math/core/remquof.rs similarity index 100% rename from libs/helper/l2math/core/remquof.rs rename to helpers/l2math/core/remquof.rs diff --git a/libs/helper/l2math/core/rint.rs b/helpers/l2math/core/rint.rs similarity index 100% rename from libs/helper/l2math/core/rint.rs rename to helpers/l2math/core/rint.rs diff --git a/libs/helper/l2math/core/rintf.rs b/helpers/l2math/core/rintf.rs similarity index 100% rename from libs/helper/l2math/core/rintf.rs rename to helpers/l2math/core/rintf.rs diff --git a/libs/helper/l2math/core/round.rs b/helpers/l2math/core/round.rs similarity index 100% rename from libs/helper/l2math/core/round.rs rename to helpers/l2math/core/round.rs diff --git a/libs/helper/l2math/core/roundf.rs b/helpers/l2math/core/roundf.rs similarity index 100% rename from libs/helper/l2math/core/roundf.rs rename to helpers/l2math/core/roundf.rs diff --git a/libs/helper/l2math/core/scalbn.rs b/helpers/l2math/core/scalbn.rs similarity index 100% rename from libs/helper/l2math/core/scalbn.rs rename to helpers/l2math/core/scalbn.rs diff --git a/libs/helper/l2math/core/scalbnf.rs b/helpers/l2math/core/scalbnf.rs similarity index 100% rename from libs/helper/l2math/core/scalbnf.rs rename to helpers/l2math/core/scalbnf.rs diff --git a/libs/helper/l2math/core/sin.rs b/helpers/l2math/core/sin.rs similarity index 100% rename from libs/helper/l2math/core/sin.rs rename to helpers/l2math/core/sin.rs diff --git a/libs/helper/l2math/core/sincos.rs b/helpers/l2math/core/sincos.rs similarity index 100% rename from libs/helper/l2math/core/sincos.rs rename to helpers/l2math/core/sincos.rs diff --git a/libs/helper/l2math/core/sincosf.rs b/helpers/l2math/core/sincosf.rs similarity index 100% rename from libs/helper/l2math/core/sincosf.rs rename to helpers/l2math/core/sincosf.rs diff --git a/libs/helper/l2math/core/sinf.rs b/helpers/l2math/core/sinf.rs similarity index 100% rename from libs/helper/l2math/core/sinf.rs rename to helpers/l2math/core/sinf.rs diff --git a/libs/helper/l2math/core/sinh.rs b/helpers/l2math/core/sinh.rs similarity index 100% rename from libs/helper/l2math/core/sinh.rs rename to helpers/l2math/core/sinh.rs diff --git a/libs/helper/l2math/core/sinhf.rs b/helpers/l2math/core/sinhf.rs similarity index 100% rename from libs/helper/l2math/core/sinhf.rs rename to helpers/l2math/core/sinhf.rs diff --git a/libs/helper/l2math/core/sqrt.rs b/helpers/l2math/core/sqrt.rs similarity index 100% rename from libs/helper/l2math/core/sqrt.rs rename to helpers/l2math/core/sqrt.rs diff --git a/libs/helper/l2math/core/sqrtf.rs b/helpers/l2math/core/sqrtf.rs similarity index 100% rename from libs/helper/l2math/core/sqrtf.rs rename to helpers/l2math/core/sqrtf.rs diff --git a/libs/helper/l2math/core/tan.rs b/helpers/l2math/core/tan.rs similarity index 100% rename from libs/helper/l2math/core/tan.rs rename to helpers/l2math/core/tan.rs diff --git a/libs/helper/l2math/core/tanf.rs b/helpers/l2math/core/tanf.rs similarity index 100% rename from libs/helper/l2math/core/tanf.rs rename to helpers/l2math/core/tanf.rs diff --git a/libs/helper/l2math/core/tanh.rs b/helpers/l2math/core/tanh.rs similarity index 100% rename from libs/helper/l2math/core/tanh.rs rename to helpers/l2math/core/tanh.rs diff --git a/libs/helper/l2math/core/tanhf.rs b/helpers/l2math/core/tanhf.rs similarity index 100% rename from libs/helper/l2math/core/tanhf.rs rename to helpers/l2math/core/tanhf.rs diff --git a/libs/helper/l2math/core/tgamma.rs b/helpers/l2math/core/tgamma.rs similarity index 100% rename from libs/helper/l2math/core/tgamma.rs rename to helpers/l2math/core/tgamma.rs diff --git a/libs/helper/l2math/core/tgammaf.rs b/helpers/l2math/core/tgammaf.rs similarity index 100% rename from libs/helper/l2math/core/tgammaf.rs rename to helpers/l2math/core/tgammaf.rs diff --git a/libs/helper/l2math/core/trunc.rs b/helpers/l2math/core/trunc.rs similarity index 100% rename from libs/helper/l2math/core/trunc.rs rename to helpers/l2math/core/trunc.rs diff --git a/libs/helper/l2math/core/truncf.rs b/helpers/l2math/core/truncf.rs similarity index 100% rename from libs/helper/l2math/core/truncf.rs rename to helpers/l2math/core/truncf.rs diff --git a/libs/helper/l2math/core/ulp.rs b/helpers/l2math/core/ulp.rs similarity index 100% rename from libs/helper/l2math/core/ulp.rs rename to helpers/l2math/core/ulp.rs diff --git a/libs/helper/l2math/lib.rs b/helpers/l2math/lib.rs similarity index 100% rename from libs/helper/l2math/lib.rs rename to helpers/l2math/lib.rs diff --git a/libs/helper/l2math/macros.rs b/helpers/l2math/macros.rs similarity index 100% rename from libs/helper/l2math/macros.rs rename to helpers/l2math/macros.rs diff --git a/libs/helper/l2math/types.rs b/helpers/l2math/types.rs similarity index 100% rename from libs/helper/l2math/types.rs rename to helpers/l2math/types.rs diff --git a/libs/helper/libtrig/Cargo.toml b/helpers/libtrig/Cargo.toml similarity index 100% rename from libs/helper/libtrig/Cargo.toml rename to helpers/libtrig/Cargo.toml diff --git a/libs/helper/libtrig/README.md b/helpers/libtrig/README.md similarity index 100% rename from libs/helper/libtrig/README.md rename to helpers/libtrig/README.md diff --git a/libs/helper/libtrig/angle.rs b/helpers/libtrig/angle.rs similarity index 100% rename from libs/helper/libtrig/angle.rs rename to helpers/libtrig/angle.rs diff --git a/libs/helper/libtrig/coords/coord2d.rs b/helpers/libtrig/coords/coord2d.rs similarity index 100% rename from libs/helper/libtrig/coords/coord2d.rs rename to helpers/libtrig/coords/coord2d.rs diff --git a/libs/helper/libtrig/coords/coord3d.rs b/helpers/libtrig/coords/coord3d.rs similarity index 100% rename from libs/helper/libtrig/coords/coord3d.rs rename to helpers/libtrig/coords/coord3d.rs diff --git a/libs/helper/libtrig/coords/mod.rs b/helpers/libtrig/coords/mod.rs similarity index 100% rename from libs/helper/libtrig/coords/mod.rs rename to helpers/libtrig/coords/mod.rs diff --git a/libs/helper/libtrig/lib.rs b/helpers/libtrig/lib.rs similarity index 100% rename from libs/helper/libtrig/lib.rs rename to helpers/libtrig/lib.rs diff --git a/libs/helper/libtrig/morenums/mod.rs b/helpers/libtrig/morenums/mod.rs similarity index 100% rename from libs/helper/libtrig/morenums/mod.rs rename to helpers/libtrig/morenums/mod.rs diff --git a/libs/helper/libtrig/morenums/u2/impls.rs b/helpers/libtrig/morenums/u2/impls.rs similarity index 100% rename from libs/helper/libtrig/morenums/u2/impls.rs rename to helpers/libtrig/morenums/u2/impls.rs diff --git a/libs/helper/libtrig/morenums/u2/mod.rs b/helpers/libtrig/morenums/u2/mod.rs similarity index 100% rename from libs/helper/libtrig/morenums/u2/mod.rs rename to helpers/libtrig/morenums/u2/mod.rs diff --git a/libs/helper/libtrig/morenums/u2/source.rs b/helpers/libtrig/morenums/u2/source.rs similarity index 100% rename from libs/helper/libtrig/morenums/u2/source.rs rename to helpers/libtrig/morenums/u2/source.rs diff --git a/libs/helper/libtrig/morenums/u2/tests.rs b/helpers/libtrig/morenums/u2/tests.rs similarity index 100% rename from libs/helper/libtrig/morenums/u2/tests.rs rename to helpers/libtrig/morenums/u2/tests.rs diff --git a/libs/helper/libtrig/morenums/u3/impls.rs b/helpers/libtrig/morenums/u3/impls.rs similarity index 100% rename from libs/helper/libtrig/morenums/u3/impls.rs rename to helpers/libtrig/morenums/u3/impls.rs diff --git a/libs/helper/libtrig/morenums/u3/mod.rs b/helpers/libtrig/morenums/u3/mod.rs similarity index 100% rename from libs/helper/libtrig/morenums/u3/mod.rs rename to helpers/libtrig/morenums/u3/mod.rs diff --git a/libs/helper/libtrig/morenums/u3/source.rs b/helpers/libtrig/morenums/u3/source.rs similarity index 100% rename from libs/helper/libtrig/morenums/u3/source.rs rename to helpers/libtrig/morenums/u3/source.rs diff --git a/libs/helper/libtrig/morenums/u3/tests.rs b/helpers/libtrig/morenums/u3/tests.rs similarity index 100% rename from libs/helper/libtrig/morenums/u3/tests.rs rename to helpers/libtrig/morenums/u3/tests.rs diff --git a/libs/helper/libtrig/pos2d.rs b/helpers/libtrig/pos2d.rs similarity index 100% rename from libs/helper/libtrig/pos2d.rs rename to helpers/libtrig/pos2d.rs diff --git a/libs/helper/libtrig/traits/float.rs b/helpers/libtrig/traits/float.rs similarity index 100% rename from libs/helper/libtrig/traits/float.rs rename to helpers/libtrig/traits/float.rs diff --git a/libs/helper/libtrig/traits/impls.rs b/helpers/libtrig/traits/impls.rs similarity index 100% rename from libs/helper/libtrig/traits/impls.rs rename to helpers/libtrig/traits/impls.rs diff --git a/libs/helper/libtrig/traits/mod.rs b/helpers/libtrig/traits/mod.rs similarity index 100% rename from libs/helper/libtrig/traits/mod.rs rename to helpers/libtrig/traits/mod.rs diff --git a/libs/helper/libtrig/traits/number.rs b/helpers/libtrig/traits/number.rs similarity index 100% rename from libs/helper/libtrig/traits/number.rs rename to helpers/libtrig/traits/number.rs diff --git a/libs/helper/libtrig/types.rs b/helpers/libtrig/types.rs similarity index 100% rename from libs/helper/libtrig/types.rs rename to helpers/libtrig/types.rs diff --git a/libs/helper/libtrig/vectors/mod.rs b/helpers/libtrig/vectors/mod.rs similarity index 100% rename from libs/helper/libtrig/vectors/mod.rs rename to helpers/libtrig/vectors/mod.rs diff --git a/libs/helper/libtrig/vectors/vec2d.rs b/helpers/libtrig/vectors/vec2d.rs similarity index 100% rename from libs/helper/libtrig/vectors/vec2d.rs rename to helpers/libtrig/vectors/vec2d.rs diff --git a/libs/helper/libtrig/vectors/vec3d.rs b/helpers/libtrig/vectors/vec3d.rs similarity index 100% rename from libs/helper/libtrig/vectors/vec3d.rs rename to helpers/libtrig/vectors/vec3d.rs diff --git a/libs/helper/macros/Cargo.toml b/helpers/macros/Cargo.toml similarity index 88% rename from libs/helper/macros/Cargo.toml rename to helpers/macros/Cargo.toml index 6a9d92c..91fb4a0 100644 --- a/libs/helper/macros/Cargo.toml +++ b/helpers/macros/Cargo.toml @@ -13,4 +13,4 @@ path = "lib.rs" [dependencies.mc] package = "macros-core" -path = "../macros-core" +path = "./macros-core" diff --git a/libs/helper/macros/README.md b/helpers/macros/README.md similarity index 100% rename from libs/helper/macros/README.md rename to helpers/macros/README.md diff --git a/libs/helper/macros/lib.rs b/helpers/macros/lib.rs similarity index 100% rename from libs/helper/macros/lib.rs rename to helpers/macros/lib.rs diff --git a/libs/helper/macros-core/Cargo.toml b/helpers/macros/macros-core/Cargo.toml similarity index 100% rename from libs/helper/macros-core/Cargo.toml rename to helpers/macros/macros-core/Cargo.toml diff --git a/libs/helper/macros-core/ffi/mod.rs b/helpers/macros/macros-core/ffi/mod.rs similarity index 100% rename from libs/helper/macros-core/ffi/mod.rs rename to helpers/macros/macros-core/ffi/mod.rs diff --git a/libs/helper/macros-core/func_mod/mod.rs b/helpers/macros/macros-core/func_mod/mod.rs similarity index 100% rename from libs/helper/macros-core/func_mod/mod.rs rename to helpers/macros/macros-core/func_mod/mod.rs diff --git a/libs/helper/macros-core/lib.rs b/helpers/macros/macros-core/lib.rs similarity index 100% rename from libs/helper/macros-core/lib.rs rename to helpers/macros/macros-core/lib.rs diff --git a/libs/helper/macros-core/mass_impl/args.rs b/helpers/macros/macros-core/mass_impl/args.rs similarity index 100% rename from libs/helper/macros-core/mass_impl/args.rs rename to helpers/macros/macros-core/mass_impl/args.rs diff --git a/libs/helper/macros-core/mass_impl/mod.rs b/helpers/macros/macros-core/mass_impl/mod.rs similarity index 100% rename from libs/helper/macros-core/mass_impl/mod.rs rename to helpers/macros/macros-core/mass_impl/mod.rs diff --git a/libs/helper/macros-core/mass_impl/variants.rs b/helpers/macros/macros-core/mass_impl/variants.rs similarity index 100% rename from libs/helper/macros-core/mass_impl/variants.rs rename to helpers/macros/macros-core/mass_impl/variants.rs diff --git a/libs/README.md b/libs/README.md deleted file mode 100644 index 10afd8a..0000000 --- a/libs/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Helper Libraries - -- [**`macros`**](./macros/) - Macros used throughout the project. -- [**`macros-core`**](./macros-core/) - Core functionality for the macros. diff --git a/libs/robot/main.rs b/libs/robot/main.rs deleted file mode 100644 index 28c73af..0000000 --- a/libs/robot/main.rs +++ /dev/null @@ -1,51 +0,0 @@ -use pylib::__init__::arc as arc_py_module; -use pylib::arc_robot_hardware::IO_OK; -use pyo3::prelude::*; -use std::io::Read; - -fn main() -> PyResult<()> { - // Initialize Python - pyo3::append_to_inittab!(arc_py_module); - pyo3::prepare_freethreaded_python(); - - // Setup hardware components - let (gamepad, gamepad_wrapper) = pylib::setup_wrapped_component!( - pylib::arc_robot_hardware::gamepad::impls::LogitechF310::default(); - pylib::__init__::hardware::gamepad::Gamepad - ); - let (op, op_wrapper) = pylib::setup_wrapped_component!(gamepad_wrapper; pylib::__init__::Op); - - // IO Thread - std::thread::spawn(move || { - use hardware::gamepad::MutableGamepad as _; - - std::thread::sleep(std::time::Duration::from_secs(1)); - gamepad.get_mut()?.set_a(true)?; - - std::thread::sleep(std::time::Duration::from_secs(1)); - gamepad.get_mut()?.set_a(false)?; - - std::thread::sleep(std::time::Duration::from_secs(1)); - gamepad.get_mut()?.set_a(true)?; - - std::thread::sleep(std::time::Duration::from_secs(1)); - op.get_mut()?.stop()?; - - op.get_mut()?.running_time(); - - IO_OK - }); - - // Main Thread - let mut code = String::new(); - std::fs::File::open("./examples/auto.py")?.read_to_string(&mut code)?; - - // Python (Main Thread) - Python::with_gil(move |py| { - let main_func: pyo3::Py = PyModule::from_code(py, &code, "auto.py", "")? - .getattr("main")? - .into(); - main_func.call1(py, (op_wrapper,))?; - Ok(()) - }) -} diff --git a/robot/Cargo.toml b/robot/Cargo.toml new file mode 100644 index 0000000..febe46a --- /dev/null +++ b/robot/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "arc-robot" +description = "ARC Robot" +repository.workspace = true +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true + +[lib] +name = "arc_robot" +path = "lib.rs" + +[dependencies.hardware] +package = "arc-robot-hardware" +path = "./hardware" + +[dependencies.pyruntime] +package = "arc-robot-python-runtime" +path = "./runtime" + +[dependencies.macros] +path = "../helpers/macros" +package = "macros" + +[dependencies.rocket] +version = "0.5" +features = [] + +[dependencies.log] +version = "0.4" diff --git a/libs/robot/README.md b/robot/README.md similarity index 100% rename from libs/robot/README.md rename to robot/README.md diff --git a/libs/robot/hardware/Cargo.toml b/robot/hardware/Cargo.toml similarity index 77% rename from libs/robot/hardware/Cargo.toml rename to robot/hardware/Cargo.toml index 6bb72e9..4a534c3 100644 --- a/libs/robot/hardware/Cargo.toml +++ b/robot/hardware/Cargo.toml @@ -11,7 +11,7 @@ license.workspace = true path = "lib.rs" [dependencies.l2math] -path = "../../helper/l2math" +path = "../../helpers/l2math" [dependencies.libtrig] -path = "../../helper/libtrig" +path = "../../helpers/libtrig" diff --git a/libs/robot/hardware/lib.rs b/robot/hardware/error.rs similarity index 93% rename from libs/robot/hardware/lib.rs rename to robot/hardware/error.rs index 72e91d3..0520c41 100644 --- a/libs/robot/hardware/lib.rs +++ b/robot/hardware/error.rs @@ -1,76 +1,70 @@ -#![doc = include_str!("../README.md")] -#![warn(missing_docs, unused, clippy::all, unsafe_code)] -#![deny(missing_debug_implementations)] - -pub mod gamepad; - -/// ### O_O -/// -/// A type that can be used to represent a result that is always `Ok` -/// -/// It is a shorthand for `Result<(), HardwareError>`. -pub const IO_OK: Result = Ok(()); - -/// An error that occurs when reading from or writing to a hardware component -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum HardwareError { - /// An IO error occurred - /// - /// This error is returned when reading from or writing to a hardware component fails. - IO, - /// Also an IO error, but this one is returned when the hardware component is disconnected. - /// - /// That means that the hardware component was connected when the program started, but it was - /// later disconnected. - Disconnected, - /// Some other error occurred - Other { - /// The error message - message: &'static str, - }, -} - -/// A result that occurs when reading or writing to a hardware component -pub type Result = core::result::Result; - -impl core::fmt::Display for HardwareError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::IO => write!(f, "IO error"), - Self::Disconnected => write!(f, "Gamepad disconnected"), - Self::Other { message } => write!(f, "{}", message), - } - } -} - -impl From<&'static str> for HardwareError { - #[inline] - fn from(message: &'static str) -> Self { - Self::Other { message } - } -} - -impl From for String { - #[inline] - fn from(error: HardwareError) -> Self { - format!("{}", error) - } -} - -impl From for &'static str { - #[inline] - fn from(error: HardwareError) -> Self { - match error { - HardwareError::IO => "IO error", - HardwareError::Disconnected => "Gamepad disconnected", - HardwareError::Other { message } => message, - } - } -} - -#[allow(unsafe_code)] -unsafe impl Send for HardwareError {} -#[allow(unsafe_code)] -unsafe impl Sync for HardwareError {} - -impl std::error::Error for HardwareError {} +/// ### O_O +/// +/// A type that can be used to represent a result that is always `Ok` +/// +/// It is a shorthand for `Result<(), HardwareError>`. +pub const IO_OK: Result = Ok(()); + +/// An error that occurs when reading from or writing to a hardware component +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum HardwareError { + /// An IO error occurred + /// + /// This error is returned when reading from or writing to a hardware component fails. + IO, + /// Also an IO error, but this one is returned when the hardware component is disconnected. + /// + /// That means that the hardware component was connected when the program started, but it was + /// later disconnected. + Disconnected, + /// Some other error occurred + Other { + /// The error message + message: &'static str, + }, +} + +/// A result that occurs when reading or writing to a hardware component +pub type Result = core::result::Result; + +impl core::fmt::Display for HardwareError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::IO => write!(f, "IO error"), + Self::Disconnected => write!(f, "Gamepad disconnected"), + Self::Other { message } => write!(f, "{}", message), + } + } +} + +impl From<&'static str> for HardwareError { + #[inline] + fn from(message: &'static str) -> Self { + Self::Other { message } + } +} + +impl From for String { + #[inline] + fn from(error: HardwareError) -> Self { + format!("{}", error) + } +} + +impl From for &'static str { + #[inline] + fn from(error: HardwareError) -> Self { + match error { + HardwareError::IO => "IO error", + HardwareError::Disconnected => "Gamepad disconnected", + HardwareError::Other { message } => message, + } + } +} + +#[allow(unsafe_code)] +unsafe impl Send for HardwareError {} +#[allow(unsafe_code)] +unsafe impl Sync for HardwareError {} + +impl std::error::Error for HardwareError {} diff --git a/libs/robot/hardware/gamepad/impls.rs b/robot/hardware/gamepad/impls.rs similarity index 61% rename from libs/robot/hardware/gamepad/impls.rs rename to robot/hardware/gamepad/impls.rs index f4fe64a..3edc94e 100644 --- a/libs/robot/hardware/gamepad/impls.rs +++ b/robot/hardware/gamepad/impls.rs @@ -216,3 +216,104 @@ impl MutableGamepad for LogitechF310 { Ok(()) } } + +/// A gamepad with no inputs. +/// +/// This is purely for stubbing. +#[repr(transparent)] +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Stub; + +impl Gamepad for Stub { + #[inline] + fn dpad(&self) -> crate::Result { + Ok(GamepadDpad::new(false, false, false, false)) + } + #[inline] + fn left_stick(&self) -> crate::Result { + Ok(GamepadStick::new(0.0, 0.0, false)) + } + #[inline] + fn right_stick(&self) -> crate::Result { + Ok(GamepadStick::new(0.0, 0.0, false)) + } + #[inline] + fn left_trigger(&self) -> crate::Result { + Ok(0.0) + } + #[inline] + fn right_trigger(&self) -> crate::Result { + Ok(0.0) + } + #[inline] + fn a(&self) -> crate::Result { + Ok(false) + } + #[inline] + fn b(&self) -> crate::Result { + Ok(false) + } + #[inline] + fn x(&self) -> crate::Result { + Ok(false) + } + #[inline] + fn y(&self) -> crate::Result { + Ok(false) + } + #[inline] + fn left_bumper(&self) -> crate::Result { + Ok(false) + } + #[inline] + fn right_bumper(&self) -> crate::Result { + Ok(false) + } +} + +impl MutableGamepad for Stub { + #[inline] + fn set_dpad(&mut self, _dpad: GamepadDpad) -> crate::Result { + Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) + } + #[inline] + fn set_left_stick(&mut self, _stick: GamepadStick) -> crate::Result { + Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) + } + #[inline] + fn set_right_stick(&mut self, _stick: GamepadStick) -> crate::Result { + Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) + } + #[inline] + fn set_left_trigger(&mut self, _trigger: f64) -> crate::Result { + Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) + } + #[inline] + fn set_right_trigger(&mut self, _trigger: f64) -> crate::Result { + Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) + } + #[inline] + fn set_a(&mut self, _value: bool) -> crate::Result { + Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) + } + #[inline] + fn set_b(&mut self, _value: bool) -> crate::Result { + Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) + } + #[inline] + fn set_x(&mut self, _value: bool) -> crate::Result { + Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) + } + #[inline] + fn set_y(&mut self, _value: bool) -> crate::Result { + Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) + } + #[inline] + fn set_left_bumper(&mut self, _value: bool) -> crate::Result { + Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) + } + #[inline] + fn set_right_bumper(&mut self, _value: bool) -> crate::Result { + Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) + } +} diff --git a/libs/robot/hardware/gamepad/mod.rs b/robot/hardware/gamepad/mod.rs similarity index 100% rename from libs/robot/hardware/gamepad/mod.rs rename to robot/hardware/gamepad/mod.rs diff --git a/robot/hardware/lib.rs b/robot/hardware/lib.rs new file mode 100644 index 0000000..d940dd0 --- /dev/null +++ b/robot/hardware/lib.rs @@ -0,0 +1,20 @@ +#![doc = include_str!("../README.md")] +#![warn(missing_docs, unused, clippy::all, unsafe_code)] +#![deny(missing_debug_implementations)] + +pub mod gamepad; +mod error; + +pub use error::*; + +#[derive(Debug, Clone)] +pub struct HardwareMap { + +} + +impl HardwareMap { + pub fn init() -> Self { + Self { + } + } +} diff --git a/robot/lib.rs b/robot/lib.rs new file mode 100644 index 0000000..6ddece5 --- /dev/null +++ b/robot/lib.rs @@ -0,0 +1,6 @@ +#![doc = include_str!("./README.md")] + +#![warn(missing_docs, unused, clippy::all, unsafe_code)] +#![deny(missing_debug_implementations)] + +pub use pyruntime; diff --git a/libs/robot/Cargo.toml b/robot/runtime/Cargo.toml similarity index 51% rename from libs/robot/Cargo.toml rename to robot/runtime/Cargo.toml index cd1548e..4b18415 100644 --- a/libs/robot/Cargo.toml +++ b/robot/runtime/Cargo.toml @@ -1,19 +1,19 @@ [package] -name = "arc-robot" -description = "ARC Robot server" +name = "arc-robot-python-runtime" +description = "ARC Robot Server Python Runtime" repository.workspace = true version.workspace = true edition.workspace = true authors.workspace = true license.workspace = true -[[bin]] -name = "arc-robot" -path = "main.rs" +[lib] +name = "arc_robot_server_python_runtime" +path = "lib.rs" [dependencies.hardware] package = "arc-robot-hardware" -path = "./hardware" +path = "../hardware" [dependencies.pylib] package = "arc-pylib" @@ -22,8 +22,3 @@ path = "../../arc" [dependencies.pyo3] version = "0.20.0" features = ["extension-module"] - -# [dependencies.rustpython_vm] -# git = "https://github.com/RustPython/RustPython" -# rev = "0fab6e606379cfda346c82fa2f3960d0449b40e9" -# package = "rustpython-vm" diff --git a/robot/runtime/lib.rs b/robot/runtime/lib.rs new file mode 100644 index 0000000..656b06e --- /dev/null +++ b/robot/runtime/lib.rs @@ -0,0 +1,90 @@ +#![doc = include_str!("../README.md")] + +#![warn(missing_docs, unused, clippy::all, unsafe_code)] +#![deny(missing_debug_implementations)] + +use pyo3::prelude::*; + +#[derive(Debug, Clone)] +struct RuntimeOpMode { + hardware: hardware::HardwareMap, + name: String +} + +impl RuntimeOpMode { + fn start(&mut self, hardware: &mut hardware::HardwareMap) -> Result<()> { + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub enum Error { + OpNotFound, +} + +pub type Result = core::result::Result; + +#[derive(Debug)] +pub struct PyRuntime { + ops: Vec, + thread: Option>, +} + +impl PyRuntime { + pub fn init() -> Self { + Self { + ops: Vec::new(), + thread: None, + } + } + pub fn start(&mut self, name: Name) -> Result<()> { + let name = name.to_string(); + let op = self.ops.iter_mut() + .find(|op| op.name == name) + .ok_or(Error::OpNotFound)?; + op.start(&mut self.hardware) + } +} + +// fn main() -> PyResult<()> { + // Setup hardware components + // let (gamepad, gamepad_wrapper) = pylib::setup_wrapped_component!( + // pylib::arc_robot_hardware::gamepad::impls::LogitechF310::default(); + // pylib::__init__::hardware::gamepad::Gamepad + // ); + // let (op, op_wrapper) = pylib::setup_wrapped_component!(gamepad_wrapper; pylib::__init__::Op); + + // IO Thread +// std::thread::spawn(move || { +// use hardware::gamepad::MutableGamepad as _; +// +// std::thread::sleep(std::time::Duration::from_secs(1)); +// gamepad.get_mut()?.set_a(true)?; +// +// std::thread::sleep(std::time::Duration::from_secs(1)); +// gamepad.get_mut()?.set_a(false)?; +// +// std::thread::sleep(std::time::Duration::from_secs(1)); +// gamepad.get_mut()?.set_a(true)?; +// +// std::thread::sleep(std::time::Duration::from_secs(1)); +// op.get_mut()?.stop()?; +// +// op.get_mut()?.running_time(); +// +// IO_OK +// }); + + // Main Thread +// let mut code = String::new(); +// std::fs::File::open("./examples/auto.py")?.read_to_string(&mut code)?; +// +// // Python (Main Thread) +// Python::with_gil(move |py| { +// let main_func: pyo3::Py = PyModule::from_code(py, &code, "auto.py", "")? +// .getattr("main")? +// .into(); +// main_func.call1(py, (op_wrapper,))?; +// Ok(()) +// }) +// } diff --git a/libs/scripts/__init__.py b/scripts/__init__.py similarity index 87% rename from libs/scripts/__init__.py rename to scripts/__init__.py index 19d75e8..ebd3e8b 100644 --- a/libs/scripts/__init__.py +++ b/scripts/__init__.py @@ -1,9 +1,9 @@ -from libs.scripts.build import build -from libs.scripts.clean import clean -from libs.scripts.doc import doc -from libs.scripts.fmt import fmt -from libs.scripts.run import run -from libs.scripts.test import test +from scripts.build import build +from scripts.clean import clean +from scripts.doc import doc +from scripts.fmt import fmt +from scripts.run import run +from scripts.test import test def run_cmd(cmd: str, cwd: str, args: list[str]) -> str | int | None: if cmd == "help" or cmd == "--help" or cmd == "-h": return hlp() diff --git a/libs/scripts/build.py b/scripts/build.py similarity index 100% rename from libs/scripts/build.py rename to scripts/build.py diff --git a/libs/scripts/clean.py b/scripts/clean.py similarity index 100% rename from libs/scripts/clean.py rename to scripts/clean.py diff --git a/libs/scripts/doc.py b/scripts/doc.py similarity index 100% rename from libs/scripts/doc.py rename to scripts/doc.py diff --git a/libs/scripts/fmt.py b/scripts/fmt.py similarity index 100% rename from libs/scripts/fmt.py rename to scripts/fmt.py diff --git a/libs/scripts/run.py b/scripts/run.py similarity index 100% rename from libs/scripts/run.py rename to scripts/run.py diff --git a/libs/scripts/test.py b/scripts/test.py similarity index 100% rename from libs/scripts/test.py rename to scripts/test.py diff --git a/server/Cargo.toml b/server/Cargo.toml new file mode 100644 index 0000000..f4f72bf --- /dev/null +++ b/server/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "arc-robot-server" +description = "ARC Robot Server" +repository.workspace = true +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +build = "comptime.rs" + +[lib] +name = "arc_rs" +path = "lib.rs" + +[[bin]] +name = "arc-robot-server" +path = "main.rs" + +[dependencies.robot] +package = "arc-robot" +path = "../robot" + +# [dependencies.pyruntime] +# package = "arc-robot-python-runtime" +# path = "./runtime" + +# [dependencies.pylib] +# package = "arc-pylib" +# path = "../../arc" +# +# [dependencies.pyo3] +# version = "0.20.0" +# features = ["extension-module"] + +[dependencies.rocket] +version = "0.5" +features = [] + +[dependencies.log] +version = "0.4" diff --git a/server/README.md b/server/README.md new file mode 100644 index 0000000..e69de29 diff --git a/server/comptime.rs b/server/comptime.rs new file mode 100644 index 0000000..545d1db --- /dev/null +++ b/server/comptime.rs @@ -0,0 +1,7 @@ +use std::process::Command; + +fn main() { + let output = Command::new("git").args(&["rev-parse", "HEAD"]).output().unwrap(); + let git_hash = String::from_utf8(output.stdout).unwrap(); + println!("cargo:rustc-env=GIT_HASH={}", git_hash); +} \ No newline at end of file diff --git a/server/html/.gitignore b/server/html/.gitignore new file mode 100644 index 0000000..e66d9fc --- /dev/null +++ b/server/html/.gitignore @@ -0,0 +1,3 @@ +# Duplicates that I have here for the sake of simplicity +/*.ico +/*.png diff --git a/server/html/SourceCodePro-Bold.ttf b/server/html/SourceCodePro-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4653b76c80383cbce2452ddbdab318ab3fdab83c GIT binary patch literal 120316 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"; +/// let html = HTML.handlebars("title", "Hello, World!"); +/// assert_eq!(html, "

Hello, World!

"); +/// ``` +pub trait HtmlHandlebarsInjector { + /// Replaces `{{__KEY__}}` with the value of `key`. + fn handlebars, V: AsRef>(self, key: K, value: V) -> Output; +} + +impl HtmlHandlebarsInjector for &str { + fn handlebars, V: AsRef>(self, key: K, value: V) -> String { + self.replace(&format!("{{{{__{}__}}}}", key.as_ref().to_uppercase()), value.as_ref()) + } +} + +impl HtmlHandlebarsInjector for String { + fn handlebars, V: AsRef>(self, key: K, value: V) -> String { + self.replace(&format!("{{{{__{}__}}}}", key.as_ref().to_uppercase()), value.as_ref()) + } +} + +/// `style.css` file. +#[get("/style.css")] +pub fn style() -> crate::html::Response<&'static str> { + res!(@CSS #200 include_str!("./style.css")) +} + +/// `SourceCodePro-Bold.ttf` file. +#[get("/SourceCodePro-Bold.ttf")] +pub fn font() -> crate::html::Response<&'static [u8]> { + res!(@TTF #200 include_bytes!("./SourceCodePro-Bold.ttf")) +} + +/// `favicon.ico` file. +#[get("/favicon.ico?")] +pub fn favicon(s: Option) -> crate::html::Response<&'static [u8]> { + let s256 = include_bytes!("../../docs/logo256.ico"); + let s192 = include_bytes!("../../docs/logo192.ico"); + let s64 = include_bytes!("../../docs/logo64.ico"); + res!(@Icon #200 match s { + Some(192) => s192, + Some(64) => s64, + _ => s256, + }) +} + +/// `logo_white_a.png` file. +#[get("/logo_white_a.png")] +pub fn logo_white_a() -> crate::html::Response<&'static [u8]> { + res!(@PNG #200 include_bytes!("../../docs/logo_white_a.png")) +} diff --git a/server/html/code/index.html b/server/html/code/index.html new file mode 100644 index 0000000..8ad9869 --- /dev/null +++ b/server/html/code/index.html @@ -0,0 +1,42 @@ + + + + + + + + ARC + + +
+ +
+ + +
+ +
+
+
{{__DEBUG__}}
+ + diff --git a/server/html/error.html b/server/html/error.html new file mode 100644 index 0000000..09a39f3 --- /dev/null +++ b/server/html/error.html @@ -0,0 +1,14 @@ + + + + + + + + ARC: Error + + +

{{__MESSAGE__}}: {{__ERROR__}}

+
{{__DEBUG__}}
+ + \ No newline at end of file diff --git a/server/html/error.rs b/server/html/error.rs new file mode 100644 index 0000000..9c13289 --- /dev/null +++ b/server/html/error.rs @@ -0,0 +1,83 @@ +use crate::prelude::*; + +/// The result type used by this crate. +pub type Result = core::result::Result; + +/// An enum of all possible errors that can occur in this crate. +#[non_exhaustive] +pub enum Error { + /// An IO error occurred. + Io(std::io::Error), + /// A UTF-8 parsing error occurred. + Utf8(std::string::FromUtf8Error), + /// An error occurred that isn't covered by the other variants. + Other(Box) +} + +impl From for Error { + fn from(e: std::io::Error) -> Self { + Self::Io(e) + } +} + +impl From for Error { + fn from(e: std::string::FromUtf8Error) -> Self { + Self::Utf8(e) + } +} + +impl From> for Error { + fn from(e: Box) -> Self { + Self::Other(e) + } +} + +impl<'a> From<&'a str> for Error { + fn from(e: &'a str) -> Self { + Self::Other(Box::new(e.to_string())) + } +} + +impl From for Error { + fn from(e: String) -> Self { + Self::Other(Box::new(e)) + } +} + +impl core::fmt::Debug for Error { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::Io(e) => write!(f, "Io({:?})", e), + Self::Utf8(e) => write!(f, "Utf8({:?})", e), + Self::Other(e) => write!(f, "Other({:?})", e.to_string()), + } + } +} + +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::Other(e) => write!(f, "{}", e.to_string()), + other => write!(f, "{}", other), + } + } +} + +impl std::error::Error for Error {} + +/// The HTML for the error page. +pub const ERROR_HTML: &'static str = include_str!("./error.html"); + +impl<'r, 'o: 'r> rocket::response::Responder<'r, 'o> for Error { + fn respond_to(self, request: &'r rocket::Request<'_>) -> rocket::response::Result<'o> { + let error = format!("{}", self); + let html = ERROR_HTML + .handlebars("message", "An Internal Server Error Occurred") + .handlebars("error", &error) + .handlebars("debug", &super::SERVER); + rocket::Response::build_from(html.respond_to(request)?) + .header(rocket::http::ContentType::HTML) + .status(rocket::http::Status::InternalServerError) + .ok() + } +} diff --git a/server/html/index.html b/server/html/index.html new file mode 100644 index 0000000..8c2bf54 --- /dev/null +++ b/server/html/index.html @@ -0,0 +1,32 @@ + + + + + + + + ARC + + +
+ +

ARC LogoRC: + Advanced + Robot + Controller +

+ + ARC is a feature complete framework for writing robot code.
+ It is designed to be easy to use, and easy to understand.
+ It is also designed to be modular, so that you can use only the parts you need.
+ ARC is also designed to be easy to extend, + so that you can add your own functionality to it. +
+
{{__DEBUG__}}
+ + diff --git a/server/html/macros.rs b/server/html/macros.rs new file mode 100644 index 0000000..1609c57 --- /dev/null +++ b/server/html/macros.rs @@ -0,0 +1,177 @@ +/// A macro to create a new error. +/// +/// This macro is used to create a new error and return it from a function. +/// +/// # Example +/// +/// ```rust +/// +#[macro_export] +macro_rules! err { + ($($args:tt)*) => {{ + $crate::__internals::log::error!($($args)*); + return Err(format!($($args)*).into()); + }}; +} + +pub use err; + +#[macro_export] +macro_rules! res { + (@$content_type:expr; #$code:expr; $body:expr) => ($crate::res!(! + $content_type; $code; $body + )); + (@$content_type:expr; #$code:literal $body:expr) => ($crate::res!(! + $content_type; $crate::html::macros::get_status($code); $body + )); + (@$content_type:expr; #$code:ident $body:expr) => ($crate::res!(! + $content_type; $crate::html::macros::Status::$code; $body + )); + + (@$content_type:ident #$code:expr; $body:expr) => ($crate::res!(! + $crate::html::macros::ContentType::$content_type; + $code; $body + )); + (@$content_type:ident #$code:literal $body:expr) => ($crate::res!(! + $crate::html::macros::ContentType::$content_type; + $crate::html::macros::get_status($code); $body + )); + (@$content_type:ident #$code:ident $body:expr) => ($crate::res!(! + $crate::html::macros::ContentType::$content_type; + $crate::html::macros::Status::$code; $body + )); + + + (#$code:expr; @$content_type:expr; $body:expr) => ($crate::res!(@@ + $content_type; $code; $body + )); + (#$code:literal @$content_type:expr; $body:expr) => ($crate::res!(@@ + $content_type; $crate::html::macros::get_status($code); $body + )); + (#$code:ident @$content_type:expr; $body:expr) => ($crate::res!(! + $content_type; $crate::html::macros::Status::$code; $body + )); + + (#$code:expr; @$content_type:ident $body:expr) => ($crate::res!(! + $crate::html::macros::ContentType::$content_type; $code; $body + )); + (#$code:literal @$content_type:ident $body:expr) => ($crate::res!(! + $crate::html::macros::ContentType::$content_type; + $crate::html::macros::get_status($code); $body + )); + (#$code:ident @$content_type:ident $body:expr) => ($crate::res!(! + $crate::html::macros::ContentType::$content_type; + $crate::html::macros::Status::$code; $body + )); + + (#$code:expr; $body:expr) => ($crate::res!(! + $crate::html::macros::ContentType::Plain; $code; $body + )); + (#$code:literal $body:expr) => ($crate::res!(! + $crate::html::macros::ContentType::Plain; + $crate::html::macros::get_status($code); $body + )); + (#$code:ident $body:expr) => ($crate::res!(! + $crate::html::macros::ContentType::Plain; + $crate::html::macros::Status::$code; $body + )); + + + (@$content_type:ident $body:expr) => ($crate::res!(! + $crate::html::macros::ContentType::$content_type; + $crate::html::macros::Status::Ok; $body + )); + (@$content_type:expr; $body:expr) => ($crate::res!(! + $content_type; $crate::html::macros::Status::Ok; $body + )); + + + ($body:expr) => ($crate::res!(! + $crate::html::macros::ContentType::Plain; + $crate::html::macros::Status::Ok; + $body + )); + (! $content_type: expr; $code: expr; $body: expr ) => ( + ($content_type, ($code, $body)) + ) +} + +pub use res; + +pub use rocket::http::ContentType; +pub use rocket::http::Status; +pub const fn get_status(code: u16) -> Status { + match code { + 100 => Status::Continue, + 101 => Status::SwitchingProtocols, + 102 => Status::Processing, + // 103 => Status::EarlyHints, + + 200 => Status::Ok, + 201 => Status::Created, + 202 => Status::Accepted, + 203 => Status::NonAuthoritativeInformation, + 204 => Status::NoContent, + 205 => Status::ResetContent, + 206 => Status::PartialContent, + 207 => Status::MultiStatus, + 208 => Status::AlreadyReported, + 226 => Status::ImUsed, + + 300 => Status::MultipleChoices, + 301 => Status::MovedPermanently, + 302 => Status::Found, + 303 => Status::SeeOther, + 304 => Status::NotModified, + 305 => Status::UseProxy, + // 306 => Status::SwitchProxy, + 307 => Status::TemporaryRedirect, + 308 => Status::PermanentRedirect, + + 400 => Status::BadRequest, + 401 => Status::Unauthorized, + 402 => Status::PaymentRequired, + 403 => Status::Forbidden, + 404 => Status::NotFound, + 405 => Status::MethodNotAllowed, + 406 => Status::NotAcceptable, + 407 => Status::ProxyAuthenticationRequired, + 408 => Status::RequestTimeout, + 409 => Status::Conflict, + 410 => Status::Gone, + 411 => Status::LengthRequired, + 412 => Status::PreconditionFailed, + 413 => Status::PayloadTooLarge, + 414 => Status::UriTooLong, + 415 => Status::UnsupportedMediaType, + 416 => Status::RangeNotSatisfiable, + 417 => Status::ExpectationFailed, + 418 => Status::ImATeapot, + 421 => Status::MisdirectedRequest, + 422 => Status::UnprocessableEntity, + 423 => Status::Locked, + 424 => Status::FailedDependency, + // 425 => Status::TooEarly, + 426 => Status::UpgradeRequired, + 428 => Status::PreconditionRequired, + 429 => Status::TooManyRequests, + 431 => Status::RequestHeaderFieldsTooLarge, + 451 => Status::UnavailableForLegalReasons, + + 500 => Status::InternalServerError, + 501 => Status::NotImplemented, + 502 => Status::BadGateway, + 503 => Status::ServiceUnavailable, + 504 => Status::GatewayTimeout, + 505 => Status::HttpVersionNotSupported, + 506 => Status::VariantAlsoNegotiates, + 507 => Status::InsufficientStorage, + 508 => Status::LoopDetected, + 510 => Status::NotExtended, + 511 => Status::NetworkAuthenticationRequired, + + _ => Status::new(code) + } +} + +pub use ::log; diff --git a/server/html/mod.rs b/server/html/mod.rs new file mode 100644 index 0000000..f60e6ec --- /dev/null +++ b/server/html/mod.rs @@ -0,0 +1,56 @@ +use crate::prelude::*; + +#[doc(hidden)] +pub mod assets; +#[doc(hidden)] +pub mod macros; +#[doc(hidden)] +pub mod error; + +#[cfg(debug_assertions)] +const __SERVER: &str = concat!( + "ARC v", env!("CARGO_PKG_VERSION"), + "-", env!("GIT_HASH") +); +#[cfg(not(debug_assertions))] +const __SERVER: &str = concat!( + "ARC v", env!("CARGO_PKG_VERSION") +); + +/// Version of the software. +/// +/// In debug builds, this is the version number and git hash. +/// In release builds, this is just the version number. +pub const SERVER: &str = __SERVER; + +pub fn make_server_identifier() -> rocket::config::Ident { + rocket::config::Ident::try_new(SERVER) + .expect("Failed to create rocket ident") +} + +pub type Response = (rocket::http::ContentType, (rocket::http::Status, T)); + +pub type Result = error::Result; + +#[doc(hidden)] +const SERVER_ERR: &str = concat!("The server encountered an internal", +" error and was unable to complete your request."); + +#[rocket::catch(default)] +pub fn error_catcher(status: rocket::http::Status, _req: &rocket::Request) -> Response { + // If it is a server error (500+) + if (status.code - 400) >= 100 { + return crate::res!(@HTML #500 error::ERROR_HTML + .handlebars("message", "An Internal Server Error Occurred") + .handlebars("error", SERVER_ERR) + .handlebars("debug", SERVER) + ); + } + // Otherwise client error + let error = format!("{}", status); + crate::res!(@HTML #status; error::ERROR_HTML + .handlebars("message", &error) + .handlebars("error", &error) + .handlebars("debug", SERVER) + ) +} diff --git a/server/html/style.css b/server/html/style.css new file mode 100644 index 0000000..7afec65 --- /dev/null +++ b/server/html/style.css @@ -0,0 +1,66 @@ +:root { + --footer-height: 30px; + --scrollbar-width: 20px; + + --c-complete-black: #000000; + --c-black: #06070E; + --c-gray: #2d2d2d; + --c-dark-white: #cccccc; + --c-blue: #00A7E1; + --c-green: #84DD63; + --c-red: #DF2935; + --c-yellow: #FFA400; + --c-transparent: #0000; +} + +@font-face { + font-family: 'SourceCodePro-Bold'; + src: url('./SourceCodePro-Bold.ttf') format('truetype'); + font-weight: bold; + font-style: normal; +} + +::-webkit-scrollbar { + width: var(--scrollbar-width); +} + +::-webkit-scrollbar-track { + background: var(--c-transparent) +} + +::-webkit-scrollbar-thumb { + background: var(--c-dark-white) +} + +body { + font-family: 'SourceCodePro-Bold'; + background-color: var(--c-gray); + color: var(--c-dark-white); + position: relative; + top: 0px; + left: 0px; + min-height: calc(99vh - var(--footer-height)); +} + +footer { + position: absolute; + bottom: 0px; + width: 100%; + align-self: center; + align-items: center; + text-align: center; +} + +h1 { + font-size: 2.5em; +} + +main { + position: relative; + padding-top: 0px; + padding-left: 0px; + padding-right: 0px; + padding-bottom: var(--footer-height); + width: 50%; + left: 25%; +} diff --git a/server/lib.rs b/server/lib.rs new file mode 100644 index 0000000..32944d9 --- /dev/null +++ b/server/lib.rs @@ -0,0 +1,32 @@ +pub mod html; + +#[macro_export] +macro_rules! inc { () => (use $crate::prelude::*; use $crate::*; ) } + +pub mod prelude { + pub use crate::html::assets::HtmlHandlebarsInjector; + pub use crate::html::macros::{err, res}; + pub use ::rocket::{ + async_main, async_run, async_test, async_trait, + build, + catch, catchers, + delete, + export, + get, + head, + launch, + main, + options, + patch, post, put, + routes, route, + uri, + }; + #[macro_export(local_inner_macros)] + macro_rules! include_hbs { + ($file:expr $(,)?) => ( + ::core::include_str!($file) + .handlebars("debug", $crate::html::SERVER) + ) + } + pub use include_hbs; +} diff --git a/server/main.rs b/server/main.rs new file mode 100644 index 0000000..e046ce0 --- /dev/null +++ b/server/main.rs @@ -0,0 +1,71 @@ +use robot::pyruntime::PyRuntime; + +use arc_rs::html::*; +arc_rs::inc!(); + +#[cfg(debug_assertions)] +const SAVE_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/code"); +#[cfg(not(debug_assertions))] +const SAVE_DIR: &str = "/arc/code"; + +#[cfg(debug_assertions)] +const TEMP_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tmp"); +#[cfg(not(debug_assertions))] +const TEMP_DIR: &str = "/arc/tmp"; + +#[get("/")] +fn index() -> Response { + res!(@HTML #200 include_hbs!("./html/index.html")) +} + +#[get("/")] +fn code() -> Response { + res!(@HTML #200 include_hbs!("./html/code/index.html")) +} + +#[post("/upload?", format = "plain", data = "")] +async fn upload<'a>(name: &'a str, input: rocket::Data<'_>) -> Result { + use rocket::data::ToByteUnit; + let location = format!("{SAVE_DIR}/{}", name); + let file = match rocket::tokio::fs::File::create(location).await { + Err(e) => return Ok(res!(@JSON #500 format!( + "{{\"ok\":false,\"msg\":\"Failed to create file: {e}\"}}" + ))), + Ok(file) => file, + }; + if let Err(e) = input.open(1.megabytes()).stream_to(file).await { + return Ok(res!(@JSON #500 format!( + "{{\"ok\":false,\"msg\":\"Failed to write to file: {e}\"}}" + ))); + } + Ok(res!("{\"ok\":true}".into())) +} + +fn main() { + let mut python_runtime = PyRuntime::init(); + + python_runtime.start("auto").unwrap(); +} + +// #[rocket::main] +// async fn main() { +// let python_runtime = PyRuntime::init(); +// +// let config = rocket::Config { +// temp_dir: TEMP_DIR.into(), +// ident: make_server_identifier(), +// ..Default::default() +// }; +// +// let rocket = rocket::custom(&config) +// .mount("/", routes![index]) +// .mount("/", routes![assets::style, assets::favicon, assets::font, assets::logo_white_a]) +// .mount("/code", routes![code, upload]) +// .register("/", catchers![error_catcher]) +// .ignite() +// .await +// .expect("Failed to start server"); +// rocket.launch() +// .await +// .expect("Failed to launch server"); +// } \ No newline at end of file diff --git a/libs/uploader/Cargo.toml b/uploader/Cargo.toml similarity index 100% rename from libs/uploader/Cargo.toml rename to uploader/Cargo.toml diff --git a/libs/uploader/main.rs b/uploader/main.rs similarity index 100% rename from libs/uploader/main.rs rename to uploader/main.rs From b73b883cf3caeffd438654f2fb79758c8b8c50e6 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sun, 24 Dec 2023 11:21:09 -0800 Subject: [PATCH 87/93] renamed log1p to a more obvious ln1p --- helpers/l2math/core.rs | 2 +- helpers/l2math/core/acosh.rs | 4 ++-- helpers/l2math/core/acoshf.rs | 4 ++-- helpers/l2math/core/asinh.rs | 4 ++-- helpers/l2math/core/asinhf.rs | 4 ++-- helpers/l2math/core/atanh.rs | 6 +++--- helpers/l2math/core/atanhf.rs | 6 +++--- helpers/l2math/core/ln.rs | 4 ++-- helpers/l2math/core/{log1p.rs => ln1p.rs} | 4 ++-- helpers/l2math/core/{log1pf.rs => ln1pf.rs} | 4 ++-- helpers/l2math/core/lnf.rs | 4 ++-- helpers/libtrig/Cargo.toml | 7 +++++-- helpers/libtrig/traits/impls.rs | 4 ++-- 13 files changed, 30 insertions(+), 27 deletions(-) rename helpers/l2math/core/{log1p.rs => ln1p.rs} (98%) rename helpers/l2math/core/{log1pf.rs => ln1pf.rs} (97%) diff --git a/helpers/l2math/core.rs b/helpers/l2math/core.rs index 0f1da76..6417d23 100644 --- a/helpers/l2math/core.rs +++ b/helpers/l2math/core.rs @@ -102,7 +102,7 @@ import!(pub fabs, fabsf, fdim, fdimf, floor, floorf, fma, fmaf, fmax, fmaxf, fmi import!(pub hypot, hypotf); import!(pub ilogb, ilogbf); import!(pub j0, j0f, j1, j1f, jn, jnf); -import!(pub ldexp, ldexpf, lgamma, lgamma_r, lgammaf, lgammaf_r, ln, lnf, log, log10, log10f, log1p, log1pf, log2, log2f, logf); +import!(pub ldexp, ldexpf, lgamma, lgamma_r, lgammaf, lgammaf_r, ln, lnf, log, log10, log10f, ln1p, ln1pf, log2, log2f, logf); import!(pub modf, modff); import!(pub nextafter, nextafterf); import!(pub pow, powf); diff --git a/helpers/l2math/core/acosh.rs b/helpers/l2math/core/acosh.rs index 6a5ad25..0ed21cf 100644 --- a/helpers/l2math/core/acosh.rs +++ b/helpers/l2math/core/acosh.rs @@ -1,6 +1,6 @@ use crate::{Float64, Radian64}; -use super::{log, log1p, sqrt}; +use super::{log, ln1p, sqrt}; consts!{ const LN2: Float64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ @@ -21,7 +21,7 @@ pub extern "C" fn acosh(x: Float64) -> Radian64 { if e < 0x3ff + 1 { /* |x| < 2, up to 2ulp error in [1,1.125] */ - return log1p(x - 1.0 + sqrt((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); + return ln1p(x - 1.0 + sqrt((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); } if e < 0x3ff + 26 { /* |x| < 0x1p26 */ diff --git a/helpers/l2math/core/acoshf.rs b/helpers/l2math/core/acoshf.rs index d108f56..3e576e1 100644 --- a/helpers/l2math/core/acoshf.rs +++ b/helpers/l2math/core/acoshf.rs @@ -1,6 +1,6 @@ use crate::{Float32, Radian32}; -use super::{log1pf, logf, sqrtf}; +use super::{ln1pf, logf, sqrtf}; consts!{ const LN2: Float32 = 0.693147180559945309417232121458176568; @@ -20,7 +20,7 @@ pub extern "C" fn acoshf(x: Float32) -> Radian32 { if a < 0x3f800000 + (1 << 23) { /* |x| < 2, invalid if x < 1 or nan */ /* up to 2ulp error in [1,1.125] */ - return log1pf(x - 1.0 + sqrtf((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); + return ln1pf(x - 1.0 + sqrtf((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); } if a < 0x3f800000 + (12 << 23) { /* |x| < 0x1p12 */ diff --git a/helpers/l2math/core/asinh.rs b/helpers/l2math/core/asinh.rs index d81af00..f1b3507 100644 --- a/helpers/l2math/core/asinh.rs +++ b/helpers/l2math/core/asinh.rs @@ -1,6 +1,6 @@ use crate::{Float64, Radian64}; -use super::{log, log1p, sqrt}; +use super::{log, ln1p, sqrt}; consts!{ const LN2: Float64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ @@ -30,7 +30,7 @@ pub extern "C" fn asinh(mut x: Float64) -> Radian64 { x = log(2.0 * x + 1.0 / (sqrt(x * x + 1.0) + x)); } else if e >= 0x3ff - 26 { /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ - x = log1p(x + x * x / (sqrt(x * x + 1.0) + 1.0)); + x = ln1p(x + x * x / (sqrt(x * x + 1.0) + 1.0)); } else { /* |x| < 0x1p-26, raise inexact if x != 0 */ let x1p120 = Float64::from_bits(0x4770000000000000); diff --git a/helpers/l2math/core/asinhf.rs b/helpers/l2math/core/asinhf.rs index 28b7ecc..0f32672 100644 --- a/helpers/l2math/core/asinhf.rs +++ b/helpers/l2math/core/asinhf.rs @@ -1,6 +1,6 @@ use crate::{Float32, Radian32}; -use super::{log1pf, logf, sqrtf}; +use super::{ln1pf, logf, sqrtf}; use core::f32::consts::LN_2; @@ -27,7 +27,7 @@ pub extern "C" fn asinhf(mut x: Float32) -> Radian32 { x = logf(2.0 * x + 1.0 / (sqrtf(x * x + 1.0) + x)); } else if i >= 0x3f800000 - (12 << 23) { /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ - x = log1pf(x + x * x / (sqrtf(x * x + 1.0) + 1.0)); + x = ln1pf(x + x * x / (sqrtf(x * x + 1.0) + 1.0)); } else { /* |x| < 0x1p-12, raise inexact if x!=0 */ let x1p120 = Float32::from_bits(0x7b800000); diff --git a/helpers/l2math/core/atanh.rs b/helpers/l2math/core/atanh.rs index 11bb17b..39a73fd 100644 --- a/helpers/l2math/core/atanh.rs +++ b/helpers/l2math/core/atanh.rs @@ -1,6 +1,6 @@ use crate::{Float64, Float32, Radian64}; -use super::log1p; +use super::ln1p; /* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ /// Inverse hyperbolic tangent @@ -25,11 +25,11 @@ pub extern "C" fn atanh(x: Float64) -> Radian64 { } } else { /* |x| < 0.5, up to 1.7ulp error */ - y = 0.5 * log1p(2.0 * y + 2.0 * y * y / (1.0 - y)); + y = 0.5 * ln1p(2.0 * y + 2.0 * y * y / (1.0 - y)); } } else { /* avoid overflow */ - y = 0.5 * log1p(2.0 * (y / (1.0 - y))); + y = 0.5 * ln1p(2.0 * (y / (1.0 - y))); } if sign { diff --git a/helpers/l2math/core/atanhf.rs b/helpers/l2math/core/atanhf.rs index 7537111..077c7f7 100644 --- a/helpers/l2math/core/atanhf.rs +++ b/helpers/l2math/core/atanhf.rs @@ -1,6 +1,6 @@ use crate::{Float32, Radian32}; -use super::log1pf; +use super::ln1pf; /* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ /// Inverse hyperbolic tangent @@ -25,11 +25,11 @@ pub extern "C" fn atanhf(mut x: Float32) -> Radian32 { } } else { /* |x| < 0.5, up to 1.7ulp error */ - x = 0.5 * log1pf(2.0 * x + 2.0 * x * x / (1.0 - x)); + x = 0.5 * ln1pf(2.0 * x + 2.0 * x * x / (1.0 - x)); } } else { /* avoid overflow */ - x = 0.5 * log1pf(2.0 * (x / (1.0 - x))); + x = 0.5 * ln1pf(2.0 * (x / (1.0 - x))); } if sign { diff --git a/helpers/l2math/core/ln.rs b/helpers/l2math/core/ln.rs index 6fa4fec..16fdde5 100644 --- a/helpers/l2math/core/ln.rs +++ b/helpers/l2math/core/ln.rs @@ -1,11 +1,11 @@ use crate::Float64; -use super::log1p; +use super::ln1p; /// Return the natural logarithm of `x`. #[inline] #[export_name = "__l2math_ln"] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ln(x: Float64) -> Float64 { - log1p(x - 1.) + ln1p(x - 1.) } diff --git a/helpers/l2math/core/log1p.rs b/helpers/l2math/core/ln1p.rs similarity index 98% rename from helpers/l2math/core/log1p.rs rename to helpers/l2math/core/ln1p.rs index 91719de..90d512e 100644 --- a/helpers/l2math/core/log1p.rs +++ b/helpers/l2math/core/ln1p.rs @@ -69,9 +69,9 @@ const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ } /// Return the natural logarithm of `1+x`. -#[export_name = "__l2math_log1p"] +#[export_name = "__l2math_ln1p"] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn log1p(x: Float64) -> Float64 { +pub extern "C" fn ln1p(x: Float64) -> Float64 { let mut ui: u64 = x.to_bits(); let mut f: Float64 = 0.; let mut c: Float64 = 0.; diff --git a/helpers/l2math/core/log1pf.rs b/helpers/l2math/core/ln1pf.rs similarity index 97% rename from helpers/l2math/core/log1pf.rs rename to helpers/l2math/core/ln1pf.rs index 3487d33..4cc75a4 100644 --- a/helpers/l2math/core/log1pf.rs +++ b/helpers/l2math/core/ln1pf.rs @@ -23,9 +23,9 @@ const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ } /// Return the natural logarithm of `1+x`. -#[export_name = "__l2math_log1pf"] +#[export_name = "__l2math_ln1pf"] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn log1pf(x: Float32) -> Float32 { +pub fn ln1pf(x: Float32) -> Float32 { let mut ui: u32 = x.to_bits(); let mut f: Float32 = 0.; let mut c: Float32 = 0.; diff --git a/helpers/l2math/core/lnf.rs b/helpers/l2math/core/lnf.rs index 1d4bdc5..1f5f223 100644 --- a/helpers/l2math/core/lnf.rs +++ b/helpers/l2math/core/lnf.rs @@ -1,11 +1,11 @@ use crate::Float32; -use super::log1pf; +use super::ln1pf; /// Return the natural logarithm of `x`. #[inline] #[export_name = "__l2math_lnf"] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lnf(x: Float32) -> Float32 { - log1pf(x - 1.) + ln1pf(x - 1.) } diff --git a/helpers/libtrig/Cargo.toml b/helpers/libtrig/Cargo.toml index d9e8f42..3119fb5 100644 --- a/helpers/libtrig/Cargo.toml +++ b/helpers/libtrig/Cargo.toml @@ -7,11 +7,14 @@ edition.workspace = true authors.workspace = true license.workspace = true +[lib] +path = "lib.rs" + [dependencies.macros] path = "../macros" [dependencies.l2math] path = "../l2math" -[lib] -path = "lib.rs" +[features] +unstable = ["l2math/unstable"] diff --git a/helpers/libtrig/traits/impls.rs b/helpers/libtrig/traits/impls.rs index babe6dc..6044ca8 100644 --- a/helpers/libtrig/traits/impls.rs +++ b/helpers/libtrig/traits/impls.rs @@ -31,7 +31,7 @@ impl Sqrt for Float64 { #[allow(unused)] impl Float for Float64 { simpl!(floor ceil round trunc abs => fabs exp exp2 ln log2 log10 cbrt - tan asin acos atan exp_m1 => expm1 ln_1p => log1p + tan asin acos atan exp_m1 => expm1 ln_1p => ln1p sinh cosh tanh asinh acosh atanh); #[inline] #[must_use] @@ -110,7 +110,7 @@ impl Float for Float32 { simpl!(floor => floorf ceil => ceilf round => roundf trunc => truncf abs => fabsf exp => expf exp2 => exp2f ln => lnf log2 => log2f log10 => log10f cbrt => cbrtf tan => tanf asin => asinf - acos => acosf atan => atanf exp_m1 => expm1f ln_1p => log1pf + acos => acosf atan => atanf exp_m1 => expm1f ln_1p => ln1pf sinh => sinhf cosh => coshf tanh => tanhf asinh => asinhf acosh => acoshf atanh => atanhf); #[inline] From 02e927f5d00535d4f4e6cd1d47a68c144b3d02ec Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sun, 24 Dec 2023 15:34:03 -0800 Subject: [PATCH 88/93] more --- arc/Cargo.toml | 8 +- arc/__init__.pyi | 67 ++- arc/__init__.rs | 12 +- arc/hardware/__init__.pyi | 29 ++ arc/hardware/dcmotor.pyi | 11 + arc/hardware/gamepad.pyi | 7 +- arc/hardware/gamepad.rs | 82 +-- arc/hardware/telemetry.pyi | 22 + arc/lib.rs | 2 +- arc/math/__init__.pyi | 127 +++++ arc/math/angle.pyi | 23 +- arc/math/pos2d.pyi | 9 +- arc/math/vec2d.pyi | 21 +- arc/math/vec4d.pyi | 105 ++++ examples/auto.py | 25 - examples/mecanum_basic_teleop.py | 24 + examples/tank_drive_teleop.py | 28 ++ examples/util/drive.py | 141 ++++-- examples/util/mecanum_drive.py | 14 - helpers/l2math/consts.rs | 151 ++++++ helpers/l2math/lib.rs | 2 + robot/Cargo.toml | 6 +- robot/{hardware => core}/Cargo.toml | 7 +- robot/{hardware => core}/error.rs | 49 +- .../gamepad/mod.rs => core/gamepad.rs} | 467 +++++++++--------- robot/core/hardware.rs | 24 + robot/core/hardware/dcmotor.rs | 16 + robot/core/hardware/uuid.rs | 83 ++++ robot/core/lib.rs | 49 ++ robot/core/telemetry.rs | 20 + robot/hardware/gamepad/impls.rs | 319 ------------ robot/hardware/lib.rs | 20 - robot/{runtime => pyruntime}/Cargo.toml | 6 +- robot/{runtime => pyruntime}/lib.rs | 82 +-- scripts/doc.py | 2 +- server/main.rs | 6 +- 36 files changed, 1213 insertions(+), 853 deletions(-) create mode 100644 arc/hardware/dcmotor.pyi create mode 100644 arc/hardware/telemetry.pyi create mode 100644 arc/math/vec4d.pyi delete mode 100644 examples/auto.py create mode 100644 examples/mecanum_basic_teleop.py create mode 100644 examples/tank_drive_teleop.py delete mode 100644 examples/util/mecanum_drive.py create mode 100644 helpers/l2math/consts.rs rename robot/{hardware => core}/Cargo.toml (66%) rename robot/{hardware => core}/error.rs (62%) rename robot/{hardware/gamepad/mod.rs => core/gamepad.rs} (86%) create mode 100644 robot/core/hardware.rs create mode 100644 robot/core/hardware/dcmotor.rs create mode 100644 robot/core/hardware/uuid.rs create mode 100644 robot/core/lib.rs create mode 100644 robot/core/telemetry.rs delete mode 100644 robot/hardware/gamepad/impls.rs delete mode 100644 robot/hardware/lib.rs rename robot/{runtime => pyruntime}/Cargo.toml (80%) rename robot/{runtime => pyruntime}/lib.rs (58%) diff --git a/arc/Cargo.toml b/arc/Cargo.toml index 38421bd..c298517 100644 --- a/arc/Cargo.toml +++ b/arc/Cargo.toml @@ -11,13 +11,13 @@ license.workspace = true path = "lib.rs" crate-type = ["cdylib", "rlib"] -[dependencies.arc_robot_hardware] -package = "arc-robot-hardware" -path = "../robot/hardware" +[dependencies.arc_robot_core] +package = "arc-robot-core" +path = "../robot/core" [dependencies.libtrig] -package = "libtrig" path = "../helpers/libtrig" +package = "libtrig" [dependencies.pyo3] #!!! Important - DO NOT ENABLE extension-module FEATURE HERE!!! diff --git a/arc/__init__.pyi b/arc/__init__.pyi index a7b3cd7..5f8d7a8 100644 --- a/arc/__init__.pyi +++ b/arc/__init__.pyi @@ -7,7 +7,9 @@ It is also designed to be modular, so that you can use only the parts you need. Additionally, it is easy to extend, so that you can add your own functionality to it. """ -from .hardware.gamepad import Gamepad as _Gamepad +from .hardware import HardwareMap as _HardwareMap +from .hardware import Telemetry as _Telemetry +from .hardware import Gamepad as _Gamepad import typing as _typing RunResult = _typing.Union[bool, int, str, None] @@ -35,20 +37,73 @@ class Op(object): def running(self) -> bool: """Whether or not the operation is running.""" ... + + @property + def hardwareMap(self) -> _HardwareMap: + """The hardware map for the robot.""" + ... + + @property + def telemetry(self) -> _Telemetry: + """The telemetry system for the robot.""" + ... + + def debug(self, *message: object) -> None: + """ + Sends a debug message using the telemetry system. -def Auto(name: str) -> _typing.Callable[[_typing.Callable[[Op], RunResult]], _typing.Callable[[Op], RunResult]]: - """Decorator for an autonomous operation.""" + See `op.telemetry.debug` for more information. + """ + self.telemetry.debug(*message) + + def log(self, *message: object) -> None: + """ + Logs message using the telemetry system. + + See `op.telemetry.log` for more information. + """ + self.telemetry.log(*message) + +__OpFunc = _typing.Callable[[Op], RunResult] +__OpAnnotation = _typing.Callable[[__OpFunc], __OpFunc] + +def Auto(name: str) -> __OpAnnotation: + """ + Decorator for an autonomous operation. + + ### Example: + ```python + @Auto("My Auto") + def main(op: Op): + op.log("Hello, world!") + ``` + """ ... -def Teleop(name: str) -> _typing.Callable[[_typing.Callable[[Op], RunResult]], _typing.Callable[[Op], RunResult]]: - """Decorator for a teleop operation.""" +def Teleop(name: str) -> __OpAnnotation: + """ + Decorator for a teleop operation. + + ### Example: + ```python + @Teleop("My Teleop") + def main(op: Op): + op.log("Hello, world!") + ``` + """ ... def sleep(seconds: float) -> None: - """Sleeps for the specified number of seconds.""" + """ + Sleeps for the specified number of seconds. + + This is a blocking operation, which means NOTHING will happen until the specified time has passed. + """ ... OK: RunResult = True """ A built-in `RunResult` that indicates that the `Op` completed successfully. + +See `RunResult` for more information. """ diff --git a/arc/__init__.rs b/arc/__init__.rs index 0a40b6d..cf272fd 100644 --- a/arc/__init__.rs +++ b/arc/__init__.rs @@ -28,16 +28,6 @@ pub struct OpHolder { start_time: std::time::Instant, } -impl Default for OpHolder { - fn default() -> Self { - Self { - running: true.into(), - gamepad: hardware::gamepad::Gamepad::default(), - start_time: std::time::Instant::now(), - } - } -} - impl OpHolder { /// Returns whether the op mode is running /// @@ -107,7 +97,7 @@ threadsafe::thread_safe!(OpHolder); /// # } /// ``` #[pyclass] -#[derive(Default, Debug, Clone)] +#[derive(Debug, Clone)] pub struct Op(ThreadSafe); impl crate::PyWrappedComponent for Op { diff --git a/arc/hardware/__init__.pyi b/arc/hardware/__init__.pyi index ed03d78..fbb2712 100644 --- a/arc/hardware/__init__.pyi +++ b/arc/hardware/__init__.pyi @@ -9,4 +9,33 @@ This module includes: - Servos """ +from .telemetry import * from .gamepad import * +from .dcmotor import * +import typing as _typing +import abc as _abc + +class HardwareComponent(_abc.ABC): + """Represents a basic hardware component.""" + + @_abc.abstractproperty + def uuid(self) -> str: + """The UUID of this hardware component.""" + ... + +class HardwareMap(object): + """ + Represents a map of hardware components. + + This class is used to get hardware components by name. + """ + + HC = _typing.TypeVar("HC", bound = HardwareComponent) + def __getitem__(self, type: type[HC]) -> _typing.Callable[[str], HC]: + """ + Get a hardware component by name. + + This method will return a function that takes a name and returns the hardware component with the specified name. + If no hardware component with the specified name exists, then this method will raise a KeyError. + """ + ... diff --git a/arc/hardware/dcmotor.pyi b/arc/hardware/dcmotor.pyi new file mode 100644 index 0000000..6a29b18 --- /dev/null +++ b/arc/hardware/dcmotor.pyi @@ -0,0 +1,11 @@ +from arc.hardware import HardwareComponent as _HardwareComponent + +class DcMotor(_HardwareComponent): + @property + def uuid(self) -> str: ... + def power(self, power: float) -> None: + """ + Set the power of the motor. + + If the power is negative, the motor will spin backwards. + """ \ No newline at end of file diff --git a/arc/hardware/gamepad.pyi b/arc/hardware/gamepad.pyi index e0b1e8d..c65b64c 100644 --- a/arc/hardware/gamepad.pyi +++ b/arc/hardware/gamepad.pyi @@ -5,9 +5,14 @@ This module contains the Gamepad class, and related classes. 99% of the time, you will only need the Gamepad class. """ -class Gamepad(object): +from arc.hardware import HardwareComponent as _HardwareComponent + +class Gamepad(_HardwareComponent): """Represents a gamepad with buttons x, y, a, and b.""" + @property + def uuid(self) -> str: ... + @property def dpad(self) -> GamepadDpad: """The state of the dpad.""" diff --git a/arc/hardware/gamepad.rs b/arc/hardware/gamepad.rs index c1d93b6..4fa0d53 100644 --- a/arc/hardware/gamepad.rs +++ b/arc/hardware/gamepad.rs @@ -3,7 +3,7 @@ //! Python identifier: `arc.hardware.gamepad` use crate::threadsafe::ThreadSafe; -use arc_robot_hardware::gamepad::{self as gp, Gamepad as _}; +use arc_robot_core::gamepad as gp; use pyo3::prelude::*; /// The struct that actually contains the necessary data for the gamepad @@ -16,61 +16,6 @@ pub struct GamepadHolder { gamepad: Box, } -impl Default for GamepadHolder { - fn default() -> Self { - Self { - gamepad: Box::new(gp::impls::Stub), - } - } -} - -macro_rules! i { - (g $n: ident $ty:ty) => { - #[inline] - fn $n(&self) -> $crate::arc_robot_hardware::Result<$ty> { - self.gamepad.$n() - } - }; - (s $n: ident $ty:ty) => { - #[inline] - fn $n(&mut self, value: $ty) -> $crate::arc_robot_hardware::Result { - self.gamepad.$n(value) - } - }; -} - -impl gp::Gamepad for GamepadHolder { - i!(g a bool); - i!(g b bool); - i!(g x bool); - i!(g y bool); - i!(g left_bumper bool); - i!(g right_bumper bool); - i!(g back bool); - i!(g start bool); - i!(g left_trigger f64); - i!(g right_trigger f64); - i!(g left_stick gp::GamepadStick); - i!(g right_stick gp::GamepadStick); - i!(g dpad gp::GamepadDpad); -} - -impl gp::MutableGamepad for GamepadHolder { - i!(s set_a bool); - i!(s set_b bool); - i!(s set_x bool); - i!(s set_y bool); - i!(s set_left_bumper bool); - i!(s set_right_bumper bool); - i!(s set_back bool); - i!(s set_start bool); - i!(s set_left_trigger f64); - i!(s set_right_trigger f64); - i!(s set_left_stick gp::GamepadStick); - i!(s set_right_stick gp::GamepadStick); - i!(s set_dpad gp::GamepadDpad); -} - crate::threadsafe::thread_safe!(GamepadHolder); /// A struct that holds the state of a gamepad stick @@ -202,7 +147,7 @@ impl GamepadDpad { /// This struct should not be used to modify the gamepad data. For that, /// use the `GamepadHolder` struct. #[pyclass] -#[derive(Default, Debug, Clone)] +#[derive(Debug, Clone)] pub struct Gamepad(ThreadSafe); impl crate::PyWrappedComponent for Gamepad { @@ -236,6 +181,7 @@ impl Gamepad { pub fn get_dpad(&self) -> core::result::Result { self.0 .get()? + .gamepad .dpad() .map(|d| GamepadDpad(d)) .map_err(|e| e.into()) @@ -246,6 +192,7 @@ impl Gamepad { pub fn get_left_stick(&self) -> core::result::Result { self.0 .get()? + .gamepad .left_stick() .map(|d| GamepadStick(d)) .map_err(|e| e.into()) @@ -256,50 +203,51 @@ impl Gamepad { pub fn get_right_stick(&self) -> core::result::Result { self.0 .get()? + .gamepad .right_stick() .map(|d| GamepadStick(d)) .map_err(|e| e.into()) } /// Returns the state of the left trigger pub fn get_left_trigger(&self) -> core::result::Result { - self.0.get()?.left_trigger().map_err(|e| e.into()) + self.0.get()?.gamepad.left_trigger().map_err(|e| e.into()) } /// Returns the state of the right trigger pub fn get_right_trigger(&self) -> core::result::Result { - self.0.get()?.right_trigger().map_err(|e| e.into()) + self.0.get()?.gamepad.right_trigger().map_err(|e| e.into()) } /// Is the 'x' button pressed? pub fn get_x(&self) -> core::result::Result { - self.0.get()?.x().map_err(|e| e.into()) + self.0.get()?.gamepad.x().map_err(|e| e.into()) } /// Is the 'y' button pressed? pub fn get_y(&self) -> core::result::Result { - self.0.get()?.y().map_err(|e| e.into()) + self.0.get()?.gamepad.y().map_err(|e| e.into()) } /// Is the 'a' button pressed? pub fn get_a(&self) -> core::result::Result { - self.0.get()?.a().map_err(|e| e.into()) + self.0.get()?.gamepad.a().map_err(|e| e.into()) } /// Is the 'b' button pressed? pub fn get_b(&self) -> core::result::Result { - self.0.get()?.b().map_err(|e| e.into()) + self.0.get()?.gamepad.b().map_err(|e| e.into()) } /// Is the left bumper pressed? pub fn get_left_bumper(&self) -> core::result::Result { - self.0.get()?.left_bumper().map_err(|e| e.into()) + self.0.get()?.gamepad.left_bumper().map_err(|e| e.into()) } /// Is the right bumper pressed? pub fn get_right_bumper(&self) -> core::result::Result { - self.0.get()?.right_bumper().map_err(|e| e.into()) + self.0.get()?.gamepad.right_bumper().map_err(|e| e.into()) } /// A non-standard 'back' button pub fn get_back(&self) -> core::result::Result { - self.0.get()?.back().map_err(|e| e.into()) + self.0.get()?.gamepad.back().map_err(|e| e.into()) } /// A non-standard 'start' button pub fn get_start(&self) -> core::result::Result { - self.0.get()?.start().map_err(|e| e.into()) + self.0.get()?.gamepad.start().map_err(|e| e.into()) } } diff --git a/arc/hardware/telemetry.pyi b/arc/hardware/telemetry.pyi new file mode 100644 index 0000000..124cbdc --- /dev/null +++ b/arc/hardware/telemetry.pyi @@ -0,0 +1,22 @@ +class Telemetry(object): + """ + The telemetry system. + + This is used to send messages to the driver station. + """ + + def debug(self, *message: object) -> None: + """ + Sends a debug message to the telemetry system. + + This always sends the message, regardless whether or not the client is going to log it. + """ + ... + + def log(self, *message: object) -> None: + """ + Sends a log message to the telemetry system. + + This always sends the message, and the client will also always log it. + """ + ... diff --git a/arc/lib.rs b/arc/lib.rs index 42b34f7..d4635ff 100644 --- a/arc/lib.rs +++ b/arc/lib.rs @@ -3,7 +3,7 @@ #![deny(missing_debug_implementations)] #[doc(hidden)] -pub use arc_robot_hardware; +pub use arc_robot_core; pub mod __init__; mod macros; diff --git a/arc/math/__init__.pyi b/arc/math/__init__.pyi index 84cd7fe..ec420e3 100644 --- a/arc/math/__init__.pyi +++ b/arc/math/__init__.pyi @@ -1,3 +1,130 @@ +""" +Mathematical utilities for arc. + +Includes: +- Angle +- Vector2D +- Vector4D +- Position2D +""" + +Float64 = float +"""A floating point number with 64 bits of precision.""" +Radian64 = float +"""An angle in radians with 64 bits of precision.""" +Degree64 = float +"""An angle in degrees with 64 bits of precision.""" + +EGAMMA: Float64 +"""The Euler-Mascheroni constant (γ)""" +FRAC_1_SQRT_3: Float64 +"""1/sqrt(3)""" +FRAC_1_SQRT_PI: Float64 +"""1/sqrt(π)""" +PHI: Float64 +"""The golden ratio (φ)""" +SQRT_3: Float64 +"""sqrt(3)""" +E: Float64 +"""Euler’s number (e)""" +FRAC_1_PI: Float64 +"""1/π""" +FRAC_1_SQRT_2: Float64 +"""1/sqrt(2)""" +FRAC_2_PI: Float64 +"""2/π""" +FRAC_2_SQRT_PI: Float64 +"""2/sqrt(π)""" +FRAC_PI_2: Float64 +"""π/2""" +FRAC_PI_3: Float64 +"""π/3""" +FRAC_PI_4: Float64 +"""π/4""" +FRAC_PI_6: Float64 +"""π/6""" +FRAC_PI_8: Float64 +"""π/8""" +LN_2: Float64 +"""ln(2)""" +LN_10: Float64 +"""ln(10)""" +LOG2_10: Float64 +"""log2(10)""" +LOG2_E: Float64 +"""log2(e)""" +LOG10_2: Float64 +"""log10(2)""" +LOG10_E: Float64 +"""log10(e)""" +PI: Float64 +"""Archimedes’ constant (π)""" +SQRT_2: Float64 +"""sqrt(2)""" +TAU: Float64 +"""The full circle constant (τ)""" + +def acos(x: Float64) -> Radian64: + """Arccosine""" + ... +def asin(x: Float64) -> Radian64: + """Arcsine""" + ... +def atan(x: Float64) -> Radian64: + """Arctangent""" + ... +def atan2(y: Float64, x: Float64) -> Radian64: + """Arctangent of y/x""" + ... +def ceil(x: Float64) -> Float64: + """Ceiling""" + ... +def cos(x: Radian64) -> Float64: + """Cosine""" + ... +def dif(x: Float64, y: Float64) -> Float64: + """Positive difference""" + ... +def floor(x: Float64) -> Float64: + """Floor""" + ... +def hypot(x: Float64, y: Float64) -> Float64: + """Calculate the length of the hypotenuse of a right-angle triangle given legs of length x and y.""" + ... +def ln(x: Float64) -> Float64: + """Natural logarithm""" + ... +def ln1p(x: Float64) -> Float64: + """Natural logarithm of 1 plus x""" + ... +def log(x: Float64) -> Float64: + """Natural logarithm""" + ... +def log2(x: Float64) -> Float64: + """Base 2 logarithm""" + ... +def log10(x: Float64) -> Float64: + """Base 10 logarithm""" + ... +def sin(x: Radian64) -> Float64: + """Sine""" + ... +def sqrt(x: Float64) -> Float64: + """Square root""" + ... +def tan(x: Radian64) -> Float64: + """Tangent""" + ... + from .angle import * from .vec2d import * +from .vec4d import * from .pos2d import * + +NonStandardFloat = float +"""A floating point number that can be NaN or infinity.""" + +INFINITY: NonStandardFloat +"""The python representation of infinity.""" +NAN: NonStandardFloat +"""The python representation of NaN.""" diff --git a/arc/math/angle.pyi b/arc/math/angle.pyi index 7504c45..251d616 100644 --- a/arc/math/angle.pyi +++ b/arc/math/angle.pyi @@ -1,4 +1,5 @@ -from .vec2d import Vec2D +from . import Degree64 as _Degree64, Float64 as _Float64, Radian64 as _Radian64 +from .vec2d import Vec2D as _Vec2D class Angle(object): """ @@ -10,17 +11,17 @@ class Angle(object): """ @staticmethod - def from_degrees(degrees: float) -> Angle: + def from_degrees(degrees: _Degree64) -> Angle: """Creates an angle from degrees.""" ... @staticmethod - def from_radians(radians: float) -> Angle: + def from_radians(radians: _Radian64) -> Angle: """Creates an angle from radians.""" ... @staticmethod - def from_vec2d(vec: Vec2D) -> Angle: + def from_vec2d(vec: _Vec2D) -> Angle: """Creates an angle from a vector.""" ... @@ -29,23 +30,23 @@ class Angle(object): """Creates an angle of zero degrees.""" ... - def degrees(self) -> float: + def degrees(self) -> _Degree64: """Returns the angle in degrees.""" ... - def radians(self) -> float: + def radians(self) -> _Radian64: """Returns the angle in radians.""" ... - def sin(self) -> float: + def sin(self) -> _Radian64: """Returns the sine of the angle.""" ... - def cos(self) -> float: + def cos(self) -> _Radian64: """Returns the cosine of the angle.""" ... - def sqrt(self) -> float: + def sqrt(self) -> _Float64: """Returns the square root of the angle.""" ... @@ -57,11 +58,11 @@ class Angle(object): """Subtracts two angles.""" ... - def __mul__(self, other: float) -> Angle: + def __mul__(self, other: _Float64) -> Angle: """Multiplies an angle by a scalar.""" ... - def __truediv__(self, other: float) -> Angle: + def __truediv__(self, other: _Float64) -> Angle: """Divides an angle by a scalar.""" ... diff --git a/arc/math/pos2d.pyi b/arc/math/pos2d.pyi index 6bf8e3b..39be423 100644 --- a/arc/math/pos2d.pyi +++ b/arc/math/pos2d.pyi @@ -1,3 +1,4 @@ +from . import Float64 as _Float64, Radian64 as _Radian64 from .vec2d import Vec2D as _Vec2D from .angle import Angle as _Angle @@ -14,12 +15,12 @@ class Pos2D(object): ... @staticmethod - def from_xyr(x: float, y: float, radians: float) -> Pos2D: + def from_xyr(x: _Float64, y: _Float64, radians: _Radian64) -> Pos2D: """Creates a position from x, y, and radians.""" ... @staticmethod - def from_xy(x: float, y: float) -> Pos2D: + def from_xy(x: _Float64, y: _Float64) -> Pos2D: """Creates a position from x and y. facing 0 degrees.""" ... @@ -38,12 +39,12 @@ class Pos2D(object): """Creates a position positioned at the origin. facing 0 degrees.""" @property - def x(self) -> float: + def x(self) -> _Float64: """The x component of the position.""" ... @property - def y(self) -> float: + def y(self) -> _Float64: """The y component of the position.""" ... diff --git a/arc/math/vec2d.pyi b/arc/math/vec2d.pyi index 1a18632..8aa587f 100644 --- a/arc/math/vec2d.pyi +++ b/arc/math/vec2d.pyi @@ -1,4 +1,5 @@ -from .angle import Angle +from .angle import Angle as _Angle +from . import Float64 as _Float64 class Vec2D(object): """ @@ -10,30 +11,30 @@ class Vec2D(object): """ @staticmethod - def from_angle(angle: Angle, length: float) -> Vec2D: + def from_angle(angle: _Angle, length: _Float64) -> Vec2D: """Creates a vector from an angle and a length.""" ... @staticmethod - def from_xy(x: float, y: float) -> Vec2D: + def new(x: _Float64, y: _Float64) -> Vec2D: """Creates a vector from x and y components.""" ... @property - def x(self) -> float: + def x(self) -> _Float64: """Returns the x component of the vector.""" ... @property - def y(self) -> float: + def y(self) -> _Float64: """Returns the y component of the vector.""" ... - def angle(self) -> Angle: + def angle(self) -> _Angle: """Returns the angle of the vector.""" ... - def magnitude(self) -> float: + def magnitude(self) -> _Float64: """Returns the magnitude of the vector.""" ... @@ -41,7 +42,7 @@ class Vec2D(object): """Returns a new normalized version of this vector.""" ... - def dot(self, other: Vec2D) -> float: + def dot(self, other: Vec2D) -> _Float64: """Returns the dot product of two vectors.""" ... @@ -53,11 +54,11 @@ class Vec2D(object): """Subtracts two vectors.""" ... - def __mul__(self, other: float) -> Vec2D: + def __mul__(self, other: _Float64) -> Vec2D: """Multiplies a vector by a scalar.""" ... - def __truediv__(self, other: float) -> Vec2D: + def __truediv__(self, other: _Float64) -> Vec2D: """Divides a vector by a scalar.""" ... diff --git a/arc/math/vec4d.pyi b/arc/math/vec4d.pyi new file mode 100644 index 0000000..690cff2 --- /dev/null +++ b/arc/math/vec4d.pyi @@ -0,0 +1,105 @@ +from . import Float64 as _Float64 + +class Vec4D(object): + """ + A type representing a 4D vector. + + It is usually used to transmit motion information to the motors. + """ + + @staticmethod + def new(x: _Float64, y: _Float64, z: _Float64, w: _Float64) -> Vec4D: + """Creates a vector from x, y, z, and w components.""" + ... + + @property + def x(self) -> _Float64: + """Returns the x component of the vector.""" + ... + + @property + def y(self) -> _Float64: + """Returns the y component of the vector.""" + ... + + @property + def z(self) -> _Float64: + """Returns the z component of the vector.""" + ... + + @property + def w(self) -> _Float64: + """Returns the w component of the vector.""" + ... + + def magnitude(self) -> _Float64: + """Returns the magnitude of the vector.""" + ... + + def normalize(self) -> Vec4D: + """Returns a new normalized version of this vector.""" + ... + + def dot(self, other: Vec4D) -> float: + """Returns the dot product of two vectors.""" + ... + + def __add__(self, other: Vec4D) -> Vec4D: + """Adds two vectors.""" + ... + + def __sub__(self, other: Vec4D) -> Vec4D: + """Subtracts two vectors.""" + ... + + def __mul__(self, other: _Float64) -> Vec4D: + """Multiplies a vector by a scalar.""" + ... + + def __truediv__(self, other: _Float64) -> Vec4D: + """Divides a vector by a scalar.""" + ... + + def __neg__(self) -> Vec4D: + """Negates a vector.""" + ... + + def __eq__(self, other: Vec4D) -> bool: + """Checks if two vectors are equal.""" + ... + + def __ne__(self, other: Vec4D) -> bool: + """Checks if two vectors are not equal.""" + ... + + def __lt__(self, other: Vec4D) -> bool: + """Checks if the magnitude of one vector is less than another.""" + ... + + def __gt__(self, other: Vec4D) -> bool: + """Checks if the magnitude of one vector is greater than another.""" + ... + + def __le__(self, other: Vec4D) -> bool: + """Checks if the magnitude of one vector is less than or equal to another.""" + ... + + def __ge__(self, other: Vec4D) -> bool: + """Checks if the magnitude of one vector is greater than or equal to another.""" + ... + + def __str__(self) -> str: + """Returns a string representation of the vector.""" + ... + + def __repr__(self) -> str: + """Returns a string representation of the vector. (for debugging)""" + ... + + def __len__(self) -> int: + """ + Returns the magnitude of the vector. + + This is the same as calling `magnitude`. + """ + ... diff --git a/examples/auto.py b/examples/auto.py deleted file mode 100644 index a5a610f..0000000 --- a/examples/auto.py +++ /dev/null @@ -1,25 +0,0 @@ -from arc.hardware import * -from arc.math import * -from arc import * - -# You are REQUIRED to have a main() function in your program. -# and you MUST NOT call it yourself. -@Auto("My Auto") -def main(op: Op): - print("Starting...") - - # holding_a = False - while op.running: - if op.gamepad.a: - print("A pressed!") - # if not holding_a: - # print("A pressed!") - # holding_a = True - # else: - # if holding_a: - # print("A released!") - # holding_a = False - - print("Done!") - - return OK diff --git a/examples/mecanum_basic_teleop.py b/examples/mecanum_basic_teleop.py new file mode 100644 index 0000000..4d7fed6 --- /dev/null +++ b/examples/mecanum_basic_teleop.py @@ -0,0 +1,24 @@ +from .util.drive import MechanumDrive +from arc.hardware import * +from arc import * + +# You are REQUIRED to have a main() function in your program. +# and you MUST NOT call it yourself. +@Teleop("Mechanum Drive example") +def main(op: Op): + op.log("Starting...") + + # Create a MechanumDrive object. + fl = op.hardwareMap[DcMotor]("motor0") + fr = op.hardwareMap[DcMotor]("motor1") + bl = op.hardwareMap[DcMotor]("motor2") + br = op.hardwareMap[DcMotor]("motor3") + drive = MechanumDrive(fl, fr, bl, br) + + # While the opmode is running... + while op.running: + # Drive the robot using the gamepad. + drive.moveUsingDefaultSheme(op.gamepad) + + op.log("Done!") + return OK diff --git a/examples/tank_drive_teleop.py b/examples/tank_drive_teleop.py new file mode 100644 index 0000000..4d2df5e --- /dev/null +++ b/examples/tank_drive_teleop.py @@ -0,0 +1,28 @@ +from .util.drive import TankDrive +from arc.hardware import * +from arc import * + +# You are REQUIRED to have a main() function in your program. +# and you MUST NOT call it yourself. +@Teleop("Tank Drive example") +def main(op: Op): + op.log("Starting...") + + # Create a tank drive with the left and right motors. + leftMotor = op.hardwareMap[DcMotor]("motor0") + rightMotor = op.hardwareMap[DcMotor]("motor1") + drive = TankDrive(leftMotor, rightMotor) + + # While the opmode is running... + while op.running: + # Get the left and right stick values. + l = op.gamepad.left_stick.y + r = op.gamepad.right_stick.y + movement = TankDrive.calc(l, r) + op.debug("Left: ", l, "Right: ", r) + + # Drive the robot with the left and right sticks. + drive.move(movement) + + op.log("Done!") + return OK diff --git a/examples/util/drive.py b/examples/util/drive.py index 2f9695d..9c9bd60 100644 --- a/examples/util/drive.py +++ b/examples/util/drive.py @@ -1,48 +1,95 @@ -from arc.math import Pos2D as _Pos2D -import abc as _abc - -class Drive(_abc.ABC): - """Represents a drive system.""" - @_abc.abstractmethod - def forward(self, distance: float) -> None: - """Drives forward the specified distance.""" - pass - - @_abc.abstractmethod - def backward(self, distance: float) -> None: - """Drives backward the specified distance.""" - pass +from arc.math import Vec2D, Vec4D, Radian64, Float64, Angle +from arc.hardware import DcMotor, Gamepad +import arc.math as l2math + +from abc import ABC, abstractmethod, abstractstaticmethod +from typing import Generic, TypeVar + +MovementVector = TypeVar("MovementVector") +"""A type variable for movement vectors.""" + +class DriveBase(ABC, Generic[MovementVector]): + """A base class for drive bases.""" + @abstractmethod + def move(self, movement: MovementVector) -> None: + """Drive the robot using a movement vector.""" + raise NotImplementedError("drive() is not implemented for this drive base.") + + @abstractmethod + def stop(self) -> None: + """Stop the robot.""" + raise NotImplementedError("stop() is not implemented for this drive base.") + + @abstractstaticmethod + def calc(*args) -> MovementVector: + """Calculate the movement vector for a drive base.""" + raise NotImplementedError("calc() is not implemented for this drive base.") + +class TankDrive(DriveBase[Vec2D]): + """A class for tank drive.""" + def __init__(self, left: DcMotor, right: DcMotor): + """Create a new TankDrive object.""" + self.left = left + self.right = right + + def move(self, movement: Vec2D): + self.left.power(movement.x) + self.right.power(movement.y) + + def stop(self): + self.move(Vec2D.new(0, 0)) - @_abc.abstractmethod - def turn_left(self, angle: float) -> None: - """Turns left the specified angle.""" - pass - - @_abc.abstractmethod - def turn_right(self, angle: float) -> None: - """Turns right the specified angle.""" - pass - -class StrafingDrive(Drive): - """Represents a drive system that can also strafe.""" - @_abc.abstractmethod - def left(self, distance: float) -> None: - """Strafes left the specified distance.""" - - @_abc.abstractmethod - def right(self, distance: float) -> None: - """Strafes right the specified distance.""" - -class AdvancedDrive(StrafingDrive): - """Represents a drive system that can also move to a position.""" - @_abc.abstractmethod - def moveto(self, pos: _Pos2D) -> None: - """Moves to the specified position.""" - pass - -class PositionAwareDrive(_abc.ABC): - """Represents a drive system that can also return its position.""" - @_abc.abstractproperty - def position(self) -> _Pos2D: - """The current position of the robot.""" - return None # type: ignore + @staticmethod + def calc(left: Float64, right: Float64) -> Vec2D: + return Vec2D.new(left, right) + +class MechanumDrive(DriveBase[Vec4D]): + """A class for mechanum drive.""" + def __init__(self, fl: DcMotor, fr: DcMotor, bl: DcMotor, br: DcMotor): + """Create a new MechanumDrive object.""" + self.fl = fl + self.fr = fr + self.bl = bl + self.br = br + + def move(self, movement: Vec4D): + self.fl.power(movement.x) + self.fr.power(movement.y) + self.bl.power(movement.z) + self.br.power(movement.w) + + def stop(self): + self.move(Vec4D.new(0, 0, 0, 0)) + + def moveUsingDefaultSheme(self, gamepad: Gamepad): + """ + Move the robot using the default scheme. + The left stick controls movement, and the right stick controls rotation. + """ + theta = gamepad.left_stick.as_angle() + power = gamepad.left_stick.as_vec2d().magnitude() + rotation = gamepad.right_stick.x + movement = MechanumDrive.calc(theta, power, rotation) + self.move(movement) + + @staticmethod + def calc(angle: Angle, speed: Float64, turn: Radian64) -> Vec4D: + sin = l2math.sin(angle.radians() - l2math.FRAC_PI_4) + cos = l2math.cos(angle.radians() - l2math.FRAC_PI_4) + mx = max(abs(sin), abs(cos)) + + # Calculate the powers for each motor. + fl = speed * (cos / mx) + turn + fr = speed * (sin / mx) - turn + bl = speed * (sin / mx) + turn + br = speed * (cos / mx) - turn + + # Pump up the power if we can + if (speed + abs(turn)) > 1: + fl /= (speed + abs(turn)) + fr /= (speed + abs(turn)) + bl /= (speed + abs(turn)) + br /= (speed + abs(turn)) + + # Calculate the final vector. + return Vec4D.new(fl, fr, bl, br) diff --git a/examples/util/mecanum_drive.py b/examples/util/mecanum_drive.py deleted file mode 100644 index 9b81c1e..0000000 --- a/examples/util/mecanum_drive.py +++ /dev/null @@ -1,14 +0,0 @@ -from .drive import AdvancedDrive, PositionAwareDrive - -class MecanumDrive(AdvancedDrive, PositionAwareDrive): - def forward(self, distance: float) -> None: - pass - - def backward(self, distance: float) -> None: - pass - - def turn_left(self, angle: float) -> None: - pass - - def turn_right(self, angle: float) -> None: - pass \ No newline at end of file diff --git a/helpers/l2math/consts.rs b/helpers/l2math/consts.rs new file mode 100644 index 0000000..9e8fb8d --- /dev/null +++ b/helpers/l2math/consts.rs @@ -0,0 +1,151 @@ +#![allow(clippy::excessive_precision)] + +use crate::{Float64, Float32}; + +/// Archimedes' constant (π) +pub const PI: Float64 = 3.14159265358979323846264338327950288_f64; + +/// The full circle constant (τ) +/// +/// Equal to 2π. +pub const TAU: Float64 = 6.28318530717958647692528676655900577_f64; + +/// The golden ratio (φ) +pub const PHI: Float64 = 1.618033988749894848204586834365638118_f64; + +/// The Euler-Mascheroni constant (γ) +pub const EGAMMA: Float64 = 0.577215664901532860606512090082402431_f64; + +/// π/2 +pub const FRAC_PI_2: Float64 = 1.57079632679489661923132169163975144_f64; + +/// π/3 +pub const FRAC_PI_3: Float64 = 1.04719755119659774615421446109316763_f64; + +/// π/4 +pub const FRAC_PI_4: Float64 = 0.785398163397448309615660845819875721_f64; + +/// π/6 +pub const FRAC_PI_6: Float64 = 0.52359877559829887307710723054658381_f64; + +/// π/8 +pub const FRAC_PI_8: Float64 = 0.39269908169872415480783042290993786_f64; + +/// 1/π +pub const FRAC_1_PI: f64 = 0.318309886183790671537767526745028724_f64; + +/// 1/sqrt(π) +pub const FRAC_1_SQRT_PI: f64 = 0.564189583547756286948079451560772586_f64; + +/// 2/π +pub const FRAC_2_PI: f64 = 0.636619772367581343075535053490057448_f64; + +/// 2/sqrt(π) +pub const FRAC_2_SQRT_PI: f64 = 1.12837916709551257389615890312154517_f64; + +/// sqrt(2) +pub const SQRT_2: f64 = 1.41421356237309504880168872420969808_f64; + +/// 1/sqrt(2) +pub const FRAC_1_SQRT_2: f64 = 0.707106781186547524400844362104849039_f64; + +/// sqrt(3) +pub const SQRT_3: f64 = 1.732050807568877293527446341505872367_f64; + +/// 1/sqrt(3) +pub const FRAC_1_SQRT_3: f64 = 0.577350269189625764509148780501957456_f64; + +/// Euler's number (e) +pub const E: f64 = 2.71828182845904523536028747135266250_f64; + +/// log2(10) +pub const LOG2_10: f64 = 3.32192809488736234787031942948939018_f64; + +/// log2(e) +pub const LOG2_E: Float64 = 1.44269504088896340735992468100189214_f64; + +/// log10(2) +pub const LOG10_2: Float64 = 0.301029995663981195213738894724493027_f64; + +/// log10(e) +pub const LOG10_E: Float64 = 0.434294481903251827651128918916605082_f64; + +/// ln(2) +pub const LN_2: Float64 = 0.693147180559945309417232121458176568_f64; + +/// ln(10) +pub const LN_10: Float64 = 2.30258509299404568401799145468436421_f64; + +/// Archimedes' constant (π) as a 32-bit float +pub const PIF: Float32 = 3.14159265358979323846264338327950288_f32; + +/// The full circle constant (τ) as a 32-bit float +/// +/// Equal to 2π. +pub const TAUF: Float32 = 6.28318530717958647692528676655900577_f32; + +/// The golden ratio (φ) as a 32-bit float +pub const PHIF: Float32 = 1.618033988749894848204586834365638118_f32; + +/// The Euler-Mascheroni constant (γ) as a 32-bit float +pub const EGAMMAF: Float32 = 0.577215664901532860606512090082402431_f32; + +/// π/2 as a 32-bit float +pub const FRAC_PI_2F: Float32 = 1.57079632679489661923132169163975144_f32; + +/// π/3 as a 32-bit float +pub const FRAC_PI_3F: Float32 = 1.04719755119659774615421446109316763_f32; + +/// π/4 as a 32-bit float +pub const FRAC_PI_4F: Float32 = 0.785398163397448309615660845819875721_f32; + +/// π/6 as a 32-bit float +pub const FRAC_PI_6F: Float32 = 0.52359877559829887307710723054658381_f32; + +/// π/8 as a 32-bit float +pub const FRAC_PI_8F: Float32 = 0.39269908169872415480783042290993786_f32; + +/// 1/π as a 32-bit float +pub const FRAC_1_PIF: Float32 = 0.318309886183790671537767526745028724_f32; + +/// 1/sqrt(π) as a 32-bit float +pub const FRAC_1_SQRT_PIF: Float32 = 0.564189583547756286948079451560772586_f32; + +/// 2/π as a 32-bit float +pub const FRAC_2_PIF: Float32 = 0.636619772367581343075535053490057448_f32; + +/// 2/sqrt(π) as a 32-bit float +pub const FRAC_2_SQRT_PIF: Float32 = 1.12837916709551257389615890312154517_f32; + +/// sqrt(2) as a 32-bit float +pub const SQRT_2F: Float32 = 1.41421356237309504880168872420969808_f32; + +/// 1/sqrt(2) as a 32-bit float +pub const FRAC_1_SQRT_2F: Float32 = 0.707106781186547524400844362104849039_f32; + +/// sqrt(3) as a 32-bit float +pub const SQRT_3F: Float32 = 1.732050807568877293527446341505872367_f32; + +/// 1/sqrt(3) as a 32-bit float +pub const FRAC_1_SQRT_3F: Float32 = 0.577350269189625764509148780501957456_f32; + +/// Euler's number (e) as a 32-bit float +pub const EF: Float32 = 2.71828182845904523536028747135266250_f32; + +/// log2(e) as a 32-bit float +pub const LOG2_EF: Float32 = 1.44269504088896340735992468100189214_f32; + +/// log2(10) as a 32-bit float +pub const LOG2_10F: Float32 = 3.32192809488736234787031942948939018_f32; + +/// log10(e) as a 32-bit float +pub const LOG10_EF: Float32 = 0.434294481903251827651128918916605082_f32; + +/// log10(2) as a 32-bit float +pub const LOG10_2F: Float32 = 0.301029995663981195213738894724493027_f32; + +/// ln(2) as a 32-bit float +pub const LN_2F: Float32 = 0.693147180559945309417232121458176568_f32; + +/// ln(10) as a 32-bit float +pub const LN_10F: Float32 = 2.30258509299404568401799145468436421_f32; diff --git a/helpers/l2math/lib.rs b/helpers/l2math/lib.rs index 887bd54..0c66894 100644 --- a/helpers/l2math/lib.rs +++ b/helpers/l2math/lib.rs @@ -15,12 +15,14 @@ mod core; mod types; +mod consts; #[path = "macros.rs"] mod __macros; pub use self::core::*; pub use self::types::*; +pub use self::consts::*; /// Approximate equality with 1 ULP of tolerance #[inline] diff --git a/robot/Cargo.toml b/robot/Cargo.toml index febe46a..98e7749 100644 --- a/robot/Cargo.toml +++ b/robot/Cargo.toml @@ -11,13 +11,9 @@ license.workspace = true name = "arc_robot" path = "lib.rs" -[dependencies.hardware] -package = "arc-robot-hardware" -path = "./hardware" - [dependencies.pyruntime] package = "arc-robot-python-runtime" -path = "./runtime" +path = "./pyruntime" [dependencies.macros] path = "../helpers/macros" diff --git a/robot/hardware/Cargo.toml b/robot/core/Cargo.toml similarity index 66% rename from robot/hardware/Cargo.toml rename to robot/core/Cargo.toml index 4a534c3..2b29b0d 100644 --- a/robot/hardware/Cargo.toml +++ b/robot/core/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "arc-robot-hardware" -description = "ARC Robot hardware" +name = "arc-robot-core" +description = "ARC Robot Core" repository.workspace = true version.workspace = true edition.workspace = true @@ -15,3 +15,6 @@ path = "../../helpers/l2math" [dependencies.libtrig] path = "../../helpers/libtrig" + +[features] +unstable = ["l2math/unstable", "libtrig/unstable"] diff --git a/robot/hardware/error.rs b/robot/core/error.rs similarity index 62% rename from robot/hardware/error.rs rename to robot/core/error.rs index 0520c41..0e47443 100644 --- a/robot/hardware/error.rs +++ b/robot/core/error.rs @@ -1,22 +1,18 @@ -/// ### O_O -/// /// A type that can be used to represent a result that is always `Ok` +/// +/// ### O_O /// /// It is a shorthand for `Result<(), HardwareError>`. pub const IO_OK: Result = Ok(()); /// An error that occurs when reading from or writing to a hardware component +#[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum HardwareError { - /// An IO error occurred - /// - /// This error is returned when reading from or writing to a hardware component fails. - IO, - /// Also an IO error, but this one is returned when the hardware component is disconnected. - /// - /// That means that the hardware component was connected when the program started, but it was - /// later disconnected. - Disconnected, + /// The device was disconnected + DeviceDisconnected, + /// The device was not found + DeviceNotFound, /// Some other error occurred Other { /// The error message @@ -24,16 +20,31 @@ pub enum HardwareError { }, } +impl HardwareError { + /// Creates a new `HardwareError::Other` with the given message + #[inline] + #[must_use = "This returns a new HardwareError"] + pub const fn new(message: &'static str) -> Self { + Self::Other { message } + } + /// Returns the error message + #[inline] + #[must_use = "This returns a new string slice"] + pub const fn as_str(&self) -> &'static str { + match self { + HardwareError::DeviceDisconnected => "Device disconnected", + HardwareError::DeviceNotFound => "Device not found", + HardwareError::Other { message } => message, + } + } +} + /// A result that occurs when reading or writing to a hardware component pub type Result = core::result::Result; impl core::fmt::Display for HardwareError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::IO => write!(f, "IO error"), - Self::Disconnected => write!(f, "Gamepad disconnected"), - Self::Other { message } => write!(f, "{}", message), - } + write!(f, "{}", self.as_str()) } } @@ -54,11 +65,7 @@ impl From for String { impl From for &'static str { #[inline] fn from(error: HardwareError) -> Self { - match error { - HardwareError::IO => "IO error", - HardwareError::Disconnected => "Gamepad disconnected", - HardwareError::Other { message } => message, - } + error.as_str() } } diff --git a/robot/hardware/gamepad/mod.rs b/robot/core/gamepad.rs similarity index 86% rename from robot/hardware/gamepad/mod.rs rename to robot/core/gamepad.rs index f729b87..55343fc 100644 --- a/robot/hardware/gamepad/mod.rs +++ b/robot/core/gamepad.rs @@ -1,236 +1,231 @@ -//! - -use l2math::Float64; -use libtrig::{Angle2D, Vec2D}; - -pub mod impls; - -/// A trait that allows for reading from a gamepad -/// -/// This is a trait so that it can be implemented for any gamepad -pub trait Gamepad: core::fmt::Debug { - /// Returns the state of the dpad - /// - /// Includes up, down, left, and right - fn dpad(&self) -> crate::Result; - /// Returns the state of the left stick - /// - /// Includes x, y, and pressed - fn left_stick(&self) -> crate::Result; - /// Returns the state of the right stick - /// - /// Includes x, y, and pressed - fn right_stick(&self) -> crate::Result; - /// Returns the state of the left trigger - fn left_trigger(&self) -> crate::Result; - /// Returns the state of the right trigger - fn right_trigger(&self) -> crate::Result; - /// Is the A button pressed? - fn a(&self) -> crate::Result; - /// Is the B button pressed? - fn b(&self) -> crate::Result; - /// Is the X button pressed? - fn x(&self) -> crate::Result; - /// Is the Y button pressed? - fn y(&self) -> crate::Result; - /// Is the left bumper pressed? - fn left_bumper(&self) -> crate::Result; - /// Is the right bumper pressed? - fn right_bumper(&self) -> crate::Result; - - /// A non-standard 'back' button - #[inline] - fn back(&self) -> crate::Result { - Err(crate::HardwareError::Other { - message: "This gamepad does not have a 'back' button", - }) - } - /// A non-standard 'start' button - #[inline] - fn start(&self) -> crate::Result { - Err(crate::HardwareError::Other { - message: "This gamepad does not have a 'start' button", - }) - } -} - -/// Allows for the gamepad to be modified -/// -/// PLEASE DO NOT MODIFY THE GAMEPAD ON THE MAIN THREAD -pub trait MutableGamepad: Gamepad { - /// Sets the state of the dpad - fn set_dpad(&mut self, dpad: GamepadDpad) -> crate::Result; - /// Sets the state of the left stick - fn set_left_stick(&mut self, stick: GamepadStick) -> crate::Result; - /// Sets the state of the right stick - fn set_right_stick(&mut self, stick: GamepadStick) -> crate::Result; - /// Sets the state of the left trigger - fn set_left_trigger(&mut self, trigger: f64) -> crate::Result; - /// Sets the state of the right trigger - fn set_right_trigger(&mut self, trigger: f64) -> crate::Result; - /// Sets the state of the A button - fn set_a(&mut self, value: bool) -> crate::Result; - /// Sets the state of the B button - fn set_b(&mut self, value: bool) -> crate::Result; - /// Sets the state of the X button - fn set_x(&mut self, value: bool) -> crate::Result; - /// Sets the state of the Y button - fn set_y(&mut self, value: bool) -> crate::Result; - /// Sets the state of the left bumper - fn set_left_bumper(&mut self, value: bool) -> crate::Result; - /// Sets the state of the right bumper - fn set_right_bumper(&mut self, value: bool) -> crate::Result; - /// Sets the state of the 'back' button - fn set_back(&mut self, _value: bool) -> crate::Result { - Err(crate::HardwareError::Other { - message: "This gamepad does not have a 'back' button", - }) - } - /// Sets the state of the 'start' button - fn set_start(&mut self, _value: bool) -> crate::Result { - Err(crate::HardwareError::Other { - message: "This gamepad does not have a 'start' button", - }) - } -} - -/// A struct that holds the state of a gamepad -/// stick -#[repr(C)] -#[derive(Default, Debug, Clone, Copy, PartialEq)] -pub struct GamepadStick { - /// How far the stick is pushed in the x direction (left/right) - pub x: f64, - /// How far the stick is pushed in the y direction (up/down) - pub y: f64, - /// Is the stick pressed down? - pub pressed: bool, -} - -impl GamepadStick { - /// Creates a new `GamepadStick` with the given values - #[inline] - #[must_use = "This returns a new GamepadStick"] - pub const fn new(x: f64, y: f64, pressed: bool) -> Self { - Self { x, y, pressed } - } - /// Creates a new `GamepadStick` with all values set to their defaults - #[inline] - #[must_use = "This returns a new GamepadStick"] - pub const fn default() -> Self { - Self::new(0.0, 0.0, false) - } - /// Turns the x and y values of the stick into an angle - /// - /// This is useful for things like precision driving - #[inline] - pub fn angle(&self) -> libtrig::Angle2D { - libtrig::prelude!(); - libtrig::Angle2D::from_radians(self.y.atan2(self.x)) - } -} - -impl From for GamepadStick { - #[inline] - #[must_use = "This returns a new GamepadStick"] - fn from(angle: Angle2D) -> Self { - libtrig::prelude!(); - Self::new(angle.cos(), angle.sin(), false) - } -} - -impl From for Angle2D { - #[inline] - #[must_use = "This returns a new Angle2D"] - fn from(stick: GamepadStick) -> Self { - stick.angle() - } -} - -impl From for GamepadStick { - #[inline] - #[must_use = "This returns a new GamepadStick"] - fn from(vec: Vec2D) -> Self { - Self::new(vec.x(), vec.y(), false) - } -} - -impl From for Vec2D { - #[inline] - #[must_use = "This returns a new Vec2D"] - fn from(stick: GamepadStick) -> Self { - Self::new(stick.x, stick.y) - } -} - -impl From<(f64, f64, bool)> for GamepadStick { - #[inline] - #[must_use = "This returns a new GamepadStick"] - fn from((x, y, pressed): (f64, f64, bool)) -> Self { - Self::new(x, y, pressed) - } -} - -impl From<(f64, f64)> for GamepadStick { - #[inline] - #[must_use = "This returns a new GamepadStick"] - fn from((x, y): (f64, f64)) -> Self { - Self::new(x, y, false) - } -} - -impl Eq for GamepadStick {} - -/// A struct that holds the state of a gamepad's Dpad -/// -/// Includes up, down, left, and right -/// -/// (Why is this not called GamepadDpad if it's more like a `+` symbol?) -#[repr(C)] -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct GamepadDpad { - /// Is the up button pressed? - pub up: bool, - /// Is the down button pressed? - pub down: bool, - /// Is the left button pressed? - pub left: bool, - /// Is the right button pressed? - pub right: bool, -} - -impl GamepadDpad { - /// Creates a new `GamepadDpad` with the given values - #[inline] - #[must_use = "This returns a new GamepadDpad"] - pub const fn new(up: bool, down: bool, left: bool, right: bool) -> Self { - Self { - up, - down, - left, - right, - } - } - /// Creates a new `GamepadDpad` with all values set to their defaults - #[inline] - #[must_use = "This returns a new GamepadDpad"] - pub const fn default() -> Self { - Self::new(false, false, false, false) - } -} - -impl From<(bool, bool, bool, bool)> for GamepadDpad { - #[inline] - #[must_use = "This returns a new GamepadDpad"] - fn from((up, down, left, right): (bool, bool, bool, bool)) -> Self { - Self::new(up, down, left, right) - } -} - -impl From for (bool, bool, bool, bool) { - #[inline] - #[must_use = "This returns a new tuple"] - fn from(dpad: GamepadDpad) -> Self { - (dpad.up, dpad.down, dpad.left, dpad.right) - } -} +use crate::HardwareComponent; + +/// A trait that allows for reading from a gamepad +/// +/// This is a trait so that it can be implemented for any gamepad +pub trait Gamepad: HardwareComponent { + /// Returns the state of the dpad + /// + /// Includes up, down, left, and right + fn dpad(&self) -> crate::Result; + /// Returns the state of the left stick + /// + /// Includes x, y, and pressed + fn left_stick(&self) -> crate::Result; + /// Returns the state of the right stick + /// + /// Includes x, y, and pressed + fn right_stick(&self) -> crate::Result; + /// Returns the state of the left trigger + fn left_trigger(&self) -> crate::Result; + /// Returns the state of the right trigger + fn right_trigger(&self) -> crate::Result; + /// Is the A button pressed? + fn a(&self) -> crate::Result; + /// Is the B button pressed? + fn b(&self) -> crate::Result; + /// Is the X button pressed? + fn x(&self) -> crate::Result; + /// Is the Y button pressed? + fn y(&self) -> crate::Result; + /// Is the left bumper pressed? + fn left_bumper(&self) -> crate::Result; + /// Is the right bumper pressed? + fn right_bumper(&self) -> crate::Result; + + /// A non-standard 'back' button + #[inline] + fn back(&self) -> crate::Result { + Err(crate::HardwareError::Other { + message: "This gamepad does not have a 'back' button", + }) + } + /// A non-standard 'start' button + #[inline] + fn start(&self) -> crate::Result { + Err(crate::HardwareError::Other { + message: "This gamepad does not have a 'start' button", + }) + } +} + +/// Allows for the gamepad to be modified +/// +/// PLEASE DO NOT MODIFY THE GAMEPAD ON THE MAIN THREAD +pub trait MutableGamepad: Gamepad { + /// Sets the state of the dpad + fn set_dpad(&mut self, dpad: GamepadDpad) -> crate::Result; + /// Sets the state of the left stick + fn set_left_stick(&mut self, stick: GamepadStick) -> crate::Result; + /// Sets the state of the right stick + fn set_right_stick(&mut self, stick: GamepadStick) -> crate::Result; + /// Sets the state of the left trigger + fn set_left_trigger(&mut self, trigger: f64) -> crate::Result; + /// Sets the state of the right trigger + fn set_right_trigger(&mut self, trigger: f64) -> crate::Result; + /// Sets the state of the A button + fn set_a(&mut self, value: bool) -> crate::Result; + /// Sets the state of the B button + fn set_b(&mut self, value: bool) -> crate::Result; + /// Sets the state of the X button + fn set_x(&mut self, value: bool) -> crate::Result; + /// Sets the state of the Y button + fn set_y(&mut self, value: bool) -> crate::Result; + /// Sets the state of the left bumper + fn set_left_bumper(&mut self, value: bool) -> crate::Result; + /// Sets the state of the right bumper + fn set_right_bumper(&mut self, value: bool) -> crate::Result; + /// Sets the state of the 'back' button + fn set_back(&mut self, _value: bool) -> crate::Result { + Err(crate::HardwareError::Other { + message: "This gamepad does not have a 'back' button", + }) + } + /// Sets the state of the 'start' button + fn set_start(&mut self, _value: bool) -> crate::Result { + Err(crate::HardwareError::Other { + message: "This gamepad does not have a 'start' button", + }) + } +} + +/// A struct that holds the state of a gamepad stick +/// +/// This is NOT a hardware component, but rather a struct +/// that is used as a wrapper for a sub-component of a gamepad. +#[repr(C)] +#[derive(Default, Debug, Clone, Copy, PartialEq)] +pub struct GamepadStick { + /// How far the stick is pushed in the x direction (left/right) + pub x: f64, + /// How far the stick is pushed in the y direction (up/down) + pub y: f64, + /// Is the stick pressed down? + pub pressed: bool, +} + +impl GamepadStick { + /// Creates a new `GamepadStick` with the given values + #[inline] + #[must_use = "This returns a new GamepadStick"] + pub const fn new(x: f64, y: f64, pressed: bool) -> Self { + Self { x, y, pressed } + } + /// Creates a new `GamepadStick` with all values set to their defaults + #[inline] + #[must_use = "This returns a new GamepadStick"] + pub const fn default() -> Self { + Self::new(0.0, 0.0, false) + } + /// Turns the x and y values of the stick into an angle + /// + /// This is useful for things like precision driving + #[inline] + pub fn angle(&self) -> libtrig::Angle2D { + libtrig::prelude!(); + libtrig::Angle2D::from_radians(self.y.atan2(self.x)) + } +} + +impl From for GamepadStick { + #[inline] + #[must_use = "This returns a new GamepadStick"] + fn from(angle: libtrig::Angle2D) -> Self { + libtrig::prelude!(); + Self::new(angle.cos(), angle.sin(), false) + } +} + +impl From for libtrig::Angle2D { + #[inline] + #[must_use = "This returns a new Angle2D"] + fn from(stick: GamepadStick) -> Self { + stick.angle() + } +} + +impl From for GamepadStick { + #[inline] + #[must_use = "This returns a new GamepadStick"] + fn from(vec: libtrig::Vec2D) -> Self { + Self::new(vec.x(), vec.y(), false) + } +} + +impl From for libtrig::Vec2D { + #[inline] + #[must_use = "This returns a new Vec2D"] + fn from(stick: GamepadStick) -> Self { + Self::new(stick.x, stick.y) + } +} + +impl From<(f64, f64, bool)> for GamepadStick { + #[inline] + #[must_use = "This returns a new GamepadStick"] + fn from((x, y, pressed): (f64, f64, bool)) -> Self { + Self::new(x, y, pressed) + } +} + +impl From<(f64, f64)> for GamepadStick { + #[inline] + #[must_use = "This returns a new GamepadStick"] + fn from((x, y): (f64, f64)) -> Self { + Self::new(x, y, false) + } +} + +impl Eq for GamepadStick {} + +/// A struct that holds the state of a gamepad's Dpad +/// +/// Includes up, down, left, and right. +/// +/// This is NOT a hardware component, but rather a struct +/// that is used as a wrapper for a sub-component of a gamepad. +/// +/// (Why is this not called GamepadDpad if it's more like a `+` symbol?) +#[repr(C)] +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct GamepadDpad { + /// Is the up button pressed? + pub up: bool, + /// Is the down button pressed? + pub down: bool, + /// Is the left button pressed? + pub left: bool, + /// Is the right button pressed? + pub right: bool, +} + +impl GamepadDpad { + /// Creates a new `GamepadDpad` with the given values + #[inline] + #[must_use = "This returns a new GamepadDpad"] + pub const fn new(up: bool, down: bool, left: bool, right: bool) -> Self { + Self { up, down, left, right } + } + /// Creates a new `GamepadDpad` with all values set to their defaults + #[inline] + #[must_use = "This returns a new GamepadDpad"] + pub const fn default() -> Self { + Self::new(false, false, false, false) + } +} + +impl From<(bool, bool, bool, bool)> for GamepadDpad { + #[inline] + #[must_use = "This returns a new GamepadDpad"] + fn from((up, down, left, right): (bool, bool, bool, bool)) -> Self { + Self::new(up, down, left, right) + } +} + +impl From for (bool, bool, bool, bool) { + #[inline] + #[must_use = "This returns a new tuple"] + fn from(dpad: GamepadDpad) -> Self { + (dpad.up, dpad.down, dpad.left, dpad.right) + } +} diff --git a/robot/core/hardware.rs b/robot/core/hardware.rs new file mode 100644 index 0000000..006828d --- /dev/null +++ b/robot/core/hardware.rs @@ -0,0 +1,24 @@ +//! Hardware components used by the robot + +use crate::*; + +mod dcmotor; + +pub use dcmotor::DcMotor; + +/// The hardware map. +/// +/// This is used to load hardware components. +/// +/// # Example +/// ```rust +/// # use arc_robot_core as robot; +/// # use robot::HardwareMap; +/// # fn example(hardware_map: impl HardwareMap) -> robot::Result<()> { +/// let motor = hardware_map.load::("motor")?; +/// # Ok(()) +/// # } +/// ``` +pub trait HardwareMap { + fn load(&self, uuid: impl Into) -> Result; +} diff --git a/robot/core/hardware/dcmotor.rs b/robot/core/hardware/dcmotor.rs new file mode 100644 index 0000000..3f5bc69 --- /dev/null +++ b/robot/core/hardware/dcmotor.rs @@ -0,0 +1,16 @@ +use crate::*; + +#[derive(Debug, Clone)] +pub struct DcMotor { + +} + +impl DcMotor { + +} + +impl HardwareComponent for DcMotor { + fn getUUID(&self) -> HardwareUUID { + todo!() + } +} diff --git a/robot/core/hardware/uuid.rs b/robot/core/hardware/uuid.rs new file mode 100644 index 0000000..62eb377 --- /dev/null +++ b/robot/core/hardware/uuid.rs @@ -0,0 +1,83 @@ +/// A Unique Hardware Identifier +/// +/// This is a struct that is used to identify a specific piece of hardware. +/// This is can be used to load a hardware component from the hardware map. +/// +/// This is a wrapper around `[char; 8]` +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct HardwareUUID([char; 8]); + +impl HardwareUUID { + /// Creates a new HardwareUUID from a `[char; 8]` + #[inline(always)] + pub const fn new(uuid: [char; 8]) -> Self { + Self(uuid) + } + /// Converts something that can be converted into a string into a HardwareUUID + /// + /// ### Note + /// + /// If the string is less than 8 characters, the rest of the UUID will be filled with `0`s + #[inline] + pub fn from_to_string(input: impl ToString) -> Self { + let mut uuid = ['0'; 8]; + input.to_string() + .chars() + .enumerate() + .for_each(|(i, c)| uuid[i] = c); + Self::new(uuid) + } +} + +impl From<[char; 8]> for HardwareUUID { + #[inline(always)] + fn from(uuid: [char; 8]) -> Self { + Self::new(uuid) + } +} + +impl From for HardwareUUID { + /// Converts a string into a HardwareUUID + /// + /// ### Note + /// + /// If the string is less than 8 characters, the rest of the UUID will be filled with `0`s + #[inline] + fn from(input: String) -> Self { + Self::from_to_string(input) + } +} + +impl<'a> From<&'a str> for HardwareUUID { + /// Converts a `str` into a HardwareUUID + /// + /// ### Note + /// + /// If the string is less than 8 characters, the rest of the UUID will be filled with `0`s + #[inline] + fn from(input: &'a str) -> Self { + Self::from_to_string(input) + } +} + +impl From for [char; 8] { + #[inline(always)] + fn from(uuid: HardwareUUID) -> Self { + uuid.0 + } +} + +impl From for String { + #[inline(always)] + fn from(uuid: HardwareUUID) -> Self { + uuid.0.iter().collect() + } +} + +impl ToString for HardwareUUID { + #[inline(always)] + fn to_string(&self) -> String { + self.0.iter().collect() + } +} diff --git a/robot/core/lib.rs b/robot/core/lib.rs new file mode 100644 index 0000000..21f5fc5 --- /dev/null +++ b/robot/core/lib.rs @@ -0,0 +1,49 @@ +#![doc = include_str!("../README.md")] +#![warn(missing_docs, unused, clippy::all, unsafe_code)] +#![deny(missing_debug_implementations)] + +pub mod hardware; +pub mod gamepad; +mod telemetry; +mod error; + +pub use error::{HardwareError, Result, IO_OK}; +pub use hardware::HardwareMap; +pub use telemetry::Telemetry; + +use gamepad::Gamepad; + +#[derive(Debug, Clone)] +pub struct OpMode where + H: HardwareMap, + T: Telemetry, + G: Gamepad, +{ + hardware_map: H, + telemetry: T, + gamepad: G, +} + +impl OpMode where + H: HardwareMap, + T: Telemetry, + G: Gamepad, +{ + /// Creates a new `OpMode` with the given hardware map, telemetry, and gamepad + #[inline(always)] + #[must_use = "This returns a new OpMode"] + pub const fn new(hardware_map: H, telemetry: T, gamepad: G) -> Self { + Self { hardware_map, telemetry, gamepad } + } +} + +#[path = "hardware/uuid.rs"] +mod __uuid; +pub use __uuid::HardwareUUID; + +/// A trait that represents a hardware component +pub trait HardwareComponent: core::fmt::Debug { + /// Returns the UUID of this component + #[allow(non_snake_case)] + fn getUUID(&self) -> HardwareUUID; +} diff --git a/robot/core/telemetry.rs b/robot/core/telemetry.rs new file mode 100644 index 0000000..9678b68 --- /dev/null +++ b/robot/core/telemetry.rs @@ -0,0 +1,20 @@ +use crate::HardwareComponent; +use core::fmt::{Debug, Display}; + +/// A type that allows sending telemetry data to the driver control station +/// +/// Although this is a trait, it is not meant to be implemented by the user. +/// Instead, it is implemented by the robot crate. +/// +/// Even though it is marked as `HardwareComponent`, it is not meant to be loaded. +/// Infact, it will always return `HardwareError::DeviceNotFound` when loaded. +pub trait Telemetry: HardwareComponent { + /// Sends a debug message to the driver control station + /// + /// It will not be displayed to the driver control station if the robot is not in debug mode. + fn debug(&self, message: T); + /// Sends a message to the driver control station + /// + /// This will always be displayed to the driver control station. + fn send(&self, message: T); +} diff --git a/robot/hardware/gamepad/impls.rs b/robot/hardware/gamepad/impls.rs deleted file mode 100644 index 3edc94e..0000000 --- a/robot/hardware/gamepad/impls.rs +++ /dev/null @@ -1,319 +0,0 @@ -//! Implementations of the `Gamepad` trait for various gamepads. - -use super::*; - -/// A gamepad with no inputs. -#[repr(C)] -#[derive(Default, Debug, Clone, Copy, PartialEq)] -pub struct LogitechF310 { - // Dpad - dpad_up: bool, - dpad_down: bool, - dpad_left: bool, - dpad_right: bool, - - // Sticks - left_stick_x: f64, - left_stick_y: f64, - right_stick_x: f64, - right_stick_y: f64, - - // Triggers - left_trigger: f64, - right_trigger: f64, - - // Buttons - a: bool, - b: bool, - x: bool, - y: bool, - - // Bumpers - left_bumper: bool, - right_bumper: bool, - - // Other - back: bool, - start: bool, - left_stick_button: bool, - right_stick_button: bool, -} - -impl LogitechF310 { - /// Creates a new `LogitechF310` with all values set to their defaults. - #[inline] - #[must_use = "This returns a new LogitechF310"] - pub const fn new() -> Self { - Self { - dpad_up: false, - dpad_down: false, - dpad_left: false, - dpad_right: false, - - left_stick_x: 0.0, - left_stick_y: 0.0, - right_stick_x: 0.0, - right_stick_y: 0.0, - - left_trigger: 0.0, - right_trigger: 0.0, - - a: false, - b: false, - x: false, - y: false, - - left_bumper: false, - right_bumper: false, - - back: false, - start: false, - left_stick_button: false, - right_stick_button: false, - } - } -} - -impl Gamepad for LogitechF310 { - #[inline] - fn dpad(&self) -> crate::Result { - Ok(GamepadDpad::new( - self.dpad_up, - self.dpad_down, - self.dpad_left, - self.dpad_right, - )) - } - #[inline] - fn left_stick(&self) -> crate::Result { - Ok(GamepadStick::new( - self.left_stick_x, - self.left_stick_y, - self.left_stick_button, - )) - } - #[inline] - fn right_stick(&self) -> crate::Result { - Ok(GamepadStick::new( - self.right_stick_x, - self.right_stick_y, - self.right_stick_button, - )) - } - #[inline] - fn left_trigger(&self) -> crate::Result { - Ok(self.left_trigger) - } - #[inline] - fn right_trigger(&self) -> crate::Result { - Ok(self.right_trigger) - } - #[inline] - fn a(&self) -> crate::Result { - Ok(self.a) - } - #[inline] - fn b(&self) -> crate::Result { - Ok(self.b) - } - #[inline] - fn x(&self) -> crate::Result { - Ok(self.x) - } - #[inline] - fn y(&self) -> crate::Result { - Ok(self.y) - } - #[inline] - fn left_bumper(&self) -> crate::Result { - Ok(self.left_bumper) - } - #[inline] - fn right_bumper(&self) -> crate::Result { - Ok(self.right_bumper) - } - #[inline] - fn back(&self) -> crate::Result { - Ok(self.back) - } - #[inline] - fn start(&self) -> crate::Result { - Ok(self.start) - } -} - -impl MutableGamepad for LogitechF310 { - #[inline] - fn set_dpad(&mut self, dpad: GamepadDpad) -> crate::Result { - self.dpad_up = dpad.up; - self.dpad_down = dpad.down; - self.dpad_left = dpad.left; - self.dpad_right = dpad.right; - Ok(()) - } - #[inline] - fn set_left_stick(&mut self, stick: GamepadStick) -> crate::Result { - self.left_stick_x = stick.x; - self.left_stick_y = stick.y; - self.left_stick_button = stick.pressed; - Ok(()) - } - #[inline] - fn set_right_stick(&mut self, stick: GamepadStick) -> crate::Result { - self.right_stick_x = stick.x; - self.right_stick_y = stick.y; - self.right_stick_button = stick.pressed; - Ok(()) - } - #[inline] - fn set_left_trigger(&mut self, trigger: f64) -> crate::Result { - self.left_trigger = trigger; - Ok(()) - } - #[inline] - fn set_right_trigger(&mut self, trigger: f64) -> crate::Result { - self.right_trigger = trigger; - Ok(()) - } - #[inline] - fn set_a(&mut self, value: bool) -> crate::Result { - self.a = value; - Ok(()) - } - #[inline] - fn set_b(&mut self, value: bool) -> crate::Result { - self.b = value; - Ok(()) - } - #[inline] - fn set_x(&mut self, value: bool) -> crate::Result { - self.x = value; - Ok(()) - } - #[inline] - fn set_y(&mut self, value: bool) -> crate::Result { - self.y = value; - Ok(()) - } - #[inline] - fn set_left_bumper(&mut self, value: bool) -> crate::Result { - self.left_bumper = value; - Ok(()) - } - #[inline] - fn set_right_bumper(&mut self, value: bool) -> crate::Result { - self.right_bumper = value; - Ok(()) - } - #[inline] - fn set_back(&mut self, value: bool) -> crate::Result { - self.back = value; - Ok(()) - } - #[inline] - fn set_start(&mut self, value: bool) -> crate::Result { - self.start = value; - Ok(()) - } -} - -/// A gamepad with no inputs. -/// -/// This is purely for stubbing. -#[repr(transparent)] -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Stub; - -impl Gamepad for Stub { - #[inline] - fn dpad(&self) -> crate::Result { - Ok(GamepadDpad::new(false, false, false, false)) - } - #[inline] - fn left_stick(&self) -> crate::Result { - Ok(GamepadStick::new(0.0, 0.0, false)) - } - #[inline] - fn right_stick(&self) -> crate::Result { - Ok(GamepadStick::new(0.0, 0.0, false)) - } - #[inline] - fn left_trigger(&self) -> crate::Result { - Ok(0.0) - } - #[inline] - fn right_trigger(&self) -> crate::Result { - Ok(0.0) - } - #[inline] - fn a(&self) -> crate::Result { - Ok(false) - } - #[inline] - fn b(&self) -> crate::Result { - Ok(false) - } - #[inline] - fn x(&self) -> crate::Result { - Ok(false) - } - #[inline] - fn y(&self) -> crate::Result { - Ok(false) - } - #[inline] - fn left_bumper(&self) -> crate::Result { - Ok(false) - } - #[inline] - fn right_bumper(&self) -> crate::Result { - Ok(false) - } -} - -impl MutableGamepad for Stub { - #[inline] - fn set_dpad(&mut self, _dpad: GamepadDpad) -> crate::Result { - Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) - } - #[inline] - fn set_left_stick(&mut self, _stick: GamepadStick) -> crate::Result { - Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) - } - #[inline] - fn set_right_stick(&mut self, _stick: GamepadStick) -> crate::Result { - Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) - } - #[inline] - fn set_left_trigger(&mut self, _trigger: f64) -> crate::Result { - Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) - } - #[inline] - fn set_right_trigger(&mut self, _trigger: f64) -> crate::Result { - Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) - } - #[inline] - fn set_a(&mut self, _value: bool) -> crate::Result { - Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) - } - #[inline] - fn set_b(&mut self, _value: bool) -> crate::Result { - Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) - } - #[inline] - fn set_x(&mut self, _value: bool) -> crate::Result { - Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) - } - #[inline] - fn set_y(&mut self, _value: bool) -> crate::Result { - Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) - } - #[inline] - fn set_left_bumper(&mut self, _value: bool) -> crate::Result { - Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) - } - #[inline] - fn set_right_bumper(&mut self, _value: bool) -> crate::Result { - Err(crate::HardwareError::Other { message: "Stub gamepad cannot be modified" }) - } -} diff --git a/robot/hardware/lib.rs b/robot/hardware/lib.rs deleted file mode 100644 index d940dd0..0000000 --- a/robot/hardware/lib.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![doc = include_str!("../README.md")] -#![warn(missing_docs, unused, clippy::all, unsafe_code)] -#![deny(missing_debug_implementations)] - -pub mod gamepad; -mod error; - -pub use error::*; - -#[derive(Debug, Clone)] -pub struct HardwareMap { - -} - -impl HardwareMap { - pub fn init() -> Self { - Self { - } - } -} diff --git a/robot/runtime/Cargo.toml b/robot/pyruntime/Cargo.toml similarity index 80% rename from robot/runtime/Cargo.toml rename to robot/pyruntime/Cargo.toml index 4b18415..cb3be4c 100644 --- a/robot/runtime/Cargo.toml +++ b/robot/pyruntime/Cargo.toml @@ -11,9 +11,9 @@ license.workspace = true name = "arc_robot_server_python_runtime" path = "lib.rs" -[dependencies.hardware] -package = "arc-robot-hardware" -path = "../hardware" +[dependencies.arc_core] +package = "arc-robot-core" +path = "../core" [dependencies.pylib] package = "arc-pylib" diff --git a/robot/runtime/lib.rs b/robot/pyruntime/lib.rs similarity index 58% rename from robot/runtime/lib.rs rename to robot/pyruntime/lib.rs index 656b06e..a4d0b5e 100644 --- a/robot/runtime/lib.rs +++ b/robot/pyruntime/lib.rs @@ -3,48 +3,48 @@ #![warn(missing_docs, unused, clippy::all, unsafe_code)] #![deny(missing_debug_implementations)] -use pyo3::prelude::*; +// use pyo3::prelude::*; -#[derive(Debug, Clone)] -struct RuntimeOpMode { - hardware: hardware::HardwareMap, - name: String -} - -impl RuntimeOpMode { - fn start(&mut self, hardware: &mut hardware::HardwareMap) -> Result<()> { - Ok(()) - } -} - -#[derive(Debug, Clone)] -pub enum Error { - OpNotFound, -} - -pub type Result = core::result::Result; - -#[derive(Debug)] -pub struct PyRuntime { - ops: Vec, - thread: Option>, -} - -impl PyRuntime { - pub fn init() -> Self { - Self { - ops: Vec::new(), - thread: None, - } - } - pub fn start(&mut self, name: Name) -> Result<()> { - let name = name.to_string(); - let op = self.ops.iter_mut() - .find(|op| op.name == name) - .ok_or(Error::OpNotFound)?; - op.start(&mut self.hardware) - } -} +// #[derive(Debug, Clone)] +// struct RuntimeOpMode { +// hardware: hardware::HardwareMap, +// name: String +// } +// +// impl RuntimeOpMode { +// fn start(&mut self, hardware: &mut hardware::HardwareMap) -> Result<()> { +// Ok(()) +// } +// } +// +// #[derive(Debug, Clone)] +// pub enum Error { +// OpNotFound, +// } +// +// pub type Result = core::result::Result; +// +// #[derive(Debug)] +// pub struct PyRuntime { +// ops: Vec, +// thread: Option>, +// } +// +// impl PyRuntime { +// pub fn init() -> Self { +// Self { +// ops: Vec::new(), +// thread: None, +// } +// } +// pub fn start(&mut self, name: Name) -> Result<()> { +// let name = name.to_string(); +// let op = self.ops.iter_mut() +// .find(|op| op.name == name) +// .ok_or(Error::OpNotFound)?; +// op.start(&mut self.hardware) +// } +// } // fn main() -> PyResult<()> { // Setup hardware components diff --git a/scripts/doc.py b/scripts/doc.py index c3da245..15dff69 100644 --- a/scripts/doc.py +++ b/scripts/doc.py @@ -5,7 +5,7 @@ def doc(cd: str, args: list[str]) -> str | int | None: PACKAGES = [ "arc-pylib", - "arc-robot-hardware", + "arc-robot-core", # "libodo", # "libpath", "libtrig", diff --git a/server/main.rs b/server/main.rs index e046ce0..c7dc86f 100644 --- a/server/main.rs +++ b/server/main.rs @@ -1,5 +1,3 @@ -use robot::pyruntime::PyRuntime; - use arc_rs::html::*; arc_rs::inc!(); @@ -42,9 +40,9 @@ async fn upload<'a>(name: &'a str, input: rocket::Data<'_>) -> Result { } fn main() { - let mut python_runtime = PyRuntime::init(); + // let mut python_runtime = PyRuntime::init(); - python_runtime.start("auto").unwrap(); + // python_runtime.start("auto").unwrap(); } // #[rocket::main] From 7ea1452c654ae1b443a4c9757e6f3cb97e7ba8e4 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sun, 24 Dec 2023 16:03:31 -0800 Subject: [PATCH 89/93] updated examples --- examples/mecanum_auto.py | 35 ++++++++++++++++++++++++++++++++ examples/mecanum_basic_teleop.py | 2 +- examples/tank_drive_teleop.py | 2 +- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 examples/mecanum_auto.py diff --git a/examples/mecanum_auto.py b/examples/mecanum_auto.py new file mode 100644 index 0000000..ac00cec --- /dev/null +++ b/examples/mecanum_auto.py @@ -0,0 +1,35 @@ +from .util.drive import MechanumDrive +from arc.hardware import * +from arc.math import * +from arc import * + +# You are REQUIRED to have a main() function in your program. +# and you MUST NOT call it yourself. +@Auto("Mechanum Drive Example Autonomous") +def main(op: Op): + op.log("Starting...") + + # Create a MechanumDrive object. + fl = op.hardwareMap[DcMotor]("motor0") + fr = op.hardwareMap[DcMotor]("motor1") + bl = op.hardwareMap[DcMotor]("motor2") + br = op.hardwareMap[DcMotor]("motor3") + drive = MechanumDrive(fl, fr, bl, br) + + # Drive forward for 2 seconds. + movement = drive.calc(Angle.from_degrees(90), 1, 0) + drive.move(movement) + + sleep(2) + + # Drive right for 2 seconds. + movement = drive.calc(Angle.from_degrees(0), 1, 0) + drive.move(movement) + + sleep(2) + + # Stop + drive.stop() + + op.log("Done!") + return OK diff --git a/examples/mecanum_basic_teleop.py b/examples/mecanum_basic_teleop.py index 4d7fed6..42825b5 100644 --- a/examples/mecanum_basic_teleop.py +++ b/examples/mecanum_basic_teleop.py @@ -4,7 +4,7 @@ # You are REQUIRED to have a main() function in your program. # and you MUST NOT call it yourself. -@Teleop("Mechanum Drive example") +@Teleop("Basic Mechanum Drive Example") def main(op: Op): op.log("Starting...") diff --git a/examples/tank_drive_teleop.py b/examples/tank_drive_teleop.py index 4d2df5e..208b3d1 100644 --- a/examples/tank_drive_teleop.py +++ b/examples/tank_drive_teleop.py @@ -4,7 +4,7 @@ # You are REQUIRED to have a main() function in your program. # and you MUST NOT call it yourself. -@Teleop("Tank Drive example") +@Teleop("Tank Drive Example") def main(op: Op): op.log("Starting...") From 7b11b51d1813df47e25e16fe5a95d1cd9198b10f Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Thu, 28 Dec 2023 08:36:59 -0800 Subject: [PATCH 90/93] Restructured the codebase --- .markdownlint.json | 4 - Cargo.toml | 33 +- arc/Cargo.toml | 6 +- arc/__init__.pyi | 6 +- arc/__init__.rs | 30 +- arc/hardware/gamepad.rs | 2 +- arc/lib.rs | 26 +- .../GUIDE_MODIFYING_ROBOT_CONFIG.md | 0 dranik.rs | 2 + epearl | 17 - epearl.bat | 35 - epearl.py | 43 -- examples/tank_drive_teleop.py | 10 +- gradle.properties | 1 - helpers/l2math/Cargo.toml | 19 - helpers/l2math/README.md | 9 - helpers/l2math/consts.rs | 151 ---- helpers/l2math/core.rs | 160 ----- helpers/l2math/core/acos.rs | 112 --- helpers/l2math/core/acosf.rs | 84 --- helpers/l2math/core/acosh.rs | 32 - helpers/l2math/core/acoshf.rs | 31 - helpers/l2math/core/asin.rs | 116 --- helpers/l2math/core/asinf.rs | 77 -- helpers/l2math/core/asinh.rs | 45 -- helpers/l2math/core/asinhf.rs | 42 -- helpers/l2math/core/atan.rs | 189 ----- helpers/l2math/core/atan2.rs | 135 ---- helpers/l2math/core/atan2f.rs | 99 --- helpers/l2math/core/atanf.rs | 117 --- helpers/l2math/core/atanh.rs | 40 -- helpers/l2math/core/atanhf.rs | 40 -- helpers/l2math/core/cbrt.rs | 111 --- helpers/l2math/core/cbrtf.rs | 77 -- helpers/l2math/core/ceil.rs | 83 --- helpers/l2math/core/ceilf.rs | 66 -- helpers/l2math/core/copysign.rs | 15 - helpers/l2math/core/copysignf.rs | 15 - helpers/l2math/core/cos.rs | 85 --- helpers/l2math/core/cosf.rs | 90 --- helpers/l2math/core/cosh.rs | 41 -- helpers/l2math/core/coshf.rs | 41 -- helpers/l2math/core/erf.rs | 310 -------- helpers/l2math/core/erff.rs | 212 ------ helpers/l2math/core/exp.rs | 156 ---- helpers/l2math/core/exp10.rs | 30 - helpers/l2math/core/exp10f.rs | 29 - helpers/l2math/core/exp2.rs | 397 ----------- helpers/l2math/core/exp2f.rs | 139 ---- helpers/l2math/core/expf.rs | 106 --- helpers/l2math/core/expm1.rs | 147 ---- helpers/l2math/core/expm1f.rs | 139 ---- helpers/l2math/core/expo2.rs | 20 - helpers/l2math/core/fabs.rs | 43 -- helpers/l2math/core/fabsf.rs | 45 -- helpers/l2math/core/fdim.rs | 24 - helpers/l2math/core/fdimf.rs | 24 - helpers/l2math/core/fenv.rs | 28 - helpers/l2math/core/floor.rs | 83 --- helpers/l2math/core/floorf.rs | 67 -- helpers/l2math/core/fma.rs | 233 ------ helpers/l2math/core/fmaf.rs | 114 --- helpers/l2math/core/fmax.rs | 16 - helpers/l2math/core/fmaxf.rs | 16 - helpers/l2math/core/fmin.rs | 16 - helpers/l2math/core/fminf.rs | 16 - helpers/l2math/core/fmod.rs | 86 --- helpers/l2math/core/fmodf.rs | 94 --- helpers/l2math/core/frexp.rs | 36 - helpers/l2math/core/frexpf.rs | 37 - helpers/l2math/core/hypot.rs | 70 -- helpers/l2math/core/hypotf.rs | 47 -- helpers/l2math/core/ilogb.rs | 37 - helpers/l2math/core/ilogbf.rs | 37 - helpers/l2math/core/j0.rs | 434 ------------ helpers/l2math/core/j0f.rs | 362 ---------- helpers/l2math/core/j1.rs | 407 ----------- helpers/l2math/core/j1f.rs | 382 ---------- helpers/l2math/core/jn.rs | 351 --------- helpers/l2math/core/jnf.rs | 265 ------- helpers/l2math/core/k_cos.rs | 66 -- helpers/l2math/core/k_cosf.rs | 33 - helpers/l2math/core/k_expo2.rs | 16 - helpers/l2math/core/k_expo2f.rs | 16 - helpers/l2math/core/k_sin.rs | 61 -- helpers/l2math/core/k_sinf.rs | 34 - helpers/l2math/core/k_tan.rs | 110 --- helpers/l2math/core/k_tanf.rs | 50 -- helpers/l2math/core/ldexp.rs | 9 - helpers/l2math/core/ldexpf.rs | 9 - helpers/l2math/core/lgamma.rs | 13 - helpers/l2math/core/lgamma_r.rs | 337 --------- helpers/l2math/core/lgammaf.rs | 13 - helpers/l2math/core/lgammaf_r.rs | 268 ------- helpers/l2math/core/ln.rs | 11 - helpers/l2math/core/ln1p.rs | 139 ---- helpers/l2math/core/ln1pf.rs | 92 --- helpers/l2math/core/lnf.rs | 11 - helpers/l2math/core/log.rs | 124 ---- helpers/l2math/core/log10.rs | 110 --- helpers/l2math/core/log10f.rs | 85 --- helpers/l2math/core/log2.rs | 100 --- helpers/l2math/core/log2f.rs | 81 --- helpers/l2math/core/logf.rs | 71 -- helpers/l2math/core/modf.rs | 44 -- helpers/l2math/core/modff.rs | 43 -- helpers/l2math/core/nextafter.rs | 41 -- helpers/l2math/core/nextafterf.rs | 41 -- helpers/l2math/core/pow.rs | 645 ----------------- helpers/l2math/core/powf.rs | 340 --------- helpers/l2math/core/rem_pio2.rs | 235 ------ helpers/l2math/core/rem_pio2_large.rs | 473 ------------- helpers/l2math/core/rem_pio2f.rs | 69 -- helpers/l2math/core/remainder.rs | 9 - helpers/l2math/core/remainderf.rs | 9 - helpers/l2math/core/remquo.rs | 117 --- helpers/l2math/core/remquof.rs | 108 --- helpers/l2math/core/rint.rs | 60 -- helpers/l2math/core/rintf.rs | 60 -- helpers/l2math/core/round.rs | 32 - helpers/l2math/core/roundf.rs | 34 - helpers/l2math/core/scalbn.rs | 37 - helpers/l2math/core/scalbnf.rs | 33 - helpers/l2math/core/sin.rs | 103 --- helpers/l2math/core/sincos.rs | 141 ---- helpers/l2math/core/sincosf.rs | 191 ----- helpers/l2math/core/sinf.rs | 97 --- helpers/l2math/core/sinh.rs | 52 -- helpers/l2math/core/sinhf.rs | 34 - helpers/l2math/core/sqrt.rs | 284 -------- helpers/l2math/core/sqrtf.rs | 176 ----- helpers/l2math/core/tan.rs | 76 -- helpers/l2math/core/tanf.rs | 82 --- helpers/l2math/core/tanh.rs | 56 -- helpers/l2math/core/tanhf.rs | 43 -- helpers/l2math/core/tgamma.rs | 211 ------ helpers/l2math/core/tgammaf.rs | 11 - helpers/l2math/core/trunc.rs | 42 -- helpers/l2math/core/truncf.rs | 44 -- helpers/l2math/core/ulp.rs | 115 --- helpers/l2math/lib.rs | 58 -- helpers/l2math/macros.rs | 21 - helpers/l2math/types.rs | 24 - helpers/libtrig/Cargo.toml | 20 - helpers/libtrig/README.md | 7 - helpers/libtrig/angle.rs | 606 ---------------- helpers/libtrig/coords/coord2d.rs | 319 --------- helpers/libtrig/coords/coord3d.rs | 9 - helpers/libtrig/coords/mod.rs | 5 - helpers/libtrig/lib.rs | 36 - helpers/libtrig/morenums/mod.rs | 27 - helpers/libtrig/morenums/u2/impls.rs | 173 ----- helpers/libtrig/morenums/u2/mod.rs | 5 - helpers/libtrig/morenums/u2/source.rs | 387 ---------- helpers/libtrig/morenums/u2/tests.rs | 95 --- helpers/libtrig/morenums/u3/impls.rs | 181 ----- helpers/libtrig/morenums/u3/mod.rs | 5 - helpers/libtrig/morenums/u3/source.rs | 462 ------------ helpers/libtrig/morenums/u3/tests.rs | 423 ----------- helpers/libtrig/pos2d.rs | 265 ------- helpers/libtrig/traits/float.rs | 668 ------------------ helpers/libtrig/traits/impls.rs | 179 ----- helpers/libtrig/traits/mod.rs | 6 - helpers/libtrig/traits/number.rs | 28 - helpers/libtrig/types.rs | 7 - helpers/libtrig/vectors/mod.rs | 5 - helpers/libtrig/vectors/vec2d.rs | 231 ------ helpers/libtrig/vectors/vec3d.rs | 226 ------ helpers/macros/Cargo.toml | 16 - helpers/macros/lib.rs | 23 - helpers/macros/macros-core/Cargo.toml | 16 - helpers/macros/macros-core/ffi/mod.rs | 98 --- helpers/macros/macros-core/func_mod/mod.rs | 258 ------- helpers/macros/macros-core/lib.rs | 14 - helpers/macros/macros-core/mass_impl/args.rs | 45 -- helpers/macros/macros-core/mass_impl/mod.rs | 45 -- .../macros/macros-core/mass_impl/variants.rs | 111 --- pyproject.toml | 9 - robot/Cargo.toml | 55 +- robot/core/Cargo.toml | 17 +- {server => robot/core}/README.md | 0 robot/core/config.rs | 25 + robot/core/gamepad.rs | 2 +- robot/core/hardware.rs | 13 +- robot/core/hardware/dcmotor.rs | 20 +- robot/core/internals/INTERNALS.md | 6 + robot/core/internals/impls.rs | 35 + robot/core/internals/impls/dcmotor.rs | 29 + robot/core/internals/impls/gamepad.rs | 125 ++++ robot/core/internals/mod.rs | 11 + robot/core/io.rs | 30 + robot/core/lib.rs | 25 +- robot/core/telemetry.rs | 3 +- {arc => robot/core}/threadsafe.rs | 194 ++--- robot/lib.rs | 122 +++- robot/pyruntime/Cargo.toml | 24 - robot/python/Cargo.toml | 19 + robot/python/README.md | 0 robot/{pyruntime => python}/lib.rs | 43 +- robot/web/Cargo.toml | 19 + robot/web/README.md | 0 robot/web/assets/logo.png | Bin 0 -> 17222 bytes robot/web/assets/logo.svg | 8 + robot/web/assets/logo192.ico | Bin 0 -> 152126 bytes robot/web/assets/logo256.ico | Bin 0 -> 12847 bytes robot/web/assets/logo64.ico | Bin 0 -> 16958 bytes robot/web/assets/logo_white.png | Bin 0 -> 14084 bytes robot/web/assets/logo_white_a.png | Bin 0 -> 49324 bytes robot/web/assets/logo_white_gear.png | Bin 0 -> 14766 bytes robot/web/lib.rs | 11 + rust-toolchain | 1 - scripts/__init__.py | 42 -- scripts/build.py | 12 - scripts/clean.py | 42 -- scripts/doc.py | 22 - scripts/fmt.py | 7 - scripts/run.py | 14 - scripts/test.py | 90 --- server/Cargo.toml | 40 -- server/comptime.rs | 7 - server/html/.gitignore | 3 - server/html/SourceCodePro-Bold.ttf | Bin 120316 -> 0 bytes server/html/assets.rs | 65 -- server/html/code/index.html | 42 -- server/html/error.html | 14 - server/html/error.rs | 83 --- server/html/index.html | 32 - server/html/macros.rs | 177 ----- server/html/mod.rs | 56 -- server/html/style.css | 66 -- server/lib.rs | 32 - server/main.rs | 69 -- uploader/Cargo.toml | 12 - uploader/main.rs | 3 - 234 files changed, 714 insertions(+), 19605 deletions(-) delete mode 100644 .markdownlint.json rename helpers/macros/README.md => docs/GUIDE_MODIFYING_ROBOT_CONFIG.md (100%) create mode 100644 dranik.rs delete mode 100644 epearl delete mode 100644 epearl.bat delete mode 100644 epearl.py delete mode 100644 gradle.properties delete mode 100644 helpers/l2math/Cargo.toml delete mode 100644 helpers/l2math/README.md delete mode 100644 helpers/l2math/consts.rs delete mode 100644 helpers/l2math/core.rs delete mode 100644 helpers/l2math/core/acos.rs delete mode 100644 helpers/l2math/core/acosf.rs delete mode 100644 helpers/l2math/core/acosh.rs delete mode 100644 helpers/l2math/core/acoshf.rs delete mode 100644 helpers/l2math/core/asin.rs delete mode 100644 helpers/l2math/core/asinf.rs delete mode 100644 helpers/l2math/core/asinh.rs delete mode 100644 helpers/l2math/core/asinhf.rs delete mode 100644 helpers/l2math/core/atan.rs delete mode 100644 helpers/l2math/core/atan2.rs delete mode 100644 helpers/l2math/core/atan2f.rs delete mode 100644 helpers/l2math/core/atanf.rs delete mode 100644 helpers/l2math/core/atanh.rs delete mode 100644 helpers/l2math/core/atanhf.rs delete mode 100644 helpers/l2math/core/cbrt.rs delete mode 100644 helpers/l2math/core/cbrtf.rs delete mode 100644 helpers/l2math/core/ceil.rs delete mode 100644 helpers/l2math/core/ceilf.rs delete mode 100644 helpers/l2math/core/copysign.rs delete mode 100644 helpers/l2math/core/copysignf.rs delete mode 100644 helpers/l2math/core/cos.rs delete mode 100644 helpers/l2math/core/cosf.rs delete mode 100644 helpers/l2math/core/cosh.rs delete mode 100644 helpers/l2math/core/coshf.rs delete mode 100644 helpers/l2math/core/erf.rs delete mode 100644 helpers/l2math/core/erff.rs delete mode 100644 helpers/l2math/core/exp.rs delete mode 100644 helpers/l2math/core/exp10.rs delete mode 100644 helpers/l2math/core/exp10f.rs delete mode 100644 helpers/l2math/core/exp2.rs delete mode 100644 helpers/l2math/core/exp2f.rs delete mode 100644 helpers/l2math/core/expf.rs delete mode 100644 helpers/l2math/core/expm1.rs delete mode 100644 helpers/l2math/core/expm1f.rs delete mode 100644 helpers/l2math/core/expo2.rs delete mode 100644 helpers/l2math/core/fabs.rs delete mode 100644 helpers/l2math/core/fabsf.rs delete mode 100644 helpers/l2math/core/fdim.rs delete mode 100644 helpers/l2math/core/fdimf.rs delete mode 100644 helpers/l2math/core/fenv.rs delete mode 100644 helpers/l2math/core/floor.rs delete mode 100644 helpers/l2math/core/floorf.rs delete mode 100644 helpers/l2math/core/fma.rs delete mode 100644 helpers/l2math/core/fmaf.rs delete mode 100644 helpers/l2math/core/fmax.rs delete mode 100644 helpers/l2math/core/fmaxf.rs delete mode 100644 helpers/l2math/core/fmin.rs delete mode 100644 helpers/l2math/core/fminf.rs delete mode 100644 helpers/l2math/core/fmod.rs delete mode 100644 helpers/l2math/core/fmodf.rs delete mode 100644 helpers/l2math/core/frexp.rs delete mode 100644 helpers/l2math/core/frexpf.rs delete mode 100644 helpers/l2math/core/hypot.rs delete mode 100644 helpers/l2math/core/hypotf.rs delete mode 100644 helpers/l2math/core/ilogb.rs delete mode 100644 helpers/l2math/core/ilogbf.rs delete mode 100644 helpers/l2math/core/j0.rs delete mode 100644 helpers/l2math/core/j0f.rs delete mode 100644 helpers/l2math/core/j1.rs delete mode 100644 helpers/l2math/core/j1f.rs delete mode 100644 helpers/l2math/core/jn.rs delete mode 100644 helpers/l2math/core/jnf.rs delete mode 100644 helpers/l2math/core/k_cos.rs delete mode 100644 helpers/l2math/core/k_cosf.rs delete mode 100644 helpers/l2math/core/k_expo2.rs delete mode 100644 helpers/l2math/core/k_expo2f.rs delete mode 100644 helpers/l2math/core/k_sin.rs delete mode 100644 helpers/l2math/core/k_sinf.rs delete mode 100644 helpers/l2math/core/k_tan.rs delete mode 100644 helpers/l2math/core/k_tanf.rs delete mode 100644 helpers/l2math/core/ldexp.rs delete mode 100644 helpers/l2math/core/ldexpf.rs delete mode 100644 helpers/l2math/core/lgamma.rs delete mode 100644 helpers/l2math/core/lgamma_r.rs delete mode 100644 helpers/l2math/core/lgammaf.rs delete mode 100644 helpers/l2math/core/lgammaf_r.rs delete mode 100644 helpers/l2math/core/ln.rs delete mode 100644 helpers/l2math/core/ln1p.rs delete mode 100644 helpers/l2math/core/ln1pf.rs delete mode 100644 helpers/l2math/core/lnf.rs delete mode 100644 helpers/l2math/core/log.rs delete mode 100644 helpers/l2math/core/log10.rs delete mode 100644 helpers/l2math/core/log10f.rs delete mode 100644 helpers/l2math/core/log2.rs delete mode 100644 helpers/l2math/core/log2f.rs delete mode 100644 helpers/l2math/core/logf.rs delete mode 100644 helpers/l2math/core/modf.rs delete mode 100644 helpers/l2math/core/modff.rs delete mode 100644 helpers/l2math/core/nextafter.rs delete mode 100644 helpers/l2math/core/nextafterf.rs delete mode 100644 helpers/l2math/core/pow.rs delete mode 100644 helpers/l2math/core/powf.rs delete mode 100644 helpers/l2math/core/rem_pio2.rs delete mode 100644 helpers/l2math/core/rem_pio2_large.rs delete mode 100644 helpers/l2math/core/rem_pio2f.rs delete mode 100644 helpers/l2math/core/remainder.rs delete mode 100644 helpers/l2math/core/remainderf.rs delete mode 100644 helpers/l2math/core/remquo.rs delete mode 100644 helpers/l2math/core/remquof.rs delete mode 100644 helpers/l2math/core/rint.rs delete mode 100644 helpers/l2math/core/rintf.rs delete mode 100644 helpers/l2math/core/round.rs delete mode 100644 helpers/l2math/core/roundf.rs delete mode 100644 helpers/l2math/core/scalbn.rs delete mode 100644 helpers/l2math/core/scalbnf.rs delete mode 100644 helpers/l2math/core/sin.rs delete mode 100644 helpers/l2math/core/sincos.rs delete mode 100644 helpers/l2math/core/sincosf.rs delete mode 100644 helpers/l2math/core/sinf.rs delete mode 100644 helpers/l2math/core/sinh.rs delete mode 100644 helpers/l2math/core/sinhf.rs delete mode 100644 helpers/l2math/core/sqrt.rs delete mode 100644 helpers/l2math/core/sqrtf.rs delete mode 100644 helpers/l2math/core/tan.rs delete mode 100644 helpers/l2math/core/tanf.rs delete mode 100644 helpers/l2math/core/tanh.rs delete mode 100644 helpers/l2math/core/tanhf.rs delete mode 100644 helpers/l2math/core/tgamma.rs delete mode 100644 helpers/l2math/core/tgammaf.rs delete mode 100644 helpers/l2math/core/trunc.rs delete mode 100644 helpers/l2math/core/truncf.rs delete mode 100644 helpers/l2math/core/ulp.rs delete mode 100644 helpers/l2math/lib.rs delete mode 100644 helpers/l2math/macros.rs delete mode 100644 helpers/l2math/types.rs delete mode 100644 helpers/libtrig/Cargo.toml delete mode 100644 helpers/libtrig/README.md delete mode 100644 helpers/libtrig/angle.rs delete mode 100644 helpers/libtrig/coords/coord2d.rs delete mode 100644 helpers/libtrig/coords/coord3d.rs delete mode 100644 helpers/libtrig/coords/mod.rs delete mode 100644 helpers/libtrig/lib.rs delete mode 100644 helpers/libtrig/morenums/mod.rs delete mode 100644 helpers/libtrig/morenums/u2/impls.rs delete mode 100644 helpers/libtrig/morenums/u2/mod.rs delete mode 100644 helpers/libtrig/morenums/u2/source.rs delete mode 100644 helpers/libtrig/morenums/u2/tests.rs delete mode 100644 helpers/libtrig/morenums/u3/impls.rs delete mode 100644 helpers/libtrig/morenums/u3/mod.rs delete mode 100644 helpers/libtrig/morenums/u3/source.rs delete mode 100644 helpers/libtrig/morenums/u3/tests.rs delete mode 100644 helpers/libtrig/pos2d.rs delete mode 100644 helpers/libtrig/traits/float.rs delete mode 100644 helpers/libtrig/traits/impls.rs delete mode 100644 helpers/libtrig/traits/mod.rs delete mode 100644 helpers/libtrig/traits/number.rs delete mode 100644 helpers/libtrig/types.rs delete mode 100644 helpers/libtrig/vectors/mod.rs delete mode 100644 helpers/libtrig/vectors/vec2d.rs delete mode 100644 helpers/libtrig/vectors/vec3d.rs delete mode 100644 helpers/macros/Cargo.toml delete mode 100644 helpers/macros/lib.rs delete mode 100644 helpers/macros/macros-core/Cargo.toml delete mode 100644 helpers/macros/macros-core/ffi/mod.rs delete mode 100644 helpers/macros/macros-core/func_mod/mod.rs delete mode 100644 helpers/macros/macros-core/lib.rs delete mode 100644 helpers/macros/macros-core/mass_impl/args.rs delete mode 100644 helpers/macros/macros-core/mass_impl/mod.rs delete mode 100644 helpers/macros/macros-core/mass_impl/variants.rs delete mode 100644 pyproject.toml rename {server => robot/core}/README.md (100%) create mode 100644 robot/core/config.rs create mode 100644 robot/core/internals/INTERNALS.md create mode 100644 robot/core/internals/impls.rs create mode 100644 robot/core/internals/impls/dcmotor.rs create mode 100644 robot/core/internals/impls/gamepad.rs create mode 100644 robot/core/internals/mod.rs create mode 100644 robot/core/io.rs rename {arc => robot/core}/threadsafe.rs (60%) delete mode 100644 robot/pyruntime/Cargo.toml create mode 100644 robot/python/Cargo.toml create mode 100644 robot/python/README.md rename robot/{pyruntime => python}/lib.rs (65%) create mode 100644 robot/web/Cargo.toml create mode 100644 robot/web/README.md create mode 100644 robot/web/assets/logo.png create mode 100644 robot/web/assets/logo.svg create mode 100644 robot/web/assets/logo192.ico create mode 100644 robot/web/assets/logo256.ico create mode 100644 robot/web/assets/logo64.ico create mode 100644 robot/web/assets/logo_white.png create mode 100644 robot/web/assets/logo_white_a.png create mode 100644 robot/web/assets/logo_white_gear.png create mode 100644 robot/web/lib.rs delete mode 100644 rust-toolchain delete mode 100644 scripts/__init__.py delete mode 100644 scripts/build.py delete mode 100644 scripts/clean.py delete mode 100644 scripts/doc.py delete mode 100644 scripts/fmt.py delete mode 100644 scripts/run.py delete mode 100644 scripts/test.py delete mode 100644 server/Cargo.toml delete mode 100644 server/comptime.rs delete mode 100644 server/html/.gitignore delete mode 100644 server/html/SourceCodePro-Bold.ttf delete mode 100644 server/html/assets.rs delete mode 100644 server/html/code/index.html delete mode 100644 server/html/error.html delete mode 100644 server/html/error.rs delete mode 100644 server/html/index.html delete mode 100644 server/html/macros.rs delete mode 100644 server/html/mod.rs delete mode 100644 server/html/style.css delete mode 100644 server/lib.rs delete mode 100644 server/main.rs delete mode 100644 uploader/Cargo.toml delete mode 100644 uploader/main.rs diff --git a/.markdownlint.json b/.markdownlint.json deleted file mode 100644 index 79251c3..0000000 --- a/.markdownlint.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "no-inline-html": false, - "line-length": false -} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index b581aa0..3fbbe34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,29 +1,12 @@ [workspace] resolver = "2" # Resolver version (keep it 2) members = [ - ################################# - ### Main crates ### - ################################# # Python interface implementation "arc", # ARC client (used to control the robot) "client", - # Code uploader (used to upload code to the robot) - "uploader", - # Robot HTTP server, used to control the robot via HTTP - "server", - # Robot runtime (used to run the robot code) + # The robot code (hardware abstractions, python runtime, http server) "robot", - - ################################# - ### Helper crates ### - ################################# - # Low level math functions - "helpers/l2math", - # Trigonometric abstractions - "helpers/libtrig", - # Macros used to simplify code - "helpers/macros", ] [workspace.package] @@ -36,19 +19,7 @@ repository = "https://github.com/DranikiRobotics/arc" # Rust edition (keep it 2021) edition = "2021" # License of the entire workspace -license = "MIT" +license = "BSD-2-Clause" # Version of the entire workspace version = "0.0.1-dev" - -[profile.release] -# Optimization level (keep it 3) -opt-level = 3 - -# Emit debug symbols -debug = true -# debug = false - -# What to do when a panic occurs -panic = "unwind" -# panic = "abort" diff --git a/arc/Cargo.toml b/arc/Cargo.toml index c298517..5a246ca 100644 --- a/arc/Cargo.toml +++ b/arc/Cargo.toml @@ -11,12 +11,12 @@ license.workspace = true path = "lib.rs" crate-type = ["cdylib", "rlib"] -[dependencies.arc_robot_core] -package = "arc-robot-core" +[dependencies.dranikcore] +package = "dranik-core" path = "../robot/core" [dependencies.libtrig] -path = "../helpers/libtrig" +git = "https://github.com/DranikiRobotics/librobomath" package = "libtrig" [dependencies.pyo3] diff --git a/arc/__init__.pyi b/arc/__init__.pyi index 5f8d7a8..7dffd2f 100644 --- a/arc/__init__.pyi +++ b/arc/__init__.pyi @@ -16,6 +16,8 @@ RunResult = _typing.Union[bool, int, str, None] """ This type is used to indicate whether or not an `Op` completed successfully. +NOTE: This does NOT exist at runtime. It is only used for type checking. + If the `Op` completed successfully, then it should return `OK` (or `None`). If the `Op` did not complete successfully, then it should return an object that @@ -67,7 +69,7 @@ class Op(object): __OpFunc = _typing.Callable[[Op], RunResult] __OpAnnotation = _typing.Callable[[__OpFunc], __OpFunc] -def Auto(name: str) -> __OpAnnotation: +def Auto(name: str, config: str) -> __OpAnnotation: """ Decorator for an autonomous operation. @@ -80,7 +82,7 @@ def Auto(name: str) -> __OpAnnotation: """ ... -def Teleop(name: str) -> __OpAnnotation: +def Teleop(name: str, config: str) -> __OpAnnotation: """ Decorator for a teleop operation. diff --git a/arc/__init__.rs b/arc/__init__.rs index cf272fd..2a2d6c1 100644 --- a/arc/__init__.rs +++ b/arc/__init__.rs @@ -24,8 +24,8 @@ pub mod math; #[derive(Debug)] pub struct OpHolder { running: threadsafe::ThreadSafeBool, - gamepad: hardware::gamepad::Gamepad, start_time: std::time::Instant, + io: dranikcore::io::IO, } impl OpHolder { @@ -42,7 +42,7 @@ impl OpHolder { /// /// This call aquires a lock on the data pub fn gamepad(&self) -> &hardware::gamepad::Gamepad { - &self.gamepad + &self.io.gamepad } /// Stops the op mode /// @@ -97,20 +97,18 @@ threadsafe::thread_safe!(OpHolder); /// # } /// ``` #[pyclass] -#[derive(Debug, Clone)] +#[derive(Default, Debug, Clone)] pub struct Op(ThreadSafe); -impl crate::PyWrappedComponent for Op { - type Holder = OpHolder; - fn new(gamepad: hardware::gamepad::Gamepad) -> ThreadSafe { - ThreadSafe::new(OpHolder { - start_time: std::time::Instant::now(), - running: true.into(), +impl From for Op { + fn from(io: dranikcore::io::IO) -> Self { + let gamepad = hardware::gamepad::Gamepad::new(io.gamepad); + let holder = OpHolder { + running: threadsafe::ThreadSafeBool::new(true), gamepad, - }) - } - fn wrap(gamepad: &ThreadSafe) -> Self { - Self(gamepad.clone()) + start_time: std::time::Instant::now(), + }; + Self(ThreadSafe::new(holder)) } } @@ -166,7 +164,8 @@ struct Auto(String); impl Auto { #[new] #[doc(hidden)] - fn __new__(name: &str) -> Self { + #[pyo3(signature = (name, **_kwargs))] + fn __new__(name: &str, _kwargs: Option<&pyo3::types::PyDict>) -> Self { Self(name.to_string()) } #[doc(hidden)] @@ -192,7 +191,8 @@ struct Teleop(String); impl Teleop { #[new] #[doc(hidden)] - fn __new__(name: &str) -> Self { + #[pyo3(signature = (name, **_kwargs))] + fn __new__(name: &str, _kwargs: Option<&pyo3::types::PyDict>) -> Self { Self(name.to_string()) } #[doc(hidden)] diff --git a/arc/hardware/gamepad.rs b/arc/hardware/gamepad.rs index 4fa0d53..a20dda7 100644 --- a/arc/hardware/gamepad.rs +++ b/arc/hardware/gamepad.rs @@ -3,7 +3,7 @@ //! Python identifier: `arc.hardware.gamepad` use crate::threadsafe::ThreadSafe; -use arc_robot_core::gamepad as gp; +use dranikcore::gamepad as gp; use pyo3::prelude::*; /// The struct that actually contains the necessary data for the gamepad diff --git a/arc/lib.rs b/arc/lib.rs index d4635ff..a3b18c1 100644 --- a/arc/lib.rs +++ b/arc/lib.rs @@ -2,12 +2,9 @@ #![warn(missing_docs, unused, clippy::all, unsafe_code)] #![deny(missing_debug_implementations)] -#[doc(hidden)] -pub use arc_robot_core; - pub mod __init__; -mod macros; -pub mod threadsafe; +#[doc(hidden)] +pub mod macros; pub use threadsafe::{ThreadSafe, ThreadSafeError}; @@ -58,3 +55,22 @@ impl PyFunction { self.0.call1(py, args) } } + +#[doc(hidden)] +#[allow(non_camel_case_types)] +#[derive(Default, Debug, Clone, Copy)] +pub struct __dranik_config; + +impl dranikcore::config::RobotConfig for __dranik_config { + fn python_preload() { + use crate::__init__::arc as __arc_pylib; + pyo3::append_to_inittab!(__arc_pylib); + } + type Args = __init__::Op; + fn build_python_main_function_args<'a>( + py: &pyo3::Python<'_>, + io: &dranikcore::io::IO + ) -> (Self::Args, Option<&'a pyo3::types::PyDict>) { + (__init__::Op::from(io), None) + } +} diff --git a/helpers/macros/README.md b/docs/GUIDE_MODIFYING_ROBOT_CONFIG.md similarity index 100% rename from helpers/macros/README.md rename to docs/GUIDE_MODIFYING_ROBOT_CONFIG.md diff --git a/dranik.rs b/dranik.rs new file mode 100644 index 0000000..41614c4 --- /dev/null +++ b/dranik.rs @@ -0,0 +1,2 @@ +dranik::use_config!(arc); +dranik::main!(); \ No newline at end of file diff --git a/epearl b/epearl deleted file mode 100644 index db711d1..0000000 --- a/epearl +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -app_path=$0 -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit -exec "python" "$APP_HOME/epearl.py" "$APP_HOME" "$@" diff --git a/epearl.bat b/epearl.bat deleted file mode 100644 index f2cbd74..0000000 --- a/epearl.bat +++ /dev/null @@ -1,35 +0,0 @@ -@REM !/bin/bat - -@echo off - -@REM Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@REM Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@REM Build -set PYTHON_EXE=python.exe -%PYTHON_EXE% --version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: no 'python' command could be found in your PATH. -echo. -echo Please install Python - -:execute -"%PYTHON_EXE%" %APP_HOME%/epearl.py %APP_HOME% %*% -:end -@REM End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd -:fail -exit /b 1 -:mainEnd -if "%OS%"=="Windows_NT" endlocal -:omega \ No newline at end of file diff --git a/epearl.py b/epearl.py deleted file mode 100644 index d381eca..0000000 --- a/epearl.py +++ /dev/null @@ -1,43 +0,0 @@ -from scripts import run_cmd, hlp - -# Parse command line arguments -def get_args() -> tuple[str, list[str]]: - # Import sys - import sys - # Get the directory path (This is always supplied via the './epearl' script files) - dir_path = sys.argv[1] - # Replace backslashes with forward slashes - if '\\' in dir_path: dir_path = dir_path.replace('\\', '/') - # Add a trailing slash if there isn't one - if dir_path[-1] != "/": dir_path += "/" - # Get the other arguments - other_args = sys.argv[2:] - # Return the directory path and the other arguments - return (dir_path, other_args) - -# Run the main function -def main() -> str | int | None: - # Get the command line arguments - (cd, args) = get_args() - # Try to get the command and its arguments - try: - # Get the command and its arguments - (cmd, args) = (args[0], args[1:]) - except IndexError: - # If there is no command, run the help command - return hlp() - # Run the command - return run_cmd(cmd, cd, args) - -# Run main() if this file is run directly -if __name__ == "__main__": - # Run main() and return its exit code - try: exit(main()) - # If we were interrupted by the user, exit with code -1 - except KeyboardInterrupt: - print("Interrupted by user") - exit(-1) - # If there was an error, print it and exit with code 1 - except Exception as e: - print("Error: {}".format(e)) - exit(1) diff --git a/examples/tank_drive_teleop.py b/examples/tank_drive_teleop.py index 208b3d1..5f9c156 100644 --- a/examples/tank_drive_teleop.py +++ b/examples/tank_drive_teleop.py @@ -1,28 +1,26 @@ -from .util.drive import TankDrive from arc.hardware import * from arc import * # You are REQUIRED to have a main() function in your program. # and you MUST NOT call it yourself. -@Teleop("Tank Drive Example") +@Teleop("Tank Drive Example", config = "tank_drive") def main(op: Op): op.log("Starting...") # Create a tank drive with the left and right motors. leftMotor = op.hardwareMap[DcMotor]("motor0") rightMotor = op.hardwareMap[DcMotor]("motor1") - drive = TankDrive(leftMotor, rightMotor) # While the opmode is running... while op.running: # Get the left and right stick values. l = op.gamepad.left_stick.y r = op.gamepad.right_stick.y - movement = TankDrive.calc(l, r) op.debug("Left: ", l, "Right: ", r) # Drive the robot with the left and right sticks. - drive.move(movement) + leftMotor.power(l) + rightMotor.power(r) op.log("Done!") - return OK + return OK \ No newline at end of file diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 6924422..0000000 --- a/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -org.gradle.jvmargs=-Xmx8G diff --git a/helpers/l2math/Cargo.toml b/helpers/l2math/Cargo.toml deleted file mode 100644 index e4d61d2..0000000 --- a/helpers/l2math/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "l2math" -description = "Low Level Math" -repository.workspace = true -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true - -[lib] -path = "lib.rs" -doctest = false - -[dependencies.macros] -path = "../macros" - -[features] -unstable = [] -ffi = [] diff --git a/helpers/l2math/README.md b/helpers/l2math/README.md deleted file mode 100644 index 6e98005..0000000 --- a/helpers/l2math/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# **L**ow **L**evel **M**ath - -

A port of MUSL's Math library to Rust for no_std environments.

- -### Disclaimer - -It is exceptionally rare that you should use this library directly. -It is intended to be used by other libraries that require low level math functionality. -If you are looking for a math library, you should probably be using [`libtrig`](../libtrig/). diff --git a/helpers/l2math/consts.rs b/helpers/l2math/consts.rs deleted file mode 100644 index 9e8fb8d..0000000 --- a/helpers/l2math/consts.rs +++ /dev/null @@ -1,151 +0,0 @@ -#![allow(clippy::excessive_precision)] - -use crate::{Float64, Float32}; - -/// Archimedes' constant (π) -pub const PI: Float64 = 3.14159265358979323846264338327950288_f64; - -/// The full circle constant (τ) -/// -/// Equal to 2π. -pub const TAU: Float64 = 6.28318530717958647692528676655900577_f64; - -/// The golden ratio (φ) -pub const PHI: Float64 = 1.618033988749894848204586834365638118_f64; - -/// The Euler-Mascheroni constant (γ) -pub const EGAMMA: Float64 = 0.577215664901532860606512090082402431_f64; - -/// π/2 -pub const FRAC_PI_2: Float64 = 1.57079632679489661923132169163975144_f64; - -/// π/3 -pub const FRAC_PI_3: Float64 = 1.04719755119659774615421446109316763_f64; - -/// π/4 -pub const FRAC_PI_4: Float64 = 0.785398163397448309615660845819875721_f64; - -/// π/6 -pub const FRAC_PI_6: Float64 = 0.52359877559829887307710723054658381_f64; - -/// π/8 -pub const FRAC_PI_8: Float64 = 0.39269908169872415480783042290993786_f64; - -/// 1/π -pub const FRAC_1_PI: f64 = 0.318309886183790671537767526745028724_f64; - -/// 1/sqrt(π) -pub const FRAC_1_SQRT_PI: f64 = 0.564189583547756286948079451560772586_f64; - -/// 2/π -pub const FRAC_2_PI: f64 = 0.636619772367581343075535053490057448_f64; - -/// 2/sqrt(π) -pub const FRAC_2_SQRT_PI: f64 = 1.12837916709551257389615890312154517_f64; - -/// sqrt(2) -pub const SQRT_2: f64 = 1.41421356237309504880168872420969808_f64; - -/// 1/sqrt(2) -pub const FRAC_1_SQRT_2: f64 = 0.707106781186547524400844362104849039_f64; - -/// sqrt(3) -pub const SQRT_3: f64 = 1.732050807568877293527446341505872367_f64; - -/// 1/sqrt(3) -pub const FRAC_1_SQRT_3: f64 = 0.577350269189625764509148780501957456_f64; - -/// Euler's number (e) -pub const E: f64 = 2.71828182845904523536028747135266250_f64; - -/// log2(10) -pub const LOG2_10: f64 = 3.32192809488736234787031942948939018_f64; - -/// log2(e) -pub const LOG2_E: Float64 = 1.44269504088896340735992468100189214_f64; - -/// log10(2) -pub const LOG10_2: Float64 = 0.301029995663981195213738894724493027_f64; - -/// log10(e) -pub const LOG10_E: Float64 = 0.434294481903251827651128918916605082_f64; - -/// ln(2) -pub const LN_2: Float64 = 0.693147180559945309417232121458176568_f64; - -/// ln(10) -pub const LN_10: Float64 = 2.30258509299404568401799145468436421_f64; - -/// Archimedes' constant (π) as a 32-bit float -pub const PIF: Float32 = 3.14159265358979323846264338327950288_f32; - -/// The full circle constant (τ) as a 32-bit float -/// -/// Equal to 2π. -pub const TAUF: Float32 = 6.28318530717958647692528676655900577_f32; - -/// The golden ratio (φ) as a 32-bit float -pub const PHIF: Float32 = 1.618033988749894848204586834365638118_f32; - -/// The Euler-Mascheroni constant (γ) as a 32-bit float -pub const EGAMMAF: Float32 = 0.577215664901532860606512090082402431_f32; - -/// π/2 as a 32-bit float -pub const FRAC_PI_2F: Float32 = 1.57079632679489661923132169163975144_f32; - -/// π/3 as a 32-bit float -pub const FRAC_PI_3F: Float32 = 1.04719755119659774615421446109316763_f32; - -/// π/4 as a 32-bit float -pub const FRAC_PI_4F: Float32 = 0.785398163397448309615660845819875721_f32; - -/// π/6 as a 32-bit float -pub const FRAC_PI_6F: Float32 = 0.52359877559829887307710723054658381_f32; - -/// π/8 as a 32-bit float -pub const FRAC_PI_8F: Float32 = 0.39269908169872415480783042290993786_f32; - -/// 1/π as a 32-bit float -pub const FRAC_1_PIF: Float32 = 0.318309886183790671537767526745028724_f32; - -/// 1/sqrt(π) as a 32-bit float -pub const FRAC_1_SQRT_PIF: Float32 = 0.564189583547756286948079451560772586_f32; - -/// 2/π as a 32-bit float -pub const FRAC_2_PIF: Float32 = 0.636619772367581343075535053490057448_f32; - -/// 2/sqrt(π) as a 32-bit float -pub const FRAC_2_SQRT_PIF: Float32 = 1.12837916709551257389615890312154517_f32; - -/// sqrt(2) as a 32-bit float -pub const SQRT_2F: Float32 = 1.41421356237309504880168872420969808_f32; - -/// 1/sqrt(2) as a 32-bit float -pub const FRAC_1_SQRT_2F: Float32 = 0.707106781186547524400844362104849039_f32; - -/// sqrt(3) as a 32-bit float -pub const SQRT_3F: Float32 = 1.732050807568877293527446341505872367_f32; - -/// 1/sqrt(3) as a 32-bit float -pub const FRAC_1_SQRT_3F: Float32 = 0.577350269189625764509148780501957456_f32; - -/// Euler's number (e) as a 32-bit float -pub const EF: Float32 = 2.71828182845904523536028747135266250_f32; - -/// log2(e) as a 32-bit float -pub const LOG2_EF: Float32 = 1.44269504088896340735992468100189214_f32; - -/// log2(10) as a 32-bit float -pub const LOG2_10F: Float32 = 3.32192809488736234787031942948939018_f32; - -/// log10(e) as a 32-bit float -pub const LOG10_EF: Float32 = 0.434294481903251827651128918916605082_f32; - -/// log10(2) as a 32-bit float -pub const LOG10_2F: Float32 = 0.301029995663981195213738894724493027_f32; - -/// ln(2) as a 32-bit float -pub const LN_2F: Float32 = 0.693147180559945309417232121458176568_f32; - -/// ln(10) as a 32-bit float -pub const LN_10F: Float32 = 2.30258509299404568401799145468436421_f32; diff --git a/helpers/l2math/core.rs b/helpers/l2math/core.rs deleted file mode 100644 index 6417d23..0000000 --- a/helpers/l2math/core.rs +++ /dev/null @@ -1,160 +0,0 @@ -macro_rules! force_eval { - ($e:expr) => { - unsafe { ::core::ptr::read_volatile(&$e) } - }; -} - -#[cfg(not(debug_assertions))] -macro_rules! i { - ($array:expr, $index:expr) => { - unsafe { *$array.get_unchecked($index) } - }; - ($array:expr, $index:expr, $t:tt, $rhs:expr) => { - unsafe { *$array.get_unchecked_mut($index) $t $rhs } - }; -} - -#[cfg(debug_assertions)] -macro_rules! i { - ($array:expr, $index:expr) => { - *$array.get($index).unwrap() - }; - ($array:expr, $index:expr, $t:tt, $rhs:expr) => { - *$array.get_mut($index).unwrap() $t $rhs - }; -} - -// Temporary macro to avoid panic codegen for division (in debug mode too). At -// the time of this writing this is only used in a few places, and once -// rust-lang/rust#72751 is fixed then this macro will no longer be necessary and -// the native `/` operator can be used and panics won't be codegen'd. -#[cfg(any(debug_assertions, not(feature = "unstable")))] -macro_rules! div { - ($a:expr, $b:expr) => { - $a / $b - }; -} - -#[cfg(all(not(debug_assertions), feature = "unstable"))] -macro_rules! div { - ($a:expr, $b:expr) => { - unsafe { core::intrinsics::unchecked_div($a, $b) } - }; -} - -macro_rules! llvm_intrinsically_optimized { - (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all(not(debug_assertions), feature = "unstable", $($clause)*))] - { - if true { // thwart the dead code lint - $e - } - } - }; -} - -macro_rules! tup { - ($name:ident $($k:ident:$v:ty),+) => ( - #[repr(C)] - #[doc(hidden)] - #[allow(non_camel_case_types)] - pub struct $name { - $( pub $k: $v ),+ - } - impl $name { - #[inline(always)] - #[must_use = "this is a constructor"] - pub const fn from(($($k),+): ($($v),+)) -> Self { - Self { $($k),+ } - } - } - ); -} - -use crate::{Float32, Float64, Int}; - -tup!(Tuple_Float64_Int f: Float64, i: Int); -tup!(Tuple_Float32_Int f: Float32, i: Int); -tup!(Tuple_Float64_Float64 f1: Float64, f2: Float64); -tup!(Tuple_Float32_Float32 f1: Float32, f2: Float32); - -macro_rules! consts { - (const $name:ident: $ty:ty = $value:expr; $($t:tt)* ) => ( - #[allow(clippy::excessive_precision)] - #[deny(clippy::approx_constant)] - const $name: $ty = $value; - consts!($($t)*); - ); - () => (); -} - -macro_rules! import { - ($p:vis $($m:ident),+) => ( - $(mod $m; #[allow(unused_imports)] $p use self::$m::*;)+ - ); -} - -// Public modules -import!(pub acos, acosf, acosh, acoshf, asin, asinf, asinh, asinhf, atan, atan2, atan2f, atanf, atanh, atanhf); -import!(pub cbrt, cbrtf, ceil, ceilf, copysign, copysignf, cos, cosf, cosh, coshf); -import!(pub erf, erff, exp, exp10, exp10f, exp2, exp2f, expf, expm1, expm1f); -import!(pub fabs, fabsf, fdim, fdimf, floor, floorf, fma, fmaf, fmax, fmaxf, fmin, fminf, fmod, fmodf, frexp, frexpf); -import!(pub hypot, hypotf); -import!(pub ilogb, ilogbf); -import!(pub j0, j0f, j1, j1f, jn, jnf); -import!(pub ldexp, ldexpf, lgamma, lgamma_r, lgammaf, lgammaf_r, ln, lnf, log, log10, log10f, ln1p, ln1pf, log2, log2f, logf); -import!(pub modf, modff); -import!(pub nextafter, nextafterf); -import!(pub pow, powf); -import!(pub remainder, remainderf, remquo, remquof, rint, rintf, round, roundf); -import!(pub scalbn, scalbnf, sin, sincos, sincosf, sinf, sinh, sinhf, sqrt, sqrtf); -import!(pub tan, tanf, tanh, tanhf, tgamma, tgammaf, trunc, truncf); -import!(pub ulp); - -// Private modules -import!( - expo2, - fenv, - k_cos, - k_cosf, - k_expo2, - k_expo2f, - k_sin, - k_sinf, - k_tan, - k_tanf, - rem_pio2, - rem_pio2_large, - rem_pio2f -); - -#[inline] -fn get_high_word(x: Float64) -> u32 { - (x.to_bits() >> 32) as u32 -} - -#[inline] -fn get_low_word(x: Float64) -> u32 { - x.to_bits() as u32 -} - -#[inline] -fn with_set_high_word(f: Float64, hi: u32) -> Float64 { - let mut tmp = f.to_bits(); - tmp &= 0x00000000_ffffffff; - tmp |= (hi as u64) << 32; - Float64::from_bits(tmp) -} - -#[inline] -fn with_set_low_word(f: Float64, lo: u32) -> Float64 { - let mut tmp = f.to_bits(); - tmp &= 0xffffffff_00000000; - tmp |= lo as u64; - Float64::from_bits(tmp) -} - -#[inline] -fn combine_words(hi: u32, lo: u32) -> Float64 { - Float64::from_bits((hi as u64) << 32 | lo as u64) -} diff --git a/helpers/l2math/core/acos.rs b/helpers/l2math/core/acos.rs deleted file mode 100644 index 4f9bd4d..0000000 --- a/helpers/l2math/core/acos.rs +++ /dev/null @@ -1,112 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/** - * acos(x) - * Method : - * acos(x) = pi/2 - asin(x) - * acos(-x) = pi/2 + asin(x) - * For |x|<=0.5 - * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) - * For x>0.5 - * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) - * = 2asin(sqrt((1-x)/2)) - * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) - * = 2f + (2c + 2s*z*R(z)) - * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term - * for f so that f+c ~ sqrt(z). - * For x<-0.5 - * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) - * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) - * - * Special cases: - * if x is NaN, return x itself; - * if |x|>1, return NaN with invalid signal. - * - * Function needed: sqrt -*/ - -use crate::{Float64, Radian64}; - -use super::sqrt; - -consts!{ -const PIO2_HI: Float64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ -const PIO2_LO: Float64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ -const PS0: Float64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ -const PS1: Float64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ -const PS2: Float64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ -const PS3: Float64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ -const PS4: Float64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ -const PS5: Float64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ -const QS1: Float64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ -const QS2: Float64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ -const QS3: Float64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ -const QS4: Float64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ -} - -fn r(z: Float64) -> Float64 { - let p: Float64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); - let q: Float64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); - p / q -} - -/// Arccosine -/// -/// Computes the inverse cosine (arc cosine) of the input value. -/// Arguments must be in the range -1 to 1. -/// Returns values in radians, in the range of 0 to pi. -#[export_name = "__l2math_acos"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn acos(x: Float64) -> Radian64 { - let x1p_120f = Float64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 - let z: Float64; - let w: Float64; - let s: Float64; - let hx: u32 = (x.to_bits() >> 32) as u32; - let ix: u32 = hx & 0x7fffffff; - /* |x| >= 1 or nan */ - if ix >= 0x3ff00000 { - let lx: u32 = x.to_bits() as u32; - - if ((ix - 0x3ff00000) | lx) == 0 { - /* acos(1)=0, acos(-1)=pi */ - if (hx >> 31) != 0 { - return 2. * PIO2_HI + x1p_120f; - } - return 0.; - } - return 0. / (x - x); - } - /* |x| < 0.5 */ - if ix < 0x3fe00000 { - if ix <= 0x3c600000 { - /* |x| < 2**-57 */ - return PIO2_HI + x1p_120f; - } - return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); - } - /* x < -0.5 */ - if (hx >> 31) != 0 { - z = (1.0 + x) * 0.5; - s = sqrt(z); - w = r(z) * s - PIO2_LO; - return 2. * (PIO2_HI - (s + w)); - } - /* x > 0.5 */ - z = (1.0 - x) * 0.5; - s = sqrt(z); - // Set the low 4 bytes to zero - let df: Float64 = Float64::from_bits(s.to_bits() & 0xff_ff_ff_ff_00_00_00_00); - let c: Float64 = (z - df * df) / (s + df); - w = r(z) * s + c; - 2. * (df + w) -} diff --git a/helpers/l2math/core/acosf.rs b/helpers/l2math/core/acosf.rs deleted file mode 100644 index ea0df99..0000000 --- a/helpers/l2math/core/acosf.rs +++ /dev/null @@ -1,84 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::{Float32, Radian32}; - -use super::sqrtf::sqrtf; - -consts!{ -const PIO2_HI: Float32 = 1.5707962513e+00; /* 0x3fc90fda */ -const PIO2_LO: Float32 = 7.5497894159e-08; /* 0x33a22168 */ -const P_S0: Float32 = 1.6666586697e-01; -const P_S1: Float32 = -4.2743422091e-02; -const P_S2: Float32 = -8.6563630030e-03; -const Q_S1: Float32 = -7.0662963390e-01; -} - -fn r(z: Float32) -> Float32 { - let p = z * (P_S0 + z * (P_S1 + z * P_S2)); - let q = 1. + z * Q_S1; - p / q -} - -/// Arccosine -/// -/// Computes the inverse cosine (arc cosine) of the input value. -/// Arguments must be in the range -1 to 1. -/// Returns values in radians, in the range of 0 to pi. -#[export_name = "__l2math_acosf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn acosf(x: Float32) -> Radian32 { - let x1p_120 = Float32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) - - let z: Float32; - let w: Float32; - let s: Float32; - - let mut hx = x.to_bits(); - let ix = hx & 0x7fffffff; - /* |x| >= 1 or nan */ - if ix >= 0x3f800000 { - if ix == 0x3f800000 { - if (hx >> 31) != 0 { - return 2. * PIO2_HI + x1p_120; - } - return 0.; - } - return 0. / (x - x); - } - /* |x| < 0.5 */ - if ix < 0x3f000000 { - if ix <= 0x32800000 { - /* |x| < 2**-26 */ - return PIO2_HI + x1p_120; - } - return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); - } - /* x < -0.5 */ - if (hx >> 31) != 0 { - z = (1. + x) * 0.5; - s = sqrtf(z); - w = r(z) * s - PIO2_LO; - return 2. * (PIO2_HI - (s + w)); - } - /* x > 0.5 */ - z = (1. - x) * 0.5; - s = sqrtf(z); - hx = s.to_bits(); - let df = Float32::from_bits(hx & 0xfffff000); - let c = (z - df * df) / (s + df); - w = r(z) * s + c; - 2. * (df + w) -} diff --git a/helpers/l2math/core/acosh.rs b/helpers/l2math/core/acosh.rs deleted file mode 100644 index 0ed21cf..0000000 --- a/helpers/l2math/core/acosh.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::{Float64, Radian64}; - -use super::{log, ln1p, sqrt}; - -consts!{ -const LN2: Float64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ -} - -/// Inverse hyperbolic cosine -/// -/// Calculates the inverse hyperbolic cosine of `x`. -/// Is defined as `log(x + sqrt(x*x-1))`. -/// `x` must be a number greater than or equal to 1. -#[export_name = "__l2math_acosh"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn acosh(x: Float64) -> Radian64 { - let u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - - /* x < 1 domain error is handled in the called functions */ - - if e < 0x3ff + 1 { - /* |x| < 2, up to 2ulp error in [1,1.125] */ - return ln1p(x - 1.0 + sqrt((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); - } - if e < 0x3ff + 26 { - /* |x| < 0x1p26 */ - return log(2.0 * x - 1.0 / (x + sqrt(x * x - 1.0))); - } - /* |x| >= 0x1p26 or nan */ - return log(x) + LN2; -} diff --git a/helpers/l2math/core/acoshf.rs b/helpers/l2math/core/acoshf.rs deleted file mode 100644 index 3e576e1..0000000 --- a/helpers/l2math/core/acoshf.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::{Float32, Radian32}; - -use super::{ln1pf, logf, sqrtf}; - -consts!{ -const LN2: Float32 = 0.693147180559945309417232121458176568; -} - -/// Inverse hyperbolic cosine -/// -/// Calculates the inverse hyperbolic cosine of `x`. -/// Is defined as `log(x + sqrt(x*x-1))`. -/// `x` must be a number greater than or equal to 1. -#[export_name = "__l2math_acoshf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn acoshf(x: Float32) -> Radian32 { - let u = x.to_bits(); - let a = u & 0x7fffffff; - - if a < 0x3f800000 + (1 << 23) { - /* |x| < 2, invalid if x < 1 or nan */ - /* up to 2ulp error in [1,1.125] */ - return ln1pf(x - 1.0 + sqrtf((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); - } - if a < 0x3f800000 + (12 << 23) { - /* |x| < 0x1p12 */ - return logf(2.0 * x - 1.0 / (x + sqrtf(x * x - 1.0))); - } - /* x >= 0x1p12 */ - return logf(x) + LN2; -} diff --git a/helpers/l2math/core/asin.rs b/helpers/l2math/core/asin.rs deleted file mode 100644 index 0496fb6..0000000 --- a/helpers/l2math/core/asin.rs +++ /dev/null @@ -1,116 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * asin(x) - * Method : - * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... - * we approximate asin(x) on [0,0.5] by - * asin(x) = x + x*x^2*R(x^2) - * where - * R(x^2) is a rational approximation of (asin(x)-x)/x^3 - * and its remez error is bounded by - * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) - * - * For x in [0.5,1] - * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) - * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; - * then for x>0.98 - * asin(x) = pi/2 - 2*(s+s*z*R(z)) - * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) - * For x<=0.98, let pio4_hi = pio2_hi/2, then - * f = hi part of s; - * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) - * and - * asin(x) = pi/2 - 2*(s+s*z*R(z)) - * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) - * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) - * - * Special cases: - * if x is NaN, return x itself; - * if |x|>1, return NaN with invalid signal. - * -*/ - -use crate::{Float64, Radian64}; - -use super::{fabs, get_high_word, get_low_word, sqrt, with_set_low_word}; - -consts!{ -const PIO2_HI: Float64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ -const PIO2_LO: Float64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ -/* coefficients for R(x^2) */ -const P_S0: Float64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ -const P_S1: Float64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ -const P_S2: Float64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ -const P_S3: Float64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ -const P_S4: Float64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ -const P_S5: Float64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ -const Q_S1: Float64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ -const Q_S2: Float64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ -const Q_S3: Float64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ -const Q_S4: Float64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ -} - -fn comp_r(z: Float64) -> Float64 { - let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); - let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); - p / q -} - -/// Arcsine -/// -/// Computes the inverse sine (arc sine) of the argument `x`. -/// Arguments to asin must be in the range -1 to 1. -/// Returns values in radians, in the range of -pi/2 to pi/2. -#[export_name = "__l2math_asin"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn asin(mut x: Float64) -> Radian64 { - let hx: u32 = get_high_word(x); - let ix: u32 = hx & 0x7fffffff; - /* |x| >= 1 or nan */ - if ix >= 0x3ff00000 { - let lx: u32 = get_low_word(x); - if ((ix - 0x3ff00000) | lx) == 0 { - /* asin(1) = +-pi/2 with inexact */ - return x * PIO2_HI + Float64::from_bits(0x3870000000000000); - } else { - return 0.0 / (x - x); - } - } - /* |x| < 0.5 */ - if ix < 0x3fe00000 { - /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ - if (0x00100000..0x3e500000).contains(&ix) { - return x; - } else { - return x + x * comp_r(x * x); - } - } - /* 1 > |x| >= 0.5 */ - let z: Float64 = (1.0 - fabs(x)) * 0.5; - let s: Float64 = sqrt(z); - let r: Float64 = comp_r(z); - if ix >= 0x3fef3333 { - /* if |x| > 0.975 */ - x = PIO2_HI - (2. * (s + s * r) - PIO2_LO); - } else { - /* f+c = sqrt(z) */ - let f: Float64 = with_set_low_word(s, 0); - let c: Float64 = (z - f * f) / (s + f); - x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f)); - } - if hx >> 31 != 0 { - -x - } else { - x - } -} diff --git a/helpers/l2math/core/asinf.rs b/helpers/l2math/core/asinf.rs deleted file mode 100644 index 093b716..0000000 --- a/helpers/l2math/core/asinf.rs +++ /dev/null @@ -1,77 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::{Float64, Float32, Radian32}; - -use super::fabsf::fabsf; -use super::sqrt::sqrt; - -consts!{ -const PIO2: Float64 = 1.570796326794896558e+00; - -/* coefficients for R(x^2) */ -const P_S0: Float32 = 1.6666586697e-01; -const P_S1: Float32 = -4.2743422091e-02; -const P_S2: Float32 = -8.6563630030e-03; -const Q_S1: Float32 = -7.0662963390e-01; -} - -fn r(z: Float32) -> Float32 { - let p = z * (P_S0 + z * (P_S1 + z * P_S2)); - let q = 1. + z * Q_S1; - p / q -} - -/// Arcsine -/// -/// Computes the inverse sine (arc sine) of the argument `x`. -/// Arguments to asin must be in the range -1 to 1. -/// Returns values in radians, in the range of -pi/2 to pi/2. -#[export_name = "__l2math_asinf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn asinf(mut x: Float32) -> Radian32 { - let x1p_120 = Float64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) - - let hx = x.to_bits(); - let ix = hx & 0x7fffffff; - - if ix >= 0x3f800000 { - /* |x| >= 1 */ - if ix == 0x3f800000 { - /* |x| == 1 */ - return ((x as Float64) * PIO2 + x1p_120) as Float32; /* asin(+-1) = +-pi/2 with inexact */ - } - return 0. / (x - x); /* asin(|x|>1) is NaN */ - } - - if ix < 0x3f000000 { - /* |x| < 0.5 */ - /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ - if (0x00800000..0x39800000).contains(&ix) { - return x; - } - return x + x * r(x * x); - } - - /* 1 > |x| >= 0.5 */ - let z = (1. - fabsf(x)) * 0.5; - let s = sqrt(z as Float64); - x = (PIO2 - 2. * (s + s * (r(z) as Float64))) as Float32; - if (hx >> 31) != 0 { - -x - } else { - x - } -} diff --git a/helpers/l2math/core/asinh.rs b/helpers/l2math/core/asinh.rs deleted file mode 100644 index f1b3507..0000000 --- a/helpers/l2math/core/asinh.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::{Float64, Radian64}; - -use super::{log, ln1p, sqrt}; - -consts!{ -const LN2: Float64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ -} - -/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ -/// Inverse hyperbolic sine -/// -/// Calculates the inverse hyperbolic sine of `x`. -/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. -#[export_name = "__l2math_asinh"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn asinh(mut x: Float64) -> Radian64 { - let mut u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - let sign = (u >> 63) != 0; - - /* |x| */ - u &= (!0) >> 1; - x = Float64::from_bits(u); - - if e >= 0x3ff + 26 { - /* |x| >= 0x1p26 or inf or nan */ - x = log(x) + LN2; - } else if e >= 0x3ff + 1 { - /* |x| >= 2 */ - x = log(2.0 * x + 1.0 / (sqrt(x * x + 1.0) + x)); - } else if e >= 0x3ff - 26 { - /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ - x = ln1p(x + x * x / (sqrt(x * x + 1.0) + 1.0)); - } else { - /* |x| < 0x1p-26, raise inexact if x != 0 */ - let x1p120 = Float64::from_bits(0x4770000000000000); - force_eval!(x + x1p120); - } - - if sign { - -x - } else { - x - } -} diff --git a/helpers/l2math/core/asinhf.rs b/helpers/l2math/core/asinhf.rs deleted file mode 100644 index 0f32672..0000000 --- a/helpers/l2math/core/asinhf.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::{Float32, Radian32}; - -use super::{ln1pf, logf, sqrtf}; - -use core::f32::consts::LN_2; - -/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ -/// Inverse hyperbolic sine -/// -/// Calculates the inverse hyperbolic sine of `x`. -/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. -#[export_name = "__l2math_asinhf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn asinhf(mut x: Float32) -> Radian32 { - let u = x.to_bits(); - let i = u & 0x7fffffff; - let sign = (u >> 31) != 0; - - /* |x| */ - x = Float32::from_bits(i); - - if i >= 0x3f800000 + (12 << 23) { - /* |x| >= 0x1p12 or inf or nan */ - x = logf(x) + LN_2; - } else if i >= 0x3f800000 + (1 << 23) { - /* |x| >= 2 */ - x = logf(2.0 * x + 1.0 / (sqrtf(x * x + 1.0) + x)); - } else if i >= 0x3f800000 - (12 << 23) { - /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ - x = ln1pf(x + x * x / (sqrtf(x * x + 1.0) + 1.0)); - } else { - /* |x| < 0x1p-12, raise inexact if x!=0 */ - let x1p120 = Float32::from_bits(0x7b800000); - force_eval!(x + x1p120); - } - - if sign { - -x - } else { - x - } -} diff --git a/helpers/l2math/core/atan.rs b/helpers/l2math/core/atan.rs deleted file mode 100644 index 2a93d69..0000000 --- a/helpers/l2math/core/atan.rs +++ /dev/null @@ -1,189 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * atan(x) - * Method - * 1. Reduce x to positive by atan(x) = -atan(-x). - * 2. According to the integer k=4t+0.25 chopped, t=x, the argument - * is further reduced to one of the following intervals and the - * arctangent of t is evaluated by the corresponding formula: - * - * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) - * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) - * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) - * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) - * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) - * - * Constants: - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. -*/ - -use crate::{Float64, Float32, Radian64}; - -use super::fabs; - -consts!{ -const ATANHI: [Float64; 4] = [ - 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ - 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ - 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ - core::f64::consts::FRAC_PI_2, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ -]; - -const ATANLO: [Float64; 4] = [ - 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ - 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ - 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ - 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ -]; - -const AT: [Float64; 11] = [ - 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ - -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ - 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ - -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ - 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ - -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ - 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ - -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ - 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ - -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ - 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ -]; -} - -/// Arctangent -/// -/// Computes the inverse tangent (arc tangent) of the input value. -/// Returns a value in radians, in the range of -pi/2 to pi/2. -#[export_name = "__l2math_atan"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn atan(x: Float64) -> Radian64 { - let mut x = x; - let mut ix = (x.to_bits() >> 32) as u32; - let sign = ix >> 31; - ix &= 0x7fff_ffff; - if ix >= 0x4410_0000 { - if x.is_nan() { - return x; - } - - let z = ATANHI[3] + Float64::from_bits(0x0380_0000); // 0x1p-120f - return if sign != 0 { -z } else { z }; - } - - let id = if ix < 0x3fdc_0000 { - /* |x| < 0.4375 */ - if ix < 0x3e40_0000 { - /* |x| < 2^-27 */ - if ix < 0x0010_0000 { - /* raise underflow for subnormal x */ - force_eval!(x as Float32); - } - - return x; - } - - -1 - } else { - x = fabs(x); - if ix < 0x3ff30000 { - /* |x| < 1.1875 */ - if ix < 0x3fe60000 { - /* 7/16 <= |x| < 11/16 */ - x = (2. * x - 1.) / (2. + x); - 0 - } else { - /* 11/16 <= |x| < 19/16 */ - x = (x - 1.) / (x + 1.); - 1 - } - } else if ix < 0x40038000 { - /* |x| < 2.4375 */ - x = (x - 1.5) / (1. + 1.5 * x); - 2 - } else { - /* 2.4375 <= |x| < 2^66 */ - x = -1. / x; - 3 - } - }; - - let z = x * x; - let w = z * z; - /* break sum from i=0 to 10 AT[i]z**(i+1) into odd and even poly */ - let s1 = z * (AT[0] + w * (AT[2] + w * (AT[4] + w * (AT[6] + w * (AT[8] + w * AT[10]))))); - let s2 = w * (AT[1] + w * (AT[3] + w * (AT[5] + w * (AT[7] + w * AT[9])))); - - if id < 0 { - return x - x * (s1 + s2); - } - - let z = i!(ATANHI, id as usize) - (x * (s1 + s2) - i!(ATANLO, id as usize) - x); - - if sign != 0 { - -z - } else { - z - } -} - -#[cfg(test)] -mod tests { - use super::atan; - use core::f64; - - #[test] - fn sanity_check() { - for (input, answer) in [ - (3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6), - (1.0, f64::consts::FRAC_PI_4), - (3.0_f64.sqrt(), f64::consts::FRAC_PI_3), - (-(3.0_f64.sqrt()) / 3.0, -f64::consts::FRAC_PI_6), - (-1.0, -f64::consts::FRAC_PI_4), - (-(3.0_f64.sqrt()), -f64::consts::FRAC_PI_3), - ] - .iter() - { - assert!( - (atan(*input) - answer) / answer < 1e-5, - "\natan({:.4}/16) = {:.4}, actual: {}", - input * 16.0, - answer, - atan(*input) - ); - } - } - - #[test] - fn zero() { - assert_eq!(atan(0.0), 0.0); - } - - #[test] - fn infinity() { - assert_eq!(atan(f64::INFINITY), f64::consts::FRAC_PI_2); - } - - #[test] - fn minus_infinity() { - assert_eq!(atan(f64::NEG_INFINITY), -f64::consts::FRAC_PI_2); - } - - #[test] - fn nan() { - assert!(atan(f64::NAN).is_nan()); - } -} diff --git a/helpers/l2math/core/atan2.rs b/helpers/l2math/core/atan2.rs deleted file mode 100644 index c98e87f..0000000 --- a/helpers/l2math/core/atan2.rs +++ /dev/null @@ -1,135 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - * -*/ -/** - * atan2(y,x) - * Method : - * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). - * 2. Reduce x to positive by (if x and y are unexceptional): - * ARG (x+iy) = arctan(y/x) ... if x > 0, - * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, - * - * Special cases: - * - * ATAN2((anything), NaN ) is NaN; - * ATAN2(NAN , (anything) ) is NaN; - * ATAN2(+-0, +(anything but NaN)) is +-0 ; - * ATAN2(+-0, -(anything but NaN)) is +-pi ; - * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; - * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; - * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; - * ATAN2(+-INF,+INF ) is +-pi/4 ; - * ATAN2(+-INF,-INF ) is +-3pi/4; - * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; - * - * Constants: - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. -*/ - -use crate::{Float64, Radian64}; - -use super::atan; -use super::fabs; - -use core::f64::consts::PI; -use core::f64::consts::FRAC_PI_2; -use core::f64::consts::FRAC_PI_4; - -consts!{ -const PI_LO: Float64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ -} - -/// Arctangent of y/x -/// -/// Computes the inverse tangent (arc tangent) of `y/x`. -/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). -/// Returns a value in radians, in the range of -pi to pi. -#[export_name = "__l2math_atan2"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn atan2(y: Float64, x: Float64) -> Radian64 { - if x.is_nan() || y.is_nan() { - return x + y; - } - let mut ix = (x.to_bits() >> 32) as u32; - let lx = x.to_bits() as u32; - let mut iy = (y.to_bits() >> 32) as u32; - let ly = y.to_bits() as u32; - if ((ix.wrapping_sub(0x3ff00000)) | lx) == 0 { - /* x = 1.0 */ - return atan(y); - } - let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ - ix &= 0x7fffffff; - iy &= 0x7fffffff; - - /* when y = 0 */ - if (iy | ly) == 0 { - return match m { - 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ - 2 => PI, /* atan(+0,-anything) = PI */ - _ => -PI, /* atan(-0,-anything) =-PI */ - }; - } - /* when x = 0 */ - if (ix | lx) == 0 { - return if m & 1 != 0 { -FRAC_PI_2 } else { FRAC_PI_2 }; - } - /* when x is INF */ - if ix == 0x7ff00000 { - if iy == 0x7ff00000 { - return match m { - 0 => FRAC_PI_4, /* atan(+INF,+INF) */ - 1 => -FRAC_PI_4, /* atan(-INF,+INF) */ - 2 => 3.0 * FRAC_PI_4, /* atan(+INF,-INF) */ - _ => -3.0 * FRAC_PI_4, /* atan(-INF,-INF) */ - }; - } else { - return match m { - 0 => 0.0, /* atan(+...,+INF) */ - 1 => -0.0, /* atan(-...,+INF) */ - 2 => PI, /* atan(+...,-INF) */ - _ => -PI, /* atan(-...,-INF) */ - }; - } - } - /* |y/x| > 0x1p64 */ - if ix.wrapping_add(64 << 20) < iy || iy == 0x7ff00000 { - return if m & 1 != 0 { -FRAC_PI_2 } else { FRAC_PI_2 }; - } - - /* z = atan(|y/x|) without spurious underflow */ - let z = if (m & 2 != 0) && iy.wrapping_add(64 << 20) < ix { - /* |y/x| < 0x1p-64, x<0 */ - 0.0 - } else { - atan(fabs(y / x)) - }; - match m { - 0 => z, /* atan(+,+) */ - 1 => -z, /* atan(-,+) */ - 2 => PI - (z - PI_LO), /* atan(+,-) */ - _ => (z - PI_LO) - PI, /* atan(-,-) */ - } -} - -#[test] -fn sanity_check() { - assert_eq!(atan2(0.0, 1.0), 0.0); - assert_eq!(atan2(0.0, -1.0), PI); - assert_eq!(atan2(-0.0, -1.0), -PI); - assert_eq!(atan2(3.0, 2.0), atan(3.0 / 2.0)); - assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI); - assert_eq!(atan2(-2.0, -1.0), atan(-2.0 / -1.0) - PI); -} diff --git a/helpers/l2math/core/atan2f.rs b/helpers/l2math/core/atan2f.rs deleted file mode 100644 index 937956d..0000000 --- a/helpers/l2math/core/atan2f.rs +++ /dev/null @@ -1,99 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::{Float32, Radian32}; - -use super::atanf; -use super::fabsf; - -use core::f32::consts::PI; -use core::f32::consts::FRAC_PI_2; -use core::f32::consts::FRAC_PI_4; - -consts!{ -const PI_LO: Float32 = -8.7422776573e-08; /* 0xb3bbbd2e */ -} - -/// Arctangent of y/x -/// -/// Computes the inverse tangent (arc tangent) of `y/x`. -/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). -/// Returns a value in radians, in the range of -pi to pi. -#[export_name = "__l2math_atan2f"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn atan2f(y: Float32, x: Float32) -> Radian32 { - if x.is_nan() || y.is_nan() { - return x + y; - } - let mut ix = x.to_bits(); - let mut iy = y.to_bits(); - - if ix == 0x3f800000 { - /* x=1.0 */ - return atanf(y); - } - let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ - ix &= 0x7fffffff; - iy &= 0x7fffffff; - - /* when y = 0 */ - if iy == 0 { - return match m { - 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ - 2 => PI, /* atan(+0,-anything) = pi */ - _ => -PI, /* atan(-0,-anything) =-pi */ - }; - } - /* when x = 0 */ - if ix == 0 { - return if m & 1 != 0 { -FRAC_PI_2 } else { FRAC_PI_2 }; - } - /* when x is INF */ - if ix == 0x7f800000 { - return if iy == 0x7f800000 { - match m { - 0 => FRAC_PI_4, /* atan(+INF,+INF) */ - 1 => -FRAC_PI_4, /* atan(-INF,+INF) */ - 2 => 3. * FRAC_PI_4, /* atan(+INF,-INF)*/ - _ => -3. * FRAC_PI_4, /* atan(-INF,-INF)*/ - } - } else { - match m { - 0 => 0., /* atan(+...,+INF) */ - 1 => -0., /* atan(-...,+INF) */ - 2 => PI, /* atan(+...,-INF) */ - _ => -PI, /* atan(-...,-INF) */ - } - }; - } - /* |y/x| > 0x1p26 */ - if (ix + (26 << 23) < iy) || (iy == 0x7f800000) { - return if m & 1 != 0 { -FRAC_PI_2 } else { FRAC_PI_2 }; - } - - /* z = atan(|y/x|) with correct underflow */ - let z = if (m & 2 != 0) && (iy + (26 << 23) < ix) { - /*|y/x| < 0x1p-26, x < 0 */ - 0. - } else { - atanf(fabsf(y / x)) - }; - match m { - 0 => z, /* atan(+,+) */ - 1 => -z, /* atan(-,+) */ - 2 => PI - (z - PI_LO), /* atan(+,-) */ - _ => (z - PI_LO) - PI, /* case 3 */ /* atan(-,-) */ - } -} diff --git a/helpers/l2math/core/atanf.rs b/helpers/l2math/core/atanf.rs deleted file mode 100644 index 520c747..0000000 --- a/helpers/l2math/core/atanf.rs +++ /dev/null @@ -1,117 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::{Float32, Radian32}; - -use super::fabsf; - -consts!{ -const ATAN_HI: [Float32; 4] = [ - 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ - 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ - 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ - 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ -]; - -const ATAN_LO: [Float32; 4] = [ - 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ - 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ - 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ - 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ -]; - -const A_T: [Float32; 5] = [ - 3.3333328366e-01, - -1.9999158382e-01, - 1.4253635705e-01, - -1.0648017377e-01, - 6.1687607318e-02, -]; -} - -/// Arctangent -/// -/// Computes the inverse tangent (arc tangent) of the input value. -/// Returns a value in radians, in the range of -pi/2 to pi/2. -#[export_name = "__l2math_atanf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn atanf(mut x: Float32) -> Radian32 { - let x1p_120 = Float32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) - - let z: Float32; - - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - if ix >= 0x4c800000 { - /* if |x| >= 2**26 */ - if x.is_nan() { - return x; - } - z = i!(ATAN_HI, 3) + x1p_120; - return if sign { -z } else { z }; - } - let id = if ix < 0x3ee00000 { - /* |x| < 0.4375 */ - if ix < 0x39800000 { - /* |x| < 2**-12 */ - if ix < 0x00800000 { - /* raise underflow for subnormal x */ - force_eval!(x * x); - } - return x; - } - -1 - } else { - x = fabsf(x); - if ix < 0x3f980000 { - /* |x| < 1.1875 */ - if ix < 0x3f300000 { - /* 7/16 <= |x| < 11/16 */ - x = (2. * x - 1.) / (2. + x); - 0 - } else { - /* 11/16 <= |x| < 19/16 */ - x = (x - 1.) / (x + 1.); - 1 - } - } else if ix < 0x401c0000 { - /* |x| < 2.4375 */ - x = (x - 1.5) / (1. + 1.5 * x); - 2 - } else { - /* 2.4375 <= |x| < 2**26 */ - x = -1. / x; - 3 - } - }; - /* end of argument reduction */ - z = x * x; - let w = z * z; - /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ - let s1 = z * (i!(A_T, 0) + w * (i!(A_T, 2) + w * i!(A_T, 4))); - let s2 = w * (i!(A_T, 1) + w * i!(A_T, 3)); - if id < 0 { - return x - x * (s1 + s2); - } - let id = id as usize; - let z = i!(ATAN_HI, id) - ((x * (s1 + s2) - i!(ATAN_LO, id)) - x); - if sign { - -z - } else { - z - } -} diff --git a/helpers/l2math/core/atanh.rs b/helpers/l2math/core/atanh.rs deleted file mode 100644 index 39a73fd..0000000 --- a/helpers/l2math/core/atanh.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::{Float64, Float32, Radian64}; - -use super::ln1p; - -/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ -/// Inverse hyperbolic tangent -/// -/// Calculates the inverse hyperbolic tangent of `x`. -/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. -#[export_name = "__l2math_atanh"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn atanh(x: Float64) -> Radian64 { - let u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - let sign = (u >> 63) != 0; - - /* |x| */ - let mut y = Float64::from_bits(u & 0x7fff_ffff_ffff_ffff); - - if e < 0x3ff - 1 { - if e < 0x3ff - 32 { - /* handle underflow */ - if e == 0 { - force_eval!(y as Float32); - } - } else { - /* |x| < 0.5, up to 1.7ulp error */ - y = 0.5 * ln1p(2.0 * y + 2.0 * y * y / (1.0 - y)); - } - } else { - /* avoid overflow */ - y = 0.5 * ln1p(2.0 * (y / (1.0 - y))); - } - - if sign { - -y - } else { - y - } -} diff --git a/helpers/l2math/core/atanhf.rs b/helpers/l2math/core/atanhf.rs deleted file mode 100644 index 077c7f7..0000000 --- a/helpers/l2math/core/atanhf.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::{Float32, Radian32}; - -use super::ln1pf; - -/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ -/// Inverse hyperbolic tangent -/// -/// Calculates the inverse hyperbolic tangent of `x`. -/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. -#[export_name = "__l2math_atanhf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn atanhf(mut x: Float32) -> Radian32 { - let mut u = x.to_bits(); - let sign = (u >> 31) != 0; - - /* |x| */ - u &= 0x7fffffff; - x = Float32::from_bits(u); - - if u < 0x3f800000 - (1 << 23) { - if u < 0x3f800000 - (32 << 23) { - /* handle underflow */ - if u < (1 << 23) { - force_eval!((x * x) as Float32); - } - } else { - /* |x| < 0.5, up to 1.7ulp error */ - x = 0.5 * ln1pf(2.0 * x + 2.0 * x * x / (1.0 - x)); - } - } else { - /* avoid overflow */ - x = 0.5 * ln1pf(2.0 * (x / (1.0 - x))); - } - - if sign { - -x - } else { - x - } -} diff --git a/helpers/l2math/core/cbrt.rs b/helpers/l2math/core/cbrt.rs deleted file mode 100644 index 7de8675..0000000 --- a/helpers/l2math/core/cbrt.rs +++ /dev/null @@ -1,111 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrt.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - * - * Optimized by Bruce D. Evans. -*/ -/** - * cbrt(x) - * Return cube root of x -*/ - -use crate::Float64; - -consts!{ -const B1: u32 = 715094163; /* B1 = (1023-1023/3-0.03306235651)*2**20 */ -const B2: u32 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */ - -/* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */ -const P0: Float64 = 1.87595182427177009643; /* 0x3ffe03e6, 0x0f61e692 */ -const P1: Float64 = -1.88497979543377169875; /* 0xbffe28e0, 0x92f02420 */ -const P2: Float64 = 1.621429720105354466140; /* 0x3ff9f160, 0x4a49d6c2 */ -const P3: Float64 = -0.758397934778766047437; /* 0xbfe844cb, 0xbee751d9 */ -const P4: Float64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ -} - -// Cube root -/// -/// Computes the cube root of the argument. -#[export_name = "__l2math_cbrt"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn cbrt(x: Float64) -> Float64 { - let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 - - let mut ui: u64 = x.to_bits(); - let mut r: Float64; - - let mut t: Float64; - - let mut hx: u32 = (ui >> 32) as u32 & 0x7fffffff; - - if hx >= 0x7ff00000 { - /* cbrt(NaN,INF) is itself */ - return x + x; - } - - // Rough cbrt to 5 bits: - // cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3) - // where e is integral and >= 0, m is real and in [0, 1), and "/" and - // "%" are integer division and modulus with rounding towards minus - // infinity. The RHS is always >= the LHS and has a maximum relative - // error of about 1 in 16. Adding a bias of -0.03306235651 to the - // (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE - // floating point representation, for finite positive normal values, - // ordinary integer divison of the value in bits magically gives - // almost exactly the RHS of the above provided we first subtract the - // exponent bias (1023 for doubles) and later add it back. We do the - // subtraction virtually to keep e >= 0 so that ordinary integer - // division rounds towards minus infinity; this is also efficient. - if hx < 0x00100000 { - /* zero or subnormal? */ - ui = (x * x1p54).to_bits(); - hx = (ui >> 32) as u32 & 0x7fffffff; - if hx == 0 { - return x; /* cbrt(0) is itself */ - } - hx = hx / 3 + B2; - } else { - hx = hx / 3 + B1; - } - ui &= 1 << 63; - ui |= (hx as u64) << 32; - t = Float64::from_bits(ui); - - // New cbrt to 23 bits: - // cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x) - // where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r) - // to within 2**-23.5 when |r - 1| < 1/10. The rough approximation - // has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this - // gives us bounds for r = t**3/x. - // - // Try to optimize for parallel evaluation as in __tanf.c. - r = (t * t) * (t / x); - t = t * ((P0 + r * (P1 + r * P2)) + ((r * r) * r) * (P3 + r * P4)); - - // Round t away from zero to 23 bits (sloppily except for ensuring that - // the result is larger in magnitude than cbrt(x) but not much more than - // 2 23-bit ulps larger). With rounding towards zero, the error bound - // would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps - // in the rounded t, the infinite-precision error in the Newton - // approximation barely affects third digit in the final error - // 0.667; the error in the rounded t can be up to about 3 23-bit ulps - // before the final error is larger than 0.667 ulps. - ui = t.to_bits(); - ui = (ui + 0x80000000) & 0xffffffffc0000000; - t = Float64::from_bits(ui); - - /* one step Newton iteration to 53 bits with error < 0.667 ulps */ - let s: Float64 = t * t; /* t*t is exact */ - r = x / s; /* error <= 0.5 ulps; |r| < |t| */ - let w: Float64 = t + t; /* t+t is exact */ - r = (r - t) / (w + r); /* r-t is exact; w+r ~= 3*t */ - t = t + t * r; /* error <= 0.5 + 0.5/3 + epsilon */ - t -} diff --git a/helpers/l2math/core/cbrtf.rs b/helpers/l2math/core/cbrtf.rs deleted file mode 100644 index cb08d2e..0000000 --- a/helpers/l2math/core/cbrtf.rs +++ /dev/null @@ -1,77 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Debugged and optimized by Bruce D. Evans. -*/ -/** - * cbrtf(x) - * Return cube root of x -*/ - -use crate::{Float64, Float32}; - -const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ -const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ - -/// Cube root -/// -/// Computes the cube root of the argument. -#[export_name = "__l2math_cbrtf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn cbrtf(x: Float32) -> Float32 { - let x1p24 = Float32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 - - let mut r: Float64; - let mut t: Float64; - let mut ui: u32 = x.to_bits(); - let mut hx: u32 = ui & 0x7fffffff; - - if hx >= 0x7f800000 { - /* cbrt(NaN,INF) is itself */ - return x + x; - } - - /* rough cbrt to 5 bits */ - if hx < 0x00800000 { - /* zero or subnormal? */ - if hx == 0 { - return x; /* cbrt(+-0) is itself */ - } - ui = (x * x1p24).to_bits(); - hx = ui & 0x7fffffff; - hx = hx / 3 + B2; - } else { - hx = hx / 3 + B1; - } - ui &= 0x80000000; - ui |= hx; - - /* - * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In - * double precision so that its terms can be arranged for efficiency - * without causing overflow or underflow. - */ - t = Float32::from_bits(ui) as Float64; - r = t * t * t; - t = t * (x as Float64 + x as Float64 + r) / (x as Float64 + r + r); - - /* - * Second step Newton iteration to 47 bits. In double precision for - * efficiency and accuracy. - */ - r = t * t * t; - t = t * (x as Float64 + x as Float64 + r) / (x as Float64 + r + r); - - /* rounding to 24 bits is perfect in round-to-nearest mode */ - t as Float32 -} diff --git a/helpers/l2math/core/ceil.rs b/helpers/l2math/core/ceil.rs deleted file mode 100644 index a8ce204..0000000 --- a/helpers/l2math/core/ceil.rs +++ /dev/null @@ -1,83 +0,0 @@ -#![allow(unreachable_code)] - -use crate::Float64; - -const TOINT: Float64 = 1. / Float64::EPSILON; - -/// Ceil -/// -/// Finds the nearest integer greater than or equal to `x`. -#[export_name = "__l2math_ceil"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn ceil(x: Float64) -> Float64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `Float64.ceil` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::ceilf64(x) } - } - } - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - { - //use an alternative implementation on x86, because the - //main implementation fails with the x87 FPU used by - //debian i386, probablly due to excess precision issues. - //basic implementation taken from https://github.com/rust-lang/libm/issues/219 - use super::fabs; - if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as Float64; - if truncated < x { - return truncated + 1.0; - } else { - return truncated; - } - } else { - return x; - } - } - let u: u64 = x.to_bits(); - let e: i64 = (u >> 52 & 0x7ff) as i64; - - if e >= 0x3ff + 52 || x == 0. { - return x; - } - // y = int(x) - x, where int(x) is an integer neighbor of x - let y = if (u >> 63) != 0 { - x - TOINT + TOINT - x - } else { - x + TOINT - TOINT - x - }; - // special case because of non-nearest rounding modes - if e < 0x3ff { - force_eval!(y); - return if (u >> 63) != 0 { -0. } else { 1. }; - } - if y < 0. { - x + y + 1. - } else { - x + y - } -} - -#[cfg(test)] -mod tests { - use super::*; - use core::f64::*; - - #[test] - fn sanity_check() { - assert_eq!(ceil(1.1), 2.0); - assert_eq!(ceil(2.9), 3.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil - #[test] - fn spec_tests() { - // Not Asserted: that the current rounding mode has no effect. - assert!(ceil(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { - assert_eq!(ceil(f), f); - } - } -} diff --git a/helpers/l2math/core/ceilf.rs b/helpers/l2math/core/ceilf.rs deleted file mode 100644 index 6bfc0d5..0000000 --- a/helpers/l2math/core/ceilf.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::{Float32, Int}; - -/// Ceil -/// -/// Finds the nearest integer greater than or equal to `x`. -#[export_name = "__l2math_ceilf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn ceilf(x: Float32) -> Float32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `Float32.ceil` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::ceilf32(x) } - } - } - let mut ui = x.to_bits(); - let e = (((ui >> 23) & 0xff).wrapping_sub(0x7f)) as Int; - - if e >= 23 { - return x; - } - if e >= 0 { - let m = 0x007fffff >> e; - if (ui & m) == 0 { - return x; - } - force_eval!(x + Float32::from_bits(0x7b800000)); - if ui >> 31 == 0 { - ui += m; - } - ui &= !m; - } else { - force_eval!(x + Float32::from_bits(0x7b800000)); - if ui >> 31 != 0 { - return -0.0; - } else if ui << 1 != 0 { - return 1.0; - } - } - Float32::from_bits(ui) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - use core::f32::*; - - #[test] - fn sanity_check() { - assert_eq!(ceilf(1.1), 2.0); - assert_eq!(ceilf(2.9), 3.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil - #[test] - fn spec_tests() { - // Not Asserted: that the current rounding mode has no effect. - assert!(ceilf(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { - assert_eq!(ceilf(f), f); - } - } -} diff --git a/helpers/l2math/core/copysign.rs b/helpers/l2math/core/copysign.rs deleted file mode 100644 index 2a5577b..0000000 --- a/helpers/l2math/core/copysign.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::Float64; - -/// Sign of Y, magnitude of X -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[export_name = "__l2math_copysign"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn copysign(x: Float64, y: Float64) -> Float64 { - let mut ux = x.to_bits(); - let uy = y.to_bits(); - ux &= (!0) >> 1; - ux |= uy & (1 << 63); - Float64::from_bits(ux) -} diff --git a/helpers/l2math/core/copysignf.rs b/helpers/l2math/core/copysignf.rs deleted file mode 100644 index b8e9cc4..0000000 --- a/helpers/l2math/core/copysignf.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::Float32; - -/// Sign of Y, magnitude of X -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[export_name = "__l2math_copysignf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn copysignf(x: Float32, y: Float32) -> Float32 { - let mut ux = x.to_bits(); - let uy = y.to_bits(); - ux &= 0x7fffffff; - ux |= uy & 0x80000000; - Float32::from_bits(ux) -} diff --git a/helpers/l2math/core/cos.rs b/helpers/l2math/core/cos.rs deleted file mode 100644 index be3f743..0000000 --- a/helpers/l2math/core/cos.rs +++ /dev/null @@ -1,85 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ -/** - * cos(x) - * Return cosine function of x. - * - * kernel function: - * k_sin ... sine function on [-pi/4,pi/4] - * k_cos ... cosine function on [-pi/4,pi/4] - * rem_pio2 ... argument reduction routine - * - * Method. - * Let S,C and T denote the sin, cos and tan respectively on - * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 - * in [-pi/4 , +pi/4], and let n = k mod 4. - * We have - * - * n sin(x) cos(x) tan(x) - * ---------------------------------------------------------- - * 0 S C T - * 1 C -S -1/T - * 2 -S -C T - * 3 -C S -1/T - * ---------------------------------------------------------- - * - * Special cases: - * Let trig be any of sin, cos, or tan. - * trig(+-INF) is NaN, with signals; - * trig(NaN) is that NaN; - * - * Accuracy: - * TRIG(x) returns trig(x) nearly rounded -*/ - -use crate::{Float64, Radian64, Int}; - -use super::{k_cos, k_sin, rem_pio2}; - -/// Cosine -/// -/// Computes the cosine of a number (in radians). -/// Returns a number between -1 and 1. -#[export_name = "__l2math_cos"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn cos(x: Radian64) -> Float64 { - let ix = (Float64::to_bits(x) >> 32) as u32 & 0x7fffffff; - - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - if ix < 0x3e46a09e { - /* if x < 2**-27 * sqrt(2) */ - /* raise inexact if x != 0 */ - if x as Int == 0 { - return 1.0; - } - } - return k_cos(x, 0.0); - } - - /* cos(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - return x - x; - } - - /* argument reduction needed */ - let (n, y0, y1) = rem_pio2(x); - match n & 3 { - 0 => k_cos(y0, y1), - 1 => -k_sin(y0, y1, 1), - 2 => -k_cos(y0, y1), - _ => k_sin(y0, y1, 1), - } -} diff --git a/helpers/l2math/core/cosf.rs b/helpers/l2math/core/cosf.rs deleted file mode 100644 index 74e6f64..0000000 --- a/helpers/l2math/core/cosf.rs +++ /dev/null @@ -1,90 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. -*/ - -use crate::{Float64, Float32}; - -use super::{k_cosf, k_sinf, rem_pio2f}; - -use core::f64::consts::FRAC_PI_2; - -/* Small multiples of pi/2 rounded to double precision. */ -const C1_PIO2: Float64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const C2_PIO2: Float64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const C3_PIO2: Float64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const C4_PIO2: Float64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ - -/// Cosine -/// -/// Computes the cosine of a number (in radians). -/// Returns a number between -1 and 1. -#[export_name = "__l2math_cosf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn cosf(x: Float32) -> Float32 { - let x64 = x as Float64; - - let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - if ix <= 0x3f490fda { - /* |x| ~<= pi/4 */ - if ix < 0x39800000 { - /* |x| < 2**-12 */ - /* raise inexact if x != 0 */ - force_eval!(x + x1p120); - return 1.; - } - return k_cosf(x64); - } - if ix <= 0x407b53d1 { - /* |x| ~<= 5*pi/4 */ - if ix > 0x4016cbe3 { - /* |x| ~> 3*pi/4 */ - return -k_cosf(if sign { x64 + C2_PIO2 } else { x64 - C2_PIO2 }); - } else if sign { - return k_sinf(x64 + C1_PIO2); - } else { - return k_sinf(C1_PIO2 - x64); - } - } - if ix <= 0x40e231d5 { - /* |x| ~<= 9*pi/4 */ - if ix > 0x40afeddf { - /* |x| ~> 7*pi/4 */ - return k_cosf(if sign { x64 + C4_PIO2 } else { x64 - C4_PIO2 }); - } else if sign { - return k_sinf(-x64 - C3_PIO2); - } else { - return k_sinf(x64 - C3_PIO2); - } - } - - /* cos(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - return x - x; - } - - /* general argument reduction needed */ - let (n, y) = rem_pio2f(x); - match n & 3 { - 0 => k_cosf(y), - 1 => k_sinf(-y), - 2 => -k_cosf(y), - _ => k_sinf(y), - } -} diff --git a/helpers/l2math/core/cosh.rs b/helpers/l2math/core/cosh.rs deleted file mode 100644 index 65e2717..0000000 --- a/helpers/l2math/core/cosh.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::{Float64, Radian64}; - -use super::exp; -use super::expm1; -use super::k_expo2; - -/// Hyperbolic cosine -/// -/// Computes the hyperbolic cosine of the argument x. -/// Is defined as `(exp(x) + exp(-x))/2` -/// Angles are specified in radians. -#[export_name = "__l2math_cosh"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn cosh(mut x: Radian64) -> Float64 { - /* |x| */ - let mut ix = x.to_bits(); - ix &= 0x7fffffffffffffff; - x = Float64::from_bits(ix); - let w = ix >> 32; - - /* |x| < log(2) */ - if w < 0x3fe62e42 { - if w < 0x3ff00000 - (26 << 20) { - let x1p120 = Float64::from_bits(0x4770000000000000); - force_eval!(x + x1p120); - return 1.; - } - let t = expm1(x); // exponential minus 1 - return 1. + t * t / (2. * (1. + t)); - } - - /* |x| < log(DBL_MAX) */ - if w < 0x40862e42 { - let t = exp(x); - /* note: if x>log(0x1p26) then the 1/t is not needed */ - return 0.5 * (t + 1. / t); - } - - /* |x| > log(DBL_MAX) or nan */ - k_expo2(x) -} diff --git a/helpers/l2math/core/coshf.rs b/helpers/l2math/core/coshf.rs deleted file mode 100644 index d24806a..0000000 --- a/helpers/l2math/core/coshf.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::{Float32, Radian32}; - -use super::expf; -use super::expm1f; -use super::k_expo2f; - -/// Hyperbolic cosine -/// -/// Computes the hyperbolic cosine of the argument x. -/// Is defined as `(exp(x) + exp(-x))/2` -/// Angles are specified in radians. -#[export_name = "__l2math_coshf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn coshf(mut x: Radian32) -> Float32 { - let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - /* |x| */ - let mut ix = x.to_bits(); - ix &= 0x7fffffff; - x = Float32::from_bits(ix); - let w = ix; - - /* |x| < log(2) */ - if w < 0x3f317217 { - if w < (0x3f800000 - (12 << 23)) { - force_eval!(x + x1p120); - return 1.; - } - let t = expm1f(x); - return 1. + t * t / (2. * (1. + t)); - } - - /* |x| < log(FLT_MAX) */ - if w < 0x42b17217 { - let t = expf(x); - return 0.5 * (t + 1. / t); - } - - /* |x| > log(FLT_MAX) or nan */ - k_expo2f(x) -} diff --git a/helpers/l2math/core/erf.rs b/helpers/l2math/core/erf.rs deleted file mode 100644 index ed37126..0000000 --- a/helpers/l2math/core/erf.rs +++ /dev/null @@ -1,310 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * double erf(double x) - * double erfc(double x) - * x - * 2 |\ - * erf(x) = --------- | exp(-t*t)dt - * sqrt(pi) \| - * 0 - * - * erfc(x) = 1-erf(x) - * Note that - * erf(-x) = -erf(x) - * erfc(-x) = 2 - erfc(x) - * - * Method: - * 1. For |x| in [0, 0.84375] - * erf(x) = x + x*R(x^2) - * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] - * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] - * where R = P/Q where P is an odd poly of degree 8 and - * Q is an odd poly of degree 10. - * -57.90 - * | R - (erf(x)-x)/x | <= 2 - * - * - * Remark. The formula is derived by noting - * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) - * and that - * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 - * is close to one. The interval is chosen because the fix - * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is - * near 0.6174), and by some experiment, 0.84375 is chosen to - * guarantee the error is less than one ulp for erf. - * - * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and - * c = 0.84506291151 rounded to single (24 bits) - * erf(x) = sign(x) * (c + P1(s)/Q1(s)) - * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 - * 1+(c+P1(s)/Q1(s)) if x < 0 - * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 - * Remark: here we use the taylor series expansion at x=1. - * erf(1+s) = erf(1) + s*Poly(s) - * = 0.845.. + P1(s)/Q1(s) - * That is, we use rational approximation to approximate - * erf(1+s) - (c = (single)0.84506291151) - * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] - * where - * P1(s) = degree 6 poly in s - * Q1(s) = degree 6 poly in s - * - * 3. For x in [1.25,1/0.35(~2.857143)], - * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) - * erf(x) = 1 - erfc(x) - * where - * R1(z) = degree 7 poly in z, (z=1/x^2) - * S1(z) = degree 8 poly in z - * - * 4. For x in [1/0.35,28] - * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 - * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 - * erf(x) = sign(x) *(1 - tiny) (raise inexact) - * erfc(x) = tiny*tiny (raise underflow) if x > 0 - * = 2 - tiny if x<0 - * - * 7. Special case: - * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, - * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, - * erfc/erf(NaN) is NaN -*/ - -use crate::Float64; - -use super::{exp, fabs, get_high_word, with_set_low_word}; - -consts!{ -const ERX: Float64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ -/* Coefficients for approximation to erf on [0,0.84375] */ -const EFX8: Float64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ -const PP0: Float64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ -const PP1: Float64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ -const PP2: Float64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ -const PP3: Float64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ -const PP4: Float64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ -const QQ1: Float64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ -const QQ2: Float64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ -const QQ3: Float64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ -const QQ4: Float64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ -const QQ5: Float64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ -/* Coefficients for approximation to erf in [0.84375,1.25] */ -const PA0: Float64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ -const PA1: Float64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ -const PA2: Float64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ -const PA3: Float64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ -const PA4: Float64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ -const PA5: Float64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ -const PA6: Float64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ -const QA1: Float64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ -const QA2: Float64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ -const QA3: Float64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ -const QA4: Float64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ -const QA5: Float64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ -const QA6: Float64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ -/* Coefficients for approximation to erfc in [1.25,1/0.35] */ -const RA0: Float64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ -const RA1: Float64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ -const RA2: Float64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ -const RA3: Float64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ -const RA4: Float64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ -const RA5: Float64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ -const RA6: Float64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ -const RA7: Float64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ -const SA1: Float64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ -const SA2: Float64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ -const SA3: Float64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ -const SA4: Float64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ -const SA5: Float64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ -const SA6: Float64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ -const SA7: Float64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ -const SA8: Float64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ -/* Coefficients for approximation to erfc in [1/.35,28] */ -const RB0: Float64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ -const RB1: Float64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ -const RB2: Float64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ -const RB3: Float64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ -const RB4: Float64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ -const RB5: Float64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ -const RB6: Float64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ -const SB1: Float64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ -const SB2: Float64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ -const SB3: Float64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ -const SB4: Float64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ -const SB5: Float64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ -const SB6: Float64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ -const SB7: Float64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ -} - -fn erfc1(x: Float64) -> Float64 { - let s = fabs(x) - 1.0; - let p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); - let q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); - 1.0 - ERX - p / q -} - -fn erfc2(ix: u32, mut x: Float64) -> Float64 { - let r: Float64; - let big_s: Float64; - if ix < 0x3ff40000 { - /* |x| < 1.25 */ - return erfc1(x); - } - - x = fabs(x); - let s: Float64 = 1.0 / (x * x); - if ix < 0x4006db6d { - /* |x| < 1/.35 ~ 2.85714 */ - r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); - big_s = 1.0 - + s * (SA1 - + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); - } else { - /* |x| > 1/.35 */ - r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); - big_s = - 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); - } - let z: Float64 = with_set_low_word(x, 0); - - exp(-z * z - 0.5625) * exp((z - x) * (z + x) + r / big_s) / x -} - -/// Error function -/// -/// Calculates an approximation to the “error function”, which estimates -/// the probability that an observation will fall within x standard -/// deviations of the mean (assuming a normal distribution). -#[export_name = "__l2math_erf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn erf(x: Float64) -> Float64 { - let r: Float64; - let s: Float64; - let z: Float64; - let y: Float64; - let mut ix: u32; - - - ix = get_high_word(x); - let sign: usize = (ix >> 31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - /* erf(nan)=nan, erf(+-inf)=+-1 */ - return 1.0 - 2.0 * (sign as Float64) + 1.0 / x; - } - if ix < 0x3feb0000 { - /* |x| < 0.84375 */ - if ix < 0x3e300000 { - /* |x| < 2**-28 */ - /* avoid underflow */ - return 0.125 * (8.0 * x + EFX8 * x); - } - z = x * x; - r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); - s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); - y = r / s; - return x + x * y; - } - if ix < 0x40180000 { - /* 0.84375 <= |x| < 6 */ - y = 1.0 - erfc2(ix, x); - } else { - let x1p_1022 = Float64::from_bits(0x0010000000000000); - y = 1.0 - x1p_1022; - } - - if sign != 0 { - -y - } else { - y - } -} - -/// Complementary error function -/// -/// Calculates the complementary probability. -/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid -/// the loss of precision that would result from subtracting -/// large probabilities (on large `x`) from 1. -#[export_name = "__l2math_erfc"] -pub extern "C" fn erfc(x: Float64) -> Float64 { - let r: Float64; - let s: Float64; - let z: Float64; - let y: Float64; - let mut ix: u32; - - - ix = get_high_word(x); - let sign: usize = (ix >> 31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - /* erfc(nan)=nan, erfc(+-inf)=0,2 */ - return 2.0 * (sign as Float64) + 1.0 / x; - } - if ix < 0x3feb0000 { - /* |x| < 0.84375 */ - if ix < 0x3c700000 { - /* |x| < 2**-56 */ - return 1.0 - x; - } - z = x * x; - r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); - s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); - y = r / s; - if sign != 0 || ix < 0x3fd00000 { - /* x < 1/4 */ - return 1.0 - (x + x * y); - } - return 0.5 - (x - 0.5 + x * y); - } - if ix < 0x403c0000 { - /* 0.84375 <= |x| < 28 */ - if sign != 0 { - return 2.0 - erfc2(ix, x); - } else { - return erfc2(ix, x); - } - } - - let x1p_1022 = Float64::from_bits(0x0010000000000000); - if sign != 0 { - 2.0 - x1p_1022 - } else { - x1p_1022 * x1p_1022 - } -} diff --git a/helpers/l2math/core/erff.rs b/helpers/l2math/core/erff.rs deleted file mode 100644 index 463de5c..0000000 --- a/helpers/l2math/core/erff.rs +++ /dev/null @@ -1,212 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::Float32; - -use super::{expf, fabsf}; - -consts!{ -const ERX: Float32 = 8.4506291151e-01; /* 0x3f58560b */ -/* Coefficients for approximation to erf on [0,0.84375] */ -const EFX8: Float32 = 1.0270333290e+00; /* 0x3f8375d4 */ -const PP0: Float32 = 1.2837916613e-01; /* 0x3e0375d4 */ -const PP1: Float32 = -3.2504209876e-01; /* 0xbea66beb */ -const PP2: Float32 = -2.8481749818e-02; /* 0xbce9528f */ -const PP3: Float32 = -5.7702702470e-03; /* 0xbbbd1489 */ -const PP4: Float32 = -2.3763017452e-05; /* 0xb7c756b1 */ -const QQ1: Float32 = 3.9791721106e-01; /* 0x3ecbbbce */ -const QQ2: Float32 = 6.5022252500e-02; /* 0x3d852a63 */ -const QQ3: Float32 = 5.0813062117e-03; /* 0x3ba68116 */ -const QQ4: Float32 = 1.3249473704e-04; /* 0x390aee49 */ -const QQ5: Float32 = -3.9602282413e-06; /* 0xb684e21a */ -/* Coefficients for approximation to erf in [0.84375,1.25] */ -const PA0: Float32 = -2.3621185683e-03; /* 0xbb1acdc6 */ -const PA1: Float32 = 4.1485610604e-01; /* 0x3ed46805 */ -const PA2: Float32 = -3.7220788002e-01; /* 0xbebe9208 */ -const PA3: Float32 = 3.1834661961e-01; /* 0x3ea2fe54 */ -const PA4: Float32 = -1.1089469492e-01; /* 0xbde31cc2 */ -const PA5: Float32 = 3.5478305072e-02; /* 0x3d1151b3 */ -const PA6: Float32 = -2.1663755178e-03; /* 0xbb0df9c0 */ -const QA1: Float32 = 1.0642088205e-01; /* 0x3dd9f331 */ -const QA2: Float32 = 5.4039794207e-01; /* 0x3f0a5785 */ -const QA3: Float32 = 7.1828655899e-02; /* 0x3d931ae7 */ -const QA4: Float32 = 1.2617121637e-01; /* 0x3e013307 */ -const QA5: Float32 = 1.3637083583e-02; /* 0x3c5f6e13 */ -const QA6: Float32 = 1.1984500103e-02; /* 0x3c445aa3 */ -/* Coefficients for approximation to erfc in [1.25,1/0.35] */ -const RA0: Float32 = -9.8649440333e-03; /* 0xbc21a093 */ -const RA1: Float32 = -6.9385856390e-01; /* 0xbf31a0b7 */ -const RA2: Float32 = -1.0558626175e+01; /* 0xc128f022 */ -const RA3: Float32 = -6.2375331879e+01; /* 0xc2798057 */ -const RA4: Float32 = -1.6239666748e+02; /* 0xc322658c */ -const RA5: Float32 = -1.8460508728e+02; /* 0xc3389ae7 */ -const RA6: Float32 = -8.1287437439e+01; /* 0xc2a2932b */ -const RA7: Float32 = -9.8143291473e+00; /* 0xc11d077e */ -const SA1: Float32 = 1.9651271820e+01; /* 0x419d35ce */ -const SA2: Float32 = 1.3765776062e+02; /* 0x4309a863 */ -const SA3: Float32 = 4.3456588745e+02; /* 0x43d9486f */ -const SA4: Float32 = 6.4538726807e+02; /* 0x442158c9 */ -const SA5: Float32 = 4.2900814819e+02; /* 0x43d6810b */ -const SA6: Float32 = 1.0863500214e+02; /* 0x42d9451f */ -const SA7: Float32 = 6.5702495575e+00; /* 0x40d23f7c */ -const SA8: Float32 = -6.0424413532e-02; /* 0xbd777f97 */ -/* Coefficients for approximation to erfc in [1/.35,28] */ -const RB0: Float32 = -9.8649431020e-03; /* 0xbc21a092 */ -const RB1: Float32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ -const RB2: Float32 = -1.7757955551e+01; /* 0xc18e104b */ -const RB3: Float32 = -1.6063638306e+02; /* 0xc320a2ea */ -const RB4: Float32 = -6.3756646729e+02; /* 0xc41f6441 */ -const RB5: Float32 = -1.0250950928e+03; /* 0xc480230b */ -const RB6: Float32 = -4.8351919556e+02; /* 0xc3f1c275 */ -const SB1: Float32 = 3.0338060379e+01; /* 0x41f2b459 */ -const SB2: Float32 = 3.2579251099e+02; /* 0x43a2e571 */ -const SB3: Float32 = 1.5367296143e+03; /* 0x44c01759 */ -const SB4: Float32 = 3.1998581543e+03; /* 0x4547fdbb */ -const SB5: Float32 = 2.5530502930e+03; /* 0x451f90ce */ -const SB6: Float32 = 4.7452853394e+02; /* 0x43ed43a7 */ -const SB7: Float32 = -2.2440952301e+01; /* 0xc1b38712 */ -} - -fn erfc1(x: Float32) -> Float32 { - let s = fabsf(x) - 1.0; - let p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); - let q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); - return 1.0 - ERX - p / q; -} - -fn erfc2(mut ix: u32, mut x: Float32) -> Float32 { - let r: Float32; - let big_s: Float32; - if ix < 0x3fa00000 { - /* |x| < 1.25 */ - return erfc1(x); - } - x = fabsf(x); - let s: Float32 = 1.0 / (x * x); - if ix < 0x4036db6d { - /* |x| < 1/0.35 */ - r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); - big_s = 1.0 - + s * (SA1 - + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); - } else { - /* |x| >= 1/0.35 */ - r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); - big_s = - 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); - } - ix = x.to_bits(); - let z = Float32::from_bits(ix & 0xffffe000); - expf(-z * z - 0.5625) * expf((z - x) * (z + x) + r / big_s) / x -} - -/// Error function -/// -/// Calculates an approximation to the “error function”, which estimates -/// the probability that an observation will fall within x standard -/// deviations of the mean (assuming a normal distribution). -#[export_name = "__l2math_erff"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn erff(x: Float32) -> Float32 { - let r: Float32; - let s: Float32; - let z: Float32; - let y: Float32; - let mut ix: u32 = x.to_bits(); - let sign = (ix >> 31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - /* erf(nan)=nan, erf(+-inf)=+-1 */ - return 1.0 - 2.0 * (sign as Float32) + 1.0 / x; - } - if ix < 0x3f580000 { - /* |x| < 0.84375 */ - if ix < 0x31800000 { - /* |x| < 2**-28 */ - /*avoid underflow */ - return 0.125 * (8.0 * x + EFX8 * x); - } - z = x * x; - r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); - s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); - y = r / s; - return x + x * y; - } - if ix < 0x40c00000 { - /* |x| < 6 */ - y = 1.0 - erfc2(ix, x); - } else { - let x1p_120 = Float32::from_bits(0x03800000); - y = 1.0 - x1p_120; - } - - if sign != 0 { - -y - } else { - y - } -} - -/// Complementary error function -/// -/// Calculates the complementary probability. -/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid -/// the loss of precision that would result from subtracting -/// large probabilities (on large `x`) from 1. -#[export_name = "__l2math_erfcf"] -pub extern "C" fn erfcf(x: Float32) -> Float32 { - let r: Float32; - let s: Float32; - let z: Float32; - let y: Float32; - let mut ix = x.to_bits(); - let sign = (ix >> 31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - /* erfc(nan)=nan, erfc(+-inf)=0,2 */ - return 2.0 * (sign as Float32) + 1.0 / x; - } - if ix < 0x3f580000 { - /* |x| < 0.84375 */ - if ix < 0x23800000 { - /* |x| < 2**-56 */ - return 1.0 - x; - } - z = x * x; - r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); - s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); - y = r / s; - if sign != 0 || ix < 0x3e800000 { - /* x < 1/4 */ - return 1.0 - (x + x * y); - } - return 0.5 - (x - 0.5 + x * y); - } - if ix < 0x41e00000 { - /* |x| < 28 */ - if sign != 0 { - return 2.0 - erfc2(ix, x); - } else { - return erfc2(ix, x); - } - } - - let x1p_120 = Float32::from_bits(0x03800000); - if sign != 0 { - 2.0 - x1p_120 - } else { - x1p_120 * x1p_120 - } -} diff --git a/helpers/l2math/core/exp.rs b/helpers/l2math/core/exp.rs deleted file mode 100644 index 8f206ec..0000000 --- a/helpers/l2math/core/exp.rs +++ /dev/null @@ -1,156 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ -/** - * ==================================================== - * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. - * - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * exp(x) - * Returns the exponential of x. - * - * Method - * 1. Argument reduction: - * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. - * Given x, find r and integer k such that - * - * x = k*ln2 + r, |r| <= 0.5*ln2. - * - * Here r will be represented as r = hi-lo for better - * accuracy. - * - * 2. Approximation of exp(r) by a special rational function on - * the interval [0,0.34658]: - * Write - * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... - * We use a special Remez algorithm on [0,0.34658] to generate - * a polynomial of degree 5 to approximate R. The maximum error - * of this polynomial approximation is bounded by 2**-59. In - * other words, - * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 - * (where z=r*r, and the values of P1 to P5 are listed below) - * and - * | 5 | -59 - * | 2.0+P1*z+...+P5*z - R(z) | <= 2 - * | | - * The computation of exp(r) thus becomes - * 2*r - * exp(r) = 1 + ---------- - * R(r) - r - * r*c(r) - * = 1 + r + ----------- (for better accuracy) - * 2 - c(r) - * where - * 2 4 10 - * c(r) = r - (P1*r + P2*r + ... + P5*r ). - * - * 3. Scale back to obtain exp(x): - * From step 1, we have - * exp(x) = 2^k * exp(r) - * - * Special cases: - * exp(INF) is INF, exp(NaN) is NaN; - * exp(-INF) is 0, and - * for finite argument, only exp(0)=1 is exact. - * - * Accuracy: - * according to an error analysis, the error is always less than - * 1 ulp (unit in the last place). - * - * Misc. info. - * For IEEE double - * if x > 709.782712893383973096 then exp(x) overflows - * if x < -745.133219101941108420 then exp(x) underflows -*/ - -use crate::{Float64, Float32, Int}; - -use super::scalbn; - -consts!{ -const HALF: [Float64; 2] = [0.5, -0.5]; -const LN2HI: Float64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ -const LN2LO: Float64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ -const INVLN2: Float64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ -const P1: Float64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ -const P2: Float64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ -const P3: Float64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ -const P4: Float64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ -const P5: Float64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ -} - -/// Exponential, base *e* -/// -/// Calculate the exponential of `x`, that is, *e* raised to the power `x` -/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). -#[export_name = "__l2math_exp"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn exp(mut x: Float64) -> Float64 { - let x1p1023 = Float64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 - let x1p_149 = Float64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149 - let hi: Float64; - let lo: Float64; - let k: Int; - let mut hx: u32; - hx = (x.to_bits() >> 32) as u32; - let sign: Int = (hx >> 31) as Int; - hx &= 0x7fffffff; /* high word of |x| */ - /* special cases */ - if hx >= 0x4086232b { - /* if |x| >= 708.39... */ - if x.is_nan() { - return x; - } - #[allow(clippy::excessive_precision)] - if x > 709.782_712_893_383_973_096 { - /* overflow if x!=inf */ - x *= x1p1023; - return x; - } - #[allow(clippy::excessive_precision)] - if x < -708.396_418_532_264_106_22 { - /* underflow if x!=-inf */ - force_eval!((-x1p_149 / x) as Float32); - #[allow(clippy::excessive_precision)] - if x < -745.133_219_101_941_108_42 { - return 0.; - } - } - } - - /* argument reduction */ - if hx > 0x3fd62e42 { - /* if |x| > 0.5 ln2 */ - if hx >= 0x3ff0a2b2 { - /* if |x| >= 1.5 ln2 */ - k = (INVLN2 * x + i!(HALF, sign as usize)) as Int; - } else { - k = 1 - sign - sign; - } - hi = x - k as Float64 * LN2HI; /* k*ln2hi is exact here */ - lo = k as Float64 * LN2LO; - x = hi - lo; - } else if hx > 0x3e300000 { - /* if |x| > 2**-28 */ - k = 0; - hi = x; - lo = 0.; - } else { - /* inexact if x!=0 */ - force_eval!(x1p1023 + x); - return 1. + x; - } - - /* x is now in primary range */ - let xx: Float64 = x * x; - let c: Float64 = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); - let y: Float64 = 1. + (x * c / (2. - c) - lo + hi); - if k == 0 { - y - } else { - scalbn(y, k) - } -} diff --git a/helpers/l2math/core/exp10.rs b/helpers/l2math/core/exp10.rs deleted file mode 100644 index c9a77f6..0000000 --- a/helpers/l2math/core/exp10.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::Float64; - -use super::{exp2, modf, pow}; - -consts!{ -const LN10: Float64 = 3.32192809488736234787031942948939; -const P10: &[Float64] = &[ - 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, -]; -} - -/// Exponential, base 10 -/// -/// Calculate `10^x`, that is, 10 raised to the power `x`. -#[export_name = "__l2math_exp10"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn exp10(x: Float64) -> Float64 { - let (mut y, n) = modf(x); - let u: u64 = n.to_bits(); - /* fabs(n) < 16 without raising invalid on nan */ - if (u >> 52 & 0x7ff) < 0x3ff + 4 { - if y == 0.0 { - return i!(P10, ((n as isize) + 15) as usize); - } - y = exp2(LN10 * y); - return y * i!(P10, ((n as isize) + 15) as usize); - } - return pow(10.0, x); -} diff --git a/helpers/l2math/core/exp10f.rs b/helpers/l2math/core/exp10f.rs deleted file mode 100644 index 6a0e301..0000000 --- a/helpers/l2math/core/exp10f.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::{Float64, Float32}; - -use super::{exp2, exp2f, modff}; - -use core::f64::consts::LN_10 as LN10_F64; -use core::f32::consts::LN_10 as LN10_F32; - -const P10: &[Float32] = &[ - 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, -]; - -/// Exponential, base 10 -/// -/// Calculate `10^x`, that is, 10 raised to the power `x`. -#[export_name = "__l2math_exp10f"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn exp10f(x: Float32) -> Float32 { - let (mut y, n) = modff(x); - let u = n.to_bits(); - /* fabsf(n) < 8 without raising invalid on nan */ - if (u >> 23 & 0xff) < 0x7f + 3 { - if y == 0.0 { - return i!(P10, ((n as isize) + 7) as usize); - } - y = exp2f(LN10_F32 * y); - return y * i!(P10, ((n as isize) + 7) as usize); - } - return exp2(LN10_F64 * (x as Float64)) as Float32; -} diff --git a/helpers/l2math/core/exp2.rs b/helpers/l2math/core/exp2.rs deleted file mode 100644 index 2c4c70d..0000000 --- a/helpers/l2math/core/exp2.rs +++ /dev/null @@ -1,397 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ -//- -// Copyright (c) 2005 David Schultz -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. - -use crate::{Float64, Float32, Int}; - -use super::scalbn; - -const TBLSIZE: usize = 256; - -#[rustfmt::skip] -static TBL: [u64; TBLSIZE * 2] = [ - // exp2(z + eps) eps - 0x3fe6a09e667f3d5d, 0x3d39880000000000, - 0x3fe6b052fa751744, 0x3cd8000000000000, - 0x3fe6c012750bd9fe, 0xbd28780000000000, - 0x3fe6cfdcddd476bf, 0x3d1ec00000000000, - 0x3fe6dfb23c651a29, 0xbcd8000000000000, - 0x3fe6ef9298593ae3, 0xbcbc000000000000, - 0x3fe6ff7df9519386, 0xbd2fd80000000000, - 0x3fe70f7466f42da3, 0xbd2c880000000000, - 0x3fe71f75e8ec5fc3, 0x3d13c00000000000, - 0x3fe72f8286eacf05, 0xbd38300000000000, - 0x3fe73f9a48a58152, 0xbd00c00000000000, - 0x3fe74fbd35d7ccfc, 0x3d2f880000000000, - 0x3fe75feb564267f1, 0x3d03e00000000000, - 0x3fe77024b1ab6d48, 0xbd27d00000000000, - 0x3fe780694fde5d38, 0xbcdd000000000000, - 0x3fe790b938ac1d00, 0x3ce3000000000000, - 0x3fe7a11473eb0178, 0xbced000000000000, - 0x3fe7b17b0976d060, 0x3d20400000000000, - 0x3fe7c1ed0130c133, 0x3ca0000000000000, - 0x3fe7d26a62ff8636, 0xbd26900000000000, - 0x3fe7e2f336cf4e3b, 0xbd02e00000000000, - 0x3fe7f3878491c3e8, 0xbd24580000000000, - 0x3fe80427543e1b4e, 0x3d33000000000000, - 0x3fe814d2add1071a, 0x3d0f000000000000, - 0x3fe82589994ccd7e, 0xbd21c00000000000, - 0x3fe8364c1eb942d0, 0x3d29d00000000000, - 0x3fe8471a4623cab5, 0x3d47100000000000, - 0x3fe857f4179f5bbc, 0x3d22600000000000, - 0x3fe868d99b4491af, 0xbd32c40000000000, - 0x3fe879cad931a395, 0xbd23000000000000, - 0x3fe88ac7d98a65b8, 0xbd2a800000000000, - 0x3fe89bd0a4785800, 0xbced000000000000, - 0x3fe8ace5422aa223, 0x3d33280000000000, - 0x3fe8be05bad619fa, 0x3d42b40000000000, - 0x3fe8cf3216b54383, 0xbd2ed00000000000, - 0x3fe8e06a5e08664c, 0xbd20500000000000, - 0x3fe8f1ae99157807, 0x3d28280000000000, - 0x3fe902fed0282c0e, 0xbd1cb00000000000, - 0x3fe9145b0b91ff96, 0xbd05e00000000000, - 0x3fe925c353aa2ff9, 0x3cf5400000000000, - 0x3fe93737b0cdc64a, 0x3d17200000000000, - 0x3fe948b82b5f98ae, 0xbd09000000000000, - 0x3fe95a44cbc852cb, 0x3d25680000000000, - 0x3fe96bdd9a766f21, 0xbd36d00000000000, - 0x3fe97d829fde4e2a, 0xbd01000000000000, - 0x3fe98f33e47a23a3, 0x3d2d000000000000, - 0x3fe9a0f170ca0604, 0xbd38a40000000000, - 0x3fe9b2bb4d53ff89, 0x3d355c0000000000, - 0x3fe9c49182a3f15b, 0x3d26b80000000000, - 0x3fe9d674194bb8c5, 0xbcec000000000000, - 0x3fe9e86319e3238e, 0x3d17d00000000000, - 0x3fe9fa5e8d07f302, 0x3d16400000000000, - 0x3fea0c667b5de54d, 0xbcf5000000000000, - 0x3fea1e7aed8eb8f6, 0x3d09e00000000000, - 0x3fea309bec4a2e27, 0x3d2ad80000000000, - 0x3fea42c980460a5d, 0xbd1af00000000000, - 0x3fea5503b23e259b, 0x3d0b600000000000, - 0x3fea674a8af46213, 0x3d38880000000000, - 0x3fea799e1330b3a7, 0x3d11200000000000, - 0x3fea8bfe53c12e8d, 0x3d06c00000000000, - 0x3fea9e6b5579fcd2, 0xbd29b80000000000, - 0x3feab0e521356fb8, 0x3d2b700000000000, - 0x3feac36bbfd3f381, 0x3cd9000000000000, - 0x3fead5ff3a3c2780, 0x3ce4000000000000, - 0x3feae89f995ad2a3, 0xbd2c900000000000, - 0x3feafb4ce622f367, 0x3d16500000000000, - 0x3feb0e07298db790, 0x3d2fd40000000000, - 0x3feb20ce6c9a89a9, 0x3d12700000000000, - 0x3feb33a2b84f1a4b, 0x3d4d470000000000, - 0x3feb468415b747e7, 0xbd38380000000000, - 0x3feb59728de5593a, 0x3c98000000000000, - 0x3feb6c6e29f1c56a, 0x3d0ad00000000000, - 0x3feb7f76f2fb5e50, 0x3cde800000000000, - 0x3feb928cf22749b2, 0xbd04c00000000000, - 0x3feba5b030a10603, 0xbd0d700000000000, - 0x3febb8e0b79a6f66, 0x3d0d900000000000, - 0x3febcc1e904bc1ff, 0x3d02a00000000000, - 0x3febdf69c3f3a16f, 0xbd1f780000000000, - 0x3febf2c25bd71db8, 0xbd10a00000000000, - 0x3fec06286141b2e9, 0xbd11400000000000, - 0x3fec199bdd8552e0, 0x3d0be00000000000, - 0x3fec2d1cd9fa64ee, 0xbd09400000000000, - 0x3fec40ab5fffd02f, 0xbd0ed00000000000, - 0x3fec544778fafd15, 0x3d39660000000000, - 0x3fec67f12e57d0cb, 0xbd1a100000000000, - 0x3fec7ba88988c1b6, 0xbd58458000000000, - 0x3fec8f6d9406e733, 0xbd1a480000000000, - 0x3feca3405751c4df, 0x3ccb000000000000, - 0x3fecb720dcef9094, 0x3d01400000000000, - 0x3feccb0f2e6d1689, 0x3cf0200000000000, - 0x3fecdf0b555dc412, 0x3cf3600000000000, - 0x3fecf3155b5bab3b, 0xbd06900000000000, - 0x3fed072d4a0789bc, 0x3d09a00000000000, - 0x3fed1b532b08c8fa, 0xbd15e00000000000, - 0x3fed2f87080d8a85, 0x3d1d280000000000, - 0x3fed43c8eacaa203, 0x3d01a00000000000, - 0x3fed5818dcfba491, 0x3cdf000000000000, - 0x3fed6c76e862e6a1, 0xbd03a00000000000, - 0x3fed80e316c9834e, 0xbd0cd80000000000, - 0x3fed955d71ff6090, 0x3cf4c00000000000, - 0x3feda9e603db32ae, 0x3cff900000000000, - 0x3fedbe7cd63a8325, 0x3ce9800000000000, - 0x3fedd321f301b445, 0xbcf5200000000000, - 0x3fede7d5641c05bf, 0xbd1d700000000000, - 0x3fedfc97337b9aec, 0xbd16140000000000, - 0x3fee11676b197d5e, 0x3d0b480000000000, - 0x3fee264614f5a3e7, 0x3d40ce0000000000, - 0x3fee3b333b16ee5c, 0x3d0c680000000000, - 0x3fee502ee78b3fb4, 0xbd09300000000000, - 0x3fee653924676d68, 0xbce5000000000000, - 0x3fee7a51fbc74c44, 0xbd07f80000000000, - 0x3fee8f7977cdb726, 0xbcf3700000000000, - 0x3feea4afa2a490e8, 0x3ce5d00000000000, - 0x3feeb9f4867ccae4, 0x3d161a0000000000, - 0x3feecf482d8e680d, 0x3cf5500000000000, - 0x3feee4aaa2188514, 0x3cc6400000000000, - 0x3feefa1bee615a13, 0xbcee800000000000, - 0x3fef0f9c1cb64106, 0xbcfa880000000000, - 0x3fef252b376bb963, 0xbd2c900000000000, - 0x3fef3ac948dd7275, 0x3caa000000000000, - 0x3fef50765b6e4524, 0xbcf4f00000000000, - 0x3fef6632798844fd, 0x3cca800000000000, - 0x3fef7bfdad9cbe38, 0x3cfabc0000000000, - 0x3fef91d802243c82, 0xbcd4600000000000, - 0x3fefa7c1819e908e, 0xbd0b0c0000000000, - 0x3fefbdba3692d511, 0xbcc0e00000000000, - 0x3fefd3c22b8f7194, 0xbd10de8000000000, - 0x3fefe9d96b2a23ee, 0x3cee430000000000, - 0x3ff0000000000000, 0x0, - 0x3ff00b1afa5abcbe, 0xbcb3400000000000, - 0x3ff0163da9fb3303, 0xbd12170000000000, - 0x3ff02168143b0282, 0x3cba400000000000, - 0x3ff02c9a3e77806c, 0x3cef980000000000, - 0x3ff037d42e11bbca, 0xbcc7400000000000, - 0x3ff04315e86e7f89, 0x3cd8300000000000, - 0x3ff04e5f72f65467, 0xbd1a3f0000000000, - 0x3ff059b0d315855a, 0xbd02840000000000, - 0x3ff0650a0e3c1f95, 0x3cf1600000000000, - 0x3ff0706b29ddf71a, 0x3d15240000000000, - 0x3ff07bd42b72a82d, 0xbce9a00000000000, - 0x3ff0874518759bd0, 0x3ce6400000000000, - 0x3ff092bdf66607c8, 0xbd00780000000000, - 0x3ff09e3ecac6f383, 0xbc98000000000000, - 0x3ff0a9c79b1f3930, 0x3cffa00000000000, - 0x3ff0b5586cf988fc, 0xbcfac80000000000, - 0x3ff0c0f145e46c8a, 0x3cd9c00000000000, - 0x3ff0cc922b724816, 0x3d05200000000000, - 0x3ff0d83b23395dd8, 0xbcfad00000000000, - 0x3ff0e3ec32d3d1f3, 0x3d1bac0000000000, - 0x3ff0efa55fdfa9a6, 0xbd04e80000000000, - 0x3ff0fb66affed2f0, 0xbd0d300000000000, - 0x3ff1073028d7234b, 0x3cf1500000000000, - 0x3ff11301d0125b5b, 0x3cec000000000000, - 0x3ff11edbab5e2af9, 0x3d16bc0000000000, - 0x3ff12abdc06c31d5, 0x3ce8400000000000, - 0x3ff136a814f2047d, 0xbd0ed00000000000, - 0x3ff1429aaea92de9, 0x3ce8e00000000000, - 0x3ff14e95934f3138, 0x3ceb400000000000, - 0x3ff15a98c8a58e71, 0x3d05300000000000, - 0x3ff166a45471c3df, 0x3d03380000000000, - 0x3ff172b83c7d5211, 0x3d28d40000000000, - 0x3ff17ed48695bb9f, 0xbd05d00000000000, - 0x3ff18af9388c8d93, 0xbd1c880000000000, - 0x3ff1972658375d66, 0x3d11f00000000000, - 0x3ff1a35beb6fcba7, 0x3d10480000000000, - 0x3ff1af99f81387e3, 0xbd47390000000000, - 0x3ff1bbe084045d54, 0x3d24e40000000000, - 0x3ff1c82f95281c43, 0xbd0a200000000000, - 0x3ff1d4873168b9b2, 0x3ce3800000000000, - 0x3ff1e0e75eb44031, 0x3ceac00000000000, - 0x3ff1ed5022fcd938, 0x3d01900000000000, - 0x3ff1f9c18438cdf7, 0xbd1b780000000000, - 0x3ff2063b88628d8f, 0x3d2d940000000000, - 0x3ff212be3578a81e, 0x3cd8000000000000, - 0x3ff21f49917ddd41, 0x3d2b340000000000, - 0x3ff22bdda2791323, 0x3d19f80000000000, - 0x3ff2387a6e7561e7, 0xbd19c80000000000, - 0x3ff2451ffb821427, 0x3d02300000000000, - 0x3ff251ce4fb2a602, 0xbd13480000000000, - 0x3ff25e85711eceb0, 0x3d12700000000000, - 0x3ff26b4565e27d16, 0x3d11d00000000000, - 0x3ff2780e341de00f, 0x3d31ee0000000000, - 0x3ff284dfe1f5633e, 0xbd14c00000000000, - 0x3ff291ba7591bb30, 0xbd13d80000000000, - 0x3ff29e9df51fdf09, 0x3d08b00000000000, - 0x3ff2ab8a66d10e9b, 0xbd227c0000000000, - 0x3ff2b87fd0dada3a, 0x3d2a340000000000, - 0x3ff2c57e39771af9, 0xbd10800000000000, - 0x3ff2d285a6e402d9, 0xbd0ed00000000000, - 0x3ff2df961f641579, 0xbcf4200000000000, - 0x3ff2ecafa93e2ecf, 0xbd24980000000000, - 0x3ff2f9d24abd8822, 0xbd16300000000000, - 0x3ff306fe0a31b625, 0xbd32360000000000, - 0x3ff31432edeea50b, 0xbd70df8000000000, - 0x3ff32170fc4cd7b8, 0xbd22480000000000, - 0x3ff32eb83ba8e9a2, 0xbd25980000000000, - 0x3ff33c08b2641766, 0x3d1ed00000000000, - 0x3ff3496266e3fa27, 0xbcdc000000000000, - 0x3ff356c55f929f0f, 0xbd30d80000000000, - 0x3ff36431a2de88b9, 0x3d22c80000000000, - 0x3ff371a7373aaa39, 0x3d20600000000000, - 0x3ff37f26231e74fe, 0xbd16600000000000, - 0x3ff38cae6d05d838, 0xbd0ae00000000000, - 0x3ff39a401b713ec3, 0xbd44720000000000, - 0x3ff3a7db34e5a020, 0x3d08200000000000, - 0x3ff3b57fbfec6e95, 0x3d3e800000000000, - 0x3ff3c32dc313a8f2, 0x3cef800000000000, - 0x3ff3d0e544ede122, 0xbd17a00000000000, - 0x3ff3dea64c1234bb, 0x3d26300000000000, - 0x3ff3ec70df1c4ecc, 0xbd48a60000000000, - 0x3ff3fa4504ac7e8c, 0xbd3cdc0000000000, - 0x3ff40822c367a0bb, 0x3d25b80000000000, - 0x3ff4160a21f72e95, 0x3d1ec00000000000, - 0x3ff423fb27094646, 0xbd13600000000000, - 0x3ff431f5d950a920, 0x3d23980000000000, - 0x3ff43ffa3f84b9eb, 0x3cfa000000000000, - 0x3ff44e0860618919, 0xbcf6c00000000000, - 0x3ff45c2042a7d201, 0xbd0bc00000000000, - 0x3ff46a41ed1d0016, 0xbd12800000000000, - 0x3ff4786d668b3326, 0x3d30e00000000000, - 0x3ff486a2b5c13c00, 0xbd2d400000000000, - 0x3ff494e1e192af04, 0x3d0c200000000000, - 0x3ff4a32af0d7d372, 0xbd1e500000000000, - 0x3ff4b17dea6db801, 0x3d07800000000000, - 0x3ff4bfdad53629e1, 0xbd13800000000000, - 0x3ff4ce41b817c132, 0x3d00800000000000, - 0x3ff4dcb299fddddb, 0x3d2c700000000000, - 0x3ff4eb2d81d8ab96, 0xbd1ce00000000000, - 0x3ff4f9b2769d2d02, 0x3d19200000000000, - 0x3ff508417f4531c1, 0xbd08c00000000000, - 0x3ff516daa2cf662a, 0xbcfa000000000000, - 0x3ff5257de83f51ea, 0x3d4a080000000000, - 0x3ff5342b569d4eda, 0xbd26d80000000000, - 0x3ff542e2f4f6ac1a, 0xbd32440000000000, - 0x3ff551a4ca5d94db, 0x3d483c0000000000, - 0x3ff56070dde9116b, 0x3d24b00000000000, - 0x3ff56f4736b529de, 0x3d415a0000000000, - 0x3ff57e27dbe2c40e, 0xbd29e00000000000, - 0x3ff58d12d497c76f, 0xbd23080000000000, - 0x3ff59c0827ff0b4c, 0x3d4dec0000000000, - 0x3ff5ab07dd485427, 0xbcc4000000000000, - 0x3ff5ba11fba87af4, 0x3d30080000000000, - 0x3ff5c9268a59460b, 0xbd26c80000000000, - 0x3ff5d84590998e3f, 0x3d469a0000000000, - 0x3ff5e76f15ad20e1, 0xbd1b400000000000, - 0x3ff5f6a320dcebca, 0x3d17700000000000, - 0x3ff605e1b976dcb8, 0x3d26f80000000000, - 0x3ff6152ae6cdf715, 0x3d01000000000000, - 0x3ff6247eb03a5531, 0xbd15d00000000000, - 0x3ff633dd1d1929b5, 0xbd12d00000000000, - 0x3ff6434634ccc313, 0xbcea800000000000, - 0x3ff652b9febc8efa, 0xbd28600000000000, - 0x3ff6623882553397, 0x3d71fe0000000000, - 0x3ff671c1c708328e, 0xbd37200000000000, - 0x3ff68155d44ca97e, 0x3ce6800000000000, - 0x3ff690f4b19e9471, 0xbd29780000000000, -]; - -// exp2(x): compute the base 2 exponential of x -// -// Accuracy: Peak error < 0.503 ulp for normalized results. -// -// Method: (accurate tables) -// -// Reduce x: -// x = k + y, for integer k and |y| <= 1/2. -// Thus we have exp2(x) = 2**k * exp2(y). -// -// Reduce y: -// y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. -// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), -// with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. -// -// We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via -// a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. -// The values in exp2t[] and eps[] are chosen such that -// exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such -// that exp2t[i] is accurate to 2**-64. -// -// Note that the range of i is +-TBLSIZE/2, so we actually index the tables -// by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are -// virtual tables, interleaved in the real table tbl[]. -// -// This method is due to Gal, with many details due to Gal and Bachelis: -// -// Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library -// for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). - -/// Exponential, base 2 -/// -/// Calculate `2^x`, that is, 2 raised to the power `x`. -#[export_name = "__l2math_exp2"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn exp2(mut x: Float64) -> Float64 { - let redux = Float64::from_bits(0x4338000000000000) / TBLSIZE as Float64; - let p1 = Float64::from_bits(0x3fe62e42fefa39ef); - let p2 = Float64::from_bits(0x3fcebfbdff82c575); - let p3 = Float64::from_bits(0x3fac6b08d704a0a6); - let p4 = Float64::from_bits(0x3f83b2ab88f70400); - let p5 = Float64::from_bits(0x3f55d88003875c74); - - // double_t r, t, z; - // uint32_t ix, i0; - // union {double f; uint64_t i;} u = {x}; - // union {uint32_t u; int32_t i;} k; - let x1p1023 = Float64::from_bits(0x7fe0000000000000); - let x1p52 = Float64::from_bits(0x4330000000000000); - let _0x1p_149 = Float64::from_bits(0xb6a0000000000000); - - /* Filter out exceptional cases. */ - let ui = Float64::to_bits(x); - let ix = ui >> 32 & 0x7fffffff; - if ix >= 0x408ff000 { - /* |x| >= 1022 or nan */ - if ix >= 0x40900000 && ui >> 63 == 0 { - /* x >= 1024 or nan */ - /* overflow */ - x *= x1p1023; - return x; - } - if ix >= 0x7ff00000 { - /* -inf or -nan */ - return -1.0 / x; - } - if ui >> 63 != 0 { - /* x <= -1022 */ - /* underflow */ - if x <= -1075.0 || x - x1p52 + x1p52 != x { - force_eval!((_0x1p_149 / x) as Float32); - } - if x <= -1075.0 { - return 0.0; - } - } - } else if ix < 0x3c900000 { - /* |x| < 0x1p-54 */ - return 1.0 + x; - } - - /* Reduce x, computing z, i0, and k. */ - let ui = Float64::to_bits(x + redux); - let mut i0 = ui as u32; - i0 = i0.wrapping_add(TBLSIZE as u32 / 2); - let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; - let ki = div!(ku as Int, TBLSIZE as Int); - i0 %= TBLSIZE as u32; - let uf = Float64::from_bits(ui) - redux; - let mut z = x - uf; - - /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ - let t = Float64::from_bits(i!(TBL, 2 * i0 as usize)); /* exp2t[i0] */ - z -= Float64::from_bits(i!(TBL, 2 * i0 as usize + 1)); /* eps[i0] */ - let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5)))); - - scalbn(r, ki) -} - -#[test] -fn i0_wrap_test() { - let x = -3.0 / 256.0; - assert_eq!(exp2(x), Float64::from_bits(0x3fefbdba3692d514)); -} diff --git a/helpers/l2math/core/exp2f.rs b/helpers/l2math/core/exp2f.rs deleted file mode 100644 index b37a4a6..0000000 --- a/helpers/l2math/core/exp2f.rs +++ /dev/null @@ -1,139 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c */ -// -// Copyright (c) 2005 David Schultz -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. -// - -use crate::{Float64, Float32}; - -const TBLSIZE: usize = 16; - -static EXP2FT: [u64; TBLSIZE] = [ - 0x3fe6a09e667f3bcd, - 0x3fe7a11473eb0187, - 0x3fe8ace5422aa0db, - 0x3fe9c49182a3f090, - 0x3feae89f995ad3ad, - 0x3fec199bdd85529c, - 0x3fed5818dcfba487, - 0x3feea4afa2a490da, - 0x3ff0000000000000, - 0x3ff0b5586cf9890f, - 0x3ff172b83c7d517b, - 0x3ff2387a6e756238, - 0x3ff306fe0a31b715, - 0x3ff3dea64c123422, - 0x3ff4bfdad5362a27, - 0x3ff5ab07dd485429, -]; - -// exp2f(x): compute the base 2 exponential of x -// -// Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. -// -// Method: (equally-spaced tables) -// -// Reduce x: -// x = k + y, for integer k and |y| <= 1/2. -// Thus we have exp2f(x) = 2**k * exp2(y). -// -// Reduce y: -// y = i/TBLSIZE + z for integer i near y * TBLSIZE. -// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), -// with |z| <= 2**-(TBLSIZE+1). -// -// We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a -// degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. -// Using double precision for everything except the reduction makes -// roundoff error insignificant and simplifies the scaling step. -// -// This method is due to Tang, but I do not use his suggested parameters: -// -// Tang, P. Table-driven Implementation of the Exponential Function -// in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). - -/// Exponential, base 2 -/// -/// Calculate `2^x`, that is, 2 raised to the power `x`. -#[export_name = "__l2math_exp2f"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn exp2f(mut x: Float32) -> Float32 { - let redux = Float32::from_bits(0x4b400000) / TBLSIZE as Float32; - let p1 = Float32::from_bits(0x3f317218); - let p2 = Float32::from_bits(0x3e75fdf0); - let p3 = Float32::from_bits(0x3d6359a4); - let p4 = Float32::from_bits(0x3c1d964e); - - // double_t t, r, z; - // uint32_t ix, i0, k; - - let x1p127 = Float32::from_bits(0x7f000000); - - /* Filter out exceptional cases. */ - let ui = Float32::to_bits(x); - let ix = ui & 0x7fffffff; - if ix > 0x42fc0000 { - /* |x| > 126 */ - if ix > 0x7f800000 { - /* NaN */ - return x; - } - if (0x43000000..0x80000000).contains(&ui) { - /* x >= 128 */ - x *= x1p127; - return x; - } - if ui >= 0x80000000 { - /* x < -126 */ - if ui >= 0xc3160000 || (ui & 0x0000ffff != 0) { - force_eval!(Float32::from_bits(0x80000001) / x); - } - if ui >= 0xc3160000 { - /* x <= -150 */ - return 0.0; - } - } - } else if ix <= 0x33000000 { - /* |x| <= 0x1p-25 */ - return 1.0 + x; - } - - /* Reduce x, computing z, i0, and k. */ - let ui = Float32::to_bits(x + redux); - let mut i0 = ui; - i0 += TBLSIZE as u32 / 2; - let k = i0 / TBLSIZE as u32; - let ukf = Float64::from_bits(((0x3ff + k) as u64) << 52); - i0 &= TBLSIZE as u32 - 1; - let mut uf = Float32::from_bits(ui); - uf -= redux; - let z: Float64 = (x - uf) as Float64; - /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ - let r: Float64 = Float64::from_bits(i!(EXP2FT, i0 as usize)); - let t: Float64 = r as Float64 * z; - let r: Float64 = r + t * (p1 as Float64 + z * p2 as Float64) + t * (z * z) * (p3 as Float64 + z * p4 as Float64); - - /* Scale by 2**k */ - (r * ukf) as Float32 -} diff --git a/helpers/l2math/core/expf.rs b/helpers/l2math/core/expf.rs deleted file mode 100644 index a4a4364..0000000 --- a/helpers/l2math/core/expf.rs +++ /dev/null @@ -1,106 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::{Float32, Int}; - -use super::scalbnf; - -consts!{ -const HALF: [Float32; 2] = [0.5, -0.5]; -const LN2_HI: Float32 = 6.9314575195e-01; /* 0x3f317200 */ -const LN2_LO: Float32 = 1.4286067653e-06; /* 0x35bfbe8e */ -const INV_LN2: Float32 = 1.4426950216e+00; /* 0x3fb8aa3b */ -/* - * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: - * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 - */ -const P1: Float32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ -const P2: Float32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ -} - -/// Exponential, base *e* -/// -/// Calculate the exponential of `x`, that is, *e* raised to the power `x` -/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). -#[export_name = "__l2math_expf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn expf(mut x: Float32) -> Float32 { - let x1p127 = Float32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = Float32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ - let mut hx = x.to_bits(); - let sign = (hx >> 31) as Int; /* sign bit of x */ - let signb: bool = sign != 0; - hx &= 0x7fffffff; /* high word of |x| */ - - /* special cases */ - if hx >= 0x42aeac50 { - /* if |x| >= -87.33655f or NaN */ - if hx > 0x7f800000 { - /* NaN */ - return x; - } - if (hx >= 0x42b17218) && (!signb) { - /* x >= 88.722839f */ - /* overflow */ - x *= x1p127; - return x; - } - if signb { - /* underflow */ - force_eval!(-x1p_126 / x); - if hx >= 0x42cff1b5 { - /* x <= -103.972084f */ - return 0.; - } - } - } - - /* argument reduction */ - let k: Int; - let hi: Float32; - let lo: Float32; - if hx > 0x3eb17218 { - /* if |x| > 0.5 ln2 */ - if hx > 0x3f851592 { - /* if |x| > 1.5 ln2 */ - k = (INV_LN2 * x + i!(HALF, sign as usize)) as Int; - } else { - k = 1 - sign - sign; - } - let kf = k as Float32; - hi = x - kf * LN2_HI; /* k*ln2hi is exact here */ - lo = kf * LN2_LO; - x = hi - lo; - } else if hx > 0x39000000 { - /* |x| > 2**-14 */ - k = 0; - hi = x; - lo = 0.; - } else { - /* raise inexact */ - force_eval!(x1p127 + x); - return 1. + x; - } - - /* x is now in primary range */ - let xx = x * x; - let c = x - xx * (P1 + xx * P2); - let y = 1. + (x * c / (2. - c) - lo + hi); - if k == 0 { - y - } else { - scalbnf(y, k) - } -} diff --git a/helpers/l2math/core/expm1.rs b/helpers/l2math/core/expm1.rs deleted file mode 100644 index 551e05e..0000000 --- a/helpers/l2math/core/expm1.rs +++ /dev/null @@ -1,147 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ - -use crate::{Float64, Int}; - -consts!{ -const O_THRESHOLD: Float64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ -const LN2_HI: Float64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ -const LN2_LO: Float64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ -const INVLN2: Float64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ -/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ -const Q1: Float64 = -3.33333333333331316428e-02; /* BFA11111 111110F4 */ -const Q2: Float64 = 1.58730158725481460165e-03; /* 3F5A01A0 19FE5585 */ -const Q3: Float64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ -const Q4: Float64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ -const Q5: Float64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ -} - -/// Exponential, base *e*, of x-1 -/// -/// Calculates the exponential of `x` and subtract 1, that is, *e* raised -/// to the power `x` minus 1 (where *e* is the base of the natural -/// system of logarithms, approximately 2.71828). -/// The result is accurate even for small values of `x`, -/// where using `exp(x)-1` would lose many significant digits. -#[export_name = "__l2math_expm1"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn expm1(mut x: Float64) -> Float64 { - let hi: Float64; - let lo: Float64; - let k: Int; - let c: Float64; - let mut t: Float64; - let mut y: Float64; - - let mut ui = x.to_bits(); - let hx = ((ui >> 32) & 0x7fffffff) as u32; - let sign = (ui >> 63) as Int; - - /* filter out huge and non-finite argument */ - if hx >= 0x4043687A { - /* if |x|>=56*ln2 */ - if x.is_nan() { - return x; - } - if sign != 0 { - return -1.0; - } - if x > O_THRESHOLD { - x *= Float64::from_bits(0x7fe0000000000000); - return x; - } - } - - /* argument reduction */ - if hx > 0x3fd62e42 { - /* if |x| > 0.5 ln2 */ - if hx < 0x3FF0A2B2 { - /* and |x| < 1.5 ln2 */ - if sign == 0 { - hi = x - LN2_HI; - lo = LN2_LO; - k = 1; - } else { - hi = x + LN2_HI; - lo = -LN2_LO; - k = -1; - } - } else { - k = (INVLN2 * x + if sign != 0 { -0.5 } else { 0.5 }) as Int; - t = k as Float64; - hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ - lo = t * LN2_LO; - } - x = hi - lo; - c = (hi - x) - lo; - } else if hx < 0x3c900000 { - /* |x| < 2**-54, return x */ - if hx < 0x00100000 { - force_eval!(x); - } - return x; - } else { - c = 0.0; - k = 0; - } - - /* x is now in primary range */ - let hfx = 0.5 * x; - let hxs = x * hfx; - let r1 = 1.0 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5)))); - t = 3.0 - r1 * hfx; - let mut e = hxs * ((r1 - t) / (6.0 - x * t)); - if k == 0 { - /* c is 0 */ - return x - (x * e - hxs); - } - e = x * (e - c) - c; - e -= hxs; - /* exp(x) ~ 2^k (x_reduced - e + 1) */ - if k == -1 { - return 0.5 * (x - e) - 0.5; - } - if k == 1 { - if x < -0.25 { - return -2.0 * (e - (x + 0.5)); - } - return 1.0 + 2.0 * (x - e); - } - ui = ((0x3ff + k) as u64) << 52; /* 2^k */ - let twopk = Float64::from_bits(ui); - if !(0..=56).contains(&k) { - /* suffice to return exp(x)-1 */ - y = x - e + 1.0; - if k == 1024 { - y = y * 2.0 * Float64::from_bits(0x7fe0000000000000); - } else { - y = y * twopk; - } - return y - 1.0; - } - ui = ((0x3ff - k) as u64) << 52; /* 2^-k */ - let uf = Float64::from_bits(ui); - if k < 20 { - y = (x - e + (1.0 - uf)) * twopk; - } else { - y = (x - (e + uf) + 1.0) * twopk; - } - y -} - -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::expm1(1.1), 2.0041660239464334); - } -} diff --git a/helpers/l2math/core/expm1f.rs b/helpers/l2math/core/expm1f.rs deleted file mode 100644 index 796a0a9..0000000 --- a/helpers/l2math/core/expm1f.rs +++ /dev/null @@ -1,139 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::{Float32, Int}; - -consts!{ -const O_THRESHOLD: Float32 = 8.8721679688e+01; /* 0x42b17180 */ -const LN2_HI: Float32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: Float32 = 9.0580006145e-06; /* 0x3717f7d1 */ -const INV_LN2: Float32 = 1.4426950216e+00; /* 0x3fb8aa3b */ -/* - * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: - * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 - * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): - */ -const Q1: Float32 = -3.3333212137e-2; /* -0x888868.0p-28 */ -const Q2: Float32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ -} - -/// Exponential, base *e*, of x-1 -/// -/// Calculates the exponential of `x` and subtract 1, that is, *e* raised -/// to the power `x` minus 1 (where *e* is the base of the natural -/// system of logarithms, approximately 2.71828). -/// The result is accurate even for small values of `x`, -/// where using `exp(x)-1` would lose many significant digits. -#[export_name = "__l2math_expm1f"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn expm1f(mut x: Float32) -> Float32 { - let x1p127 = Float32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - - let mut hx = x.to_bits(); - let sign = (hx >> 31) != 0; - hx &= 0x7fffffff; - - /* filter out huge and non-finite argument */ - if hx >= 0x4195b844 { - /* if |x|>=27*ln2 */ - if hx > 0x7f800000 { - /* NaN */ - return x; - } - if sign { - return -1.; - } - if x > O_THRESHOLD { - x *= x1p127; - return x; - } - } - - let k: Int; - let hi: Float32; - let lo: Float32; - let mut c = 0f32; - /* argument reduction */ - if hx > 0x3eb17218 { - /* if |x| > 0.5 ln2 */ - if hx < 0x3F851592 { - /* and |x| < 1.5 ln2 */ - if !sign { - hi = x - LN2_HI; - lo = LN2_LO; - k = 1; - } else { - hi = x + LN2_HI; - lo = -LN2_LO; - k = -1; - } - } else { - k = (INV_LN2 * x + (if sign { -0.5 } else { 0.5 })) as Int; - let t = k as Float32; - hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ - lo = t * LN2_LO; - } - x = hi - lo; - c = (hi - x) - lo; - } else if hx < 0x33000000 { - /* when |x|<2**-25, return x */ - if hx < 0x00800000 { - force_eval!(x * x); - } - return x; - } else { - k = 0; - } - - /* x is now in primary range */ - let hfx = 0.5 * x; - let hxs = x * hfx; - let r1 = 1. + hxs * (Q1 + hxs * Q2); - let t = 3. - r1 * hfx; - let mut e = hxs * ((r1 - t) / (6. - x * t)); - if k == 0 { - /* c is 0 */ - return x - (x * e - hxs); - } - e = x * (e - c) - c; - e -= hxs; - /* exp(x) ~ 2^k (x_reduced - e + 1) */ - if k == -1 { - return 0.5 * (x - e) - 0.5; - } - if k == 1 { - if x < -0.25 { - return -2. * (e - (x + 0.5)); - } - return 1. + 2. * (x - e); - } - let twopk = Float32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */ - if !(0..=56).contains(&k) { - /* suffice to return exp(x)-1 */ - let mut y = x - e + 1.; - if k == 128 { - y = y * 2. * x1p127; - } else { - y = y * twopk; - } - return y - 1.; - } - let uf = Float32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ - if k < 23 { - (x - e + (1. - uf)) * twopk - } else { - (x - (e + uf) + 1.) * twopk - } -} diff --git a/helpers/l2math/core/expo2.rs b/helpers/l2math/core/expo2.rs deleted file mode 100644 index e2e02f5..0000000 --- a/helpers/l2math/core/expo2.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::{Float64, Int}; - -use super::{combine_words, exp}; - -/// Exponential function, base 2 -/// -/// Calculate `e^x/2`. This is slightly more accurate than `0.5 * exp(x/2) * exp(x/2)`. -/// -/// Only for `x >= log(DBL_MAX)`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn expo2(x: Float64) -> Float64 { - /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ - const K: Int = 2043; - let kln2 = Float64::from_bits(0x40962066151add8b); - - /* note that k is odd and scale*scale overflows */ - let scale = combine_words(((0x3ff + K / 2) as u32) << 20, 0); - /* exp(x - k ln2) * 2**(k-1) */ - exp(x - kln2) * scale * scale -} diff --git a/helpers/l2math/core/fabs.rs b/helpers/l2math/core/fabs.rs deleted file mode 100644 index 6dc124c..0000000 --- a/helpers/l2math/core/fabs.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::Float64; - -/// Absolute value (magnitude) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[export_name = "__l2math_fabs"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn fabs(x: Float64) -> Float64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `Float64.abs` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::fabsf64(x) } - } - } - Float64::from_bits(x.to_bits() & (u64::MAX / 2)) -} - -#[cfg(test)] -mod tests { - use super::*; - use core::f64::*; - - #[test] - fn sanity_check() { - assert_eq!(fabs(-1.0), 1.0); - assert_eq!(fabs(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabs(NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabs(f), 0.0); - } - for f in [INFINITY, NEG_INFINITY].iter().copied() { - assert_eq!(fabs(f), INFINITY); - } - } -} diff --git a/helpers/l2math/core/fabsf.rs b/helpers/l2math/core/fabsf.rs deleted file mode 100644 index df352f1..0000000 --- a/helpers/l2math/core/fabsf.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::Float32; - -/// Absolute value (magnitude) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[export_name = "__l2math_fabsf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn fabsf(x: Float32) -> Float32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `Float32.abs` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::fabsf32(x) } - } - } - Float32::from_bits(x.to_bits() & 0x7fffffff) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - use core::f32::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf(-1.0), 1.0); - assert_eq!(fabsf(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf(NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf(f), 0.0); - } - for f in [INFINITY, NEG_INFINITY].iter().copied() { - assert_eq!(fabsf(f), INFINITY); - } - } -} diff --git a/helpers/l2math/core/fdim.rs b/helpers/l2math/core/fdim.rs deleted file mode 100644 index be8d270..0000000 --- a/helpers/l2math/core/fdim.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::Float64; - -#[allow(clippy::tabs_in_doc_comments)] -/// Positive difference -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[export_name = "__l2math_fdim"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn fdim(x: Float64, y: Float64) -> Float64 { - if x.is_nan() { - x - } else if y.is_nan() { - y - } else if x > y { - x - y - } else { - 0.0 - } -} diff --git a/helpers/l2math/core/fdimf.rs b/helpers/l2math/core/fdimf.rs deleted file mode 100644 index ba46798..0000000 --- a/helpers/l2math/core/fdimf.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::Float32; - -#[allow(clippy::tabs_in_doc_comments)] -/// Positive difference -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[export_name = "__l2math_fdimf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn fdimf(x: Float32, y: Float32) -> Float32 { - if x.is_nan() { - x - } else if y.is_nan() { - y - } else if x > y { - x - y - } else { - 0.0 - } -} diff --git a/helpers/l2math/core/fenv.rs b/helpers/l2math/core/fenv.rs deleted file mode 100644 index 3c74d68..0000000 --- a/helpers/l2math/core/fenv.rs +++ /dev/null @@ -1,28 +0,0 @@ -// src: musl/src/fenv/fenv.c -use crate::Int; -/* Dummy functions for archs lacking fenv implementation */ - -pub(crate) const FE_UNDERFLOW: Int = 0; -pub(crate) const FE_INEXACT: Int = 0; - -pub(crate) const FE_TONEAREST: Int = 0; - -#[inline] -pub(crate) fn feclearexcept(_mask: Int) -> Int { - 0 -} - -#[inline] -pub(crate) fn feraiseexcept(_mask: Int) -> Int { - 0 -} - -#[inline] -pub(crate) fn fetestexcept(_mask: Int) -> Int { - 0 -} - -#[inline] -pub(crate) fn fegetround() -> Int { - FE_TONEAREST -} diff --git a/helpers/l2math/core/floor.rs b/helpers/l2math/core/floor.rs deleted file mode 100644 index a41783a..0000000 --- a/helpers/l2math/core/floor.rs +++ /dev/null @@ -1,83 +0,0 @@ -#![allow(unreachable_code)] - -use crate::{Float64, Int}; - -const TOINT: Float64 = 1. / Float64::EPSILON; - -/// Floor -/// -/// Finds the nearest integer less than or equal to `x`. -#[export_name = "__l2math_floor"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn floor(x: Float64) -> Float64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `Float64.floor` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::floorf64(x) } - } - } - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - { - //use an alternative implementation on x86, because the - //main implementation fails with the x87 FPU used by - //debian i386, probablly due to excess precision issues. - //basic implementation taken from https://github.com/rust-lang/libm/issues/219 - use super::fabs; - if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as Float64; - if truncated > x { - return truncated - 1.0; - } else { - return truncated; - } - } else { - return x; - } - } - let ui = x.to_bits(); - let e = ((ui >> 52) & 0x7ff) as Int; - - if (e >= 0x3ff + 52) || (x == 0.) { - return x; - } - /* y = int(x) - x, where int(x) is an integer neighbor of x */ - let y = if (ui >> 63) != 0 { - x - TOINT + TOINT - x - } else { - x + TOINT - TOINT - x - }; - /* special case because of non-nearest rounding modes */ - if e < 0x3ff { - force_eval!(y); - return if (ui >> 63) != 0 { -1. } else { 0. }; - } - if y > 0. { - x + y - 1. - } else { - x + y - } -} - -#[cfg(test)] -mod tests { - use super::*; - use core::f64::*; - - #[test] - fn sanity_check() { - assert_eq!(floor(1.1), 1.0); - assert_eq!(floor(2.9), 2.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor - #[test] - fn spec_tests() { - // Not Asserted: that the current rounding mode has no effect. - assert!(floor(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { - assert_eq!(floor(f), f); - } - } -} diff --git a/helpers/l2math/core/floorf.rs b/helpers/l2math/core/floorf.rs deleted file mode 100644 index 2dd9b58..0000000 --- a/helpers/l2math/core/floorf.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::{Float32, Int}; - -/// Floor -/// -/// Finds the nearest integer less than or equal to `x`. -#[export_name = "__l2math_floorf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn floorf(x: Float32) -> Float32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `Float32.floor` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::floorf32(x) } - } - } - let mut ui = x.to_bits(); - let e = (((ui >> 23) as Int) & 0xff) - 0x7f; - - if e >= 23 { - return x; - } - if e >= 0 { - let m: u32 = 0x007fffff >> e; - if (ui & m) == 0 { - return x; - } - force_eval!(x + Float32::from_bits(0x7b800000)); - if ui >> 31 != 0 { - ui += m; - } - ui &= !m; - } else { - force_eval!(x + Float32::from_bits(0x7b800000)); - if ui >> 31 == 0 { - ui = 0; - } else if ui << 1 != 0 { - return -1.0; - } - } - Float32::from_bits(ui) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - use core::f32::*; - - #[test] - fn sanity_check() { - assert_eq!(floorf(0.5), 0.0); - assert_eq!(floorf(1.1), 1.0); - assert_eq!(floorf(2.9), 2.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor - #[test] - fn spec_tests() { - // Not Asserted: that the current rounding mode has no effect. - assert!(floorf(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { - assert_eq!(floorf(f), f); - } - } -} diff --git a/helpers/l2math/core/fma.rs b/helpers/l2math/core/fma.rs deleted file mode 100644 index b711a25..0000000 --- a/helpers/l2math/core/fma.rs +++ /dev/null @@ -1,233 +0,0 @@ -use crate::{Float64, Float32, Int}; - -use super::scalbn; - -const ZEROINFNAN: Int = 0x7ff - 0x3ff - 52 - 1; - -struct Num { - m: u64, - e: Int, - sign: Int, -} - -fn normalize(x: Float64) -> Num { - let x1p63: Float64 = Float64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 - - let mut ix: u64 = x.to_bits(); - let mut e: Int = (ix >> 52) as Int; - let sign: Int = e & 0x800; - e &= 0x7ff; - if e == 0 { - ix = (x * x1p63).to_bits(); - e = (ix >> 52) as Int & 0x7ff; - e = if e != 0 { e - 63 } else { 0x800 }; - } - ix &= (1 << 52) - 1; - ix |= 1 << 52; - ix <<= 1; - e -= 0x3ff + 52 + 1; - Num { m: ix, e, sign } -} - -#[inline] -fn mul(x: u64, y: u64) -> (u64, u64) { - let t = (x as u128).wrapping_mul(y as u128); - ((t >> 64) as u64, t as u64) -} - -/// Floating multiply add -/// -/// Computes `(x*y)+z`, rounded as one ternary operation: -/// Computes the value (as if) to infinite precision and rounds once to the result format, -/// according to the rounding mode characterized by the value of FLT_ROUNDS. -#[export_name = "__l2math_fma"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn fma(x: Float64, y: Float64, z: Float64) -> Float64 { - let x1p63: Float64 = Float64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 - let x0_ffffff8p_63 = Float64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 - - /* normalize so top 10bits and last bit are 0 */ - let nx = normalize(x); - let ny = normalize(y); - let nz = normalize(z); - - if nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN { - return x * y + z; - } - if nz.e >= ZEROINFNAN { - if nz.e > ZEROINFNAN { - /* z==0 */ - return x * y + z; - } - return z; - } - - /* mul: r = x*y */ - let zhi: u64; - let zlo: u64; - let (mut rhi, mut rlo) = mul(nx.m, ny.m); - /* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */ - - /* align exponents */ - let mut e: Int = nx.e + ny.e; - let mut d: Int = nz.e - e; - /* shift bits z<<=kz, r>>=kr, so kz+kr == d, set e = e+kr (== ez-kz) */ - if d > 0 { - if d < 64 { - zlo = nz.m << d; - zhi = nz.m >> (64 - d); - } else { - zlo = 0; - zhi = nz.m; - e = nz.e - 64; - d -= 64; - if d == 0 { - } else if d < 64 { - rlo = rhi << (64 - d) | rlo >> d | ((rlo << (64 - d)) != 0) as u64; - rhi = rhi >> d; - } else { - rlo = 1; - rhi = 0; - } - } - } else { - zhi = 0; - d = -d; - if d == 0 { - zlo = nz.m; - } else if d < 64 { - zlo = nz.m >> d | ((nz.m << (64 - d)) != 0) as u64; - } else { - zlo = 1; - } - } - - /* add */ - let mut sign: Int = nx.sign ^ ny.sign; - let samesign: bool = (sign ^ nz.sign) == 0; - let mut nonzero: Int = 1; - if samesign { - /* r += z */ - rlo = rlo.wrapping_add(zlo); - rhi += zhi + (rlo < zlo) as u64; - } else { - /* r -= z */ - let (res, borrow) = rlo.overflowing_sub(zlo); - rlo = res; - rhi = rhi.wrapping_sub(zhi.wrapping_add(borrow as u64)); - if (rhi >> 63) != 0 { - rlo = (rlo as i64).wrapping_neg() as u64; - rhi = (rhi as i64).wrapping_neg() as u64 - (rlo != 0) as u64; - sign = (sign == 0) as Int; - } - nonzero = (rhi != 0) as Int; - } - - /* set rhi to top 63bit of the result (last bit is sticky) */ - if nonzero != 0 { - e += 64; - d = rhi.leading_zeros() as Int - 1; - /* note: d > 0 */ - rhi = rhi << d | rlo >> (64 - d) | ((rlo << d) != 0) as u64; - } else if rlo != 0 { - d = rlo.leading_zeros() as Int - 1; - if d < 0 { - rhi = rlo >> 1 | (rlo & 1); - } else { - rhi = rlo << d; - } - } else { - /* exact +-0 */ - return x * y + z; - } - e -= d; - - /* convert to double */ - let mut i: i64 = rhi as i64; /* i is in [1<<62,(1<<63)-1] */ - if sign != 0 { - i = -i; - } - let mut r: Float64 = i as Float64; /* |r| is in [0x1p62,0x1p63] */ - - if e < -1022 - 62 { - /* result is subnormal before rounding */ - if e == -1022 - 63 { - let mut c: Float64 = x1p63; - if sign != 0 { - c = -c; - } - if r == c { - /* min normal after rounding, underflow depends - on arch behaviour which can be imitated by - a double to float conversion */ - let fltmin: Float32 = (x0_ffffff8p_63 * Float32::MIN_POSITIVE as Float64 * r) as Float32; - return Float64::MIN_POSITIVE / Float32::MIN_POSITIVE as Float64 * fltmin as Float64; - } - /* one bit is lost when scaled, add another top bit to - only round once at conversion if it is inexact */ - if (rhi << 53) != 0 { - i = (rhi >> 1 | (rhi & 1) | 1 << 62) as i64; - if sign != 0 { - i = -i; - } - r = i as Float64; - r = 2. * r - c; /* remove top bit */ - - /* raise underflow portably, such that it - cannot be optimized away */ - { - let tiny: Float64 = Float64::MIN_POSITIVE / Float32::MIN_POSITIVE as Float64 * r; - r += (tiny * tiny) * (r - r); - } - } - } else { - /* only round once when scaled */ - d = 10; - i = ((rhi >> d | ((rhi << (64 - d)) != 0) as u64) << d) as i64; - if sign != 0 { - i = -i; - } - r = i as Float64; - } - } - scalbn(r, e) -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn fma_segfault() { - // These two inputs cause fma to segfault on release due to overflow: - assert_eq!( - fma( - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313 - ), - -0.00000000000000022204460492503126, - ); - - let result = fma(-0.992, -0.992, -0.992); - //force rounding to storage format on x86 to prevent superious errors. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let result = force_eval!(result); - assert_eq!(result, -0.007936000000000007,); - } - - #[test] - fn fma_sbb() { - assert_eq!( - fma(-(1.0 - Float64::EPSILON), Float64::MIN, Float64::MIN), - -3991680619069439e277 - ); - } - - #[test] - fn fma_underflow() { - assert_eq!( - fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), - 0.0, - ); - } -} diff --git a/helpers/l2math/core/fmaf.rs b/helpers/l2math/core/fmaf.rs deleted file mode 100644 index 2d8aa3a..0000000 --- a/helpers/l2math/core/fmaf.rs +++ /dev/null @@ -1,114 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_fmaf.c */ -/*- - * Copyright (c) 2005-2011 David Schultz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. -*/ - -use crate::{Float64, Float32, Int}; - -use core::ptr::read_volatile; - -use super::fenv::{ - feclearexcept, fegetround, feraiseexcept, fetestexcept, FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, -}; - -/** - * Fused multiply-add: Compute x * y + z with a single rounding error. - * - * A double has more than twice as much precision than a float, so - * direct double-precision arithmetic suffices, except where double - * rounding occurs. -*/ - -/// Floating multiply add -/// -/// Computes `(x*y)+z`, rounded as one ternary operation: -/// Computes the value (as if) to infinite precision and rounds once to the result format, -/// according to the rounding mode characterized by the value of FLT_ROUNDS. -#[export_name = "__l2math_fmaf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn fmaf(x: Float32, y: Float32, mut z: Float32) -> Float32 { - let mut result: Float64; - let mut ui: u64; - let xy: Float64 = x as Float64 * y as Float64; - result = xy + z as Float64; - ui = result.to_bits(); - let e: Int = (ui >> 52) as Int & 0x7ff; - /* Common case: The double precision result is fine. */ - if ( - /* not a halfway case */ - ui & 0x1fffffff) != 0x10000000 || - /* NaN */ - e == 0x7ff || - /* exact */ - (result - xy == z as Float64 && result - z as Float64 == xy) || - /* not round-to-nearest */ - fegetround() != FE_TONEAREST - { - /* - underflow may not be raised correctly, example: - fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) - */ - if (0x3ff - 149..0x3ff - 126).contains(&e) && fetestexcept(FE_INEXACT) != 0 { - feclearexcept(FE_INEXACT); - // prevent `xy + vz` from being CSE'd with `xy + z` above - let vz: Float32 = unsafe { read_volatile(&z) }; - result = xy + vz as Float64; - if fetestexcept(FE_INEXACT) != 0 { - feraiseexcept(FE_UNDERFLOW); - } else { - feraiseexcept(FE_INEXACT); - } - } - z = result as Float32; - return z; - } - - // If result is inexact, and exactly halfway between two float values, - // we need to adjust the low-order bit in the direction of the error. - let neg = ui >> 63 != 0; - let err = if neg == (z as Float64 > xy) { - xy - result + z as Float64 - } else { - z as Float64 - result + xy - }; - if neg == (err < 0.0) { - ui += 1; - } else { - ui -= 1; - } - Float64::from_bits(ui) as Float32 -} - -#[cfg(test)] -mod tests { - #[test] - fn issue_263() { - let a = f32::from_bits(1266679807); - let b = f32::from_bits(1300234242); - let c = f32::from_bits(1115553792); - let expected = f32::from_bits(1501560833); - assert_eq!(super::fmaf(a, b, c), expected); - } -} diff --git a/helpers/l2math/core/fmax.rs b/helpers/l2math/core/fmax.rs deleted file mode 100644 index a5a43c6..0000000 --- a/helpers/l2math/core/fmax.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::Float64; - -/// Returns the maximum of the two arguments, signaling NaNs if either argument is a signaling NaN. -#[export_name = "__l2math_fmax"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn fmax(x: Float64, y: Float64) -> Float64 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if x.is_nan() || x < y { y } else { x }) * 1.0 -} diff --git a/helpers/l2math/core/fmaxf.rs b/helpers/l2math/core/fmaxf.rs deleted file mode 100644 index 5c94f21..0000000 --- a/helpers/l2math/core/fmaxf.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::Float32; - -/// Returns the maximum of the two arguments, signaling NaNs if either argument is a signaling NaN. -#[export_name = "__l2math_fmaxf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn fmaxf(x: Float32, y: Float32) -> Float32 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if x.is_nan() || x < y { y } else { x }) * 1.0 -} diff --git a/helpers/l2math/core/fmin.rs b/helpers/l2math/core/fmin.rs deleted file mode 100644 index 37753df..0000000 --- a/helpers/l2math/core/fmin.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::Float64; - -/// Returns the minimum of two numbers. -#[export_name = "__l2math_fmin"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn fmin(x: Float64, y: Float64) -> Float64 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if y.is_nan() || x < y { x } else { y }) * 1.0 -} diff --git a/helpers/l2math/core/fminf.rs b/helpers/l2math/core/fminf.rs deleted file mode 100644 index f8a0deb..0000000 --- a/helpers/l2math/core/fminf.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::Float32; - -/// Returns the minimum of two numbers. -#[export_name = "__l2math_fminf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn fminf(x: Float32, y: Float32) -> Float32 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if y.is_nan() || x < y { x } else { y }) * 1.0 -} diff --git a/helpers/l2math/core/fmod.rs b/helpers/l2math/core/fmod.rs deleted file mode 100644 index 0d81aed..0000000 --- a/helpers/l2math/core/fmod.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::Float64; - -/// Remainder of floating point division -/// -/// A.K.A. `modulus` or `modulo` in other languages. -/// -/// Computes the floating-point remainder of the division operation `x/y`. -#[export_name = "__l2math_fmod"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn fmod(x: Float64, y: Float64) -> Float64 { - let mut uxi = x.to_bits(); - let mut uyi = y.to_bits(); - let mut ex = (uxi >> 52 & 0x7ff) as i64; - let mut ey = (uyi >> 52 & 0x7ff) as i64; - let sx = uxi >> 63; - let mut i; - - if uyi << 1 == 0 || y.is_nan() || ex == 0x7ff { - return (x * y) / (x * y); - } - if uxi << 1 <= uyi << 1 { - if uxi << 1 == uyi << 1 { - return 0.0 * x; - } - return x; - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 12; - while i >> 63 == 0 { - ex -= 1; - i <<= 1; - } - uxi <<= -ex + 1; - } else { - uxi &= u64::MAX >> 12; - uxi |= 1 << 52; - } - if ey == 0 { - i = uyi << 12; - while i >> 63 == 0 { - ey -= 1; - i <<= 1; - } - uyi <<= -ey + 1; - } else { - uyi &= u64::MAX >> 12; - uyi |= 1 << 52; - } - - /* x mod y */ - while ex > ey { - i = uxi.wrapping_sub(uyi); - if i >> 63 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - uxi <<= 1; - ex -= 1; - } - i = uxi.wrapping_sub(uyi); - if i >> 63 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - while uxi >> 52 == 0 { - uxi <<= 1; - ex -= 1; - } - - /* scale result */ - if ex > 0 { - uxi -= 1 << 52; - uxi |= (ex as u64) << 52; - } else { - uxi >>= -ex + 1; - } - uxi |= sx << 63; - - Float64::from_bits(uxi) -} diff --git a/helpers/l2math/core/fmodf.rs b/helpers/l2math/core/fmodf.rs deleted file mode 100644 index 1eaebf9..0000000 --- a/helpers/l2math/core/fmodf.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::{Float32, Int}; - -/// Remainder of floating point division -/// -/// A.K.A. `modulus` or `modulo` in other languages. -/// -/// Computes the floating-point remainder of the division operation `x/y`. -#[export_name = "__l2math_fmodf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn fmodf(x: Float32, y: Float32) -> Float32 { - let mut uxi = x.to_bits(); - let mut uyi = y.to_bits(); - let mut ex = (uxi >> 23 & 0xff) as Int; - let mut ey = (uyi >> 23 & 0xff) as Int; - let sx = uxi & 0x80000000; - let mut i; - - if uyi << 1 == 0 || y.is_nan() || ex == 0xff { - return (x * y) / (x * y); - } - - if uxi << 1 <= uyi << 1 { - if uxi << 1 == uyi << 1 { - return 0.0 * x; - } - - return x; - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 9; - while i >> 31 == 0 { - ex -= 1; - i <<= 1; - } - - uxi <<= -ex + 1; - } else { - uxi &= u32::MAX >> 9; - uxi |= 1 << 23; - } - - if ey == 0 { - i = uyi << 9; - while i >> 31 == 0 { - ey -= 1; - i <<= 1; - } - - uyi <<= -ey + 1; - } else { - uyi &= u32::MAX >> 9; - uyi |= 1 << 23; - } - - /* x mod y */ - while ex > ey { - i = uxi.wrapping_sub(uyi); - if i >> 31 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - uxi <<= 1; - - ex -= 1; - } - - i = uxi.wrapping_sub(uyi); - if i >> 31 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - - while uxi >> 23 == 0 { - uxi <<= 1; - ex -= 1; - } - - /* scale result up */ - if ex > 0 { - uxi -= 1 << 23; - uxi |= (ex as u32) << 23; - } else { - uxi >>= -ex + 1; - } - uxi |= sx; - - Float32::from_bits(uxi) -} diff --git a/helpers/l2math/core/frexp.rs b/helpers/l2math/core/frexp.rs deleted file mode 100644 index 8e57160..0000000 --- a/helpers/l2math/core/frexp.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::{Float64, Int}; - -/// Breaks the number into a normalized fraction and a base-2 exponent -/// -/// Satisfying: -/// -/// * `x = f * 2^exp` -/// * `0.5 <= abs(f) < 1.0` -pub fn frexp(x: Float64) -> (Float64, Int) { - let mut y = x.to_bits(); - let ee = ((y >> 52) & 0x7ff) as Int; - - if ee == 0 { - if x != 0.0 { - let x1p64 = Float64::from_bits(0x43f0000000000000); - let (x, e) = frexp(x * x1p64); - return (x, e - 64); - } - return (x, 0); - } else if ee == 0x7ff { - return (x, 0); - } - - let e = ee - 0x3fe; - y &= 0x800fffffffffffff; - y |= 0x3fe0000000000000; - return (Float64::from_bits(y), e); -} - -/// FFI bindings for frexp -#[inline] -#[doc(hidden)] -#[export_name = "__l2math_frexp"] -pub extern "C" fn __l2math_frexp(x: Float64) -> super::Tuple_Float64_Int { - super::Tuple_Float64_Int::from(frexp(x)) -} diff --git a/helpers/l2math/core/frexpf.rs b/helpers/l2math/core/frexpf.rs deleted file mode 100644 index cd8df06..0000000 --- a/helpers/l2math/core/frexpf.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::{Float32, Int}; - -/// Breaks the number into a normalized fraction and a base-2 exponent -/// -/// Satisfying: -/// -/// * `x = f * 2^exp` -/// * `0.5 <= abs(f) < 1.0` -pub fn frexpf(x: Float32) -> (Float32, Int) { - let mut y = x.to_bits(); - let ee: Int = ((y >> 23) & 0xff) as Int; - - if ee == 0 { - if x != 0.0 { - let x1p64 = Float32::from_bits(0x5f800000); - let (x, e) = frexpf(x * x1p64); - return (x, e - 64); - } else { - return (x, 0); - } - } else if ee == 0xff { - return (x, 0); - } - - let e = ee - 0x7e; - y &= 0x807fffff; - y |= 0x3f000000; - (Float32::from_bits(y), e) -} - -/// FFI bindings for frexpf -#[inline] -#[doc(hidden)] -#[export_name = "__l2math_frexpf"] -pub extern "C" fn __l2math_frexpf(x: Float32) -> super::Tuple_Float32_Int { - super::Tuple_Float32_Int::from(frexpf(x)) -} diff --git a/helpers/l2math/core/hypot.rs b/helpers/l2math/core/hypot.rs deleted file mode 100644 index 0f96b6c..0000000 --- a/helpers/l2math/core/hypot.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::Float64; - -use super::sqrt; - -const SPLIT: Float64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 - -fn sq(x: Float64) -> (Float64, Float64) { - let xc = x * SPLIT; - let xh = x - xc + xc; - let xl = x - xh; - let hi = x * x; - let lo = xh * xh - hi + 2. * xh * xl + xl * xl; - (hi, lo) -} - -/// Calculate the length of the hypotenuse of a right-angle triangle given legs of length x and y. -#[export_name = "__l2math_hypot"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn hypot(mut x: Float64, mut y: Float64) -> Float64 { - let x1p700 = Float64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 - let x1p_700 = Float64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700 - - let mut uxi = x.to_bits(); - let mut uyi = y.to_bits(); - let uti; - let mut z: Float64; - - /* arrange |x| >= |y| */ - uxi &= -1i64 as u64 >> 1; - uyi &= -1i64 as u64 >> 1; - if uxi < uyi { - uti = uxi; - uxi = uyi; - uyi = uti; - } - - /* special cases */ - let ex: i64 = (uxi >> 52) as i64; - let ey: i64 = (uyi >> 52) as i64; - x = Float64::from_bits(uxi); - y = Float64::from_bits(uyi); - /* note: hypot(inf,nan) == inf */ - if ey == 0x7ff { - return y; - } - if ex == 0x7ff || uyi == 0 { - return x; - } - /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ - /* 64 difference is enough for ld80 double_t */ - if ex - ey > 64 { - return x + y; - } - - /* precise sqrt argument in nearest rounding mode without overflow */ - /* xh*xh must not overflow and xl*xl must not underflow in sq */ - z = 1.; - if ex > 0x3ff + 510 { - z = x1p700; - x *= x1p_700; - y *= x1p_700; - } else if ey < 0x3ff - 450 { - z = x1p_700; - x *= x1p700; - y *= x1p700; - } - let (hx, lx) = sq(x); - let (hy, ly) = sq(y); - z * sqrt(ly + lx + hy + hx) -} diff --git a/helpers/l2math/core/hypotf.rs b/helpers/l2math/core/hypotf.rs deleted file mode 100644 index 4fbe395..0000000 --- a/helpers/l2math/core/hypotf.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::{Float64, Float32}; - -const NEG_1_SHIFT_1R: u32 = 0x7FFFFFFF; - -use super::sqrtf; - -/// Calculate the length of the hypotenuse of a right-angle triangle given legs of length x and y. -#[export_name = "__l2math_hypotf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn hypotf(mut x: Float32, mut y: Float32) -> Float32 { - let x1p90 = Float32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 - let x1p_90 = Float32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90 - - let mut uxi = x.to_bits(); - let mut uyi = y.to_bits(); - let uti; - let mut z: Float32; - - uxi &= NEG_1_SHIFT_1R; - uyi &= NEG_1_SHIFT_1R; - if uxi < uyi { - uti = uxi; - uxi = uyi; - uyi = uti; - } - - x = Float32::from_bits(uxi); - y = Float32::from_bits(uyi); - if uyi == 0xff << 23 { - return y; - } - if uxi >= 0xff << 23 || uyi == 0 || uxi - uyi >= 25 << 23 { - return x + y; - } - - z = 1.; - if uxi >= (0x7f + 60) << 23 { - z = x1p90; - x *= x1p_90; - y *= x1p_90; - } else if uyi < (0x7f - 60) << 23 { - z = x1p_90; - x *= x1p90; - y *= x1p90; - } - z * sqrtf((x as Float64 * x as Float64 + y as Float64 * y as Float64) as Float32) -} diff --git a/helpers/l2math/core/ilogb.rs b/helpers/l2math/core/ilogb.rs deleted file mode 100644 index bfc482b..0000000 --- a/helpers/l2math/core/ilogb.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::{Float64, Int}; - -const FP_ILOGBNAN: Int = -1 - 0x7fffffff; -const FP_ILOGB0: Int = FP_ILOGBNAN; - -/// Get exponent of floating point value -#[export_name = "__l2math_ilogb"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -#[allow(clippy::zero_divided_by_zero)] -pub fn ilogb(x: Float64) -> Int { - let mut i: u64 = x.to_bits(); - let e = ((i >> 52) & 0x7ff) as Int; - - if e == 0 { - i <<= 12; - if i == 0 { - force_eval!(0.0 / 0.0); - return FP_ILOGB0; - } - /* subnormal x */ - let mut e = -0x3ff; - while (i >> 63) == 0 { - e -= 1; - i <<= 1; - } - e - } else if e == 0x7ff { - force_eval!(0.0 / 0.0); - if (i << 12) != 0 { - FP_ILOGBNAN - } else { - Int::max_value() - } - } else { - e - 0x3ff - } -} diff --git a/helpers/l2math/core/ilogbf.rs b/helpers/l2math/core/ilogbf.rs deleted file mode 100644 index 1276a6d..0000000 --- a/helpers/l2math/core/ilogbf.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::{Float32, Int}; - -const FP_ILOGBNAN: Int = -1 - 0x7fffffff; -const FP_ILOGB0: Int = FP_ILOGBNAN; - -/// Get exponent of floating point value -#[export_name = "__l2math_ilogbf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -#[allow(clippy::zero_divided_by_zero)] -pub fn ilogbf(x: Float32) -> Int { - let mut i = x.to_bits(); - let e = ((i >> 23) & 0xff) as Int; - - if e == 0 { - i <<= 9; - if i == 0 { - force_eval!(0.0 / 0.0); - return FP_ILOGB0; - } - /* subnormal x */ - let mut e = -0x7f; - while (i >> 31) == 0 { - e -= 1; - i <<= 1; - } - e - } else if e == 0xff { - force_eval!(0.0 / 0.0); - if (i << 9) != 0 { - FP_ILOGBNAN - } else { - Int::max_value() - } - } else { - e - 0x7f - } -} diff --git a/helpers/l2math/core/j0.rs b/helpers/l2math/core/j0.rs deleted file mode 100644 index 33e8c60..0000000 --- a/helpers/l2math/core/j0.rs +++ /dev/null @@ -1,434 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/** - * j0(x), y0(x) - * Bessel function of the first and second kinds of order zero. - * Method -- j0(x): - * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... - * 2. Reduce x to |x| since j0(x)=j0(-x), and - * for x in (0,2) - * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; - * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) - * for x in (2,inf) - * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) - * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) - * as follow: - * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) - * = 1/sqrt(2) * (cos(x) + sin(x)) - * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) - * = 1/sqrt(2) * (sin(x) - cos(x)) - * (To avoid cancellation, use - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - * to compute the worse one.) - * - * 3 Special cases - * j0(nan)= nan - * j0(0) = 1 - * j0(inf) = 0 - * - * Method -- y0(x): - * 1. For x<2. - * Since - * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) - * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. - * We use the following function to approximate y0, - * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 - * where - * U(z) = u00 + u01*z + ... + u06*z^6 - * V(z) = 1 + v01*z + ... + v04*z^4 - * with absolute approximation error bounded by 2**-72. - * Note: For tiny x, U/V = u0 and j0(x)~1, hence - * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) - * 2. For x>=2. - * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) - * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) - * by the method mentioned above. - * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. -*/ - -use crate::Float64; - -use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; - -consts!{ -const INVSQRTPI: Float64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -const TPI: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -} - -/* common method when |x|>=2 */ -fn common(ix: u32, x: Float64, y0: bool) -> Float64 { - let mut c: Float64; - let mut ss: Float64; - let mut cc: Float64; - let z: Float64; - - /* - * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) - * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) - * - * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) - * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - */ - let s = sin(x); - c = cos(x); - if y0 { - c = -c; - } - cc = s + c; - /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ - if ix < 0x7fe00000 { - ss = s - c; - z = -cos(2.0 * x); - if s * c < 0.0 { - cc = z / ss; - } else { - ss = z / cc; - } - if ix < 0x48000000 { - if y0 { - ss = -ss; - } - cc = pzero(x) * cc - qzero(x) * ss; - } - } - return INVSQRTPI * cc / sqrt(x); -} - -/* R0/S0 on [0, 2.00] */ -consts!{ -const R02: Float64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ -const R03: Float64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ -const R04: Float64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ -const R05: Float64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ -const S01: Float64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ -const S02: Float64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ -const S03: Float64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ -const S04: Float64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ -} - -/// Bessel function of the first kind of order zero -/// -/// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/j0.html) -#[export_name = "__l2math_j0"] -pub extern "C" fn j0(mut x: Float64) -> Float64 { - let z: Float64; - let r: Float64; - let s: Float64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - - /* j0(+-inf)=0, j0(nan)=nan */ - if ix >= 0x7ff00000 { - return 1.0 / (x * x); - } - x = fabs(x); - - if ix >= 0x40000000 { - /* |x| >= 2 */ - /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ - return common(ix, x, false); - } - - /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ - if ix >= 0x3f200000 { - /* |x| >= 2**-13 */ - /* up to 4ulp error close to 2 */ - z = x * x; - r = z * (R02 + z * (R03 + z * (R04 + z * R05))); - s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); - return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); - } - - /* 1 - x*x/4 */ - /* prevent underflow */ - /* inexact should be raised when x!=0, this is not done correctly */ - if ix >= 0x38000000 { - /* |x| >= 2**-127 */ - x = 0.25 * x * x; - } - return 1.0 - x; -} - -consts!{ -const U00: Float64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ -const U01: Float64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ -const U02: Float64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ -const U03: Float64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ -const U04: Float64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ -const U05: Float64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ -const U06: Float64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ -const V01: Float64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ -const V02: Float64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ -const V03: Float64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ -const V04: Float64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ -} - -/// Bessel function of the second kind of order zero -/// -/// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/y0.html) -#[export_name = "__l2math_y0"] -#[allow(clippy::zero_divided_by_zero)] -pub extern "C" fn y0(x: Float64) -> Float64 { - let z: Float64; - let u: Float64; - let v: Float64; - let ix = get_high_word(x); - let lx = get_low_word(x); - /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ - if ((ix << 1) | lx) == 0 { - return -1.0 / 0.0; - } - if (ix >> 31) != 0 { - return 0.0 / 0.0; - } - if ix >= 0x7ff00000 { - return 1.0 / x; - } - - if ix >= 0x40000000 { - /* x >= 2 */ - /* large ulp errors near zeros: 3.958, 7.086,.. */ - return common(ix, x, true); - } - - /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ - if ix >= 0x3e400000 { - /* x >= 2**-27 */ - /* large ulp error near the first zero, x ~= 0.89 */ - z = x * x; - u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); - v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); - return u / v + TPI * (j0(x) * log(x)); - } - return U00 + TPI * log(x); -} - -/* The asymptotic expansions of pzero is - * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. - * For x >= 2, We approximate pzero by - * pzero(x) = 1 + (R/S) - * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 - * S = 1 + pS0*s^2 + ... + pS4*s^10 - * and - * | pzero(x)-1-R/S | <= 2 ** ( -60.26) -*/ -consts!{ -const PR8: [Float64; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ - -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ - -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ - -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ - -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ -]; -const PS8: [Float64; 5] = [ - 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ - 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ - 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ - 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ - 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ -]; - -const PR5: [Float64; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ - -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ - -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ - -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ - -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ - -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ -]; -const PS5: [Float64; 5] = [ - 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ - 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ - 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ - 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ - 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ -]; - -const PR3: [Float64; 6] = [ - /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ - -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ - -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ - -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ - -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ - -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ -]; -const PS3: [Float64; 5] = [ - 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ - 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ - 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ - 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ - 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ -]; - -const PR2: [Float64; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ - -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ - -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ - -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ - -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ - -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ -]; -const PS2: [Float64; 5] = [ - 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ - 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ - 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ - 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ - 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ -]; -} - -fn pzero(x: Float64) -> Float64 { - let p: &[Float64; 6]; - let q: &[Float64; 5]; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 { - p = &PR8; - q = &PS8; - } else if ix >= 0x40122E8B { - p = &PR5; - q = &PS5; - } else if ix >= 0x4006DB6D { - p = &PR3; - q = &PS3; - } else - /*ix >= 0x40000000*/ - { - p = &PR2; - q = &PS2; - } - let z = 1.0 / (x * x); - let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); - return 1.0 + r / s; -} - -/* For x >= 8, the asymptotic expansions of qzero is - * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. - * We approximate pzero by - * qzero(x) = s*(-1.25 + (R/S)) - * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 - * S = 1 + qS0*s^2 + ... + qS5*s^12 - * and - * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) -*/ -consts!{ -const QR8: [Float64; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ - 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ - 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ - 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ - 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ -]; -const QS8: [Float64; 6] = [ - 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ - 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ - 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ - 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ - 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ - -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ -]; - -const QR5: [Float64; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ - 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ - 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ - 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ - 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ - 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ -]; -const QS5: [Float64; 6] = [ - 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ - 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ - 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ - 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ - 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ - -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ -]; - -const QR3: [Float64; 6] = [ - /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ - 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ - 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ - 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ - 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ - 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ -]; -const QS3: [Float64; 6] = [ - 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ - 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ - 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ - 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ - 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ - -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ -]; - -const QR2: [Float64; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ - 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ - 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ - 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ - 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ - 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ -]; -const QS2: [Float64; 6] = [ - 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ - 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ - 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ - 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ - 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ - -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ -]; -} - -fn qzero(x: Float64) -> Float64 { - let p: &[Float64; 6]; - let q: &[Float64; 6]; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 { - p = &QR8; - q = &QS8; - } else if ix >= 0x40122E8B { - p = &QR5; - q = &QS5; - } else if ix >= 0x4006DB6D { - p = &QR3; - q = &QS3; - } else - /*ix >= 0x40000000*/ - { - p = &QR2; - q = &QS2; - } - let z = 1.0 / (x * x); - let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); - return (-0.125 + r / s) / x; -} diff --git a/helpers/l2math/core/j0f.rs b/helpers/l2math/core/j0f.rs deleted file mode 100644 index 99a446a..0000000 --- a/helpers/l2math/core/j0f.rs +++ /dev/null @@ -1,362 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::Float32; - -use super::{cosf, fabsf, logf, sinf, sqrtf}; - -consts!{ -const INVSQRTPI: Float32 = 5.6418961287e-01; /* 0x3f106ebb */ -const TPI: Float32 = 6.3661974669e-01; /* 0x3f22f983 */ -} - -fn common(ix: u32, x: Float32, y0: bool) -> Float32 { - let z: Float32; - let mut c: Float32; - let mut ss: Float32; - let mut cc: Float32; - /* - * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) - * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) - */ - let s: Float32 = sinf(x); - c = cosf(x); - if y0 { - c = -c; - } - cc = s + c; - if ix < 0x7f000000 { - ss = s - c; - z = -cosf(2.0 * x); - if s * c < 0.0 { - cc = z / ss; - } else { - ss = z / cc; - } - if ix < 0x58800000 { - if y0 { - ss = -ss; - } - cc = pzerof(x) * cc - qzerof(x) * ss; - } - } - return INVSQRTPI * cc / sqrtf(x); -} - -/* R0/S0 on [0, 2.00] */ -consts!{ -const R02: Float32 = 1.5625000000e-02; /* 0x3c800000 */ -const R03: Float32 = -1.8997929874e-04; /* 0xb947352e */ -const R04: Float32 = 1.8295404516e-06; /* 0x35f58e88 */ -const R05: Float32 = -4.6183270541e-09; /* 0xb19eaf3c */ -const S01: Float32 = 1.5619102865e-02; /* 0x3c7fe744 */ -const S02: Float32 = 1.1692678527e-04; /* 0x38f53697 */ -const S03: Float32 = 5.1354652442e-07; /* 0x3509daa6 */ -const S04: Float32 = 1.1661400734e-09; /* 0x30a045e8 */ -} - -/// Bessel function of the first kind of order zero -/// -/// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/j0.html) -#[export_name = "__l2math_j0f"] -pub extern "C" fn j0f(mut x: Float32) -> Float32 { - let z: Float32; - let r: Float32; - let s: Float32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - return 1.0 / (x * x); - } - x = fabsf(x); - - if ix >= 0x40000000 { - /* |x| >= 2 */ - /* large ulp error near zeros */ - return common(ix, x, false); - } - if ix >= 0x3a000000 { - /* |x| >= 2**-11 */ - /* up to 4ulp error near 2 */ - z = x * x; - r = z * (R02 + z * (R03 + z * (R04 + z * R05))); - s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); - return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); - } - if ix >= 0x21800000 { - /* |x| >= 2**-60 */ - x = 0.25 * x * x; - } - return 1.0 - x; -} - -consts!{ -const U00: Float32 = -7.3804296553e-02; /* 0xbd9726b5 */ -const U01: Float32 = 1.7666645348e-01; /* 0x3e34e80d */ -const U02: Float32 = -1.3818567619e-02; /* 0xbc626746 */ -const U03: Float32 = 3.4745343146e-04; /* 0x39b62a69 */ -const U04: Float32 = -3.8140706238e-06; /* 0xb67ff53c */ -const U05: Float32 = 1.9559013964e-08; /* 0x32a802ba */ -const U06: Float32 = -3.9820518410e-11; /* 0xae2f21eb */ -const V01: Float32 = 1.2730483897e-02; /* 0x3c509385 */ -const V02: Float32 = 7.6006865129e-05; /* 0x389f65e0 */ -const V03: Float32 = 2.5915085189e-07; /* 0x348b216c */ -const V04: Float32 = 4.4111031494e-10; /* 0x2ff280c2 */ -} - -/// Bessel function of the second kind of order zero -/// -/// [CPP Reference](https://pubs.opengroup.org/onlinepubs/7908799/xsh/y0.html) -#[export_name = "__l2math_y0f"] -#[allow(clippy::zero_divided_by_zero)] -pub extern "C" fn y0f(x: Float32) -> Float32 { - let ix: u32 = x.to_bits(); - if (ix & 0x7fffffff) == 0 { - return -1.0 / 0.0; - } - if (ix >> 31) != 0 { - return 0.0 / 0.0; - } - if ix >= 0x7f800000 { - return 1.0 / x; - } - if ix >= 0x40000000 { - /* |x| >= 2.0 */ - /* large ulp error near zeros */ - return common(ix, x, true); - } - if ix >= 0x39000000 { - /* x >= 2**-13 */ - /* large ulp error at x ~= 0.89 */ - let z = x * x; - let u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); - let v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); - return u / v + TPI * (j0f(x) * logf(x)); - } - return U00 + TPI * logf(x); -} - -/* The asymptotic expansions of pzero is - * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. - * For x >= 2, We approximate pzero by - * pzero(x) = 1 + (R/S) - * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 - * S = 1 + pS0*s^2 + ... + pS4*s^10 - * and - * | pzero(x)-1-R/S | <= 2 ** ( -60.26) -*/ -consts!{ -const PR8: [Float32; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - -7.0312500000e-02, /* 0xbd900000 */ - -8.0816707611e+00, /* 0xc1014e86 */ - -2.5706311035e+02, /* 0xc3808814 */ - -2.4852163086e+03, /* 0xc51b5376 */ - -5.2530439453e+03, /* 0xc5a4285a */ -]; -const PS8: [Float32; 5] = [ - 1.1653436279e+02, /* 0x42e91198 */ - 3.8337448730e+03, /* 0x456f9beb */ - 4.0597855469e+04, /* 0x471e95db */ - 1.1675296875e+05, /* 0x47e4087c */ - 4.7627726562e+04, /* 0x473a0bba */ -]; -const PR5: [Float32; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -1.1412546255e-11, /* 0xad48c58a */ - -7.0312492549e-02, /* 0xbd8fffff */ - -4.1596107483e+00, /* 0xc0851b88 */ - -6.7674766541e+01, /* 0xc287597b */ - -3.3123129272e+02, /* 0xc3a59d9b */ - -3.4643338013e+02, /* 0xc3ad3779 */ -]; -const PS5: [Float32; 5] = [ - 6.0753936768e+01, /* 0x42730408 */ - 1.0512523193e+03, /* 0x44836813 */ - 5.9789707031e+03, /* 0x45bad7c4 */ - 9.6254453125e+03, /* 0x461665c8 */ - 2.4060581055e+03, /* 0x451660ee */ -]; - -const PR3: [Float32; 6] = [ - /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - -2.5470459075e-09, /* 0xb12f081b */ - -7.0311963558e-02, /* 0xbd8fffb8 */ - -2.4090321064e+00, /* 0xc01a2d95 */ - -2.1965976715e+01, /* 0xc1afba52 */ - -5.8079170227e+01, /* 0xc2685112 */ - -3.1447946548e+01, /* 0xc1fb9565 */ -]; -const PS3: [Float32; 5] = [ - 3.5856033325e+01, /* 0x420f6c94 */ - 3.6151397705e+02, /* 0x43b4c1ca */ - 1.1936077881e+03, /* 0x44953373 */ - 1.1279968262e+03, /* 0x448cffe6 */ - 1.7358093262e+02, /* 0x432d94b8 */ -]; - -const PR2: [Float32; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -8.8753431271e-08, /* 0xb3be98b7 */ - -7.0303097367e-02, /* 0xbd8ffb12 */ - -1.4507384300e+00, /* 0xbfb9b1cc */ - -7.6356959343e+00, /* 0xc0f4579f */ - -1.1193166733e+01, /* 0xc1331736 */ - -3.2336456776e+00, /* 0xc04ef40d */ -]; -const PS2: [Float32; 5] = [ - 2.2220300674e+01, /* 0x41b1c32d */ - 1.3620678711e+02, /* 0x430834f0 */ - 2.7047027588e+02, /* 0x43873c32 */ - 1.5387539673e+02, /* 0x4319e01a */ - 1.4657617569e+01, /* 0x416a859a */ -]; -} - -fn pzerof(x: Float32) -> Float32 { - let p: &[Float32; 6]; - let q: &[Float32; 5]; - let ix = x.to_bits() & 0x7fffffff; - if ix >= 0x41000000 { - p = &PR8; - q = &PS8; - } else if ix >= 0x409173eb { - p = &PR5; - q = &PS5; - } else if ix >= 0x4036d917 { - p = &PR3; - q = &PS3; - } else - /*ix >= 0x40000000*/ - { - p = &PR2; - q = &PS2; - } - let z = 1.0 / (x * x); - let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); - return 1.0 + r / s; -} - -/* For x >= 8, the asymptotic expansions of qzero is - * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. - * We approximate pzero by - * qzero(x) = s*(-1.25 + (R/S)) - * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 - * S = 1 + qS0*s^2 + ... + qS5*s^12 - * and - * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) -*/ -consts!{ -const QR8: [Float32; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - 7.3242187500e-02, /* 0x3d960000 */ - 1.1768206596e+01, /* 0x413c4a93 */ - 5.5767340088e+02, /* 0x440b6b19 */ - 8.8591972656e+03, /* 0x460a6cca */ - 3.7014625000e+04, /* 0x471096a0 */ -]; -const QS8: [Float32; 6] = [ - 1.6377603149e+02, /* 0x4323c6aa */ - 8.0983447266e+03, /* 0x45fd12c2 */ - 1.4253829688e+05, /* 0x480b3293 */ - 8.0330925000e+05, /* 0x49441ed4 */ - 8.4050156250e+05, /* 0x494d3359 */ - -3.4389928125e+05, /* 0xc8a7eb69 */ -]; - -const QR5: [Float32; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.8408595828e-11, /* 0x2da1ec79 */ - 7.3242180049e-02, /* 0x3d95ffff */ - 5.8356351852e+00, /* 0x40babd86 */ - 1.3511157227e+02, /* 0x43071c90 */ - 1.0272437744e+03, /* 0x448067cd */ - 1.9899779053e+03, /* 0x44f8bf4b */ -]; -const QS5: [Float32; 6] = [ - 8.2776611328e+01, /* 0x42a58da0 */ - 2.0778142090e+03, /* 0x4501dd07 */ - 1.8847289062e+04, /* 0x46933e94 */ - 5.6751113281e+04, /* 0x475daf1d */ - 3.5976753906e+04, /* 0x470c88c1 */ - -5.3543427734e+03, /* 0xc5a752be */ -]; - -const QR3: [Float32; 6] = [ - /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - 4.3774099900e-09, /* 0x3196681b */ - 7.3241114616e-02, /* 0x3d95ff70 */ - 3.3442313671e+00, /* 0x405607e3 */ - 4.2621845245e+01, /* 0x422a7cc5 */ - 1.7080809021e+02, /* 0x432acedf */ - 1.6673394775e+02, /* 0x4326bbe4 */ -]; -const QS3: [Float32; 6] = [ - 4.8758872986e+01, /* 0x42430916 */ - 7.0968920898e+02, /* 0x44316c1c */ - 3.7041481934e+03, /* 0x4567825f */ - 6.4604252930e+03, /* 0x45c9e367 */ - 2.5163337402e+03, /* 0x451d4557 */ - -1.4924745178e+02, /* 0xc3153f59 */ -]; - -const QR2: [Float32; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.5044444979e-07, /* 0x342189db */ - 7.3223426938e-02, /* 0x3d95f62a */ - 1.9981917143e+00, /* 0x3fffc4bf */ - 1.4495602608e+01, /* 0x4167edfd */ - 3.1666231155e+01, /* 0x41fd5471 */ - 1.6252708435e+01, /* 0x4182058c */ -]; -const QS2: [Float32; 6] = [ - 3.0365585327e+01, /* 0x41f2ecb8 */ - 2.6934811401e+02, /* 0x4386ac8f */ - 8.4478375244e+02, /* 0x44533229 */ - 8.8293585205e+02, /* 0x445cbbe5 */ - 2.1266638184e+02, /* 0x4354aa98 */ - -5.3109550476e+00, /* 0xc0a9f358 */ -]; -} - -fn qzerof(x: Float32) -> Float32 { - let p: &[Float32; 6]; - let q: &[Float32; 6]; - let ix = x.to_bits() & 0x7fffffff; - if ix >= 0x41000000 { - p = &QR8; - q = &QS8; - } else if ix >= 0x409173eb { - p = &QR5; - q = &QS5; - } else if ix >= 0x4036d917 { - p = &QR3; - q = &QS3; - } else - /*ix >= 0x40000000*/ - { - p = &QR2; - q = &QS2; - } - let z = 1.0 / (x * x); - let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); - return (-0.125 + r / s) / x; -} diff --git a/helpers/l2math/core/j1.rs b/helpers/l2math/core/j1.rs deleted file mode 100644 index db551ce..0000000 --- a/helpers/l2math/core/j1.rs +++ /dev/null @@ -1,407 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * j1(x), y1(x) - * Bessel function of the first and second kinds of order zero. - * Method -- j1(x): - * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... - * 2. Reduce x to |x| since j1(x)=-j1(-x), and - * for x in (0,2) - * j1(x) = x/2 + x*z*R0/S0, where z = x*x; - * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) - * for x in (2,inf) - * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) - * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) - * as follow: - * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) - * = 1/sqrt(2) * (sin(x) - cos(x)) - * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) - * = -1/sqrt(2) * (sin(x) + cos(x)) - * (To avoid cancellation, use - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - * to compute the worse one.) - * - * 3 Special cases - * j1(nan)= nan - * j1(0) = 0 - * j1(inf) = 0 - * - * Method -- y1(x): - * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN - * 2. For x<2. - * Since - * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) - * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. - * We use the following function to approximate y1, - * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 - * where for x in [0,2] (abs err less than 2**-65.89) - * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 - * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 - * Note: For tiny x, 1/x dominate y1 and hence - * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) - * 3. For x>=2. - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) - * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) - * by method mentioned above. -*/ - -use crate::Float64; - -use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; - -consts!{ -const INVSQRTPI: Float64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -const TPI: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -} - -fn common(ix: u32, x: Float64, y1: bool, sign: bool) -> Float64 { - /* - * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) - * - * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) - * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - */ - let mut s = sin(x); - if y1 { - s = -s; - } - let c = cos(x); - let mut cc = s - c; - if ix < 0x7fe00000 { - /* avoid overflow in 2*x */ - let mut ss = -s - c; - let z = cos(2.0 * x); - if s * c > 0.0 { - cc = z / ss; - } else { - ss = z / cc; - } - if ix < 0x48000000 { - if y1 { - ss = -ss; - } - cc = pone(x) * cc - qone(x) * ss; - } - } - if sign { - cc = -cc; - } - return INVSQRTPI * cc / sqrt(x); -} - -/* R0/S0 on [0,2] */ -consts!{ -const R00: Float64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ -const R01: Float64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ -const R02: Float64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ -const R03: Float64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ -const S01: Float64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ -const S02: Float64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ -const S03: Float64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ -const S04: Float64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ -const S05: Float64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ -} - -/// Bessel function of the first kind of order one -/// -/// Calculates the Bessel function of the first kind of order one of `x`. -#[export_name = "__l2math_j1"] -pub extern "C" fn j1(x: Float64) -> Float64 { - let mut z: Float64; - let r: Float64; - let s: Float64; - let mut ix = get_high_word(x); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - return 1.0 / (x * x); - } - if ix >= 0x40000000 { - /* |x| >= 2 */ - return common(ix, fabs(x), false, sign); - } - if ix >= 0x38000000 { - /* |x| >= 2**-127 */ - z = x * x; - r = z * (R00 + z * (R01 + z * (R02 + z * R03))); - s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); - z = r / s; - } else { - /* avoid underflow, raise inexact if x!=0 */ - z = x; - } - return (0.5 + z) * x; -} - -consts!{ -const U0: [Float64; 5] = [ - -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ - 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ - -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ - 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ - -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ -]; -const V0: [Float64; 5] = [ - 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ - 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ - 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ - 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ - 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ -]; -} - -/// Bessel function of the second kind of order one -/// -/// Calculates the Bessel function of the second kind of order one of `x`. -#[export_name = "__l2math_y1"] -#[allow(clippy::zero_divided_by_zero)] -pub extern "C" fn y1(x: Float64) -> Float64 { - let ix = get_high_word(x); - let lx = get_low_word(x); - - /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ - if (ix << 1 | lx) == 0 { - return -1.0 / 0.0; - } - if (ix >> 31) != 0 { - return 0.0 / 0.0; - } - if ix >= 0x7ff00000 { - return 1.0 / x; - } - - if ix >= 0x40000000 { - /* x >= 2 */ - return common(ix, x, true, false); - } - if ix < 0x3c900000 { - /* x < 2**-54 */ - return -TPI / x; - } - let z = x * x; - let u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); - let v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); - return x * (u / v) + TPI * (j1(x) * log(x) - 1.0 / x); -} - -/* For x >= 8, the asymptotic expansions of pone is - * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. - * We approximate pone by - * pone(x) = 1 + (R/S) - * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 - * S = 1 + ps0*s^2 + ... + ps4*s^10 - * and - * | pone(x)-1-R/S | <= 2 ** ( -60.06) -*/ -consts!{ -const PR8: [Float64; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ - 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ - 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ - 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ - 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ -]; -const PS8: [Float64; 5] = [ - 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ - 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ - 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ - 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ - 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ -]; - -const PR5: [Float64; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ - 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ - 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ - 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ - 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ - 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ -]; -const PS5: [Float64; 5] = [ - 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ - 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ - 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ - 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ - 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ -]; - -const PR3: [Float64; 6] = [ - 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ - 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ - 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ - 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ - 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ - 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ -]; -const PS3: [Float64; 5] = [ - 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ - 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ - 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ - 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ - 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ -]; - -const PR2: [Float64; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ - 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ - 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ - 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ - 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ - 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ -]; -const PS2: [Float64; 5] = [ - 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ - 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ - 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ - 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ - 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ -]; -} - -fn pone(x: Float64) -> Float64 { - let p: &[Float64; 6]; - let q: &[Float64; 5]; - let ix = get_high_word(x) & 0x7fffffff; - if ix >= 0x40200000 { - p = &PR8; - q = &PS8; - } else if ix >= 0x40122E8B { - p = &PR5; - q = &PS5; - } else if ix >= 0x4006DB6D { - p = &PR3; - q = &PS3; - } else - /*ix >= 0x40000000*/ - { - p = &PR2; - q = &PS2; - } - let z = 1.0 / (x * x); - let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); - return 1.0 + r / s; -} - -/* For x >= 8, the asymptotic expansions of qone is - * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. - * We approximate pone by - * qone(x) = s*(0.375 + (R/S)) - * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 - * S = 1 + qs1*s^2 + ... + qs6*s^12 - * and - * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) -*/ -consts!{ -const QR8: [Float64; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ - -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ - -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ - -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ - -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ -]; -const QS8: [Float64; 6] = [ - 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ - 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ - 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ - 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ - 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ - -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ -]; - -const QR5: [Float64; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ - -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ - -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ - -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ - -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ - -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ -]; -const QS5: [Float64; 6] = [ - 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ - 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ - 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ - 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ - 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ - -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ -]; - -const QR3: [Float64; 6] = [ - -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ - -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ - -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ - -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ - -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ - -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ -]; -const QS3: [Float64; 6] = [ - 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ - 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ - 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ - 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ - 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ - -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ -]; - -const QR2: [Float64; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ - -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ - -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ - -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ - -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ - -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ -]; -const QS2: [Float64; 6] = [ - 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ - 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ - 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ - 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ - 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ - -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ -]; -} - -fn qone(x: Float64) -> Float64 { - let p: &[Float64; 6]; - let q: &[Float64; 6]; - let ix = get_high_word(x) & 0x7fffffff; - if ix >= 0x40200000 { - p = &QR8; - q = &QS8; - } else if ix >= 0x40122E8B { - p = &QR5; - q = &QS5; - } else if ix >= 0x4006DB6D { - p = &QR3; - q = &QS3; - } else - /*ix >= 0x40000000*/ - { - p = &QR2; - q = &QS2; - } - let z = 1.0 / (x * x); - let r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - let s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); - return (0.375 + r / s) / x; -} diff --git a/helpers/l2math/core/j1f.rs b/helpers/l2math/core/j1f.rs deleted file mode 100644 index 6e10b2c..0000000 --- a/helpers/l2math/core/j1f.rs +++ /dev/null @@ -1,382 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::{Float64, Float32}; - -use super::{cosf, fabsf, logf, sinf, sqrtf}; - -consts!{ -const INVSQRTPI: Float32 = 5.6418961287e-01; /* 0x3f106ebb */ -const TPI: Float32 = 6.3661974669e-01; /* 0x3f22f983 */ -} - -fn common(ix: u32, x: Float32, y1: bool, sign: bool) -> Float32 { - let mut s = sinf(x) as Float64; - if y1 { - s = -s; - } - let c = cosf(x) as Float64; - let mut cc = s - c; - if ix < 0x7f000000 { - let mut ss = -s - c; - let z = cosf(2.0 * x) as Float64; - if s * c > 0.0 { - cc = z / ss; - } else { - ss = z / cc; - } - if ix < 0x58800000 { - if y1 { - ss = -ss; - } - cc = (ponef(x) as Float64) * cc - (qonef(x) as Float64) * ss; - } - } - if sign { - cc = -cc; - } - return (((INVSQRTPI as Float64) * cc) / (sqrtf(x) as Float64)) as Float32; -} - -/* R0/S0 on [0,2] */ -consts!{ -const R00: Float32 = -6.2500000000e-02; /* 0xbd800000 */ -const R01: Float32 = 1.4070566976e-03; /* 0x3ab86cfd */ -const R02: Float32 = -1.5995563444e-05; /* 0xb7862e36 */ -const R03: Float32 = 4.9672799207e-08; /* 0x335557d2 */ -const S01: Float32 = 1.9153760746e-02; /* 0x3c9ce859 */ -const S02: Float32 = 1.8594678841e-04; /* 0x3942fab6 */ -const S03: Float32 = 1.1771846857e-06; /* 0x359dffc2 */ -const S04: Float32 = 5.0463624390e-09; /* 0x31ad6446 */ -const S05: Float32 = 1.2354227016e-11; /* 0x2d59567e */ -} - -/// Bessel function of the first kind of order one -/// -/// Calculates the Bessel function of the first kind of order one of `x`. -#[export_name = "__l2math_j1f"] -pub extern "C" fn j1f(x: Float32) -> Float32 { - let mut z: Float32; - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - return 1.0 / (x * x); - } - if ix >= 0x40000000 { - /* |x| >= 2 */ - return common(ix, fabsf(x), false, sign); - } - if ix >= 0x39000000 { - /* |x| >= 2**-13 */ - z = x * x; - let r = z * (R00 + z * (R01 + z * (R02 + z * R03))); - let s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); - z = 0.5 + r / s; - } else { - z = 0.5; - } - return z * x; -} - -consts!{ -const U0: [Float32; 5] = [ - -1.9605709612e-01, /* 0xbe48c331 */ - 5.0443872809e-02, /* 0x3d4e9e3c */ - -1.9125689287e-03, /* 0xbafaaf2a */ - 2.3525259166e-05, /* 0x37c5581c */ - -9.1909917899e-08, /* 0xb3c56003 */ -]; -const V0: [Float32; 5] = [ - 1.9916731864e-02, /* 0x3ca3286a */ - 2.0255257550e-04, /* 0x3954644b */ - 1.3560879779e-06, /* 0x35b602d4 */ - 6.2274145840e-09, /* 0x31d5f8eb */ - 1.6655924903e-11, /* 0x2d9281cf */ -]; -} - -/// Bessel function of the second kind of order one -/// -/// Calculates the Bessel function of the second kind of order one of `x`. -#[export_name = "__l2math_y1f"] -#[allow(clippy::zero_divided_by_zero)] -pub extern "C" fn y1f(x: Float32) -> Float32 { - let ix = x.to_bits(); - if (ix & 0x7fffffff) == 0 { - return -1.0 / 0.0; - } - if (ix >> 31) != 0 { - return 0.0 / 0.0; - } - if ix >= 0x7f800000 { - return 1.0 / x; - } - if ix >= 0x40000000 { - /* |x| >= 2.0 */ - return common(ix, x, true, false); - } - if ix < 0x33000000 { - /* x < 2**-25 */ - return -TPI / x; - } - let z = x * x; - let u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); - let v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); - return x * (u / v) + TPI * (j1f(x) * logf(x) - 1.0 / x); -} - -/** - * For x >= 8, the asymptotic expansions of pone is - * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. - * We approximate pone by - * pone(x) = 1 + (R/S) - * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 - * S = 1 + ps0*s^2 + ... + ps4*s^10 - * and - * | pone(x)-1-R/S | <= 2 ** ( -60.06) -*/ -const PR8: [Float32; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - 1.171_875e-1, /* 0x3df00000 */ - 1.323_948_1e1, /* 0x4153d4ea */ - 4.120_518_5e2, /* 0x43ce06a3 */ - 3.874_745_4e3, /* 0x45722bed */ - 7.914_479_5e3, /* 0x45f753d6 */ -]; -const PS8: [Float32; 5] = [ - 1.142_073_7e2, /* 0x42e46a2c */ - 3.650_931e3, /* 0x45642ee5 */ - 3.695_620_7e4, /* 0x47105c35 */ - 9.760_28e4, /* 0x47bea166 */ - 3.080_427_1e4, /* 0x46f0a88b */ -]; - -const PR5: [Float32; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.319_905_2e-11, /* 0x2d68333f */ - 1.171_874_9e-1, /* 0x3defffff */ - 6.802_751, /* 0x40d9b023 */ - 1.083_081_8e2, /* 0x42d89dca */ - 5.176_361_7e2, /* 0x440168b7 */ - 5.287_152e2, /* 0x44042dc6 */ -]; -const PS5: [Float32; 5] = [ - 5.928_059_8e1, /* 0x426d1f55 */ - 9.914_014e2, /* 0x4477d9b1 */ - 5.353_267e3, /* 0x45a74a23 */ - 7.844_690_4e3, /* 0x45f52586 */ - 1.504_046_9e3, /* 0x44bc0180 */ -]; - -const PR3: [Float32; 6] = [ - 3.025_039e-9, /* 0x314fe10d */ - 1.171_868_7e-1, /* 0x3defffab */ - 3.932_977_4, /* 0x407bb5e7 */ - 3.511_940_4e1, /* 0x420c7a45 */ - 9.105_501e1, /* 0x42b61c2a */ - 4.855_906_7e1, /* 0x42423c7c */ -]; -const PS3: [Float32; 5] = [ - 3.479_131e1, /* 0x420b2a4d */ - 3.367_624_5e2, /* 0x43a86198 */ - 1.046_871_5e3, /* 0x4482dbe3 */ - 8.908_113_4e2, /* 0x445eb3ed */ - 1.037_879_3e2, /* 0x42cf936c */ -]; - -const PR2: [Float32; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.077_108_3e-7, /* 0x33e74ea8 */ - 1.171_762_2e-1, /* 0x3deffa16 */ - 2.368_515, /* 0x401795c0 */ - 1.224_261_1e1, /* 0x4143e1bc */ - 1.769_397_2e1, /* 0x418d8d41 */ - 5.073_523, /* 0x40a25a4d */ -]; -const PS2: [Float32; 5] = [ - 2.143_648_5e1, /* 0x41ab7dec */ - 1.252_902_3e2, /* 0x42fa9499 */ - 2.322_764_7e2, /* 0x436846c7 */ - 1.176_793_75e2, /* 0x42eb5bd7 */ - 8.364_639, /* 0x4105d590 */ -]; - -fn ponef(x: Float32) -> Float32 { - let p: &[Float32; 6]; - let q: &[Float32; 5]; - - - - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 { - p = &PR8; - q = &PS8; - } else if ix >= 0x409173eb { - p = &PR5; - q = &PS5; - } else if ix >= 0x4036d917 { - p = &PR3; - q = &PS3; - } else - /*ix >= 0x40000000*/ - { - p = &PR2; - q = &PS2; - } - let z: Float32 = 1.0 / (x * x); - let r: Float32 = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - let s: Float32 = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); - return 1.0 + r / s; -} - -/** - * For x >= 8, the asymptotic expansions of qone is - * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. - * We approximate pone by - * qone(x) = s*(0.375 + (R/S)) - * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 - * S = 1 + qs1*s^2 + ... + qs6*s^12 - * and - * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) -*/ - -const QR8: [Float32; 6] = [ - /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - -1.025_390_6e-1, /* 0xbdd20000 */ - -1.627_175_3e1, /* 0xc1822c8d */ - -7.596_017_5e2, /* 0xc43de683 */ - -1.184_980_7e4, /* 0xc639273a */ - -4.843_851e4, /* 0xc73d3683 */ -]; -const QS8: [Float32; 6] = [ - 1.613_953_7e2, /* 0x43216537 */ - 7.825_386e3, /* 0x45f48b17 */ - 1.338_753_4e5, /* 0x4802bcd6 */ - 7.196_577_5e5, /* 0x492fb29c */ - 6.666_012_5e5, /* 0x4922be94 */ - -2.944_902_5e5, /* 0xc88fcb48 */ -]; - -const QR5: [Float32; 6] = [ - /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -2.089_799_3e-11, /* 0xadb7d219 */ - -1.025_390_5e-1, /* 0xbdd1fffe */ - -8.056_448, /* 0xc100e736 */ - -1.836_696e2, /* 0xc337ab6b */ - -1.373_193_7e3, /* 0xc4aba633 */ - -2.612_444_3e3, /* 0xc523471c */ -]; -const QS5: [Float32; 6] = [ - 8.127_655e1, /* 0x42a28d98 */ - 1.991_798_7e3, /* 0x44f8f98f */ - 1.746_848_4e4, /* 0x468878f8 */ - 4.985_142_6e4, /* 0x4742bb6d */ - 2.794_807_4e4, /* 0x46da5826 */ - -4.719_183_6e3, /* 0xc5937978 */ -]; - -const QR3: [Float32; 6] = [ - -5.078_312_4e-9, /* 0xb1ae7d4f */ - -1.025_378_3e-1, /* 0xbdd1ff5b */ - -4.610_116, /* 0xc0938612 */ - -5.784_722e1, /* 0xc267638e */ - -2.282_445_4e2, /* 0xc3643e9a */ - -2.192_101_3e2, /* 0xc35b35cb */ -]; -const QS3: [Float32; 6] = [ - 4.766_515_4e1, /* 0x423ea91e */ - 6.738_651e2, /* 0x4428775e */ - 3.380_152_8e3, /* 0x45534272 */ - 5.547_729e3, /* 0x45ad5dd5 */ - 1.903_119_1e3, /* 0x44ede3d0 */ - -1.352_011_9e2, /* 0xc3073381 */ -]; - -const QR2: [Float32; 6] = [ - /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -1.783_817_3e-7, /* 0xb43f8932 */ - -1.025_170_46e-1, /* 0xbdd1f475 */ - -2.752_205_6, /* 0xc0302423 */ - -1.966_361_6e1, /* 0xc19d4f16 */ - -4.232_531_4e1, /* 0xc2294d1f */ - -2.137_192_2e1, /* 0xc1aaf9b2 */ -]; -const QS2: [Float32; 6] = [ - 2.953_336_3e1, /* 0x41ec4454 */ - 2.529_815_5e2, /* 0x437cfb47 */ - 7.575_028e2, /* 0x443d602e */ - 7.393_932e2, /* 0x4438d92a */ - 1.559_49e2, /* 0x431bf2f2 */ - -4.959_499, /* 0xc09eb437 */ -]; - -fn qonef(x: Float32) -> Float32 { - let p: &[Float32; 6]; - let q: &[Float32; 6]; - - - - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 { - p = &QR8; - q = &QS8; - } else if ix >= 0x409173eb { - p = &QR5; - q = &QS5; - } else if ix >= 0x4036d917 { - p = &QR3; - q = &QS3; - } else - /*ix >= 0x40000000*/ - { - p = &QR2; - q = &QS2; - } - let z: Float32 = 1.0 / (x * x); - let r: Float32 = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); - let s: Float32 = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); - return (0.375 + r / s) / x; -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::{j1f, y1f}; - #[test] - fn test_j1f_2488() { - // 0x401F3E49 - assert_eq!(j1f(2.4881766_f32), 0.49999475_f32); - } - #[test] - fn test_y1f_2002() { - //allow slightly different result on x87 - let res = y1f(2.0000002_f32); - if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && (res == -0.10703231_f32) - { - return; - } - assert_eq!(res, -0.10703229_f32); - } -} diff --git a/helpers/l2math/core/jn.rs b/helpers/l2math/core/jn.rs deleted file mode 100644 index 7c2e431..0000000 --- a/helpers/l2math/core/jn.rs +++ /dev/null @@ -1,351 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * jn(n, x), yn(n, x) - * floating point Bessel's function of the 1st and 2nd kind - * of order n - * - * Special cases: - * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; - * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. - * Note 2. About jn(n,x), yn(n,x) - * For n=0, j0(x) is called, - * for n=1, j1(x) is called, - * for n<=x, forward recursion is used starting - * from values of j0(x) and j1(x). - * for n>x, a continued fraction approximation to - * j(n,x)/j(n-1,x) is evaluated and then backward - * recursion is used starting from a supposed value - * for j(n,x). The resulting value of j(0,x) is - * compared with the actual value to correct the - * supposed value of j(n,x). - * - * yn(n,x) is similar in all respects, except - * that forward recursion is used for all - * values of n>1. -*/ - -use crate::{Float64, Int}; - -use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, y1}; - -consts!{ -const INVSQRTPI: Float64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -} - -/// Bessel function of the first kind of order zero of `x`. -/// -/// Calculates the Bessel function of the first kind of order zero of `x`. -#[export_name = "__l2math_jn"] -pub extern "C" fn jn(n: Int, mut x: Float64) -> Float64 { - let mut ix = get_high_word(x); - let lx = get_low_word(x); - let nm1: Int; - let mut i: Int; - let mut sign: bool; - let mut a: Float64; - let mut b: Float64; - let mut temp: Float64; - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - // -lx == !lx + 1 - if (ix | (lx | ((!lx).wrapping_add(1))) >> 31) > 0x7ff00000 { - /* nan */ - return x; - } - - /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) - * Thus, J(-n,x) = J(n,-x) - */ - /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ - if n == 0 { - return j0(x); - } - if n < 0 { - nm1 = -(n + 1); - x = -x; - sign = !sign; - } else { - nm1 = n - 1; - } - if nm1 == 0 { - return j1(x); - } - - sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ - x = fabs(x); - if (ix | lx) == 0 || ix == 0x7ff00000 { - /* if x is 0 or inf */ - b = 0.0; - } else if (nm1 as Float64) < x { - /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ - if ix >= 0x52d00000 { - /* x > 2**302 */ - /* (x >> n**2) - * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Let s=sin(x), c=cos(x), - * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then - * - * n sin(xn)*sqt2 cos(xn)*sqt2 - * ---------------------------------- - * 0 s-c c+s - * 1 -s-c -c+s - * 2 -s+c -c-s - * 3 s+c c-s - */ - temp = match nm1 & 3 { - 0 => -cos(x) + sin(x), - 1 => -cos(x) - sin(x), - 2 => cos(x) - sin(x), - _ => cos(x) + sin(x), - }; - b = INVSQRTPI * temp / sqrt(x); - } else { - a = j0(x); - b = j1(x); - i = 0; - while i < nm1 { - i += 1; - temp = b; - b = b * (2.0 * (i as Float64) / x) - a; /* avoid underflow */ - a = temp; - } - } - } else if ix < 0x3e100000 { - /* x < 2**-29 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 32 { - /* underflow */ - b = 0.0; - } else { - temp = x * 0.5; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as Float64; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } - } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: Float64; - let mut q0: Float64; - let mut q1: Float64; - let mut w: Float64; - - let mut z: Float64; - let mut tmp: Float64; - - - let mut k: Int; - - let nf: Float64 = (nm1 as Float64) + 1.0; - w = 2.0 * nf / x; - let h: Float64 = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e9 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as Float64) + nf) / x - t); - i -= 1; - } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf * log(fabs(w)); - if tmp < 7.097_827_128_933_84e2 { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as Float64)) / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as Float64)) / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p500 = Float64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 - if b > x1p500 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; - } - } - z = j0(x); - w = j1(x); - if fabs(z) >= fabs(w) { - b = t * z / b; - } else { - b = t * w / a; - } - } - - if sign { - -b - } else { - b - } -} - -/// Bessel function of the second kind of order zero of `x`. -/// -/// Calculates the Bessel function of the second kind of order zero of `x`. -#[export_name = "__l2math_yn"] -#[allow(clippy::zero_divided_by_zero)] -pub extern "C" fn yn(n: Int, x: Float64) -> Float64 { - let mut ix: u32; - - let mut ib: u32; - let nm1: Int; - let mut sign: bool; - let mut i: Int; - let mut a: Float64; - let mut b: Float64; - let mut temp: Float64; - - ix = get_high_word(x); - let lx: u32 = get_low_word(x); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - // -lx == !lx + 1 - if (ix | (lx | ((!lx).wrapping_add(1))) >> 31) > 0x7ff00000 { - /* nan */ - return x; - } - if sign && (ix | lx) != 0 { - /* x < 0 */ - return 0.0 / 0.0; - } - if ix == 0x7ff00000 { - return 0.0; - } - - if n == 0 { - return y0(x); - } - if n < 0 { - nm1 = -(n + 1); - sign = (n & 1) != 0; - } else { - nm1 = n - 1; - sign = false; - } - if nm1 == 0 { - if sign { - return -y1(x); - } else { - return y1(x); - } - } - - if ix >= 0x52d00000 { - /* x > 2**302 */ - /* (x >> n**2) - * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Let s=sin(x), c=cos(x), - * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then - * - * n sin(xn)*sqt2 cos(xn)*sqt2 - * ---------------------------------- - * 0 s-c c+s - * 1 -s-c -c+s - * 2 -s+c -c-s - * 3 s+c c-s - */ - temp = match nm1 & 3 { - 0 => -sin(x) - cos(x), - 1 => -sin(x) + cos(x), - 2 => sin(x) + cos(x), - _ => sin(x) - cos(x), - }; - b = INVSQRTPI * temp / sqrt(x); - } else { - a = y0(x); - b = y1(x); - /* quit if b is -inf */ - ib = get_high_word(b); - i = 0; - while i < nm1 && ib != 0xfff00000 { - i += 1; - temp = b; - b = (2.0 * (i as Float64) / x) * b - a; - ib = get_high_word(b); - a = temp; - } - } - - if sign { - -b - } else { - b - } -} diff --git a/helpers/l2math/core/jnf.rs b/helpers/l2math/core/jnf.rs deleted file mode 100644 index aa6d5dd..0000000 --- a/helpers/l2math/core/jnf.rs +++ /dev/null @@ -1,265 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::{Float32, Int}; - -use super::{fabsf, j0f, j1f, logf, y0f, y1f}; - -/// Bessel function of the first kind of order zero -/// -/// Calculates the Bessel function of the first kind of order zero of `x`. -#[export_name = "__l2math_jnf"] -pub extern "C" fn jnf(n: Int, mut x: Float32) -> Float32 { - let mut ix: u32; - let mut nm1: Int; - let mut sign: bool; - let mut i: Int; - let mut a: Float32; - let mut b: Float32; - let mut temp: Float32; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix > 0x7f800000 { - /* nan */ - return x; - } - - /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ - if n == 0 { - return j0f(x); - } - if n < 0 { - nm1 = -(n + 1); - x = -x; - sign = !sign; - } else { - nm1 = n - 1; - } - if nm1 == 0 { - return j1f(x); - } - - sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ - x = fabsf(x); - if ix == 0 || ix == 0x7f800000 { - /* if x is 0 or inf */ - b = 0.0; - } else if (nm1 as Float32) < x { - /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ - a = j0f(x); - b = j1f(x); - i = 0; - while i < nm1 { - i += 1; - temp = b; - b = b * (2.0 * (i as Float32) / x) - a; - a = temp; - } - } else if ix < 0x35800000 { - // x < 2**-20 - //x is tiny, return the first Taylor expansion of J(n,x) - // J(n,x) = 1/n!*(x/2)^n - ... - if nm1 > 8 { - /* underflow */ - nm1 = 8; - } - temp = 0.5 * x; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as Float32; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } else { - // use backward recurrence - // x x^2 x^2 - // J(n,x)/J(n-1,x) = ---- ------ ------ ..... - // 2n - 2(n+1) - 2(n+2) - // - // 1 1 1 - // (for large x) = ---- ------ ------ ..... - // 2n 2(n+1) 2(n+2) - // -- - ------ - ------ - - // x x x - // - // Let w = 2n/x and h=2/x, then the above quotient - // is equal to the continued fraction: - // 1 - // = ----------------------- - // 1 - // w - ----------------- - // 1 - // w+h - --------- - // w+2h - ... - // - // To determine how many terms needed, let - // Q(0) = w, Q(1) = w(w+h) - 1, - // Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - // When Q(k) > 1e4 good for single - // When Q(k) > 1e9 good for double - // When Q(k) > 1e17 good for quadruple - /* determine k */ - let mut t: Float32; - let mut q0: Float32; - let mut q1: Float32; - let mut w: Float32; - - let mut z: Float32; - let mut tmp: Float32; - - let mut k: Int; - - let nf: Float32 = (nm1 as Float32) + 1.0; - w = 2.0 * (nf as Float32) / x; - let h: Float32 = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e4 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as Float32) + nf) / x - t); - i -= 1; - } - a = t; - b = 1.0; - // estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - // Hence, if n*(log(2n/x)) > ... - // single 8.8722839355e+01 - // double 7.09782712893383973096e+02 - // long double 1.1356523406294143949491931077970765006170e+04 - // then recurrent value may overflow and the result is - // likely underflow to zero - tmp = nf * logf(fabsf(w)); - if tmp < 88.721_68 { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as Float32) * b / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as Float32) * b / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p60 = Float32::from_bits(0x5d800000); // 0x1p60 == 2^60 - if b > x1p60 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; - } - } - z = j0f(x); - w = j1f(x); - if fabsf(z) >= fabsf(w) { - b = t * z / b; - } else { - b = t * w / a; - } - } - - if sign { - -b - } else { - b - } -} - -/// Bessel function of the second kind of order zero -/// -/// Calculates the Bessel function of the second kind of order zero of `x`. -#[export_name = "__l2math_ynf"] -#[allow(clippy::zero_divided_by_zero)] -pub extern "C" fn ynf(n: Int, x: Float32) -> Float32 { - let mut ix: u32; - let mut ib: u32; - let nm1: Int; - let mut sign: bool; - let mut i: Int; - let mut a: Float32; - let mut b: Float32; - let mut temp: Float32; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - if ix > 0x7f800000 { - /* nan */ - return x; - } - if sign && ix != 0 { - /* x < 0 */ - return 0.0 / 0.0; - } - if ix == 0x7f800000 { - return 0.0; - } - - if n == 0 { - return y0f(x); - } - if n < 0 { - nm1 = -(n + 1); - sign = (n & 1) != 0; - } else { - nm1 = n - 1; - sign = false; - } - if nm1 == 0 { - if sign { - return -y1f(x); - } else { - return y1f(x); - } - } - - a = y0f(x); - b = y1f(x); - /* quit if b is -inf */ - ib = b.to_bits(); - i = 0; - while i < nm1 && ib != 0xff800000 { - i += 1; - temp = b; - b = (2.0 * (i as Float32) / x) * b - a; - ib = b.to_bits(); - a = temp; - } - - if sign { - -b - } else { - b - } -} diff --git a/helpers/l2math/core/k_cos.rs b/helpers/l2math/core/k_cos.rs deleted file mode 100644 index 9cf6506..0000000 --- a/helpers/l2math/core/k_cos.rs +++ /dev/null @@ -1,66 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/k_cos.c -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunSoft, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -use crate::Float64; - -consts!{ -const C1: Float64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ -const C2: Float64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ -const C3: Float64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ -const C4: Float64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ -const C5: Float64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ -const C6: Float64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ -} - -// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 -// Input x is assumed to be bounded by ~pi/4 in magnitude. -// Input y is the tail of x. -// -// Algorithm -// 1. Since cos(-x) = cos(x), we need only to consider positive x. -// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. -// 3. cos(x) is approximated by a polynomial of degree 14 on -// [0,pi/4] -// 4 14 -// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x -// where the remez error is -// -// | 2 4 6 8 10 12 14 | -58 -// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 -// | | -// -// 4 6 8 10 12 14 -// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then -// cos(x) ~ 1 - x*x/2 + r -// since cos(x+y) ~ cos(x) - sin(x)*y -// ~ cos(x) - x*y, -// a correction term is necessary in cos(x) and hence -// cos(x+y) = 1 - (x*x/2 - (r - x*y)) -// For better accuracy, rearrange to -// cos(x+y) ~ w + (tmp + (r-x*y)) -// where w = 1 - x*x/2 and tmp is a tiny correction term -// (1 - x*x/2 == w + tmp exactly in infinite precision). -// The exactness of w + tmp in infinite precision depends on w -// and tmp having the same precision as x. If they have extra -// precision due to compiler bugs, then the extra precision is -// only good provided it is retained in all terms of the final -// expression for cos(). Retention happens in all cases tested -// under FreeBSD, so don't pessimize things by forcibly clipping -// any extra precision in w. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_cos(x: Float64, y: Float64) -> Float64 { - let z = x * x; - let w = z * z; - let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); - let hz = 0.5 * z; - let w = 1.0 - hz; - w + (((1.0 - w) - hz) + (z * r - x * y)) -} diff --git a/helpers/l2math/core/k_cosf.rs b/helpers/l2math/core/k_cosf.rs deleted file mode 100644 index b8a7680..0000000 --- a/helpers/l2math/core/k_cosf.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Debugged and optimized by Bruce D. Evans. -*/ - -use crate::{Float64, Float32}; - -/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ -consts!{ -const C0: Float64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ -const C1: Float64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ -const C2: Float64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ -const C3: Float64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_cosf(x: Float64) -> Float32 { - let z = x * x; - let w = z * z; - let r = C2 + z * C3; - (((1.0 + z * C0) + w * C1) + (w * z) * r) as Float32 -} diff --git a/helpers/l2math/core/k_expo2.rs b/helpers/l2math/core/k_expo2.rs deleted file mode 100644 index 4b90004..0000000 --- a/helpers/l2math/core/k_expo2.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::{Float64, Int}; - -use super::exp; - -/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ -const K: Int = 2043; - -/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_expo2(x: Float64) -> Float64 { - let k_ln2 = Float64::from_bits(0x40962066151add8b); - /* note that k is odd and scale*scale overflows */ - let scale = Float64::from_bits(((((0x3ff + K / 2) as u32) << 20) as u64) << 32); - /* exp(x - k ln2) * 2**(k-1) */ - exp(x - k_ln2) * scale * scale -} diff --git a/helpers/l2math/core/k_expo2f.rs b/helpers/l2math/core/k_expo2f.rs deleted file mode 100644 index 360b4dd..0000000 --- a/helpers/l2math/core/k_expo2f.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::{Float32, Int}; - -use super::expf; - -/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ -const K: Int = 235; - -/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_expo2f(x: Float32) -> Float32 { - let k_ln2 = Float32::from_bits(0x4322e3bc); - /* note that k is odd and scale*scale overflows */ - let scale = Float32::from_bits(((0x7f + K / 2) as u32) << 23); - /* exp(x - k ln2) * 2**(k-1) */ - expf(x - k_ln2) * scale * scale -} diff --git a/helpers/l2math/core/k_sin.rs b/helpers/l2math/core/k_sin.rs deleted file mode 100644 index 0f6d8bb..0000000 --- a/helpers/l2math/core/k_sin.rs +++ /dev/null @@ -1,61 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/k_sin.c -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunSoft, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -use crate::{Float64, Int}; - -consts!{ -const S1: Float64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ -const S2: Float64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ -const S3: Float64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ -const S4: Float64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ -const S5: Float64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ -const S6: Float64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ -} - -// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 -// Input x is assumed to be bounded by ~pi/4 in magnitude. -// Input y is the tail of x. -// Input iy indicates whether y is 0. (if iy=0, y assume to be 0). -// -// Algorithm -// 1. Since sin(-x) = -sin(x), we need only to consider positive x. -// 2. Callers must return sin(-0) = -0 without calling here since our -// odd polynomial is not evaluated in a way that preserves -0. -// Callers may do the optimization sin(x) ~ x for tiny x. -// 3. sin(x) is approximated by a polynomial of degree 13 on -// [0,pi/4] -// 3 13 -// sin(x) ~ x + S1*x + ... + S6*x -// where -// -// |sin(x) 2 4 6 8 10 12 | -58 -// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 -// | x | -// -// 4. sin(x+y) = sin(x) + sin'(x')*y -// ~ sin(x) + (1-x*x/2)*y -// For better accuracy, let -// 3 2 2 2 2 -// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) -// then 3 2 -// sin(x) = x + (S1*x + (x *(r-y/2)+y)) -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_sin(x: Float64, y: Float64, iy: Int) -> Float64 { - let z = x * x; - let w = z * z; - let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); - let v = z * x; - if iy == 0 { - x + v * (S1 + z * r) - } else { - x - ((z * (0.5 * y - v * r) - y) - v * S1) - } -} diff --git a/helpers/l2math/core/k_sinf.rs b/helpers/l2math/core/k_sinf.rs deleted file mode 100644 index 22a80fb..0000000 --- a/helpers/l2math/core/k_sinf.rs +++ /dev/null @@ -1,34 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. -*/ - -use crate::{Float64, Float32}; - -/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ -consts!{ -const S1: Float64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ -const S2: Float64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ -const S3: Float64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ -const S4: Float64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_sinf(x: Float64) -> Float32 { - let z = x * x; - let w = z * z; - let r = S3 + z * S4; - let s = z * x; - ((x + s * (S1 + z * S2)) + s * w * r) as Float32 -} diff --git a/helpers/l2math/core/k_tan.rs b/helpers/l2math/core/k_tan.rs deleted file mode 100644 index e0a1fa8..0000000 --- a/helpers/l2math/core/k_tan.rs +++ /dev/null @@ -1,110 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ -// -// ==================================================== -// Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. -// -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -use crate::{Float64, Int}; - -// kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 -// Input x is assumed to be bounded by ~pi/4 in magnitude. -// Input y is the tail of x. -// Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. -// -// Algorithm -// 1. Since tan(-x) = -tan(x), we need only to consider positive x. -// 2. Callers must return tan(-0) = -0 without calling here since our -// odd polynomial is not evaluated in a way that preserves -0. -// Callers may do the optimization tan(x) ~ x for tiny x. -// 3. tan(x) is approximated by a odd polynomial of degree 27 on -// [0,0.67434] -// 3 27 -// tan(x) ~ x + T1*x + ... + T13*x -// where -// -// |tan(x) 2 4 26 | -59.2 -// |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 -// | x | -// -// Note: tan(x+y) = tan(x) + tan'(x)*y -// ~ tan(x) + (1+x*x)*y -// Therefore, for better accuracy in computing tan(x+y), let -// 3 2 2 2 2 -// r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) -// then -// 3 2 -// tan(x+y) = x + (T1*x + (x *(r+y)+y)) -// -// 4. For x in [0.67434,pi/4], let y = pi/4 - x, then -// tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) -// = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) -#[allow(clippy::excessive_precision)] -static T: [Float64; 13] = [ - 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ - 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ - 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ - 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ - 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ - 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ - 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ - 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ - 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ - 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ - 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ - -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ - 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ -]; -consts!{ -const PIO4: Float64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ -const PIO4_LO: Float64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_tan(mut x: Float64, mut y: Float64, odd: Int) -> Float64 { - let hx = (Float64::to_bits(x) >> 32) as u32; - let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ - if big { - let sign = hx >> 31; - if sign != 0 { - x = -x; - y = -y; - } - x = (PIO4 - x) + (PIO4_LO - y); - y = 0.0; - } - let z = x * x; - let w = z * z; - /* - * Break x^5*(T[1]+x^2*T[2]+...) into - * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + - * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) - */ - let r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11])))); - let v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12]))))); - let s = z * x; - let r = y + z * (s * (r + v) + y) + s * T[0]; - let w = x + r; - if big { - let sign = hx >> 31; - let s = 1.0 - 2.0 * odd as Float64; - let v = s - 2.0 * (x + (r - w * w / (w + s))); - return if sign != 0 { -v } else { v }; - } - if odd == 0 { - return w; - } - /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ - let w0 = zero_low_word(w); - let v = r - (w0 - x); /* w0+v = r+x */ - let a = -1.0 / w; - let a0 = zero_low_word(a); - a0 + a * (1.0 + a0 * w0 + a0 * v) -} - -fn zero_low_word(x: Float64) -> Float64 { - Float64::from_bits(Float64::to_bits(x) & 0xFFFF_FFFF_0000_0000) -} diff --git a/helpers/l2math/core/k_tanf.rs b/helpers/l2math/core/k_tanf.rs deleted file mode 100644 index e441a42..0000000 --- a/helpers/l2math/core/k_tanf.rs +++ /dev/null @@ -1,50 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ -/** - * ==================================================== - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. - * - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ - -use crate::{Float64, Float32}; - -/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ -consts!{ -const T: [Float64; 6] = [ - 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ - 0.133392002712976742718, /* 0x1112fd38999f72.0p-55 */ - 0.0533812378445670393523, /* 0x1b54c91d865afe.0p-57 */ - 0.0245283181166547278873, /* 0x191df3908c33ce.0p-58 */ - 0.00297435743359967304927, /* 0x185dadfcecf44e.0p-61 */ - 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ -]; -} - -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn k_tanf(x: Float64, odd: bool) -> Float32 { - let z = x * x; - /* - * Split up the polynomial into small independent terms to give - * opportunities for parallel evaluation. The chosen splitting is - * micro-optimized for Athlons (XP, X64). It costs 2 multiplications - * relative to Horner's method on sequential machines. - * - * We add the small terms from lowest degree up for efficiency on - * non-sequential machines (the lowest degree terms tend to be ready - * earlier). Apart from this, we don't care about order of - * operations, and don't need to to care since we have precision to - * spare. However, the chosen splitting is good for accuracy too, - * and would give results as accurate as Horner's method if the - * small terms were added from highest degree down. - */ - let mut r = T[4] + z * T[5]; - let t = T[2] + z * T[3]; - let w = z * z; - let s = z * x; - let u = T[0] + z * T[1]; - r = (x + s * u) + (s * w) * (t + w * r); - (if odd { -1. / r } else { r }) as Float32 -} diff --git a/helpers/l2math/core/ldexp.rs b/helpers/l2math/core/ldexp.rs deleted file mode 100644 index 0ebe297..0000000 --- a/helpers/l2math/core/ldexp.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::{Float64, Int}; - -/// Returns `x` * 2`n`. -#[inline] -#[export_name = "__l2math_ldexp"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn ldexp(x: Float64, n: Int) -> Float64 { - super::scalbn(x, n) -} diff --git a/helpers/l2math/core/ldexpf.rs b/helpers/l2math/core/ldexpf.rs deleted file mode 100644 index 56e5649..0000000 --- a/helpers/l2math/core/ldexpf.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::{Float32, Int}; - -/// Returns `x` * 2`n`. -#[inline] -#[export_name = "__l2math_ldexpf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf(x: Float32, n: Int) -> Float32 { - super::scalbnf(x, n) -} diff --git a/helpers/l2math/core/lgamma.rs b/helpers/l2math/core/lgamma.rs deleted file mode 100644 index abf2ea5..0000000 --- a/helpers/l2math/core/lgamma.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::Float64; - -use super::lgamma_r; - -/// Natural logarithm of gamma function -/// -/// Returns the natural logarithm of the absolute value of the gamma function of x. -#[inline] -#[export_name = "__l2math_lgamma"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn lgamma(x: Float64) -> Float64 { - lgamma_r(x).0 -} diff --git a/helpers/l2math/core/lgamma_r.rs b/helpers/l2math/core/lgamma_r.rs deleted file mode 100644 index 53ff464..0000000 --- a/helpers/l2math/core/lgamma_r.rs +++ /dev/null @@ -1,337 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - * -*/ -/** - * lgamma_r(x, signgamp) - * Reentrant version of the logarithm of the Gamma function - * with user provide pointer for the sign of Gamma(x). - * - * Method: - * 1. Argument Reduction for 0 < x <= 8 - * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may - * reduce x to a number in [1.5,2.5] by - * lgamma(1+s) = log(s) + lgamma(s) - * for example, - * lgamma(7.3) = log(6.3) + lgamma(6.3) - * = log(6.3*5.3) + lgamma(5.3) - * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) - * 2. Polynomial approximation of lgamma around its - * minimun ymin=1.461632144968362245 to maintain monotonicity. - * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use - * Let z = x-ymin; - * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) - * where - * poly(z) is a 14 degree polynomial. - * 2. Rational approximation in the primary interval [2,3] - * We use the following approximation: - * s = x-2.0; - * lgamma(x) = 0.5*s + s*P(s)/Q(s) - * with accuracy - * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 - * Our algorithms are based on the following observation - * - * zeta(2)-1 2 zeta(3)-1 3 - * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... - * 2 3 - * - * where Euler = 0.5771... is the Euler constant, which is very - * close to 0.5. - * - * 3. For x>=8, we have - * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... - * (better formula: - * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) - * Let z = 1/x, then we approximation - * f(z) = lgamma(x) - (x-0.5)(log(x)-1) - * by - * 3 5 11 - * w = w0 + w1*z + w2*z + w3*z + ... + w6*z - * where - * |w - f(z)| < 2**-58.74 - * - * 4. For negative x, since (G is gamma function) - * -x*G(-x)*G(x) = PI/sin(PI*x), - * we have - * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) - * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 - * Hence, for x<0, signgam = sign(sin(PI*x)) and - * lgamma(x) = log(|Gamma(x)|) - * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); - * Note: one should avoid compute PI*(-x) directly in the - * computation of sin(PI*(-x)). - * - * 5. Special Cases - * lgamma(2+s) ~ s*(1-Euler) for tiny s - * lgamma(1) = lgamma(2) = 0 - * lgamma(x) ~ -log(|x|) for tiny x - * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero - * lgamma(inf) = inf - * lgamma(-inf) = inf (bug for bug compatible with C99!?) - * -*/ - -use crate::{Float64, Int}; - -use super::{floor, k_cos, k_sin, log}; - -consts!{ -const PI: Float64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ -const A0: Float64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ -const A1: Float64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ -const A2: Float64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ -const A3: Float64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ -const A4: Float64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ -const A5: Float64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ -const A6: Float64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ -const A7: Float64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ -const A8: Float64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ -const A9: Float64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ -const A10: Float64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ -const A11: Float64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ -const TC: Float64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ -const TF: Float64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ -/* tt = -(tail of TF) */ -const TT: Float64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ -const T0: Float64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ -const T1: Float64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ -const T2: Float64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ -const T3: Float64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ -const T4: Float64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ -const T5: Float64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ -const T6: Float64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ -const T7: Float64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ -const T8: Float64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ -const T9: Float64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ -const T10: Float64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ -const T11: Float64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ -const T12: Float64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ -const T13: Float64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ -const T14: Float64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ -const U0: Float64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const U1: Float64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ -const U2: Float64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ -const U3: Float64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ -const U4: Float64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ -const U5: Float64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ -const V1: Float64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ -const V2: Float64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ -const V3: Float64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ -const V4: Float64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ -const V5: Float64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ -const S0: Float64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const S1: Float64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ -const S2: Float64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ -const S3: Float64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ -const S4: Float64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ -const S5: Float64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ -const S6: Float64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ -const R1: Float64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ -const R2: Float64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ -const R3: Float64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ -const R4: Float64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ -const R5: Float64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ -const R6: Float64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ -const W0: Float64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ -const W1: Float64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ -const W2: Float64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ -const W3: Float64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ -const W4: Float64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ -const W5: Float64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ -const W6: Float64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ -} - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: Float64) -> Float64 { - let mut n: Int; - - /* spurious inexact if odd int */ - x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ - - n = (x * 4.0) as Int; - n = div!(n + 1, 2); - x -= (n as Float64) * 0.5; - x *= PI; - - match n { - 1 => k_cos(x, 0.0), - 2 => k_sin(-x, 0.0, 0), - 3 => -k_cos(x, 0.0), - _ => k_sin(x, 0.0, 0), - } -} - -/// Natural logarithm of gamma function -/// -/// Returns the natural logarithm of the absolute value of the gamma function of x, -/// and the sign of the gamma function of x -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgamma_r(mut x: Float64) -> (Float64, Int) { - let u: u64 = x.to_bits(); - let mut t: Float64; - let y: Float64; - let mut z: Float64; - let nadj: Float64; - let p: Float64; - let p1: Float64; - let p2: Float64; - let p3: Float64; - let q: Float64; - let mut r: Float64; - let w: Float64; - - - let i: Int; - let mut signgam: Int; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - let sign: bool = (u >> 63) != 0; - let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; - if ix >= 0x7ff00000 { - return (x * x, signgam); - } - if ix < (0x3ff - 70) << 20 { - /* |x|<2**-70, return -log(|x|) */ - if sign { - x = -x; - signgam = -1; - } - return (-log(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { - /* -integer */ - return (1.0 / (x - x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = log(PI / (t * x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3feccccc { - /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -log(x); - if ix >= 0x3FE76944 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3FCDA661 { - y = x - (TC - 1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3FFBB4C3 { - /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3FF3B4C4 { - /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y * y; - p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); - p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); - p = y * p1 + p2; - r += p - 0.5 * y; - } - 1 => { - z = y * y; - w = z * y; - p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ - p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); - p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); - p = z * p1 - (TT - w * (p2 + y * p3)); - r += TF + p; - } - 2 => { - p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); - p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); - r += -0.5 * y + p1 / p2; - } - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => {} - } - } else if ix < 0x40200000 { - /* x < 8.0 */ - i = x as Int; - y = x - (i as Float64); - p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); - q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); - r = 0.5 * y + p / q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { - z *= y + 6.0; - } - if i >= 6 { - z *= y + 5.0; - } - if i >= 5 { - z *= y + 4.0; - } - if i >= 4 { - z *= y + 3.0; - } - if i >= 3 { - z *= y + 2.0; - r += log(z); - } - } else if ix < 0x43900000 { - /* 8.0 <= x < 2**58 */ - t = log(x); - z = 1.0 / x; - y = z * z; - w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); - r = (x - 0.5) * (t - 1.0) + w; - } else { - /* 2**58 <= x <= inf */ - r = x * (log(x) - 1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} - -/// FFI bindings for lgamma_r -#[inline] -#[doc(hidden)] -#[export_name = "__l2math_lgamma_r"] -pub extern "C" fn __l2math_lgamma_r(x: Float64) -> super::Tuple_Float64_Int { - super::Tuple_Float64_Int::from(lgamma_r(x)) -} diff --git a/helpers/l2math/core/lgammaf.rs b/helpers/l2math/core/lgammaf.rs deleted file mode 100644 index 77a1138..0000000 --- a/helpers/l2math/core/lgammaf.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::Float32; - -use super::lgammaf_r; - -/// Natural logarithm of gamma function -/// -/// Returns the natural logarithm of the absolute value of the gamma function of x. -#[inline] -#[export_name = "__l2math_lgammaf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgammaf(x: Float32) -> Float32 { - lgammaf_r(x).0 -} diff --git a/helpers/l2math/core/lgammaf_r.rs b/helpers/l2math/core/lgammaf_r.rs deleted file mode 100644 index 7699f55..0000000 --- a/helpers/l2math/core/lgammaf_r.rs +++ /dev/null @@ -1,268 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::{Float64, Float32, Int}; - -use super::{floorf, k_cosf, k_sinf, logf}; - -consts!{ -const PI: Float32 = 3.1415927410e+00; /* 0x40490fdb */ -const A0: Float32 = 7.7215664089e-02; /* 0x3d9e233f */ -const A1: Float32 = 3.2246702909e-01; /* 0x3ea51a66 */ -const A2: Float32 = 6.7352302372e-02; /* 0x3d89f001 */ -const A3: Float32 = 2.0580807701e-02; /* 0x3ca89915 */ -const A4: Float32 = 7.3855509982e-03; /* 0x3bf2027e */ -const A5: Float32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ -const A6: Float32 = 1.1927076848e-03; /* 0x3a9c54a1 */ -const A7: Float32 = 5.1006977446e-04; /* 0x3a05b634 */ -const A8: Float32 = 2.2086278477e-04; /* 0x39679767 */ -const A9: Float32 = 1.0801156895e-04; /* 0x38e28445 */ -const A10: Float32 = 2.5214456400e-05; /* 0x37d383a2 */ -const A11: Float32 = 4.4864096708e-05; /* 0x383c2c75 */ -const TC: Float32 = 1.4616321325e+00; /* 0x3fbb16c3 */ -const TF: Float32 = -1.2148628384e-01; /* 0xbdf8cdcd */ -/* TT = -(tail of TF) */ -const TT: Float32 = 6.6971006518e-09; /* 0x31e61c52 */ -const T0: Float32 = 4.8383611441e-01; /* 0x3ef7b95e */ -const T1: Float32 = -1.4758771658e-01; /* 0xbe17213c */ -const T2: Float32 = 6.4624942839e-02; /* 0x3d845a15 */ -const T3: Float32 = -3.2788541168e-02; /* 0xbd064d47 */ -const T4: Float32 = 1.7970675603e-02; /* 0x3c93373d */ -const T5: Float32 = -1.0314224288e-02; /* 0xbc28fcfe */ -const T6: Float32 = 6.1005386524e-03; /* 0x3bc7e707 */ -const T7: Float32 = -3.6845202558e-03; /* 0xbb7177fe */ -const T8: Float32 = 2.2596477065e-03; /* 0x3b141699 */ -const T9: Float32 = -1.4034647029e-03; /* 0xbab7f476 */ -const T10: Float32 = 8.8108185446e-04; /* 0x3a66f867 */ -const T11: Float32 = -5.3859531181e-04; /* 0xba0d3085 */ -const T12: Float32 = 3.1563205994e-04; /* 0x39a57b6b */ -const T13: Float32 = -3.1275415677e-04; /* 0xb9a3f927 */ -const T14: Float32 = 3.3552918467e-04; /* 0x39afe9f7 */ -const U0: Float32 = -7.7215664089e-02; /* 0xbd9e233f */ -const U1: Float32 = 6.3282704353e-01; /* 0x3f2200f4 */ -const U2: Float32 = 1.4549225569e+00; /* 0x3fba3ae7 */ -const U3: Float32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ -const U4: Float32 = 2.2896373272e-01; /* 0x3e6a7578 */ -const U5: Float32 = 1.3381091878e-02; /* 0x3c5b3c5e */ -const V1: Float32 = 2.4559779167e+00; /* 0x401d2ebe */ -const V2: Float32 = 2.1284897327e+00; /* 0x4008392d */ -const V3: Float32 = 7.6928514242e-01; /* 0x3f44efdf */ -const V4: Float32 = 1.0422264785e-01; /* 0x3dd572af */ -const V5: Float32 = 3.2170924824e-03; /* 0x3b52d5db */ -const S0: Float32 = -7.7215664089e-02; /* 0xbd9e233f */ -const S1: Float32 = 2.1498242021e-01; /* 0x3e5c245a */ -const S2: Float32 = 3.2577878237e-01; /* 0x3ea6cc7a */ -const S3: Float32 = 1.4635047317e-01; /* 0x3e15dce6 */ -const S4: Float32 = 2.6642270386e-02; /* 0x3cda40e4 */ -const S5: Float32 = 1.8402845599e-03; /* 0x3af135b4 */ -const S6: Float32 = 3.1947532989e-05; /* 0x3805ff67 */ -const R1: Float32 = 1.3920053244e+00; /* 0x3fb22d3b */ -const R2: Float32 = 7.2193557024e-01; /* 0x3f38d0c5 */ -const R3: Float32 = 1.7193385959e-01; /* 0x3e300f6e */ -const R4: Float32 = 1.8645919859e-02; /* 0x3c98bf54 */ -const R5: Float32 = 7.7794247773e-04; /* 0x3a4beed6 */ -const R6: Float32 = 7.3266842264e-06; /* 0x36f5d7bd */ -const W0: Float32 = 4.1893854737e-01; /* 0x3ed67f1d */ -const W1: Float32 = 8.3333335817e-02; /* 0x3daaaaab */ -const W2: Float32 = -2.7777778450e-03; /* 0xbb360b61 */ -const W3: Float32 = 7.9365057172e-04; /* 0x3a500cfd */ -const W4: Float32 = -5.9518753551e-04; /* 0xba1c065c */ -const W5: Float32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ -const W6: Float32 = -1.6309292987e-03; /* 0xbad5c4e8 */ -} - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: Float32) -> Float32 { - let mut y: Float64; - let mut n: isize; - - /* spurious inexact if odd int */ - x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ - - n = (x * 4.0) as isize; - n = div!(n + 1, 2); - y = (x as Float64) - (n as Float64) * 0.5; - y *= core::f64::consts::PI; - match n { - 1 => k_cosf(y), - 2 => k_sinf(-y), - 3 => -k_cosf(y), - _ => k_sinf(y), - } -} - -/// Natural logarithm of gamma function -/// -/// Returns the natural logarithm of the absolute value of the gamma function of x, -/// and the sign of the gamma function of x -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lgammaf_r(mut x: Float32) -> (Float32, Int) { - let u = x.to_bits(); - let mut t: Float32; - let y: Float32; - let mut z: Float32; - let nadj: Float32; - let p: Float32; - let p1: Float32; - let p2: Float32; - let p3: Float32; - let q: Float32; - let mut r: Float32; - let w: Float32; - let i: Int; - let mut signgam = 1; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - let sign: bool = (u >> 31) != 0; - let ix: u32 = u & 0x7fffffff; - if ix >= 0x7f800000 { - return (x * x, signgam); - } - if ix < 0x35000000 { - /* |x| < 2**-21, return -log(|x|) */ - if sign { - signgam = -1; - x = -x; - } - return (-logf(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { - /* -integer */ - return (1.0 / (x - x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = logf(PI / (t * x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if ix == 0x3f800000 || ix == 0x40000000 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3f666666 { - /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -logf(x); - if ix >= 0x3f3b4a20 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3e6d3308 { - y = x - (TC - 1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3fdda618 { - /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3F9da620 { - /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y * y; - p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); - p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); - p = y * p1 + p2; - r += p - 0.5 * y; - } - 1 => { - z = y * y; - w = z * y; - p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ - p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); - p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); - p = z * p1 - (TT - w * (p2 + y * p3)); - r += TF + p; - } - 2 => { - p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); - p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); - r += -0.5 * y + p1 / p2; - } - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => {} - } - } else if ix < 0x41000000 { - /* x < 8.0 */ - i = x as Int; - y = x - (i as Float32); - p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); - q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); - r = 0.5 * y + p / q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { - z *= y + 6.0; - } - if i >= 6 { - z *= y + 5.0; - } - if i >= 5 { - z *= y + 4.0; - } - if i >= 4 { - z *= y + 3.0; - } - if i >= 3 { - z *= y + 2.0; - r += logf(z); - } - } else if ix < 0x5c800000 { - /* 8.0 <= x < 2**58 */ - t = logf(x); - z = 1.0 / x; - y = z * z; - w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); - r = (x - 0.5) * (t - 1.0) + w; - } else { - /* 2**58 <= x <= inf */ - r = x * (logf(x) - 1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} - -/// FFI bindings for lgammaf_r -#[inline] -#[doc(hidden)] -#[export_name = "__l2math_lgammaf_r"] -pub extern "C" fn __l2math_lgammaf_r(x: Float32) -> super::Tuple_Float32_Int { - super::Tuple_Float32_Int::from(lgammaf_r(x)) -} diff --git a/helpers/l2math/core/ln.rs b/helpers/l2math/core/ln.rs deleted file mode 100644 index 16fdde5..0000000 --- a/helpers/l2math/core/ln.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::Float64; - -use super::ln1p; - -/// Return the natural logarithm of `x`. -#[inline] -#[export_name = "__l2math_ln"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ln(x: Float64) -> Float64 { - ln1p(x - 1.) -} diff --git a/helpers/l2math/core/ln1p.rs b/helpers/l2math/core/ln1p.rs deleted file mode 100644 index 90d512e..0000000 --- a/helpers/l2math/core/ln1p.rs +++ /dev/null @@ -1,139 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * double log1p(double x) - * Return the natural logarithm of 1+x. - * - * Method : - * 1. Argument Reduction: find k and f such that - * 1+x = 2^k * (1+f), - * where sqrt(2)/2 < 1+f < sqrt(2) . - * - * Note. If k=0, then f=x is exact. However, if k!=0, then f - * may not be representable exactly. In that case, a correction - * term is need. Let u=1+x rounded. Let c = (1+x)-u, then - * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), - * and add back the correction term c/u. - * (Note: when x > 2**53, one can simply return log(x)) - * - * 2. Approximation of log(1+f): See log.c - * - * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c - * - * Special cases: - * log1p(x) is NaN with signal if x < -1 (including -INF) ; - * log1p(+INF) is +INF; log1p(-1) is -INF with signal; - * log1p(NaN) is that NaN with no signal. - * - * Accuracy: - * according to an error analysis, the error is always less than - * 1 ulp (unit in the last place). - * - * Constants: - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - * - * Note: Assuming log() return accurate answer, the following - * algorithm can be used to compute log1p(x) to within a few ULP: - * - * u = 1+x; - * if(u==1.0) return x ; else - * return log(u)*(x/(u-1.0)); - * - * See HP-15C Advanced Functions Handbook, p.193. -*/ - -use crate::{Float64, Float32, Int}; - -consts!{ -const LN2_HI: Float64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ -const LN2_LO: Float64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ -const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ -} - -/// Return the natural logarithm of `1+x`. -#[export_name = "__l2math_ln1p"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn ln1p(x: Float64) -> Float64 { - let mut ui: u64 = x.to_bits(); - let mut f: Float64 = 0.; - let mut c: Float64 = 0.; - let mut hu: u32; - let mut k: Int; - - let hx: u32 = (ui >> 32) as u32; - k = 1; - if hx < 0x3fda827a || (hx >> 31) > 0 { - /* 1+x < sqrt(2)+ */ - if hx >= 0xbff00000 { - /* x <= -1.0 */ - if x == -1. { - return x / 0.0; /* log1p(-1) = -inf */ - } - return (x - x) / 0.0; /* log1p(x<-1) = NaN */ - } - if hx << 1 < 0x3ca00000 << 1 { - /* |x| < 2**-53 */ - /* underflow if subnormal */ - if (hx & 0x7ff00000) == 0 { - force_eval!(x as Float32); - } - return x; - } - if hx <= 0xbfd2bec4 { - /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ - k = 0; - c = 0.; - f = x; - } - } else if hx >= 0x7ff00000 { - return x; - } - if k > 0 { - ui = (1. + x).to_bits(); - hu = (ui >> 32) as u32; - hu += 0x3ff00000 - 0x3fe6a09e; - k = (hu >> 20) as Int - 0x3ff; - /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ - if k < 54 { - c = if k >= 2 { - 1. - (Float64::from_bits(ui) - x) - } else { - x - (Float64::from_bits(ui) - 1.) - }; - c /= Float64::from_bits(ui); - } else { - c = 0.; - } - /* reduce u into [sqrt(2)/2, sqrt(2)] */ - hu = (hu & 0x000fffff) + 0x3fe6a09e; - ui = (hu as u64) << 32 | (ui & 0xffffffff); - f = Float64::from_bits(ui) - 1.; - } - let hfsq: Float64 = 0.5 * f * f; - let s: Float64 = f / (2.0 + f); - let z: Float64 = s * s; - let w: Float64 = z * z; - let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); - let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - let r: Float64 = t2 + t1; - let dk: Float64 = k as Float64; - s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI -} diff --git a/helpers/l2math/core/ln1pf.rs b/helpers/l2math/core/ln1pf.rs deleted file mode 100644 index 4cc75a4..0000000 --- a/helpers/l2math/core/ln1pf.rs +++ /dev/null @@ -1,92 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ - -use crate::{Float32, Int}; - -consts!{ -const LN2_HI: Float32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: Float32 = 9.0580006145e-06; /* 0x3717f7d1 */ -/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ -} - -/// Return the natural logarithm of `1+x`. -#[export_name = "__l2math_ln1pf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ln1pf(x: Float32) -> Float32 { - let mut ui: u32 = x.to_bits(); - let mut f: Float32 = 0.; - let mut c: Float32 = 0.; - let mut iu: u32; - let mut k: Int; - let ix: u32 = ui; - k = 1; - if ix < 0x3ed413d0 || (ix >> 31) > 0 { - /* 1+x < sqrt(2)+ */ - if ix >= 0xbf800000 { - /* x <= -1.0 */ - if x == -1. { - return x / 0.0; /* log1p(-1)=+inf */ - } - return (x - x) / 0.0; /* log1p(x<-1)=NaN */ - } - if ix << 1 < 0x33800000 << 1 { - /* |x| < 2**-24 */ - /* underflow if subnormal */ - if (ix & 0x7f800000) == 0 { - force_eval!(x * x); - } - return x; - } - if ix <= 0xbe95f619 { - /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ - k = 0; - c = 0.; - f = x; - } - } else if ix >= 0x7f800000 { - return x; - } - if k > 0 { - ui = (1. + x).to_bits(); - iu = ui; - iu += 0x3f800000 - 0x3f3504f3; - k = (iu >> 23) as Int - 0x7f; - /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ - if k < 25 { - c = if k >= 2 { - 1. - (Float32::from_bits(ui) - x) - } else { - x - (Float32::from_bits(ui) - 1.) - }; - c /= Float32::from_bits(ui); - } else { - c = 0.; - } - /* reduce u into [sqrt(2)/2, sqrt(2)] */ - iu = (iu & 0x007fffff) + 0x3f3504f3; - ui = iu; - f = Float32::from_bits(ui) - 1.; - } - let s: Float32 = f / (2.0 + f); - let z: Float32 = s * s; - let w: Float32 = z * z; - let t1: Float32 = w * (LG2 + w * LG4); - let t2: Float32 = z * (LG1 + w * LG3); - let r: Float32 = t2 + t1; - let hfsq: Float32 = 0.5 * f * f; - let dk: Float32 = k as Float32; - s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI -} diff --git a/helpers/l2math/core/lnf.rs b/helpers/l2math/core/lnf.rs deleted file mode 100644 index 1f5f223..0000000 --- a/helpers/l2math/core/lnf.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::Float32; - -use super::ln1pf; - -/// Return the natural logarithm of `x`. -#[inline] -#[export_name = "__l2math_lnf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn lnf(x: Float32) -> Float32 { - ln1pf(x - 1.) -} diff --git a/helpers/l2math/core/log.rs b/helpers/l2math/core/log.rs deleted file mode 100644 index 9ad2f7b..0000000 --- a/helpers/l2math/core/log.rs +++ /dev/null @@ -1,124 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * log(x) - * Return the logarithm of x - * - * Method : - * 1. Argument Reduction: find k and f such that - * x = 2^k * (1+f), - * where sqrt(2)/2 < 1+f < sqrt(2) . - * - * 2. Approximation of log(1+f). - * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) - * = 2s + 2/3 s**3 + 2/5 s**5 + ....., - * = 2s + s*R - * We use a special Remez algorithm on [0,0.1716] to generate - * a polynomial of degree 14 to approximate R The maximum error - * of this polynomial approximation is bounded by 2**-58.45. In - * other words, - * 2 4 6 8 10 12 14 - * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s - * (the values of Lg1 to Lg7 are listed in the program) - * and - * | 2 14 | -58.45 - * | Lg1*s +...+Lg7*s - R(z) | <= 2 - * | | - * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. - * In order to guarantee error in log below 1ulp, we compute log - * by - * log(1+f) = f - s*(f - R) (if f is not too large) - * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) - * - * 3. Finally, log(x) = k*ln2 + log(1+f). - * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) - * Here ln2 is split into two floating point number: - * ln2_hi + ln2_lo, - * where n*ln2_hi is always exact for |n| < 2000. - * - * Special cases: - * log(x) is NaN with signal if x < 0 (including -INF) ; - * log(+INF) is +INF; log(0) is -INF with signal; - * log(NaN) is that NaN with no signal. - * - * Accuracy: - * according to an error analysis, the error is always less than - * 1 ulp (unit in the last place). - * - * Constants: - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. -*/ - -use crate::{Float64, Int}; - -consts!{ -const LN2_HI: Float64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ -const LN2_LO: Float64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ -const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ -} - -/// Returns the logarithm of `x`. -#[export_name = "__l2math_log"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn log(mut x: Float64) -> Float64 { - let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 - - let mut ui = x.to_bits(); - let mut hx: u32 = (ui >> 32) as u32; - let mut k: Int = 0; - - if (hx < 0x00100000) || ((hx >> 31) != 0) { - /* x < 2**-126 */ - if ui << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if hx >> 31 != 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale x up */ - k -= 54; - x *= x1p54; - ui = x.to_bits(); - hx = (ui >> 32) as u32; - } else if hx >= 0x7ff00000 { - return x; - } else if hx == 0x3ff00000 && ui << 32 == 0 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - hx += 0x3ff00000 - 0x3fe6a09e; - k += ((hx >> 20) as Int) - 0x3ff; - hx = (hx & 0x000fffff) + 0x3fe6a09e; - ui = ((hx as u64) << 32) | (ui & 0xffffffff); - x = Float64::from_bits(ui); - - let f: Float64 = x - 1.0; - let hfsq: Float64 = 0.5 * f * f; - let s: Float64 = f / (2.0 + f); - let z: Float64 = s * s; - let w: Float64 = z * z; - let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); - let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - let r: Float64 = t2 + t1; - let dk: Float64 = k as Float64; - s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI -} diff --git a/helpers/l2math/core/log10.rs b/helpers/l2math/core/log10.rs deleted file mode 100644 index 8a52c00..0000000 --- a/helpers/l2math/core/log10.rs +++ /dev/null @@ -1,110 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Return the base 10 logarithm of x. See log.c for most comments. - * - * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 - * as in log.c, then combine and scale in extra precision: - * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) -*/ - -use crate::{Float64, Int}; - -consts!{ -const IVLN10HI: Float64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ -const IVLN10LO: Float64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ -const LOG10_2HI: Float64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ -const LOG10_2LO: Float64 = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ -const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ -} - -/// Returns the base 10 logarithm of `x`. -#[export_name = "__l2math_log10"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn log10(mut x: Float64) -> Float64 { - let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 - let mut ui: u64 = x.to_bits(); - let mut w: Float64; - let mut hi: Float64; - let mut val_hi: Float64; - let mut val_lo: Float64; - let mut hx: u32; - let mut k: Int; - - hx = (ui >> 32) as u32; - k = 0; - if hx < 0x00100000 || (hx >> 31) > 0 { - if ui << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (hx >> 31) > 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale x up */ - k -= 54; - x *= x1p54; - ui = x.to_bits(); - hx = (ui >> 32) as u32; - } else if hx >= 0x7ff00000 { - return x; - } else if hx == 0x3ff00000 && ui << 32 == 0 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - hx += 0x3ff00000 - 0x3fe6a09e; - k += (hx >> 20) as Int - 0x3ff; - hx = (hx & 0x000fffff) + 0x3fe6a09e; - ui = (hx as u64) << 32 | (ui & 0xffffffff); - x = Float64::from_bits(ui); - - let f: Float64 = x - 1.0; - let hfsq: Float64 = 0.5 * f * f; - let s: Float64 = f / (2.0 + f); - let z: Float64 = s * s; - w = z * z; - let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); - let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - let r: Float64 = t2 + t1; - - /* See log2.c for details. */ - /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ - hi = f - hfsq; - ui = hi.to_bits(); - ui &= (-1i64 as u64) << 32; - hi = Float64::from_bits(ui); - let lo: Float64 = f - hi - hfsq + s * (hfsq + r); - - /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ - val_hi = hi * IVLN10HI; - let dk: Float64 = k as Float64; - let y: Float64 = dk * LOG10_2HI; - val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI; - - /* - * Extra precision in for adding y is not strictly needed - * since there is no very large cancellation near x = sqrt(2) or - * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs - * with some parallelism and it reduces the error for many args. - */ - w = y + val_hi; - val_lo += (y - w) + val_hi; - val_hi = w; - - val_lo + val_hi -} diff --git a/helpers/l2math/core/log10f.rs b/helpers/l2math/core/log10f.rs deleted file mode 100644 index d506eb7..0000000 --- a/helpers/l2math/core/log10f.rs +++ /dev/null @@ -1,85 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * See comments in log10.c. -*/ - -use crate::{Float32, Int}; - -consts!{ -const IVLN10HI: Float32 = 4.3432617188e-01; /* 0x3ede6000 */ -const IVLN10LO: Float32 = -3.1689971365e-05; /* 0xb804ead9 */ -const LOG10_2HI: Float32 = 3.0102920532e-01; /* 0x3e9a2080 */ -const LOG10_2LO: Float32 = 7.9034151668e-07; /* 0x355427db */ -/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ -} - -/// Returns the base 10 logarithm of `x`. -#[export_name = "__l2math_log10f"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn log10f(mut x: Float32) -> Float32 { - let x1p25f = Float32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 - - let mut ui: u32 = x.to_bits(); - let mut hi: Float32; - let mut ix: u32; - let mut k: Int; - - ix = ui; - k = 0; - if ix < 0x00800000 || (ix >> 31) > 0 { - /* x < 2**-126 */ - if ix << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (ix >> 31) > 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale up x */ - k -= 25; - x *= x1p25f; - ui = x.to_bits(); - ix = ui; - } else if ix >= 0x7f800000 { - return x; - } else if ix == 0x3f800000 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - ix += 0x3f800000 - 0x3f3504f3; - k += (ix >> 23) as Int - 0x7f; - ix = (ix & 0x007fffff) + 0x3f3504f3; - ui = ix; - x = Float32::from_bits(ui); - - let f: Float32 = x - 1.0; - let s: Float32 = f / (2.0 + f); - let z: Float32 = s * s; - let w: Float32 = z * z; - let t1: Float32 = w * (LG2 + w * LG4); - let t2: Float32 = z * (LG1 + w * LG3); - let r: Float32 = t2 + t1; - let hfsq: Float32 = 0.5 * f * f; - - hi = f - hfsq; - ui = hi.to_bits(); - ui &= 0xfffff000; - hi = Float32::from_bits(ui); - let lo: Float32 = f - hi - hfsq + s * (hfsq + r); - let dk: Float32 = k as Float32; - dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI -} diff --git a/helpers/l2math/core/log2.rs b/helpers/l2math/core/log2.rs deleted file mode 100644 index b3e54e6..0000000 --- a/helpers/l2math/core/log2.rs +++ /dev/null @@ -1,100 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Return the base 2 logarithm of x. See log.c for most comments. - * - * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 - * as in log.c, then combine and scale in extra precision: - * log2(x) = (f - f*f/2 + r)/log(2) + k -*/ - -use crate::{Float64, Int}; - -consts!{ -const IVLN2HI: Float64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ -const IVLN2LO: Float64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ -const LG1: Float64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ -const LG2: Float64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ -const LG3: Float64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ -const LG4: Float64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ -const LG5: Float64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ -const LG6: Float64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ -const LG7: Float64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ -} - -/// Returns the base 2 logarithm of `x`. -#[export_name = "__l2math_log2"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn log2(mut x: Float64) -> Float64 { - let x1p54 = Float64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 - let mut ui: u64 = x.to_bits(); - let mut w: Float64; - let mut hi: Float64; - let mut val_hi: Float64; - let mut val_lo: Float64; - let mut hx: u32; - let mut k: Int; - - hx = (ui >> 32) as u32; - k = 0; - if hx < 0x00100000 || (hx >> 31) > 0 { - if ui << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (hx >> 31) > 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale x up */ - k -= 54; - x *= x1p54; - ui = x.to_bits(); - hx = (ui >> 32) as u32; - } else if hx >= 0x7ff00000 { - return x; - } else if hx == 0x3ff00000 && ui << 32 == 0 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - hx += 0x3ff00000 - 0x3fe6a09e; - k += (hx >> 20) as Int - 0x3ff; - hx = (hx & 0x000fffff) + 0x3fe6a09e; - ui = (hx as u64) << 32 | (ui & 0xffffffff); - x = Float64::from_bits(ui); - - let f: Float64 = x - 1.0; - let hfsq: Float64 = 0.5 * f * f; - let s: Float64 = f / (2.0 + f); - let z: Float64 = s * s; - w = z * z; - let t1: Float64 = w * (LG2 + w * (LG4 + w * LG6)); - let t2: Float64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); - let r: Float64 = t2 + t1; - - /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ - hi = f - hfsq; - ui = hi.to_bits(); - ui &= (-1i64 as u64) << 32; - hi = Float64::from_bits(ui); - let lo: Float64 = f - hi - hfsq + s * (hfsq + r); - - val_hi = hi * IVLN2HI; - val_lo = (lo + hi) * IVLN2LO + lo * IVLN2HI; - - /* spadd(val_hi, val_lo, y), except for not using double_t: */ - let y: Float64 = k.into(); - w = y + val_hi; - val_lo += (y - w) + val_hi; - val_hi = w; - - val_lo + val_hi -} diff --git a/helpers/l2math/core/log2f.rs b/helpers/l2math/core/log2f.rs deleted file mode 100644 index fc8adf4..0000000 --- a/helpers/l2math/core/log2f.rs +++ /dev/null @@ -1,81 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * See comments in log2.c. -*/ - -use crate::{Float32, Int}; - -consts!{ -const IVLN2HI: Float32 = 1.4428710938e+00; /* 0x3fb8b000 */ -const IVLN2LO: Float32 = -1.7605285393e-04; /* 0xb9389ad4 */ -/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ -const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ -} - -/// Returns the base 2 logarithm of `x`. -#[export_name = "__l2math_log2f"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn log2f(mut x: Float32) -> Float32 { - let x1p25f = Float32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 - let mut ui: u32 = x.to_bits(); - let mut hi: Float32; - let mut ix: u32; - let mut k: Int; - - ix = ui; - k = 0; - if ix < 0x00800000 || (ix >> 31) > 0 { - /* x < 2**-126 */ - if ix << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (ix >> 31) > 0 { - return (x - x) / 0.0; /* log(-#) = NaN */ - } - /* subnormal number, scale up x */ - k -= 25; - x *= x1p25f; - ui = x.to_bits(); - ix = ui; - } else if ix >= 0x7f800000 { - return x; - } else if ix == 0x3f800000 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - ix += 0x3f800000 - 0x3f3504f3; - k += (ix >> 23) as Int - 0x7f; - ix = (ix & 0x007fffff) + 0x3f3504f3; - ui = ix; - x = Float32::from_bits(ui); - - let f: Float32 = x - 1.0; - let s: Float32 = f / (2.0 + f); - let z: Float32 = s * s; - let w: Float32 = z * z; - let t1: Float32 = w * (LG2 + w * LG4); - let t2: Float32 = z * (LG1 + w * LG3); - let r: Float32 = t2 + t1; - let hfsq: Float32 = 0.5 * f * f; - - hi = f - hfsq; - ui = hi.to_bits(); - ui &= 0xfffff000; - hi = Float32::from_bits(ui); - let lo: Float32 = f - hi - hfsq + s * (hfsq + r); - (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as Float32 -} diff --git a/helpers/l2math/core/logf.rs b/helpers/l2math/core/logf.rs deleted file mode 100644 index 2ff9d7f..0000000 --- a/helpers/l2math/core/logf.rs +++ /dev/null @@ -1,71 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::{Float32, Int}; - -consts!{ -const LN2_HI: Float32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO: Float32 = 9.0580006145e-06; /* 0x3717f7d1 */ -/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1: Float32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ -const LG2: Float32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3: Float32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4: Float32 = 0.24279078841; /* 0xf89e26.0p-26 */ -} - -/// Returns the logarithm of `x` -#[export_name = "__l2math_logf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn logf(mut x: Float32) -> Float32 { - let x1p25 = Float32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 - - let mut ix = x.to_bits(); - let mut k: Int = 0; - - if (ix < 0x00800000) || ((ix >> 31) != 0) { - /* x < 2**-126 */ - if ix << 1 == 0 { - return -1. / (x * x); /* log(+-0)=-inf */ - } - if (ix >> 31) != 0 { - return (x - x) / 0.; /* log(-#) = NaN */ - } - /* subnormal number, scale up x */ - k -= 25; - x *= x1p25; - ix = x.to_bits(); - } else if ix >= 0x7f800000 { - return x; - } else if ix == 0x3f800000 { - return 0.; - } - - /* reduce x into [sqrt(2)/2, sqrt(2)] */ - ix += 0x3f800000 - 0x3f3504f3; - k += ((ix >> 23) as Int) - 0x7f; - ix = (ix & 0x007fffff) + 0x3f3504f3; - x = Float32::from_bits(ix); - - let f = x - 1.; - let s = f / (2. + f); - let z = s * s; - let w = z * z; - let t1 = w * (LG2 + w * LG4); - let t2 = z * (LG1 + w * LG3); - let r = t2 + t1; - let hfsq = 0.5 * f * f; - let dk = k as Float32; - s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI -} diff --git a/helpers/l2math/core/modf.rs b/helpers/l2math/core/modf.rs deleted file mode 100644 index f2fbcfc..0000000 --- a/helpers/l2math/core/modf.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::{Float64, Int}; - -/// Breaks the given number into an integral and a fractional part. -pub fn modf(x: Float64) -> (Float64, Float64) { - let rv2: Float64; - let mut u = x.to_bits(); - let e = ((u >> 52 & 0x7ff) as Int) - 0x3ff; - - /* no fractional part */ - if e >= 52 { - rv2 = x; - if e == 0x400 && (u << 12) != 0 { - /* nan */ - return (x, rv2); - } - u &= 1 << 63; - return (Float64::from_bits(u), rv2); - } - - /* no integral part*/ - if e < 0 { - u &= 1 << 63; - rv2 = Float64::from_bits(u); - return (x, rv2); - } - - let mask: u64 = ((!0) >> 12) >> e; - if (u & mask) == 0 { - rv2 = x; - u &= 1 << 63; - return (Float64::from_bits(u), rv2); - } - u &= !mask; - rv2 = Float64::from_bits(u); - return (x - rv2, rv2); -} - -/// FFI bindings for modf -#[inline] -#[doc(hidden)] -#[export_name = "__l2math_modf"] -pub extern "C" fn __l2math_modf(x: Float64) -> super::Tuple_Float64_Float64 { - super::Tuple_Float64_Float64::from(modf(x)) -} diff --git a/helpers/l2math/core/modff.rs b/helpers/l2math/core/modff.rs deleted file mode 100644 index e25848d..0000000 --- a/helpers/l2math/core/modff.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::{Float32, Int}; - -/// Breaks the given number into an integral and a fractional part. -pub fn modff(x: Float32) -> (Float32, Float32) { - let rv2: Float32; - let mut u: u32 = x.to_bits(); - let e = ((u >> 23 & 0xff) as Int) - 0x7f; - - /* no fractional part */ - if e >= 23 { - rv2 = x; - if e == 0x80 && (u << 9) != 0 { - /* nan */ - return (x, rv2); - } - u &= 0x80000000; - return (Float32::from_bits(u), rv2); - } - /* no integral part */ - if e < 0 { - u &= 0x80000000; - rv2 = Float32::from_bits(u); - return (x, rv2); - } - - let mask: u32 = 0x007fffff >> e; - if (u & mask) == 0 { - rv2 = x; - u &= 0x80000000; - return (Float32::from_bits(u), rv2); - } - u &= !mask; - rv2 = Float32::from_bits(u); - return (x - rv2, rv2); -} - -/// FFI bindings for modff -#[inline] -#[doc(hidden)] -#[export_name = "__l2math_modff"] -pub extern "C" fn __l2math_modff(x: Float32) -> super::Tuple_Float32_Float32 { - super::Tuple_Float32_Float32::from(modff(x)) -} diff --git a/helpers/l2math/core/nextafter.rs b/helpers/l2math/core/nextafter.rs deleted file mode 100644 index 1432552..0000000 --- a/helpers/l2math/core/nextafter.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::Float64; - -/// Returns the next representable floating-point value following `x` in the direction of `y`. -#[export_name = "__l2math_nextafter"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn nextafter(x: Float64, y: Float64) -> Float64 { - if x.is_nan() || y.is_nan() { - return x + y; - } - - let mut ux_i = x.to_bits(); - let uy_i = y.to_bits(); - if ux_i == uy_i { - return y; - } - - let ax = ux_i & (!1u64 / 2); - let ay = uy_i & (!1u64 / 2); - if ax == 0 { - if ay == 0 { - return y; - } - ux_i = (uy_i & 1u64 << 63) | 1; - } else if ax > ay || ((ux_i ^ uy_i) & 1u64 << 63) != 0 { - ux_i -= 1; - } else { - ux_i += 1; - } - - let e = ux_i >> 52 & 0x7ff; - // raise overflow if ux.f is infinite and x is finite - if e == 0x7ff { - force_eval!(x + x); - } - let ux_f = Float64::from_bits(ux_i); - // raise underflow if ux.f is subnormal or zero - if e == 0 { - force_eval!(x * x + ux_f * ux_f); - } - ux_f -} diff --git a/helpers/l2math/core/nextafterf.rs b/helpers/l2math/core/nextafterf.rs deleted file mode 100644 index 63232b0..0000000 --- a/helpers/l2math/core/nextafterf.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::Float32; - -/// Returns the next representable floating-point value following `x` in the direction of `y`. -#[export_name = "__l2math_nextafterf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn nextafterf(x: Float32, y: Float32) -> Float32 { - if x.is_nan() || y.is_nan() { - return x + y; - } - - let mut ux_i = x.to_bits(); - let uy_i = y.to_bits(); - if ux_i == uy_i { - return y; - } - - let ax = ux_i & 0x7fff_ffff_u32; - let ay = uy_i & 0x7fff_ffff_u32; - if ax == 0 { - if ay == 0 { - return y; - } - ux_i = (uy_i & 0x8000_0000_u32) | 1; - } else if ax > ay || ((ux_i ^ uy_i) & 0x8000_0000_u32) != 0 { - ux_i -= 1; - } else { - ux_i += 1; - } - - let e = ux_i & 0x7f80_0000_u32; - // raise overflow if ux_f is infinite and x is finite - if e == 0x7f80_0000_u32 { - force_eval!(x + x); - } - let ux_f = Float32::from_bits(ux_i); - // raise underflow if ux_f is subnormal or zero - if e == 0 { - force_eval!(x * x + ux_f * ux_f); - } - ux_f -} diff --git a/helpers/l2math/core/pow.rs b/helpers/l2math/core/pow.rs deleted file mode 100644 index 4a942c8..0000000 --- a/helpers/l2math/core/pow.rs +++ /dev/null @@ -1,645 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ -/** - * ==================================================== - * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. - * - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ - -// pow(x,y) return x**y -// -// n -// Method: Let x = 2 * (1+f) -// 1. Compute and return log2(x) in two pieces: -// log2(x) = w1 + w2, -// where w1 has 53-24 = 29 bit trailing zeros. -// 2. Perform y*log2(x) = n+y' by simulating muti-precision -// arithmetic, where |y'|<=0.5. -// 3. Return x**y = 2**n*exp(y'*log2) -// -// Special cases: -// 1. (anything) ** 0 is 1 -// 2. 1 ** (anything) is 1 -// 3. (anything except 1) ** NAN is NAN -// 4. NAN ** (anything except 0) is NAN -// 5. +-(|x| > 1) ** +INF is +INF -// 6. +-(|x| > 1) ** -INF is +0 -// 7. +-(|x| < 1) ** +INF is +0 -// 8. +-(|x| < 1) ** -INF is +INF -// 9. -1 ** +-INF is 1 -// 10. +0 ** (+anything except 0, NAN) is +0 -// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 -// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero -// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero -// 14. -0 ** (+odd integer) is -0 -// 15. -0 ** (-odd integer) is -INF, raise divbyzero -// 16. +INF ** (+anything except 0,NAN) is +INF -// 17. +INF ** (-anything except 0,NAN) is +0 -// 18. -INF ** (+odd integer) is -INF -// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) -// 20. (anything) ** 1 is (anything) -// 21. (anything) ** -1 is 1/(anything) -// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) -// 23. (-anything except 0 and inf) ** (non-integer) is NAN -// -// Accuracy: -// pow(x,y) returns x**y nearly rounded. In particular -// pow(integer,integer) -// always returns the correct integer provided it is -// representable. -// -// Constants : -// The hexadecimal values are the intended ones for the following -// constants. The decimal values may be used, provided that the -// compiler will convert from decimal to binary accurately enough -// to produce the hexadecimal values shown. -// - -use crate::{Float64, Int}; - -use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; - -consts!{ -const BP: [Float64; 2] = [1.0, 1.5]; -const DP_H: [Float64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ -const DP_L: [Float64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ -const TWO53: Float64 = 9007199254740992.0; /* 0x43400000_00000000 */ -const HUGE: Float64 = 1.0e300; -const TINY: Float64 = 1.0e-300; - -// poly coefs for (3/2)*(log(x)-2s-2/3*s**3: -const L1: Float64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ -const L2: Float64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ -const L3: Float64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ -const L4: Float64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ -const L5: Float64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ -const L6: Float64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ -const P1: Float64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ -const P2: Float64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ -const P3: Float64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ -const P4: Float64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ -const P5: Float64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ -const LG2: Float64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ -const LG2_H: Float64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ -const LG2_L: Float64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ -const OVT: Float64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ -const CP: Float64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ -const CP_H: Float64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ -const CP_L: Float64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ -const IVLN2: Float64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ -const IVLN2_H: Float64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ -const IVLN2_L: Float64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ -} - -/// Returns `x` raised to the power `y`. -#[export_name = "__l2math_pow"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn pow(x: Float64, y: Float64) -> Float64 { - let t1: Float64; - let t2: Float64; - - let (hx, lx): (Int, u32) = ((x.to_bits() >> 32) as Int, x.to_bits() as u32); - let (hy, ly): (Int, u32) = ((y.to_bits() >> 32) as Int, y.to_bits() as u32); - - let mut ix: Int = hx & 0x7fffffff; - let iy: Int = hy & 0x7fffffff; - - /* x**0 = 1, even if x is NaN */ - if ((iy as u32) | ly) == 0 { - return 1.0; - } - - /* 1**y = 1, even if y is NaN */ - if hx == 0x3ff00000 && lx == 0 { - return 1.0; - } - - /* NaN if either arg is NaN */ - if ix > 0x7ff00000 - || (ix == 0x7ff00000 && lx != 0) - || iy > 0x7ff00000 - || (iy == 0x7ff00000 && ly != 0) - { - return x + y; - } - - /* determine if y is an odd int when x < 0 - * yisint = 0 ... y is not an integer - * yisint = 1 ... y is an odd int - * yisint = 2 ... y is an even int - */ - let mut yisint: Int = 0; - let mut k: Int; - let mut j: Int; - if hx < 0 { - if iy >= 0x43400000 { - yisint = 2; /* even integer y */ - } else if iy >= 0x3ff00000 { - k = (iy >> 20) - 0x3ff; /* exponent */ - - if k > 20 { - j = (ly >> (52 - k)) as Int; - - if (j << (52 - k)) == (ly as Int) { - yisint = 2 - (j & 1); - } - } else if ly == 0 { - j = iy >> (20 - k); - - if (j << (20 - k)) == iy { - yisint = 2 - (j & 1); - } - } - } - } - - if ly == 0 { - /* special value of y */ - if iy == 0x7ff00000 { - /* y is +-inf */ - - return if ((ix - 0x3ff00000) | (lx as Int)) == 0 { - /* (-1)**+-inf is 1 */ - 1.0 - } else if ix >= 0x3ff00000 { - /* (|x|>1)**+-inf = inf,0 */ - if hy >= 0 { - y - } else { - 0.0 - } - } else { - /* (|x|<1)**+-inf = 0,inf */ - if hy >= 0 { - 0.0 - } else { - -y - } - }; - } - - if iy == 0x3ff00000 { - /* y is +-1 */ - return if hy >= 0 { x } else { 1.0 / x }; - } - - if hy == 0x40000000 { - /* y is 2 */ - return x * x; - } - - if hy == 0x3fe00000 { - /* y is 0.5 */ - if hx >= 0 { - /* x >= +0 */ - return sqrt(x); - } - } - } - - let mut ax: Float64 = fabs(x); - if lx == 0 { - /* special value of x */ - if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { - /* x is +-0,+-inf,+-1 */ - let mut z: Float64 = ax; - - if hy < 0 { - /* z = (1/|x|) */ - z = 1.0 / z; - } - - if hx < 0 { - if ((ix - 0x3ff00000) | yisint) == 0 { - z = (z - z) / (z - z); /* (-1)**non-int is NaN */ - } else if yisint == 1 { - z = -z; /* (x<0)**odd = -(|x|**odd) */ - } - } - - return z; - } - } - - let mut s: Float64 = 1.0; /* sign of result */ - if hx < 0 { - if yisint == 0 { - /* (x<0)**(non-int) is NaN */ - return (x - x) / (x - x); - } - - if yisint == 1 { - /* (x<0)**(odd int) */ - s = -1.0; - } - } - - /* |y| is HUGE */ - if iy > 0x41e00000 { - /* if |y| > 2**31 */ - if iy > 0x43f00000 { - /* if |y| > 2**64, must o/uflow */ - if ix <= 0x3fefffff { - return if hy < 0 { HUGE * HUGE } else { TINY * TINY }; - } - - if ix >= 0x3ff00000 { - return if hy > 0 { HUGE * HUGE } else { TINY * TINY }; - } - } - - /* over/underflow if x is not close to one */ - if ix < 0x3fefffff { - return if hy < 0 { - s * HUGE * HUGE - } else { - s * TINY * TINY - }; - } - if ix > 0x3ff00000 { - return if hy > 0 { - s * HUGE * HUGE - } else { - s * TINY * TINY - }; - } - - /* now |1-x| is TINY <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ - let t: Float64 = ax - 1.0; /* t has 20 trailing zeros */ - #[allow(clippy::excessive_precision)] - let w: Float64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); - let u: Float64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ - let v: Float64 = t * IVLN2_L - w * IVLN2; - t1 = with_set_low_word(u + v, 0); - t2 = v - (t1 - u); - } else { - // double ss,s2,s_h,s_l,t_h,t_l; - let mut n: Int = 0; - - if ix < 0x00100000 { - /* take care subnormal number */ - ax *= TWO53; - n -= 53; - ix = get_high_word(ax) as Int; - } - - n += (ix >> 20) - 0x3ff; - j = ix & 0x000fffff; - - /* determine interval */ - let k: Int; - ix = j | 0x3ff00000; /* normalize ix */ - if j <= 0x3988E { - /* |x|> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18), - ); - let t_l: Float64 = ax - (t_h - i!(BP, k as usize)); - let s_l: Float64 = v * ((u - s_h * t_h) - s_h * t_l); - - /* compute log(ax) */ - let s2: Float64 = ss * ss; - let mut r: Float64 = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); - r += s_l * (s_h + ss); - let s2: Float64 = s_h * s_h; - let t_h: Float64 = with_set_low_word(3.0 + s2 + r, 0); - let t_l: Float64 = r - ((t_h - 3.0) - s2); - - /* u+v = ss*(1+...) */ - let u: Float64 = s_h * t_h; - let v: Float64 = s_l * t_h + t_l * ss; - - /* 2/(3log2)*(ss+...) */ - let p_h: Float64 = with_set_low_word(u + v, 0); - let p_l = v - (p_h - u); - let z_h: Float64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ - let z_l: Float64 = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); - - /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ - let t: Float64 = n as Float64; - t1 = with_set_low_word(((z_h + z_l) + i!(DP_H, k as usize)) + t, 0); - t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); - } - - /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ - let y1: Float64 = with_set_low_word(y, 0); - let p_l: Float64 = (y - y1) * t1 + y * t2; - let mut p_h: Float64 = y1 * t1; - let z: Float64 = p_l + p_h; - let mut j: Int = (z.to_bits() >> 32) as Int; - let i: Int = z.to_bits() as Int; - // let (j, i): (Int, Int) = ((z.to_bits() >> 32) as Int, z.to_bits() as Int); - - if j >= 0x40900000 { - /* z >= 1024 */ - if (j - 0x40900000) | i != 0 { - /* if z > 1024 */ - return s * HUGE * HUGE; /* overflow */ - } - - if p_l + OVT > z - p_h { - return s * HUGE * HUGE; /* overflow */ - } - } else if (j & 0x7fffffff) >= 0x4090cc00 { - /* z <= -1075 */ - // FIXME: instead of abs(j) use unsigned j - - if (((j as u32) - 0xc090cc00) | (i as u32)) != 0 { - /* z < -1075 */ - return s * TINY * TINY; /* underflow */ - } - - if p_l <= z - p_h { - return s * TINY * TINY; /* underflow */ - } - } - - /* compute 2**(p_h+p_l) */ - let i: Int = j & 0x7fffffff; - k = (i >> 20) - 0x3ff; - let mut n: Int = 0; - - if i > 0x3fe00000 { - /* if |z| > 0.5, set n = [z+0.5] */ - n = j + (0x00100000 >> (k + 1)); - k = ((n & 0x7fffffff) >> 20) - 0x3ff; /* new k for n */ - let t: Float64 = with_set_high_word(0.0, (n & !(0x000fffff >> k)) as u32); - n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); - if j < 0 { - n = -n; - } - p_h -= t; - } - - let t: Float64 = with_set_low_word(p_l + p_h, 0); - let u: Float64 = t * LG2_H; - let v: Float64 = (p_l - (t - p_h)) * LG2 + t * LG2_L; - let mut z: Float64 = u + v; - let w: Float64 = v - (z - u); - let t: Float64 = z * z; - let t1: Float64 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); - let r: Float64 = (z * t1) / (t1 - 2.0) - (w + z * w); - z = 1.0 - (r - z); - j = get_high_word(z) as Int; - j += n << 20; - - if (j >> 20) <= 0 { - /* subnormal output */ - z = scalbn(z, n); - } else { - z = with_set_high_word(z, j as u32); - } - - s * z -} - -#[cfg(test)] -mod tests { - use super::Float64; - - use ::core::f64::consts::{E, PI}; - use ::core::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; - use super::pow; - - const POS_ZERO: &[Float64] = &[0.0]; - const NEG_ZERO: &[Float64] = &[-0.0]; - const POS_ONE: &[Float64] = &[1.0]; - const NEG_ONE: &[Float64] = &[-1.0]; - const POS_FLOATS: &[Float64] = &[99.0 / 70.0, E, PI]; - const NEG_FLOATS: &[Float64] = &[-99.0 / 70.0, -E, -PI]; - const POS_SMALL_FLOATS: &[Float64] = &[(1.0 / 2.0), MIN_POSITIVE, EPSILON]; - const NEG_SMALL_FLOATS: &[Float64] = &[-(1.0 / 2.0), -MIN_POSITIVE, -EPSILON]; - const POS_EVENS: &[Float64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, MAX]; - const NEG_EVENS: &[Float64] = &[MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; - const POS_ODDS: &[Float64] = &[3.0, 7.0]; - const NEG_ODDS: &[Float64] = &[-7.0, -3.0]; - const NANS: &[Float64] = &[NAN]; - const POS_INF: &[Float64] = &[INFINITY]; - const NEG_INF: &[Float64] = &[NEG_INFINITY]; - - const ALL: &[&[Float64]] = &[ - POS_ZERO, - NEG_ZERO, - NANS, - NEG_SMALL_FLOATS, - POS_SMALL_FLOATS, - NEG_FLOATS, - POS_FLOATS, - NEG_EVENS, - POS_EVENS, - NEG_ODDS, - POS_ODDS, - NEG_INF, - POS_INF, - NEG_ONE, - POS_ONE, - ]; - const POS: &[&[Float64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; - const NEG: &[&[Float64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; - - fn pow_test(base: Float64, exponent: Float64, expected: Float64) { - let res = pow(base, exponent); - assert!( - if expected.is_nan() { - res.is_nan() - } else { - pow(base, exponent) == expected - }, - "{} ** {} was {} instead of {}", - base, - exponent, - res, - expected - ); - } - - fn test_sets_as_base(sets: &[&[Float64]], exponent: Float64, expected: Float64) { - sets.iter() - .for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); - } - - fn test_sets_as_exponent(base: Float64, sets: &[&[Float64]], expected: Float64) { - sets.iter() - .for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); - } - - fn test_sets(sets: &[&[Float64]], computed: &dyn Fn(Float64) -> Float64, expected: &dyn Fn(Float64) -> Float64) { - sets.iter().for_each(|s| { - s.iter().for_each(|val| { - let exp = expected(*val); - let res = computed(*val); - - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let exp = force_eval!(exp); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let res = force_eval!(res); - assert!( - if exp.is_nan() { - res.is_nan() - } else { - exp == res - }, - "test for {} was {} instead of {}", - val, - res, - exp - ); - }) - }); - } - - #[test] - fn zero_as_exponent() { - test_sets_as_base(ALL, 0.0, 1.0); - test_sets_as_base(ALL, -0.0, 1.0); - } - - #[test] - fn one_as_base() { - test_sets_as_exponent(1.0, ALL, 1.0); - } - - #[test] - fn nan_inputs() { - // NAN as the base: - // (NAN ^ anything *but 0* should be NAN) - test_sets_as_exponent(NAN, &ALL[2..], NAN); - - // NAN as the exponent: - // (anything *but 1* ^ NAN should be NAN) - test_sets_as_base(&ALL[..(ALL.len() - 2)], NAN, NAN); - } - - #[test] - fn infinity_as_base() { - // Positive Infinity as the base: - // (+Infinity ^ positive anything but 0 and NAN should be +Infinity) - test_sets_as_exponent(INFINITY, &POS[1..], INFINITY); - - // (+Infinity ^ negative anything except 0 and NAN should be 0.0) - test_sets_as_exponent(INFINITY, &NEG[1..], 0.0); - - // Negative Infinity as the base: - // (-Infinity ^ positive odd ints should be -Infinity) - test_sets_as_exponent(NEG_INFINITY, &[POS_ODDS], NEG_INFINITY); - - // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) - // We can lump in pos/neg odd ints here because they don't seem to - // cause panics (div by zero) in release mode (I think). - test_sets(ALL, &|v: Float64| pow(NEG_INFINITY, v), &|v: Float64| pow(-0.0, -v)); - } - - #[test] - fn infinity_as_exponent() { - // Positive/Negative base greater than 1: - // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes NAN as the base) - test_sets_as_base(&ALL[5..(ALL.len() - 2)], INFINITY, INFINITY); - - // (pos/neg > 1 ^ -Infinity should be 0.0) - test_sets_as_base(&ALL[5..ALL.len() - 2], NEG_INFINITY, 0.0); - - // Positive/Negative base less than 1: - let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; - - // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes NAN as the base) - test_sets_as_base(base_below_one, INFINITY, 0.0); - - // (pos/neg < 1 ^ -Infinity should be Infinity) - test_sets_as_base(base_below_one, NEG_INFINITY, INFINITY); - - // Positive/Negative 1 as the base: - // (pos/neg 1 ^ Infinity should be 1) - test_sets_as_base(&[NEG_ONE, POS_ONE], INFINITY, 1.0); - - // (pos/neg 1 ^ -Infinity should be 1) - test_sets_as_base(&[NEG_ONE, POS_ONE], NEG_INFINITY, 1.0); - } - - #[test] - fn zero_as_base() { - // Positive Zero as the base: - // (+0 ^ anything positive but 0 and NAN should be +0) - test_sets_as_exponent(0.0, &POS[1..], 0.0); - - // (+0 ^ anything negative but 0 and NAN should be Infinity) - // (this should panic because we're dividing by zero) - test_sets_as_exponent(0.0, &NEG[1..], INFINITY); - - // Negative Zero as the base: - // (-0 ^ anything positive but 0, NAN, and odd ints should be +0) - test_sets_as_exponent(-0.0, &POS[3..], 0.0); - - // (-0 ^ anything negative but 0, NAN, and odd ints should be Infinity) - // (should panic because of divide by zero) - test_sets_as_exponent(-0.0, &NEG[3..], INFINITY); - - // (-0 ^ positive odd ints should be -0) - test_sets_as_exponent(-0.0, &[POS_ODDS], -0.0); - - // (-0 ^ negative odd ints should be -Infinity) - // (should panic because of divide by zero) - test_sets_as_exponent(-0.0, &[NEG_ODDS], NEG_INFINITY); - } - - #[test] - fn special_cases() { - // One as the exponent: - // (anything ^ 1 should be anything - i.e. the base) - test_sets(ALL, &|v: Float64| pow(v, 1.0), &|v: Float64| v); - - // Negative One as the exponent: - // (anything ^ -1 should be 1/anything) - test_sets(ALL, &|v: Float64| pow(v, -1.0), &|v: Float64| 1.0 / v); - - // Factoring -1 out: - // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS] - .iter() - .for_each(|int_set| { - int_set.iter().for_each(|int| { - test_sets(ALL, &|v: Float64| pow(-v, *int), &|v: Float64| { - pow(-1.0, *int) * pow(v, *int) - }); - }) - }); - - // Negative base (imaginary results): - // (-anything except 0 and Infinity ^ non-integer should be NAN) - NEG[1..(NEG.len() - 1)].iter().for_each(|set| { - set.iter().for_each(|val| { - test_sets(&ALL[3..7], &|v: Float64| pow(*val, v), &|_| NAN); - }) - }); - } - - #[test] - fn normal_cases() { - assert_eq!(pow(2.0, 20.0), (1 << 20) as Float64); - assert_eq!(pow(-1.0, 9.0), -1.0); - assert!(pow(-1.0, 2.2).is_nan()); - assert!(pow(-1.0, -1.14).is_nan()); - } -} diff --git a/helpers/l2math/core/powf.rs b/helpers/l2math/core/powf.rs deleted file mode 100644 index 24c8bc8..0000000 --- a/helpers/l2math/core/powf.rs +++ /dev/null @@ -1,340 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -use crate::{Float32, Int}; - -use super::{fabsf, scalbnf, sqrtf}; - -consts!{ -const BP: [Float32; 2] = [1.0, 1.5]; -const DP_H: [Float32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ -const DP_L: [Float32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ -const TWO24: Float32 = 16777216.0; /* 0x4b800000 */ -const HUGE: Float32 = 1.0e30; -const TINY: Float32 = 1.0e-30; -const L1: Float32 = 6.0000002384e-01; /* 0x3f19999a */ -const L2: Float32 = 4.2857143283e-01; /* 0x3edb6db7 */ -const L3: Float32 = 3.3333334327e-01; /* 0x3eaaaaab */ -const L4: Float32 = 2.7272811532e-01; /* 0x3e8ba305 */ -const L5: Float32 = 2.3066075146e-01; /* 0x3e6c3255 */ -const L6: Float32 = 2.0697501302e-01; /* 0x3e53f142 */ -const P1: Float32 = 1.6666667163e-01; /* 0x3e2aaaab */ -const P2: Float32 = -2.7777778450e-03; /* 0xbb360b61 */ -const P3: Float32 = 6.6137559770e-05; /* 0x388ab355 */ -const P4: Float32 = -1.6533901999e-06; /* 0xb5ddea0e */ -const P5: Float32 = 4.1381369442e-08; /* 0x3331bb4c */ -const LG2: Float32 = 6.9314718246e-01; /* 0x3f317218 */ -const LG2_H: Float32 = 6.93145752e-01; /* 0x3f317200 */ -const LG2_L: Float32 = 1.42860654e-06; /* 0x35bfbe8c */ -const OVT: Float32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ -const CP: Float32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ -const CP_H: Float32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ -const CP_L: Float32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ -const IVLN2: Float32 = 1.4426950216e+00; -const IVLN2_H: Float32 = 1.4426879883e+00; -const IVLN2_L: Float32 = 7.0526075433e-06; -} - -/// Returns `x` raised to the power `y`. -#[export_name = "__l2math_powf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -#[allow(clippy::comparison_chain)] -pub extern "C" fn powf(x: Float32, y: Float32) -> Float32 { - let mut z: Float32; - let mut ax: Float32; - let z_h: Float32; - let z_l: Float32; - let mut p_h: Float32; - let mut p_l: Float32; - let mut t1: Float32; - let t2: Float32; - let mut r: Float32; - let s: Float32; - let mut sn: Float32; - let mut t: Float32; - let mut u: Float32; - let mut v: Float32; - let mut w: Float32; - let mut j: Int; - let mut k: Int; - let mut yisint: Int; - let mut n: Int; - let mut ix: Int; - let mut is: Int; - let hx: Int = x.to_bits() as Int; - let hy: Int = y.to_bits() as Int; - ix = hx & 0x7fffffff; - let iy: Int = hy & 0x7fffffff; - - /* x**0 = 1, even if x is NaN */ - if iy == 0 { - return 1.0; - } - - /* 1**y = 1, even if y is NaN */ - if hx == 0x3f800000 { - return 1.0; - } - - /* NaN if either arg is NaN */ - if ix > 0x7f800000 || iy > 0x7f800000 { - return x + y; - } - - /* determine if y is an odd int when x < 0 - * yisint = 0 ... y is not an integer - * yisint = 1 ... y is an odd int - * yisint = 2 ... y is an even int - */ - yisint = 0; - if hx < 0 { - if iy >= 0x4b800000 { - yisint = 2; /* even integer y */ - } else if iy >= 0x3f800000 { - k = (iy >> 23) - 0x7f; /* exponent */ - j = iy >> (23 - k); - if (j << (23 - k)) == iy { - yisint = 2 - (j & 1); - } - } - } - - /* special value of y */ - if iy == 0x7f800000 { - /* y is +-inf */ - if ix == 0x3f800000 { - /* (-1)**+-inf is 1 */ - return 1.0; - } else if ix > 0x3f800000 { - /* (|x|>1)**+-inf = inf,0 */ - return if hy >= 0 { y } else { 0.0 }; - } else { - /* (|x|<1)**+-inf = 0,inf */ - return if hy >= 0 { 0.0 } else { -y }; - } - } - if iy == 0x3f800000 { - /* y is +-1 */ - return if hy >= 0 { x } else { 1.0 / x }; - } - - if hy == 0x40000000 { - /* y is 2 */ - return x * x; - } - - if hy == 0x3f000000 - /* y is 0.5 */ - && hx >= 0 - { - /* x >= +0 */ - return sqrtf(x); - } - - ax = fabsf(x); - /* special value of x */ - if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { - /* x is +-0,+-inf,+-1 */ - z = ax; - if hy < 0 { - /* z = (1/|x|) */ - z = 1.0 / z; - } - - if hx < 0 { - if ((ix - 0x3f800000) | yisint) == 0 { - z = (z - z) / (z - z); /* (-1)**non-int is NaN */ - } else if yisint == 1 { - z = -z; /* (x<0)**odd = -(|x|**odd) */ - } - } - return z; - } - - sn = 1.0; /* sign of result */ - if hx < 0 { - if yisint == 0 { - /* (x<0)**(non-int) is NaN */ - return (x - x) / (x - x); - } - - if yisint == 1 { - /* (x<0)**(odd int) */ - sn = -1.0; - } - } - - /* |y| is HUGE */ - if iy > 0x4d000000 { - /* if |y| > 2**27 */ - /* over/underflow if x is not close to one */ - if ix < 0x3f7ffff8 { - return if hy < 0 { - sn * HUGE * HUGE - } else { - sn * TINY * TINY - }; - } - - if ix > 0x3f800007 { - return if hy > 0 { - sn * HUGE * HUGE - } else { - sn * TINY * TINY - }; - } - - /* now |1-x| is TINY <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ - t = ax - 1.; /* t has 20 trailing zeros */ - w = (t * t) * (0.5 - t * (0.333_333_34 - t * 0.25)); - u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ - v = t * IVLN2_L - w * IVLN2; - t1 = u + v; - is = t1.to_bits() as Int; - t1 = Float32::from_bits(is as u32 & 0xfffff000); - t2 = v - (t1 - u); - } else { - let mut s2: Float32; - let mut s_h: Float32; - - let mut t_h: Float32; - let mut t_l: Float32; - - n = 0; - /* take care subnormal number */ - if ix < 0x00800000 { - ax *= TWO24; - n -= 24; - ix = ax.to_bits() as Int; - } - n += ((ix) >> 23) - 0x7f; - j = ix & 0x007fffff; - /* determine interval */ - ix = j | 0x3f800000; /* normalize ix */ - if j <= 0x1cc471 { - /* |x|> 1) & 0xfffff000) | 0x20000000) as Int; - t_h = Float32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); - t_l = ax - (t_h - i!(BP, k as usize)); - let s_l: Float32 = v * ((u - s_h * t_h) - s_h * t_l); - /* compute log(ax) */ - s2 = s * s; - r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); - r += s_l * (s_h + s); - s2 = s_h * s_h; - t_h = 3.0 + s2 + r; - is = t_h.to_bits() as Int; - t_h = Float32::from_bits(is as u32 & 0xfffff000); - t_l = r - ((t_h - 3.0) - s2); - /* u+v = s*(1+...) */ - u = s_h * t_h; - v = s_l * t_h + t_l * s; - /* 2/(3log2)*(s+...) */ - p_h = u + v; - is = p_h.to_bits() as Int; - p_h = Float32::from_bits(is as u32 & 0xfffff000); - p_l = v - (p_h - u); - z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ - z_l = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); - /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ - t = n as Float32; - t1 = ((z_h + z_l) + i!(DP_H, k as usize)) + t; - is = t1.to_bits() as Int; - t1 = Float32::from_bits(is as u32 & 0xfffff000); - t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); - }; - - /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ - is = y.to_bits() as Int; - let y1: Float32 = Float32::from_bits(is as u32 & 0xfffff000); - p_l = (y - y1) * t1 + y * t2; - p_h = y1 * t1; - z = p_l + p_h; - j = z.to_bits() as Int; - if j > 0x43000000 { - /* if z > 128 */ - return sn * HUGE * HUGE; /* overflow */ - } else if j == 0x43000000 { - /* if z == 128 */ - if p_l + OVT > z - p_h { - return sn * HUGE * HUGE; /* overflow */ - } - } else if - ((j & 0x7fffffff) > 0x43160000) || - (j as u32 == 0xc3160000 - /* z == -150 */ - && p_l <= z - p_h) - { - return sn * TINY * TINY; /* underflow */ - } - - /* - * compute 2**(p_h+p_l) - */ - let i: Int = j & 0x7fffffff; - k = (i >> 23) - 0x7f; - n = 0; - if i > 0x3f000000 { - /* if |z| > 0.5, set n = [z+0.5] */ - n = j + (0x00800000 >> (k + 1)); - k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */ - t = Float32::from_bits(n as u32 & !(0x007fffff >> k)); - n = ((n & 0x007fffff) | 0x00800000) >> (23 - k); - if j < 0 { - n = -n; - } - p_h -= t; - } - t = p_l + p_h; - is = t.to_bits() as Int; - t = Float32::from_bits(is as u32 & 0xffff8000); - u = t * LG2_H; - v = (p_l - (t - p_h)) * LG2 + t * LG2_L; - z = u + v; - w = v - (z - u); - t = z * z; - t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); - r = (z * t1) / (t1 - 2.0) - (w + z * w); - z = 1.0 - (r - z); - j = z.to_bits() as Int; - j += n << 23; - if (j >> 23) <= 0 { - /* subnormal output */ - z = scalbnf(z, n); - } else { - z = Float32::from_bits(j as u32); - } - sn * z -} diff --git a/helpers/l2math/core/rem_pio2.rs b/helpers/l2math/core/rem_pio2.rs deleted file mode 100644 index 2aad5a0..0000000 --- a/helpers/l2math/core/rem_pio2.rs +++ /dev/null @@ -1,235 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunPro, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== -// -// Optimized by Bruce D. Evans. - -use crate::{Float64, Int}; - -use super::rem_pio2_large; - -consts!{ -const EPS: Float64 = 2.2204460492503131e-16; -} - -// TODO: Support FLT_EVAL_METHOD? - -consts!{ -const TO_INT: Float64 = 1.5 / EPS; -// 53 bits of 2/pi -const INV_PIO2: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -// first 33 bits of pi/2 -const PIO2_1: Float64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ -// pi/2 - PIO2_1 -const PIO2_1T: Float64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ -// second 33 bits of pi/2 -const PIO2_2: Float64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ -// pi/2 - (PIO2_1+PIO2_2) -const PIO2_2T: Float64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ -// third 33 bits of pi/2 -const PIO2_3: Float64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ -// pi/2 - (PIO2_1+PIO2_2+PIO2_3) -const PIO2_3T: Float64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ -} - -/// return the remainder of x rem pi/2 in y[0]+y[1] -/// use rem_pio2_large() for large x -/// -/// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn rem_pio2(x: Float64) -> (Int, Float64, Float64) { - let x1p24 = Float64::from_bits(0x4170000000000000); - - let sign = (Float64::to_bits(x) >> 63) as Int; - let ix = (Float64::to_bits(x) >> 32) as u32 & 0x7fffffff; - - fn medium(x: Float64, ix: u32) -> (Int, Float64, Float64) { - /* rint(x/(pi/2)), Assume round-to-nearest. */ - let tmp = x as Float64 * INV_PIO2 + TO_INT; - // force rounding of tmp to it's storage format on x87 to avoid - // excess precision issues. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let tmp = force_eval!(tmp); - let f_n = tmp - TO_INT; - let n = f_n as Int; - let mut r = x - f_n * PIO2_1; - let mut w = f_n * PIO2_1T; /* 1st round, good to 85 bits */ - let mut y0 = r - w; - let ui = Float64::to_bits(y0); - let ey = (ui >> 52) as Int & 0x7ff; - let ex = (ix >> 20) as Int; - if ex - ey > 16 { - /* 2nd round, good to 118 bits */ - let t = r; - w = f_n * PIO2_2; - r = t - w; - w = f_n * PIO2_2T - ((t - r) - w); - y0 = r - w; - let ey = (Float64::to_bits(y0) >> 52) as Int & 0x7ff; - if ex - ey > 49 { - /* 3rd round, good to 151 bits, covers all cases */ - let t = r; - w = f_n * PIO2_3; - r = t - w; - w = f_n * PIO2_3T - ((t - r) - w); - y0 = r - w; - } - } - let y1 = (r - y0) - w; - (n, y0, y1) - } - - if ix <= 0x400f6a7a { - /* |x| ~<= 5pi/4 */ - if (ix & 0xfffff) == 0x921fb { - /* |x| ~= pi/2 or 2pi/2 */ - return medium(x, ix); /* cancellation -- use medium case */ - } - if ix <= 0x4002d97c { - /* |x| ~<= 3pi/4 */ - if sign == 0 { - let z = x - PIO2_1; /* one round good to 85 bits */ - let y0 = z - PIO2_1T; - let y1 = (z - y0) - PIO2_1T; - return (1, y0, y1); - } else { - let z = x + PIO2_1; - let y0 = z + PIO2_1T; - let y1 = (z - y0) + PIO2_1T; - return (-1, y0, y1); - } - } else if sign == 0 { - let z = x - 2.0 * PIO2_1; - let y0 = z - 2.0 * PIO2_1T; - let y1 = (z - y0) - 2.0 * PIO2_1T; - return (2, y0, y1); - } else { - let z = x + 2.0 * PIO2_1; - let y0 = z + 2.0 * PIO2_1T; - let y1 = (z - y0) + 2.0 * PIO2_1T; - return (-2, y0, y1); - } - } - if ix <= 0x401c463b { - /* |x| ~<= 9pi/4 */ - if ix <= 0x4015fdbc { - /* |x| ~<= 7pi/4 */ - if ix == 0x4012d97c { - /* |x| ~= 3pi/2 */ - return medium(x, ix); - } - if sign == 0 { - let z = x - 3.0 * PIO2_1; - let y0 = z - 3.0 * PIO2_1T; - let y1 = (z - y0) - 3.0 * PIO2_1T; - return (3, y0, y1); - } else { - let z = x + 3.0 * PIO2_1; - let y0 = z + 3.0 * PIO2_1T; - let y1 = (z - y0) + 3.0 * PIO2_1T; - return (-3, y0, y1); - } - } else { - if ix == 0x401921fb { - /* |x| ~= 4pi/2 */ - return medium(x, ix); - } - if sign == 0 { - let z = x - 4.0 * PIO2_1; - let y0 = z - 4.0 * PIO2_1T; - let y1 = (z - y0) - 4.0 * PIO2_1T; - return (4, y0, y1); - } else { - let z = x + 4.0 * PIO2_1; - let y0 = z + 4.0 * PIO2_1T; - let y1 = (z - y0) + 4.0 * PIO2_1T; - return (-4, y0, y1); - } - } - } - if ix < 0x413921fb { - /* |x| ~< 2^20*(pi/2), medium size */ - return medium(x, ix); - } - /* - * all other (large) arguments - */ - if ix >= 0x7ff00000 { - /* x is inf or NaN */ - let y0 = x - x; - let y1 = y0; - return (0, y0, y1); - } - /* set z = scalbn(|x|,-ilogb(x)+23) */ - let mut ui = Float64::to_bits(x); - ui &= (!1) >> 12; - ui |= (0x3ff + 23) << 52; - let mut z = Float64::from_bits(ui); - let mut tx = [0.0; 3]; - for i in 0..2 { - i!(tx,i, =, z as Int as Float64); - z = (z - i!(tx, i)) * x1p24; - } - i!(tx,2, =, z); - /* skip zero terms, first term is non-zero */ - let mut i = 2; - while i != 0 && i!(tx, i) == 0.0 { - i -= 1; - } - let mut ty = [0.0; 3]; - let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix as Int) >> 20) - (0x3ff + 23), 1); - if sign != 0 { - return (-n, -i!(ty, 0), -i!(ty, 1)); - } - (n, i!(ty, 0), i!(ty, 1)) -} - -#[cfg(test)] -mod tests { - use super::rem_pio2; - - #[test] - fn test_near_pi() { - let arg = 3.141592025756836; - let arg = force_eval!(arg); - assert_eq!( - rem_pio2(arg), - (2, -6.278329573009626e-7, -2.1125998133974653e-23) - ); - let arg = 3.141592033207416; - let arg = force_eval!(arg); - assert_eq!( - rem_pio2(arg), - (2, -6.20382377148128e-7, -2.1125998133974653e-23) - ); - let arg = 3.141592144966125; - let arg = force_eval!(arg); - assert_eq!( - rem_pio2(arg), - (2, -5.086236681942706e-7, -2.1125998133974653e-23) - ); - let arg = 3.141592979431152; - let arg = force_eval!(arg); - assert_eq!( - rem_pio2(arg), - (2, 3.2584135866119817e-7, -2.1125998133974653e-23) - ); - } - - #[test] - fn test_overflow_b9b847() { - let _ = rem_pio2(-3054214.5490637687); - } - - #[test] - fn test_overflow_4747b9() { - let _ = rem_pio2(917340800458.2274); - } -} diff --git a/helpers/l2math/core/rem_pio2_large.rs b/helpers/l2math/core/rem_pio2_large.rs deleted file mode 100644 index db432df..0000000 --- a/helpers/l2math/core/rem_pio2_large.rs +++ /dev/null @@ -1,473 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ - -use crate::{Float64, Int}; - -use super::floor; -use super::scalbn; - -// initial value for jk -const INIT_JK: [usize; 4] = [3, 4, 4, 6]; - -// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi -// -// integer array, contains the (24*i)-th to (24*i+23)-th -// bit of 2/pi after binary point. The corresponding -// floating value is -// -// ipio2[i] * 2^(-24(i+1)). -// -// NB: This table must have at least (e0-3)/24 + jk terms. -// For quad precision (e0 <= 16360, jk = 6), this is 686. -#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] -const IPIO2: [Int; 66] = [ - 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, - 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, - 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, - 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, - 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, - 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, - 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, - 0x73A8C9, 0x60E27B, 0xC08C6B, -]; - -#[cfg(target_pointer_width = "64")] -const IPIO2: [Int; 690] = [ - 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, - 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, - 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, - 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, - 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, - 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, - 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, - 0x73A8C9, 0x60E27B, 0xC08C6B, 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, - 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, 0xDE4F98, 0x327DBB, 0xC33D26, - 0xEF6B1E, 0x5EF89F, 0x3A1F35, 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, - 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, 0x467D86, 0x2D71E3, 0x9AC69B, - 0x006233, 0x7CD2B4, 0x97A7B4, 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, - 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, 0xCB2324, 0x778AD6, 0x23545A, - 0xB91F00, 0x1B0AF1, 0xDFCE19, 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, - 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, 0xDE3B58, 0x929BDE, 0x2822D2, - 0xE88628, 0x4D58E2, 0x32CAC6, 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, - 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, 0xD36710, 0xD8DDAA, 0x425FAE, - 0xCE616A, 0xA4280A, 0xB499D3, 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, - 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, 0x36D9CA, 0xD2A828, 0x8D61C2, - 0x77C912, 0x142604, 0x9B4612, 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, - 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, 0xC3E7B3, 0x28F8C7, 0x940593, - 0x3E71C1, 0xB3092E, 0xF3450B, 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, - 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, 0x9794E8, 0x84E6E2, 0x973199, - 0x6BED88, 0x365F5F, 0x0EFDBB, 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, - 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, 0x90AA47, 0x02E774, 0x24D6BD, - 0xA67DF7, 0x72486E, 0xEF169F, 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, - 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, 0x10D86D, 0x324832, 0x754C5B, - 0xD4714E, 0x6E5445, 0xC1090B, 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, - 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, 0x6AE290, 0x89D988, 0x50722C, - 0xBEA404, 0x940777, 0x7030F3, 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, - 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, 0x3BDF08, 0x2B3715, 0xA0805C, - 0x93805A, 0x921110, 0xD8E80F, 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, - 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, 0xAA140A, 0x2F2689, 0x768364, - 0x333B09, 0x1A940E, 0xAA3A51, 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, - 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, 0x5BC3D8, 0xC492F5, 0x4BADC6, - 0xA5CA4E, 0xCD37A7, 0x36A9E6, 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, - 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, 0x306529, 0xBF5657, 0x3AFF47, - 0xB9F96A, 0xF3BE75, 0xDF9328, 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, - 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, 0xA8654F, 0xA5C1D2, 0x0F3F0B, - 0xCD785B, 0x76F923, 0x048B7B, 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, - 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, 0xDA4886, 0xA05DF7, 0xF480C6, - 0x2FF0AC, 0x9AECDD, 0xBC5C3F, 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, - 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, 0x2A1216, 0x2DB7DC, 0xFDE5FA, - 0xFEDB89, 0xFDBE89, 0x6C76E4, 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, - 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, 0x48D784, 0x16DF30, 0x432DC7, - 0x356125, 0xCE70C9, 0xB8CB30, 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, - 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, 0xC4F133, 0x5F6E13, 0xE4305D, - 0xA92E85, 0xC3B21D, 0x3632A1, 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, - 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, 0xCBDA11, 0xD0BE7D, 0xC1DB9B, - 0xBD17AB, 0x81A2CA, 0x5C6A08, 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, - 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, 0x4F6A68, 0xA82A4A, 0x5AC44F, - 0xBCF82D, 0x985AD7, 0x95C7F4, 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, - 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, 0xD0C0B2, 0x485551, 0x0EFB1E, - 0xC37295, 0x3B06A3, 0x3540C0, 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, - 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, 0x3C3ABA, 0x461846, 0x5F7555, - 0xF5BDD2, 0xC6926E, 0x5D2EAC, 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, - 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, 0x745D7C, 0xB2AD6B, 0x9D6ECD, - 0x7B723E, 0x6A11C6, 0xA9CFF7, 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, - 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, 0xBEFDFD, 0xEF4556, 0x367ED9, - 0x13D9EC, 0xB9BA8B, 0xFC97C4, 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, - 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, 0x9C2A3E, 0xCC5F11, 0x4A0BFD, - 0xFBF4E1, 0x6D3B8E, 0x2C86E2, 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, - 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, 0xCC2254, 0xDC552A, 0xD6C6C0, - 0x96190B, 0xB8701A, 0x649569, 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, - 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, 0x9B5861, 0xBC57E1, 0xC68351, - 0x103ED8, 0x4871DD, 0xDD1C2D, 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, - 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, 0x382682, 0x9BE7CA, 0xA40D51, - 0xB13399, 0x0ED7A9, 0x480569, 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, - 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, 0x5FD45E, 0xA4677B, 0x7AACBA, - 0xA2F655, 0x23882B, 0x55BA41, 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, - 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, 0xAE5ADB, 0x86C547, 0x624385, - 0x3B8621, 0x94792C, 0x876110, 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, - 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, 0xB1933D, 0x0B7CBD, 0xDC51A4, - 0x63DD27, 0xDDE169, 0x19949A, 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, - 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, 0x4D7E6F, 0x5119A5, 0xABF9B5, - 0xD6DF82, 0x61DD96, 0x023616, 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, - 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, -]; - -consts!{ -const PIO2: [Float64; 8] = [ - 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ - 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ - 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ - 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ - 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ - 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ - 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ - 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ -]; -} - -// fn rem_pio2_large(x : &[Float64], y : &mut [Float64], e0 : Int, prec : usize) -> Int -// -// Input parameters: -// x[] The input value (must be positive) is broken into nx -// pieces of 24-bit integers in double precision format. -// x[i] will be the i-th 24 bit of x. The scaled exponent -// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 -// match x's up to 24 bits. -// -// Example of breaking a double positive z into x[0]+x[1]+x[2]: -// e0 = ilogb(z)-23 -// z = scalbn(z,-e0) -// for i = 0,1,2 -// x[i] = floor(z) -// z = (z-x[i])*2**24 -// -// y[] ouput result in an array of double precision numbers. -// The dimension of y[] is: -// 24-bit precision 1 -// 53-bit precision 2 -// 64-bit precision 2 -// 113-bit precision 3 -// The actual value is the sum of them. Thus for 113-bit -// precison, one may have to do something like: -// -// long double t,w,r_head, r_tail; -// t = (long double)y[2] + (long double)y[1]; -// w = (long double)y[0]; -// r_head = t+w; -// r_tail = w - (r_head - t); -// -// e0 The exponent of x[0]. Must be <= 16360 or you need to -// expand the ipio2 table. -// -// prec an integer indicating the precision: -// 0 24 bits (single) -// 1 53 bits (double) -// 2 64 bits (extended) -// 3 113 bits (quad) -// -// Here is the description of some local variables: -// -// jk jk+1 is the initial number of terms of ipio2[] needed -// in the computation. The minimum and recommended value -// for jk is 3,4,4,6 for single, double, extended, and quad. -// jk+1 must be 2 larger than you might expect so that our -// recomputation test works. (Up to 24 bits in the integer -// part (the 24 bits of it that we compute) and 23 bits in -// the fraction part may be lost to cancelation before we -// recompute.) -// -// jz local integer variable indicating the number of -// terms of ipio2[] used. -// -// jx nx - 1 -// -// jv index for pointing to the suitable ipio2[] for the -// computation. In general, we want -// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 -// is an integer. Thus -// e0-3-24*jv >= 0 or (e0-3)/24 >= jv -// Hence jv = max(0,(e0-3)/24). -// -// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. -// -// q[] double array with integral value, representing the -// 24-bits chunk of the product of x and 2/pi. -// -// q0 the corresponding exponent of q[0]. Note that the -// exponent for q[i] would be q0-24*i. -// -// PIo2[] double precision array, obtained by cutting pi/2 -// into 24 bits chunks. -// -// f[] ipio2[] in floating point -// -// iq[] integer array by breaking up q[] in 24-bits chunk. -// -// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] -// -// ih integer. If >0 it indicates q[] is >= 0.5, hence -// it also indicates the *sign* of the result. - -/// Return the last three digits of N with y = x - N*pi/2 -/// so that |y| < pi/2. -/// -/// The method is to compute the integer (mod 8) and fraction parts of -/// (2/pi)*x without doing the full multiplication. In general we -/// skip the part of the product that are known to be a huge integer ( -/// more accurately, = 0 mod 8 ). Thus the number of operations are -/// independent of the exponent of the input. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn rem_pio2_large(x: &[Float64], y: &mut [Float64], e0: Int, prec: usize) -> Int { - let x1p24 = Float64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 - let x1p_24 = Float64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) - - #[cfg(all(target_pointer_width = "64", feature = "checked"))] - assert!(e0 <= 16360); - - let nx = x.len(); - - let mut fw: Float64; - let mut n: Int; - let mut ih: Int; - let mut z: Float64; - let mut f: [Float64; 20] = [0.; 20]; - let mut fq: [Float64; 20] = [0.; 20]; - let mut q: [Float64; 20] = [0.; 20]; - let mut iq: [Int; 20] = [0; 20]; - - /* initialize jk*/ - let jk = i!(INIT_JK, prec); - let jp = jk; - - /* determine jx,jv,q0, note that 3>q0 */ - let jx = nx - 1; - let mut jv = div!(e0 - 3, 24); - if jv < 0 { - jv = 0; - } - let mut q0 = e0 - 24 * (jv + 1); - let jv = jv as usize; - - /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ - let mut j = (jv as Int) - (jx as Int); - let m = jx + jk; - for i in 0..=m { - i!(f, i, =, if j < 0 { - 0. - } else { - i!(IPIO2, j as usize) as Float64 - }); - j += 1; - } - - /* compute q[0],q[1],...q[jk] */ - for i in 0..=jk { - fw = 0f64; - for j in 0..=jx { - fw += i!(x, j) * i!(f, jx + i - j); - } - i!(q, i, =, fw); - } - - let mut jz = jk; - - 'recompute: loop { - /* distill q[] into iq[] reversingly */ - let mut i = 0; - z = i!(q, jz); - for j in (1..=jz).rev() { - fw = (x1p_24 * z) as Int as Float64; - i!(iq, i as usize, =, (z - x1p24 * fw) as Int); - z = i!(q, j - 1) + fw; - i += 1; - } - - /* compute n */ - z = scalbn(z, q0); /* actual value of z */ - z -= 8.0 * floor(z * 0.125); /* trim off integer >= 8 */ - n = z as Int; - z -= n as Float64; - ih = 0; - if q0 > 0 { - /* need iq[jz-1] to determine n */ - i = i!(iq, jz - 1) >> (24 - q0); - n += i; - i!(iq, jz - 1, -=, i << (24 - q0)); - ih = i!(iq, jz - 1) >> (23 - q0); - } else if q0 == 0 { - ih = i!(iq, jz - 1) >> 23; - } else if z >= 0.5 { - ih = 2; - } - - if ih > 0 { - /* q > 0.5 */ - n += 1; - let mut carry = 0; - for i in 0..jz { - /* compute 1-q */ - let j = i!(iq, i); - if carry == 0 { - if j != 0 { - carry = 1; - i!(iq, i, =, 0x1000000 - j); - } - } else { - i!(iq, i, =, 0xffffff - j); - } - } - if q0 > 0 { - /* rare case: chance is 1 in 12 */ - match q0 { - 1 => { - i!(iq, jz - 1, &=, 0x7fffff); - } - 2 => { - i!(iq, jz - 1, &=, 0x3fffff); - } - _ => {} - } - } - if ih == 2 { - z = 1. - z; - if carry != 0 { - z -= scalbn(1., q0); - } - } - } - - /* check if recomputation is needed */ - if z == 0. { - let mut j = 0; - for i in (jk..=jz - 1).rev() { - j |= i!(iq, i); - } - if j == 0 { - /* need recomputation */ - let mut k = 1; - while i!(iq, jk - k, ==, 0) { - k += 1; /* k = no. of terms needed */ - } - - for i in (jz + 1)..=(jz + k) { - /* add q[jz+1] to q[jz+k] */ - i!(f, jx + i, =, i!(IPIO2, jv + i) as Float64); - fw = 0f64; - for j in 0..=jx { - fw += i!(x, j) * i!(f, jx + i - j); - } - i!(q, i, =, fw); - } - jz += k; - continue 'recompute; - } - } - - break; - } - - /* chop off zero terms */ - if z == 0. { - jz -= 1; - q0 -= 24; - while i!(iq, jz) == 0 { - jz -= 1; - q0 -= 24; - } - } else { - /* break z into 24-bit if necessary */ - z = scalbn(z, -q0); - if z >= x1p24 { - fw = (x1p_24 * z) as Int as Float64; - i!(iq, jz, =, (z - x1p24 * fw) as Int); - jz += 1; - q0 += 24; - i!(iq, jz, =, fw as Int); - } else { - i!(iq, jz, =, z as Int); - } - } - - /* convert integer "bit" chunk to floating-point value */ - fw = scalbn(1., q0); - for i in (0..=jz).rev() { - i!(q, i, =, fw * (i!(iq, i) as Float64)); - fw *= x1p_24; - } - - /* compute PIo2[0,...,jp]*q[jz,...,0] */ - for i in (0..=jz).rev() { - fw = 0f64; - let mut k = 0; - while (k <= jp) && (k <= jz - i) { - fw += i!(PIO2, k) * i!(q, i + k); - k += 1; - } - i!(fq, jz - i, =, fw); - } - - /* compress fq[] into y[] */ - match prec { - 0 => { - fw = 0f64; - for i in (0..=jz).rev() { - fw += i!(fq, i); - } - i!(y, 0, =, if ih == 0 { fw } else { -fw }); - } - 1 | 2 => { - fw = 0f64; - for i in (0..=jz).rev() { - fw += i!(fq, i); - } - // TODO: drop excess precision here once double_t is used - fw = fw as Float64; - i!(y, 0, =, if ih == 0 { fw } else { -fw }); - fw = i!(fq, 0) - fw; - for i in 1..=jz { - fw += i!(fq, i); - } - i!(y, 1, =, if ih == 0 { fw } else { -fw }); - } - 3 => { - /* painful */ - for i in (1..=jz).rev() { - fw = i!(fq, i - 1) + i!(fq, i); - i!(fq, i, +=, i!(fq, i - 1) - fw); - i!(fq, i - 1, =, fw); - } - for i in (2..=jz).rev() { - fw = i!(fq, i - 1) + i!(fq, i); - i!(fq, i, +=, i!(fq, i - 1) - fw); - i!(fq, i - 1, =, fw); - } - fw = 0f64; - for i in (2..=jz).rev() { - fw += i!(fq, i); - } - if ih == 0 { - i!(y, 0, =, i!(fq, 0)); - i!(y, 1, =, i!(fq, 1)); - i!(y, 2, =, fw); - } else { - i!(y, 0, =, -i!(fq, 0)); - i!(y, 1, =, -i!(fq, 1)); - i!(y, 2, =, -fw); - } - } - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => {} - } - n & 7 -} diff --git a/helpers/l2math/core/rem_pio2f.rs b/helpers/l2math/core/rem_pio2f.rs deleted file mode 100644 index 814be4a..0000000 --- a/helpers/l2math/core/rem_pio2f.rs +++ /dev/null @@ -1,69 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Debugged and optimized by Bruce D. Evans. -*/ - -use crate::{Float64, Float32, Int}; - -use super::rem_pio2_large; - -const TOINT: Float64 = 1.5 / Float64::EPSILON; - -consts!{ -// 53 bits of 2/pi -const INV_PIO2: Float64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -// first 25 bits of pi/2 -const PIO2_1: Float64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ -// pi/2 - pio2_1 -const PIO2_1T: Float64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ -} - -/// Return the remainder of x rem pi/2 in *y -/// -/// use double precision for everything except passing x -/// use __rem_pio2_large() for large x -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub(crate) fn rem_pio2f(x: Float32) -> (Int, Float64) { - let x64 = x as Float64; - - let mut tx: [Float64; 1] = [0.]; - let mut ty: [Float64; 1] = [0.]; - - let ix = x.to_bits() & 0x7fffffff; - /* 25+53 bit pi is good enough for medium size */ - if ix < 0x4dc90fdb { - /* |x| ~< 2^28*(pi/2), medium size */ - /* Use a specialized rint() to get fn. Assume round-to-nearest. */ - let tmp = x64 * INV_PIO2 + TOINT; - // force rounding of tmp to it's storage format on x87 to avoid - // excess precision issues. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let tmp = force_eval!(tmp); - let f_n = tmp - TOINT; - return (f_n as Int, x64 - f_n * PIO2_1 - f_n * PIO2_1T); - } - if ix >= 0x7f800000 { - /* x is inf or NaN */ - return (0, x64 - x64); - } - /* scale x into [2^23, 2^24-1] */ - let sign = (x.to_bits() >> 31) != 0; - let e0 = ((ix >> 23) - (0x7f + 23)) as Int; /* e0 = ilogb(|x|)-23, positive */ - tx[0] = Float32::from_bits(ix - (e0 << 23) as u32) as Float64; - let n = rem_pio2_large(&tx, &mut ty, e0, 0); - if sign { - return (-n, -ty[0]); - } - (n, ty[0]) -} diff --git a/helpers/l2math/core/remainder.rs b/helpers/l2math/core/remainder.rs deleted file mode 100644 index ac2c5f5..0000000 --- a/helpers/l2math/core/remainder.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::Float64; - -/// Returns the remainder of `x/y`. -#[inline] -#[export_name = "__l2math_remainder"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn remainder(x: Float64, y: Float64) -> Float64 { - super::remquo(x, y).0 -} diff --git a/helpers/l2math/core/remainderf.rs b/helpers/l2math/core/remainderf.rs deleted file mode 100644 index c5789f2..0000000 --- a/helpers/l2math/core/remainderf.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::Float32; - -/// Returns the remainder of `x/y`. -#[inline] -#[export_name = "__l2math_remainderf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn remainderf(x: Float32, y: Float32) -> Float32 { - super::remquof(x, y).0 -} diff --git a/helpers/l2math/core/remquo.rs b/helpers/l2math/core/remquo.rs deleted file mode 100644 index 0b6bf0f..0000000 --- a/helpers/l2math/core/remquo.rs +++ /dev/null @@ -1,117 +0,0 @@ -use crate::{Float64, Int}; - -/// Return the remainder and part of the quotient of `x` and `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remquo(mut x: Float64, mut y: Float64) -> (Float64, Int) { - let ux: u64 = x.to_bits(); - let mut uy: u64 = y.to_bits(); - let mut ex = ((ux >> 52) & 0x7ff) as Int; - let mut ey = ((uy >> 52) & 0x7ff) as Int; - let sx = (ux >> 63) != 0; - let sy = (uy >> 63) != 0; - let mut q: u32; - let mut i: u64; - let mut uxi: u64 = ux; - - if (uy << 1) == 0 || y.is_nan() || ex == 0x7ff { - return ((x * y) / (x * y), 0); - } - if (ux << 1) == 0 { - return (x, 0); - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 12; - while (i >> 63) == 0 { - ex -= 1; - i <<= 1; - } - uxi <<= -ex + 1; - } else { - uxi &= (!0) >> 12; - uxi |= 1 << 52; - } - if ey == 0 { - i = uy << 12; - while (i >> 63) == 0 { - ey -= 1; - i <<= 1; - } - uy <<= -ey + 1; - } else { - uy &= (!0) >> 12; - uy |= 1 << 52; - } - - q = 0; - - if ex + 1 != ey { - if ex < ey { - return (x, 0); - } - /* x mod y */ - while ex > ey { - i = uxi.wrapping_sub(uy); - if (i >> 63) == 0 { - uxi = i; - q += 1; - } - uxi <<= 1; - q <<= 1; - ex -= 1; - } - i = uxi.wrapping_sub(uy); - if (i >> 63) == 0 { - uxi = i; - q += 1; - } - if uxi == 0 { - ex = -60; - } else { - while (uxi >> 52) == 0 { - uxi <<= 1; - ex -= 1; - } - } - } - - /* scale result and decide between |x| and |x|-|y| */ - if ex > 0 { - uxi -= 1 << 52; - uxi |= (ex as u64) << 52; - } else { - uxi >>= -ex + 1; - } - x = Float64::from_bits(uxi); - if sy { - y = -y; - } - if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { - x -= y; - // TODO: this matches musl behavior, but it is incorrect - q = q.wrapping_add(1); - } - q &= 0x7fffffff; - let quo = if sx ^ sy { -(q as Int) } else { q as Int }; - (if sx { -x } else { x }, quo) -} - -/// FFI bindings for remquo -#[inline] -#[doc(hidden)] -#[export_name = "__l2math_remquo"] -pub extern "C" fn __l2math_remquo(x: Float64, y: Float64) -> super::Tuple_Float64_Int { - super::Tuple_Float64_Int::from(remquo(x, y)) -} - -#[cfg(test)] -mod tests { - use super::remquo; - - #[test] - fn test_q_overflow() { - // 0xc000000000000001, 0x04c0000000000004 - let _ = remquo(-2.0000000000000004, 8.406091369059082e-286); - } -} diff --git a/helpers/l2math/core/remquof.rs b/helpers/l2math/core/remquof.rs deleted file mode 100644 index 2b1416e..0000000 --- a/helpers/l2math/core/remquof.rs +++ /dev/null @@ -1,108 +0,0 @@ -use crate::{Float32, Int}; - -/// Return the remainder and part of the quotient of `x` and `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remquof(mut x: Float32, mut y: Float32) -> (Float32, Int) { - let ux: u32 = x.to_bits(); - let mut uy: u32 = y.to_bits(); - let mut ex = ((ux >> 23) & 0xff) as Int; - let mut ey = ((uy >> 23) & 0xff) as Int; - let sx = (ux >> 31) != 0; - let sy = (uy >> 31) != 0; - let mut q: u32; - let mut i: u32; - let mut uxi: u32 = ux; - - if (uy << 1) == 0 || y.is_nan() || ex == 0xff { - return ((x * y) / (x * y), 0); - } - if (ux << 1) == 0 { - return (x, 0); - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 9; - while (i >> 31) == 0 { - ex -= 1; - i <<= 1; - } - uxi <<= -ex + 1; - } else { - uxi &= (!0) >> 9; - uxi |= 1 << 23; - } - if ey == 0 { - i = uy << 9; - while (i >> 31) == 0 { - ey -= 1; - i <<= 1; - } - uy <<= -ey + 1; - } else { - uy &= (!0) >> 9; - uy |= 1 << 23; - } - - q = 0; - if ex + 1 != ey { - if ex < ey { - return (x, 0); - } - /* x mod y */ - while ex > ey { - i = uxi.wrapping_sub(uy); - if (i >> 31) == 0 { - uxi = i; - q += 1; - } - uxi <<= 1; - q <<= 1; - ex -= 1; - } - i = uxi.wrapping_sub(uy); - if (i >> 31) == 0 { - uxi = i; - q += 1; - } - if uxi == 0 { - ex = -30; - } else { - while (uxi >> 23) == 0 { - uxi <<= 1; - ex -= 1; - } - } - } - - /* scale result and decide between |x| and |x|-|y| */ - if ex > 0 { - uxi -= 1 << 23; - uxi |= (ex as u32) << 23; - } else { - uxi >>= -ex + 1; - } - x = Float32::from_bits(uxi); - if sy { - y = -y; - } - if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { - x -= y; - q += 1; - } - q &= 0x7fffffff; - let quo = if sx ^ sy { -(q as Int) } else { q as Int }; - if sx { - (-x, quo) - } else { - (x, quo) - } -} - -/// FFI bindings for remquof -#[inline] -#[doc(hidden)] -#[export_name = "__l2math_remquof"] -pub extern "C" fn __l2math_remquof(x: Float32, y: Float32) -> super::Tuple_Float32_Int { - super::Tuple_Float32_Int::from(remquof(x, y)) -} diff --git a/helpers/l2math/core/rint.rs b/helpers/l2math/core/rint.rs deleted file mode 100644 index 767f79e..0000000 --- a/helpers/l2math/core/rint.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::Float64; - -/// Round to nearest integer, rounding halfway cases away from zero. -#[export_name = "__l2math_rint"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn rint(x: Float64) -> Float64 { - let one_over_e = 1.0 / Float64::EPSILON; - let as_u64: u64 = x.to_bits(); - let exponent: u64 = as_u64 >> 52 & 0x7ff; - let is_positive = (as_u64 >> 63) == 0; - if exponent >= 0x3ff + 52 { - return x; - } - let ans = if is_positive { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xplusoneovere = x + one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xplusoneovere = force_eval!(xplusoneovere); - xplusoneovere - one_over_e - } else { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xminusoneovere = x - one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xminusoneovere = force_eval!(xminusoneovere); - xminusoneovere + one_over_e - }; - - if ans != 0.0 { - return ans; - }; - if is_positive { - 0.0 - } else { - -0.0 - } -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::rint; - - #[test] - fn negative_zero() { - assert_eq!(rint(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(rint(-1.0), -1.0); - assert_eq!(rint(2.8), 3.0); - assert_eq!(rint(-0.5), -0.0); - assert_eq!(rint(0.5), 0.0); - assert_eq!(rint(-1.5), -2.0); - assert_eq!(rint(1.5), 2.0); - } -} diff --git a/helpers/l2math/core/rintf.rs b/helpers/l2math/core/rintf.rs deleted file mode 100644 index b67e114..0000000 --- a/helpers/l2math/core/rintf.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::Float32; - -/// Round to nearest integer, rounding halfway cases away from zero. -#[export_name = "__l2math_rintf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn rintf(x: Float32) -> Float32 { - let one_over_e = 1.0 / Float32::EPSILON; - let as_u32: u32 = x.to_bits(); - let exponent: u32 = as_u32 >> 23 & 0xff; - let is_positive = (as_u32 >> 31) == 0; - if exponent >= 0x7f + 23 { - return x; - } - let ans = if is_positive { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xplusoneovere = x + one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xplusoneovere = force_eval!(xplusoneovere); - xplusoneovere - one_over_e - } else { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xminusoneovere = x - one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xminusoneovere = force_eval!(xminusoneovere); - xminusoneovere + one_over_e - }; - - if ans != 0.0 { - return ans; - }; - if is_positive { - 0.0 - } else { - -0.0 - } -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::rintf; - - #[test] - fn negative_zero() { - assert_eq!(rintf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(rintf(-1.0), -1.0); - assert_eq!(rintf(2.8), 3.0); - assert_eq!(rintf(-0.5), -0.0); - assert_eq!(rintf(0.5), 0.0); - assert_eq!(rintf(-1.5), -2.0); - assert_eq!(rintf(1.5), 2.0); - } -} diff --git a/helpers/l2math/core/round.rs b/helpers/l2math/core/round.rs deleted file mode 100644 index 79ca5b6..0000000 --- a/helpers/l2math/core/round.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::Float64; - -use super::copysign; -use super::trunc; - -/// Rounds `x` to the nearest integer in the direction of the current rounding mode. -#[inline] -#[export_name = "__l2math_round"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn round(x: Float64) -> Float64 { - trunc(x + copysign(0.5 - 0.25 * Float64::EPSILON, x)) -} - -#[cfg(test)] -mod tests { - use super::round; - - #[test] - fn negative_zero() { - assert_eq!(round(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(round(-1.0), -1.0); - assert_eq!(round(2.8), 3.0); - assert_eq!(round(-0.5), -1.0); - assert_eq!(round(0.5), 1.0); - assert_eq!(round(-1.5), -2.0); - assert_eq!(round(1.5), 2.0); - } -} diff --git a/helpers/l2math/core/roundf.rs b/helpers/l2math/core/roundf.rs deleted file mode 100644 index 26821ea..0000000 --- a/helpers/l2math/core/roundf.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::Float32; - -use super::copysignf; -use super::truncf; - -/// Rounds `x` to the nearest integer in the direction of the current rounding mode. -#[inline] -#[export_name = "__l2math_roundf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn roundf(x: Float32) -> Float32 { - truncf(x + copysignf(0.5 - 0.25 * Float32::EPSILON, x)) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::roundf; - - #[test] - fn negative_zero() { - assert_eq!(roundf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(roundf(-1.0), -1.0); - assert_eq!(roundf(2.8), 3.0); - assert_eq!(roundf(-0.5), -1.0); - assert_eq!(roundf(0.5), 1.0); - assert_eq!(roundf(-1.5), -2.0); - assert_eq!(roundf(1.5), 2.0); - } -} diff --git a/helpers/l2math/core/scalbn.rs b/helpers/l2math/core/scalbn.rs deleted file mode 100644 index be0871d..0000000 --- a/helpers/l2math/core/scalbn.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::{Float64, Int}; - -/// Returns `x * 2^n` -#[export_name = "__l2math_scalbn"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn scalbn(x: Float64, mut n: Int) -> Float64 { - let x1p1023 = Float64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 - let x1p53 = Float64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 - let x1p_1022 = Float64::from_bits(0x0010000000000000); // 0x1p-1022 === 2 ^ (-1022) - - let mut y = x; - - if n > 1023 { - y *= x1p1023; - n -= 1023; - if n > 1023 { - y *= x1p1023; - n -= 1023; - if n > 1023 { - n = 1023; - } - } - } else if n < -1022 { - /* make sure final n < -53 to avoid double - rounding in the subnormal range */ - y *= x1p_1022 * x1p53; - n += 1022 - 53; - if n < -1022 { - y *= x1p_1022 * x1p53; - n += 1022 - 53; - if n < -1022 { - n = -1022; - } - } - } - y * Float64::from_bits(((0x3ff + n) as u64) << 52) -} diff --git a/helpers/l2math/core/scalbnf.rs b/helpers/l2math/core/scalbnf.rs deleted file mode 100644 index b093147..0000000 --- a/helpers/l2math/core/scalbnf.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::{Float32, Int}; - -/// Returns `x * 2^n` -#[export_name = "__l2math_scalbnf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf(mut x: Float32, mut n: Int) -> Float32 { - let x1p127 = Float32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = Float32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 - let x1p24 = Float32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 - - if n > 127 { - x *= x1p127; - n -= 127; - if n > 127 { - x *= x1p127; - n -= 127; - if n > 127 { - n = 127; - } - } - } else if n < -126 { - x *= x1p_126 * x1p24; - n += 126 - 24; - if n < -126 { - x *= x1p_126 * x1p24; - n += 126 - 24; - if n < -126 { - n = -126; - } - } - } - x * Float32::from_bits(((0x7f + n) as u32) << 23) -} diff --git a/helpers/l2math/core/sin.rs b/helpers/l2math/core/sin.rs deleted file mode 100644 index 85b1a2c..0000000 --- a/helpers/l2math/core/sin.rs +++ /dev/null @@ -1,103 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunPro, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -use crate::{Float64, Radian64}; - -use super::{k_cos, k_sin, rem_pio2}; - -/// Returns the sine function of x. -/// -/// ### Info: -/// -/// ```text -/// kernel function: -/// k_sin ... sine function on [-pi/4,pi/4] -/// k_cos ... cose function on [-pi/4,pi/4] -/// rem_pio2 ... argument reduction routine -/// -/// Method. -/// Let S,C and T denote the sin, cos and tan respectively on -/// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 -/// in [-pi/4 , +pi/4], and let n = k mod 4. -/// We have -/// -/// n sin(x) cos(x) tan(x) -/// ---------------------------------------------------------- -/// 0 S C T -/// 1 C -S -1/T -/// 2 -S -C T -/// 3 -C S -1/T -/// ---------------------------------------------------------- -/// -/// Special cases: -/// Let trig be any of sin, cos, or tan. -/// trig(+-INF) is NaN, with signals; -/// trig(NaN) is that NaN; -/// -/// Accuracy: -/// TRIG(x) returns trig(x) nearly rounded -/// ``` -#[export_name = "__l2math_sin"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn sin(x: Radian64) -> Float64 { - let x1p120 = Float64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 - - /* High word of x. */ - let ix = (Float64::to_bits(x) >> 32) as u32 & 0x7fffffff; - - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - if ix < 0x3e500000 { - /* |x| < 2**-26 */ - /* raise inexact if x != 0 and underflow if subnormal*/ - if ix < 0x00100000 { - force_eval!(x / x1p120); - } else { - force_eval!(x + x1p120); - } - return x; - } - return k_sin(x, 0.0, 0); - } - - /* sin(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - return x - x; - } - - /* argument reduction needed */ - let (n, y0, y1) = rem_pio2(x); - match n & 3 { - 0 => k_sin(y0, y1, 1), - 1 => k_cos(y0, y1), - 2 => -k_sin(y0, y1, 1), - _ => -k_cos(y0, y1), - } -} - -#[test] -fn test_sin_30() { - let thirty = 0.52359877559829887307710723054658381403286156656251763682915743205130273438103483310467247089035284466369134775221371777451564076825843037195422656802141351957504735045032308685092660743715815915506366073813516261098890768807927470563113052754520031819094142; - let result = sin(thirty); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let result = force_eval!(result); - assert_eq!(result, 0.5); -} - -#[test] -fn test_near_pi() { - let x = Float64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 - let sx = Float64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 - let result = sin(x); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let result = force_eval!(result); - assert_eq!(result, sx); -} diff --git a/helpers/l2math/core/sincos.rs b/helpers/l2math/core/sincos.rs deleted file mode 100644 index 6640842..0000000 --- a/helpers/l2math/core/sincos.rs +++ /dev/null @@ -1,141 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ - -use crate::{Float64, Radian64}; - -use super::{get_high_word, k_cos, k_sin, rem_pio2}; - -/// Simultaneously computes the sine and cosine of the argument x. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sincos(x: Radian64) -> (Float64, Float64) { - let ix = get_high_word(x) & 0x7fffffff; - - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - /* if |x| < 2**-27 * sqrt(2) */ - if ix < 0x3e46a09e { - /* raise inexact if x!=0 and underflow if subnormal */ - let x1p120 = Float64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 - if ix < 0x00100000 { - force_eval!(x / x1p120); - } else { - force_eval!(x + x1p120); - } - return (x, 1.0); - } - return (k_sin(x, 0.0, 0), k_cos(x, 0.0)); - } - - /* sincos(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - let rv = x - x; - return (rv, rv); - } - - /* argument reduction needed */ - let (n, y0, y1) = rem_pio2(x); - let s = k_sin(y0, y1, 1); - let c = k_cos(y0, y1); - match n & 3 { - 0 => (s, c), - 1 => (c, -s), - 2 => (-s, -c), - 3 => (-c, s), - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => (0.0, 1.0), - } -} - -/// FFI bindings for sincos -#[inline] -#[doc(hidden)] -#[export_name = "__l2math_sincos"] -pub extern "C" fn __l2math_sincos(x: Float64) -> super::Tuple_Float64_Float64 { - super::Tuple_Float64_Float64::from(sincos(x)) -} - -// These tests are based on those from sincosf.rs -#[cfg(test)] -mod tests { - use super::sincos; - use super::Float64; - - const TOLERANCE: Float64 = 1e-6; - - #[test] - fn with_pi() { - let (s, c) = sincos(core::f64::consts::PI); - assert!( - (s - 0.0).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - 0.0, - (s - 0.0).abs(), - TOLERANCE - ); - assert!( - (c + 1.0).abs() < TOLERANCE, - "|{} + {}| = {} >= {}", - c, - 1.0, - (s + 1.0).abs(), - TOLERANCE - ); - } - - #[test] - fn rotational_symmetry() { - use core::f64::consts::PI; - const N: usize = 24; - for n in 0..N { - let theta = 2. * PI * (n as Float64) / (N as Float64); - let (s, c) = sincos(theta); - let (s_plus, c_plus) = sincos(theta + 2. * PI); - let (s_minus, c_minus) = sincos(theta - 2. * PI); - - assert!( - (s - s_plus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - s_plus, - (s - s_plus).abs(), - TOLERANCE - ); - assert!( - (s - s_minus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - s_minus, - (s - s_minus).abs(), - TOLERANCE - ); - assert!( - (c - c_plus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - c, - c_plus, - (c - c_plus).abs(), - TOLERANCE - ); - assert!( - (c - c_minus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - c, - c_minus, - (c - c_minus).abs(), - TOLERANCE - ); - } - } -} diff --git a/helpers/l2math/core/sincosf.rs b/helpers/l2math/core/sincosf.rs deleted file mode 100644 index cd635de..0000000 --- a/helpers/l2math/core/sincosf.rs +++ /dev/null @@ -1,191 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. -*/ - -use crate::{Float64, Float32, Radian32}; - -use super::{k_cosf, k_sinf, rem_pio2f}; - -use core::f32::consts::FRAC_PI_2; -use core::f32::consts::PI; - -const S1PIO2: Float32 = FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const S2PIO2: Float32 = PI; /* 0x400921FB, 0x54442D18 */ -const S3PIO2: Float32 = 3.0 * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const S4PIO2: Float32 = 2.0 * PI; /* 0x401921FB, 0x54442D18 */ - -/// Simultaneously computes the sine and cosine of the argument x. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sincosf(x: Radian32) -> (Float32, Float32) { - let s: Float32; - let c: Float32; - let mut ix = x.to_bits(); - let sign: bool = (ix >> 31) != 0; - ix &= 0x7fffffff; - - /* |x| ~<= pi/4 */ - if ix <= 0x3f490fda { - /* |x| < 2**-12 */ - if ix < 0x39800000 { - /* raise inexact if x!=0 and underflow if subnormal */ - - let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120 == 2^120 - if ix < 0x00100000 { - force_eval!(x / x1p120); - } else { - force_eval!(x + x1p120); - } - return (x, 1.0); - } - return (k_sinf(x as Float64), k_cosf(x as Float64)); - } - - /* |x| ~<= 5*pi/4 */ - if ix <= 0x407b53d1 { - if ix <= 0x4016cbe3 { - /* |x| ~<= 3pi/4 */ - if sign { - s = -k_cosf((x + S1PIO2) as Float64); - c = k_sinf((x + S1PIO2) as Float64); - } else { - s = k_cosf((S1PIO2 - x) as Float64); - c = k_sinf((S1PIO2 - x) as Float64); - } - } - /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ - else if sign { - s = -k_sinf((x + S2PIO2) as Float64); - c = -k_cosf((x + S2PIO2) as Float64); - } else { - s = -k_sinf((x - S2PIO2) as Float64); - c = -k_cosf((x - S2PIO2) as Float64); - } - - return (s, c); - } - - /* |x| ~<= 9*pi/4 */ - if ix <= 0x40e231d5 { - if ix <= 0x40afeddf { - /* |x| ~<= 7*pi/4 */ - if sign { - s = k_cosf((x + S3PIO2) as Float64); - c = -k_sinf((x + S3PIO2) as Float64); - } else { - s = -k_cosf((x - S3PIO2) as Float64); - c = k_sinf((x - S3PIO2) as Float64); - } - } else if sign { - s = k_sinf((x + S4PIO2) as Float64); - c = k_cosf((x + S4PIO2) as Float64); - } else { - s = k_sinf((x - S4PIO2) as Float64); - c = k_cosf((x - S4PIO2) as Float64); - } - - return (s, c); - } - - /* sin(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - let rv = x - x; - return (rv, rv); - } - - /* general argument reduction needed */ - let (n, y) = rem_pio2f(x); - s = k_sinf(y); - c = k_cosf(y); - match n & 3 { - 0 => (s, c), - 1 => (c, -s), - 2 => (-s, -c), - 3 => (-c, s), - #[cfg(debug_assertions)] - _ => unreachable!(), - #[cfg(not(debug_assertions))] - _ => (0.0, 1.0), - } -} - -/// FFI bindings for sincosf -#[inline] -#[doc(hidden)] -#[export_name = "__l2math_sincosf"] -pub extern "C" fn __l2math_sincosf(x: Float32) -> super::Tuple_Float32_Float32 { - super::Tuple_Float32_Float32::from(sincosf(x)) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::sincosf; - use super::Float32; - use crate::_eqf; - - #[test] - fn with_pi() { - let (s, c) = sincosf(core::f32::consts::PI); - _eqf(s.abs(), 0.0).unwrap(); - _eqf(c, -1.0).unwrap(); - } - - #[test] - fn rotational_symmetry() { - use core::f32::consts::PI; - const N: usize = 24; - for n in 0..N { - let theta = 2. * PI * (n as Float32) / (N as Float32); - let (s, c) = sincosf(theta); - let (s_plus, c_plus) = sincosf(theta + 2. * PI); - let (s_minus, c_minus) = sincosf(theta - 2. * PI); - - const TOLERANCE: Float32 = 1e-6; - assert!( - (s - s_plus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - s_plus, - (s - s_plus).abs(), - TOLERANCE - ); - assert!( - (s - s_minus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - s_minus, - (s - s_minus).abs(), - TOLERANCE - ); - assert!( - (c - c_plus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - c, - c_plus, - (c - c_plus).abs(), - TOLERANCE - ); - assert!( - (c - c_minus).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - c, - c_minus, - (c - c_minus).abs(), - TOLERANCE - ); - } - } -} diff --git a/helpers/l2math/core/sinf.rs b/helpers/l2math/core/sinf.rs deleted file mode 100644 index fc9ffc0..0000000 --- a/helpers/l2math/core/sinf.rs +++ /dev/null @@ -1,97 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. -*/ - -use crate::{Float64, Float32, Radian32}; - -use super::{k_cosf, k_sinf, rem_pio2f}; - -use core::f64::consts::FRAC_PI_2; - -/* Small multiples of pi/2 rounded to double precision. */ -const S1_PIO2: Float64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const S2_PIO2: Float64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const S3_PIO2: Float64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const S4_PIO2: Float64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ - -/// Returns the sine of the argument x. -#[export_name = "__l2math_sinf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn sinf(x: Radian32) -> Float32 { - let x64 = x as Float64; - - let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - if ix <= 0x3f490fda { - /* |x| ~<= pi/4 */ - if ix < 0x39800000 { - /* |x| < 2**-12 */ - /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { - x / x1p120 - } else { - x + x1p120 - }); - return x; - } - return k_sinf(x64); - } - if ix <= 0x407b53d1 { - /* |x| ~<= 5*pi/4 */ - if ix <= 0x4016cbe3 { - /* |x| ~<= 3pi/4 */ - if sign { - return -k_cosf(x64 + S1_PIO2); - } else { - return k_cosf(x64 - S1_PIO2); - } - } - return k_sinf(if sign { - -(x64 + S2_PIO2) - } else { - -(x64 - S2_PIO2) - }); - } - if ix <= 0x40e231d5 { - /* |x| ~<= 9*pi/4 */ - if ix <= 0x40afeddf { - /* |x| ~<= 7*pi/4 */ - if sign { - return k_cosf(x64 + S3_PIO2); - } else { - return -k_cosf(x64 - S3_PIO2); - } - } - return k_sinf(if sign { x64 + S4_PIO2 } else { x64 - S4_PIO2 }); - } - - /* sin(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - return x - x; - } - - /* general argument reduction needed */ - let (n, y) = rem_pio2f(x); - match n & 3 { - 0 => k_sinf(y), - 1 => k_cosf(y), - 2 => k_sinf(-y), - _ => -k_cosf(y), - } -} diff --git a/helpers/l2math/core/sinh.rs b/helpers/l2math/core/sinh.rs deleted file mode 100644 index 37dc1e9..0000000 --- a/helpers/l2math/core/sinh.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::{Float64, Radian64}; - -use super::{expm1, expo2}; - -// sinh(x) = (exp(x) - 1/exp(x))/2 -// = (exp(x)-1 + (exp(x)-1)/exp(x))/2 -// = x + x^3/6 + o(x^5) -// - -/// Returns the hyperbolic sine of `x`. -#[export_name = "__l2math_sinh"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn sinh(x: Radian64) -> Float64 { - // union {double f; uint64_t i;} u = {.f = x}; - // uint32_t w; - // double t, h, absx; - - let mut uf: Float64 = x; - let mut ui: u64 = Float64::to_bits(uf); - let t: Float64; - let mut h: Float64; - - h = 0.5; - if ui >> 63 != 0 { - h = -h; - } - /* |x| */ - ui &= !1 / 2; - uf = Float64::from_bits(ui); - let absx: Float64 = uf; - let w: u32 = (ui >> 32) as u32; - - /* |x| < log(DBL_MAX) */ - if w < 0x40862e42 { - t = expm1(absx); - if w < 0x3ff00000 { - if w < 0x3ff00000 - (26 << 20) { - /* note: inexact and underflow are raised by expm1 */ - /* note: this branch avoids spurious underflow */ - return x; - } - return h * (2.0 * t - t * t / (t + 1.0)); - } - /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ - return h * (t + t / (t + 1.0)); - } - - /* |x| > log(DBL_MAX) or nan */ - /* note: the result is stored to handle overflow */ - t = 2.0 * h * expo2(absx); - t -} diff --git a/helpers/l2math/core/sinhf.rs b/helpers/l2math/core/sinhf.rs deleted file mode 100644 index 881dddf..0000000 --- a/helpers/l2math/core/sinhf.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::{Float32, Radian32}; - -use super::expm1f; -use super::k_expo2f; - -/// Returns the hyperbolic sine of `x`. -#[export_name = "__l2math_sinhf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn sinhf(x: Radian32) -> Float32 { - let mut h = 0.5f32; - let mut ix = x.to_bits(); - if (ix >> 31) != 0 { - h = -h; - } - /* |x| */ - ix &= 0x7fffffff; - let absx = Float32::from_bits(ix); - let w = ix; - - /* |x| < log(FLT_MAX) */ - if w < 0x42b17217 { - let t = expm1f(absx); - if w < 0x3f800000 { - if w < (0x3f800000 - (12 << 23)) { - return x; - } - return h * (2. * t - t * t / (t + 1.)); - } - return h * (t + t / (t + 1.)); - } - - /* |x| > logf(FLT_MAX) or nan */ - 2. * h * k_expo2f(absx) -} diff --git a/helpers/l2math/core/sqrt.rs b/helpers/l2math/core/sqrt.rs deleted file mode 100644 index ff11511..0000000 --- a/helpers/l2math/core/sqrt.rs +++ /dev/null @@ -1,284 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/** - * sqrt(x) - * Return correctly rounded sqrt. - * ------------------------------------------ - * | Use the hardware sqrt if you have one | - * ------------------------------------------ - * Method: - * Bit by bit method using integer arithmetic. (Slow, but portable) - * 1. Normalization - * Scale x to y in [1,4) with even powers of 2: - * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then - * sqrt(x) = 2^k * sqrt(y) - * 2. Bit by bit computation - * Let q = sqrt(y) truncated to i bit after binary point (q = 1), - * i 0 - * i+1 2 - * s = 2*q , and y = 2 * ( y - q ). (1) - * i i i i - * - * To compute q from q , one checks whether - * i+1 i - * - * -(i+1) 2 - * (q + 2 ) <= y. (2) - * i - * -(i+1) - * If (2) is false, then q = q ; otherwise q = q + 2 . - * i+1 i i+1 i - * - * With some algebraic manipulation, it is not difficult to see - * that (2) is equivalent to - * -(i+1) - * s + 2 <= y (3) - * i i - * - * The advantage of (3) is that s and y can be computed by - * i i - * the following recurrence formula: - * if (3) is false - * - * s = s , y = y ; (4) - * i+1 i i+1 i - * - * otherwise, - * -i -(i+1) - * s = s + 2 , y = y - s - 2 (5) - * i+1 i i+1 i i - * - * One may easily use induction to prove (4) and (5). - * Note. Since the left hand side of (3) contain only i+2 bits, - * it does not necessary to do a full (53-bit) comparison - * in (3). - * 3. Final rounding - * After generating the 53 bits result, we compute one more bit. - * Together with the remainder, we can decide whether the - * result is exact, bigger than 1/2ulp, or less than 1/2ulp - * (it will never equal to 1/2ulp). - * The rounding mode can be detected by checking whether - * huge + tiny is equal to huge, and whether huge - tiny is - * equal to huge for some floating point number "huge" and "tiny". - * - * Special cases: - * sqrt(+-0) = +-0 ... exact - * sqrt(inf) = inf - * sqrt(-ve) = NaN ... with invalid signal - * sqrt(NaN) = NaN ... with invalid signal for signaling NaN -*/ - -#[allow(unused_imports)] -use crate::{Float64, Int}; - -/// Returns the square root of `x`. -#[export_name = "__l2math_sqrt"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn sqrt(x: Float64) -> Float64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `Float64.sqrt` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return if x < 0.0 { - ::core::f64::NAN - } else { - unsafe { ::core::intrinsics::sqrtf64(x) } - } - } - } - #[cfg(target_feature = "sse2")] - { - // Note: This path is unlikely since LLVM will usually have already - // optimized sqrt calls into hardware instructions if sse2 is available, - // but if someone does end up here they'll apprected the speed increase. - #[cfg(target_arch = "x86")] - use core::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::*; - unsafe { - let m = _mm_set_sd(x); - let m_sqrt = _mm_sqrt_pd(m); - _mm_cvtsd_f64(m_sqrt) - } - } - #[cfg(not(target_feature = "sse2"))] - { - use core::num::Wrapping; - - const TINY: Float64 = 1.0e-300; - - let mut z: Float64; - let sign: Wrapping = Wrapping(0x80000000); - let mut ix0: Int; - let mut s0: Int; - let mut q: Int; - let mut m: Int; - let mut t: Int; - let mut i: Int; - let mut r: Wrapping; - let mut t1: Wrapping; - let mut s1: Wrapping; - let mut ix1: Wrapping; - let mut q1: Wrapping; - - ix0 = (x.to_bits() >> 32) as Int; - ix1 = Wrapping(x.to_bits() as u32); - - /* take care of Inf and NaN */ - if (ix0 & 0x7ff00000) == 0x7ff00000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } - /* take care of zero */ - if ix0 <= 0 { - if ((ix0 & !(sign.0 as Int)) | ix1.0 as Int) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix0 < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } - /* normalize x */ - m = ix0 >> 20; - if m == 0 { - /* subnormal x */ - while ix0 == 0 { - m -= 21; - ix0 |= (ix1 >> 11).0 as Int; - ix1 <<= 21; - } - i = 0; - while (ix0 & 0x00100000) == 0 { - i += 1; - ix0 <<= 1; - } - m -= i - 1; - ix0 |= (ix1 >> (32 - i) as usize).0 as Int; - ix1 = ix1 << i as usize; - } - m -= 1023; /* unbias exponent */ - ix0 = (ix0 & 0x000fffff) | 0x00100000; - if (m & 1) == 1 { - /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as Int; - ix1 += ix1; - } - m >>= 1; /* m = [m/2] */ - - /* generate sqrt(x) bit by bit */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as Int; - ix1 += ix1; - q = 0; /* [q,q1] = sqrt(x) */ - q1 = Wrapping(0); - s0 = 0; - s1 = Wrapping(0); - r = Wrapping(0x00200000); /* r = moving bit from right to left */ - - while r != Wrapping(0) { - t = s0 + r.0 as Int; - if t <= ix0 { - s0 = t + r.0 as Int; - ix0 -= t; - q += r.0 as Int; - } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as Int; - ix1 += ix1; - r >>= 1; - } - - r = sign; - while r != Wrapping(0) { - t1 = s1 + r; - t = s0; - if t < ix0 || (t == ix0 && t1 <= ix1) { - s1 = t1 + r; - if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { - s0 += 1; - } - ix0 -= t; - if ix1 < t1 { - ix0 -= 1; - } - ix1 -= t1; - q1 += r; - } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as Int; - ix1 += ix1; - r >>= 1; - } - - /* use floating add to find out rounding direction */ - if (ix0 as u32 | ix1.0) != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if q1.0 == 0xffffffff { - q1 = Wrapping(0); - q += 1; - } else if z > 1.0 { - if q1.0 == 0xfffffffe { - q += 1; - } - q1 += Wrapping(2); - } else { - q1 += q1 & Wrapping(1); - } - } - } - ix0 = (q >> 1) + 0x3fe00000; - ix1 = q1 >> 1; - if (q & 1) == 1 { - ix1 |= sign; - } - ix0 += m << 20; - Float64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use core::f64::*; - - #[test] - fn sanity_check() { - assert_eq!(sqrt(100.0), 10.0); - assert_eq!(sqrt(4.0), 2.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt - #[test] - fn spec_tests() { - // Not Asserted: FE_INVALID exception is raised if argument is negative. - assert!(sqrt(-1.0).is_nan()); - assert!(sqrt(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY].iter().copied() { - assert_eq!(sqrt(f), f); - } - } - - #[test] - fn conformance_tests() { - let values = [3.14159265359, 10000.0, Float64::from_bits(0x0000000f), INFINITY]; - let results = [ - 4610661241675116657u64, - 4636737291354636288u64, - 2197470602079456986u64, - 9218868437227405312u64, - ]; - - for i in 0..values.len() { - let bits = Float64::to_bits(sqrt(values[i])); - assert_eq!(results[i], bits); - } - } -} diff --git a/helpers/l2math/core/sqrtf.rs b/helpers/l2math/core/sqrtf.rs deleted file mode 100644 index 0ad1d5c..0000000 --- a/helpers/l2math/core/sqrtf.rs +++ /dev/null @@ -1,176 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrtf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. -*/ - -#[allow(unused_imports)] -use crate::{Float32, Int}; - -/// Returns the square root of `x`. -#[export_name = "__l2math_sqrtf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn sqrtf(x: Float32) -> Float32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `Float32.sqrt` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return if x < 0.0 { - ::core::f32::NAN - } else { - unsafe { ::core::intrinsics::sqrtf32(x) } - } - } - } - #[cfg(target_feature = "sse")] - { - // Note: This path is unlikely since LLVM will usually have already - // optimized sqrt calls into hardware instructions if sse is available, - // but if someone does end up here they'll apprected the speed increase. - #[cfg(target_arch = "x86")] - use core::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::*; - unsafe { - let m = _mm_set_ss(x); - let m_sqrt = _mm_sqrt_ss(m); - _mm_cvtss_f32(m_sqrt) - } - } - #[cfg(not(target_feature = "sse"))] - { - const TINY: Float32 = 1.0e-30; - - let mut z: Float32; - let sign: Int = 0x80000000u32 as Int; - let mut ix: Int; - let mut s: Int; - let mut q: Int; - let mut m: Int; - let mut t: Int; - let mut i: Int; - let mut r: u32; - - ix = x.to_bits() as Int; - - /* take care of Inf and NaN */ - if (ix as u32 & 0x7f800000) == 0x7f800000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } - - /* take care of zero */ - if ix <= 0 { - if (ix & !sign) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } - - /* normalize x */ - m = ix >> 23; - if m == 0 { - /* subnormal x */ - i = 0; - while ix & 0x00800000 == 0 { - ix <<= 1; - i = i + 1; - } - m -= i - 1; - } - m -= 127; /* unbias exponent */ - ix = (ix & 0x007fffff) | 0x00800000; - if m & 1 == 1 { - /* odd m, double x to make it even */ - ix += ix; - } - m >>= 1; /* m = [m/2] */ - - /* generate sqrt(x) bit by bit */ - ix += ix; - q = 0; - s = 0; - r = 0x01000000; /* r = moving bit from right to left */ - - while r != 0 { - t = s + r as Int; - if t <= ix { - s = t + r as Int; - ix -= t; - q += r as Int; - } - ix += ix; - r >>= 1; - } - - /* use floating add to find out rounding direction */ - if ix != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if z > 1.0 { - q += 2; - } else { - q += q & 1; - } - } - } - - ix = (q >> 1) + 0x3f000000; - ix += m << 23; - Float32::from_bits(ix as u32) - } -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - use core::f32::*; - - #[test] - fn sanity_check() { - assert_eq!(sqrtf(100.0), 10.0); - assert_eq!(sqrtf(4.0), 2.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt - #[test] - fn spec_tests() { - // Not Asserted: FE_INVALID exception is raised if argument is negative. - assert!(sqrtf(-1.0).is_nan()); - assert!(sqrtf(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY].iter().copied() { - assert_eq!(sqrtf(f), f); - } - } - - #[test] - #[allow(clippy::excessive_precision)] - fn conformance_tests() { - let values = [ - 3.14159265359f32, - 10000.0f32, - Float32::from_bits(0x0000000f), - INFINITY, - ]; - let results = [1071833029u32, 1120403456u32, 456082799u32, 2139095040u32]; - - for i in 0..values.len() { - let bits = Float32::to_bits(sqrtf(values[i])); - assert_eq!(results[i], bits); - } - } -} diff --git a/helpers/l2math/core/tan.rs b/helpers/l2math/core/tan.rs deleted file mode 100644 index 39f283e..0000000 --- a/helpers/l2math/core/tan.rs +++ /dev/null @@ -1,76 +0,0 @@ -// origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */ -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunPro, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== - -use crate::{Float64, Float32, Radian64}; - -use super::{k_tan, rem_pio2}; - -/// Returns tangent of `x`. -/// -/// ### Info: -/// -/// ```text -/// kernel function: -/// k_tan ... tangent function on [-pi/4,pi/4] -/// rem_pio2 ... argument reduction routine -/// -/// Method. -/// Let S,C and T denote the sin, cos and tan respectively on -/// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 -/// in [-pi/4 , +pi/4], and let n = k mod 4. -/// We have -/// -/// n sin(x) cos(x) tan(x) -/// ---------------------------------------------------------- -/// 0 S C T -/// 1 C -S -1/T -/// 2 -S -C T -/// 3 -C S -1/T -/// ---------------------------------------------------------- -/// -/// Special cases: -/// Let trig be any of sin, cos, or tan. -/// trig(+-INF) is NaN, with signals; -/// trig(NaN) is that NaN; -/// -/// Accuracy: -/// TRIG(x) returns trig(x) nearly rounded -/// ``` -#[export_name = "__l2math_tan"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn tan(x: Radian64) -> Float64 { - let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let ix = (Float64::to_bits(x) >> 32) as u32 & 0x7fffffff; - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - if ix < 0x3e400000 { - /* |x| < 2**-27 */ - /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00100000 { - x / x1p120 as Float64 - } else { - x + x1p120 as Float64 - }); - return x; - } - return k_tan(x, 0.0, 0); - } - - /* tan(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - return x - x; - } - - /* argument reduction */ - let (n, y0, y1) = rem_pio2(x); - k_tan(y0, y1, n & 1) -} diff --git a/helpers/l2math/core/tanf.rs b/helpers/l2math/core/tanf.rs deleted file mode 100644 index f8ed0f2..0000000 --- a/helpers/l2math/core/tanf.rs +++ /dev/null @@ -1,82 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.c */ -/** - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== -*/ -/** - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. -*/ - -use crate::{Float64, Float32, Radian32}; - -use super::{k_tanf, rem_pio2f}; - -use core::f64::consts::FRAC_PI_2; - -/* Small multiples of pi/2 rounded to double precision. */ -const T1_PIO2: Float64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const T2_PIO2: Float64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const T3_PIO2: Float64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const T4_PIO2: Float64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ - -/// Returns tangent of `x`. -#[export_name = "__l2math_tanf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn tanf(x: Radian32) -> Float32 { - let x64 = x as Float64; - - let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - if ix <= 0x3f490fda { - /* |x| ~<= pi/4 */ - if ix < 0x39800000 { - /* |x| < 2**-12 */ - /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { - x / x1p120 - } else { - x + x1p120 - }); - return x; - } - return k_tanf(x64, false); - } - if ix <= 0x407b53d1 { - /* |x| ~<= 5*pi/4 */ - if ix <= 0x4016cbe3 { - /* |x| ~<= 3pi/4 */ - return k_tanf(if sign { x64 + T1_PIO2 } else { x64 - T1_PIO2 }, true); - } else { - return k_tanf(if sign { x64 + T2_PIO2 } else { x64 - T2_PIO2 }, false); - } - } - if ix <= 0x40e231d5 { - /* |x| ~<= 9*pi/4 */ - if ix <= 0x40afeddf { - /* |x| ~<= 7*pi/4 */ - return k_tanf(if sign { x64 + T3_PIO2 } else { x64 - T3_PIO2 }, true); - } else { - return k_tanf(if sign { x64 + T4_PIO2 } else { x64 - T4_PIO2 }, false); - } - } - - /* tan(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - return x - x; - } - - /* argument reduction */ - let (n, y) = rem_pio2f(x); - k_tanf(y, n & 1 != 0) -} diff --git a/helpers/l2math/core/tanh.rs b/helpers/l2math/core/tanh.rs deleted file mode 100644 index 69a7adc..0000000 --- a/helpers/l2math/core/tanh.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::{Float64, Float32, Radian64}; - -/** - * tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) - * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) - * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) -*/ - -use super::expm1; - -/// Returns the hyperbolic tangent of `x`. -#[export_name = "__l2math_tanh"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn tanh(mut x: Radian64) -> Float64 { - let mut uf: Float64 = x; - let mut ui: u64 = Float64::to_bits(uf); - let mut t: Float64; - - /* x = |x| */ - let sign: bool = ui >> 63 != 0; - ui &= !1 / 2; - uf = Float64::from_bits(ui); - x = uf; - let w: u32 = (ui >> 32) as u32; - - if w > 0x3fe193ea { - /* |x| > log(3)/2 ~= 0.5493 or nan */ - if w > 0x40340000 { - /* |x| > 20 or nan */ - /* note: this branch avoids raising overflow */ - t = 1.0 - 0.0 / x; - } else { - t = expm1(2.0 * x); - t = 1.0 - 2.0 / (t + 2.0); - } - } else if w > 0x3fd058ae { - /* |x| > log(5/3)/2 ~= 0.2554 */ - t = expm1(2.0 * x); - t = t / (t + 2.0); - } else if w >= 0x00100000 { - /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ - t = expm1(-2.0 * x); - t = -t / (t + 2.0); - } else { - /* |x| is subnormal */ - /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ - force_eval!(x as Float32); - t = x; - } - - if sign { - -t - } else { - t - } -} diff --git a/helpers/l2math/core/tanhf.rs b/helpers/l2math/core/tanhf.rs deleted file mode 100644 index 0801d00..0000000 --- a/helpers/l2math/core/tanhf.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::{Float32, Radian32}; - -use super::expm1f; - -/// Returns the hyperbolic tangent of `x`. -#[export_name = "__l2math_tanhf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn tanhf(mut x: Radian32) -> Float32 { - /* x = |x| */ - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - x = Float32::from_bits(ix); - let w = ix; - - let tt = if w > 0x3f0c9f54 { - /* |x| > log(3)/2 ~= 0.5493 or nan */ - if w > 0x41200000 { - /* |x| > 10 */ - 1. + 0. / x - } else { - let t = expm1f(2. * x); - 1. - 2. / (t + 2.) - } - } else if w > 0x3e82c578 { - /* |x| > log(5/3)/2 ~= 0.2554 */ - let t = expm1f(2. * x); - t / (t + 2.) - } else if w >= 0x00800000 { - /* |x| >= 0x1p-126 */ - let t = expm1f(-2. * x); - -t / (t + 2.) - } else { - /* |x| is subnormal */ - force_eval!(x * x); - x - }; - if sign { - -tt - } else { - tt - } -} diff --git a/helpers/l2math/core/tgamma.rs b/helpers/l2math/core/tgamma.rs deleted file mode 100644 index 0e08d92..0000000 --- a/helpers/l2math/core/tgamma.rs +++ /dev/null @@ -1,211 +0,0 @@ -/* -"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) -"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) -"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) - -approximation method: - - (x - 0.5) S(x) -Gamma(x) = (x + g - 0.5) * ---------------- - exp(x + g - 0.5) - -with - a1 a2 a3 aN -S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] - x + 1 x + 2 x + 3 x + N - -with a0, a1, a2, a3,.. aN constants which depend on g. - -for x < 0 the following reflection formula is used: - -Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) - -most ideas and constants are from boost and python -*/ - -use crate::{Float64, Float32}; - -use super::{exp, floor, k_cos, k_sin, pow}; - -use core::f64::consts::PI; - -/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ -fn sinpi(mut x: Float64) -> Float64 { - let mut n: isize; - - /* argument reduction: x = |x| mod 2 */ - /* spurious inexact when x is odd int */ - x = x * 0.5; - x = 2.0 * (x - floor(x)); - - /* reduce x into [-.25,.25] */ - n = (4.0 * x) as isize; - n = div!(n + 1, 2); - x -= (n as Float64) * 0.5; - - x *= PI; - match n { - 1 => k_cos(x, 0.0), - 2 => k_sin(-x, 0.0, 0), - 3 => -k_cos(x, 0.0), - _ => k_sin(x, 0.0, 0), - } -} - -consts!{ -const N: usize = 12; -//static const double g = 6.024680040776729583740234375; -const GMHALF: Float64 = 5.524680040776729583740234375; -const SNUM: [Float64; N + 1] = [ - 23531376880.410759688572007674451636754734846804940, - 42919803642.649098768957899047001988850926355848959, - 35711959237.355668049440185451547166705960488635843, - 17921034426.037209699919755754458931112671403265390, - 6039542586.3520280050642916443072979210699388420708, - 1439720407.3117216736632230727949123939715485786772, - 248874557.86205415651146038641322942321632125127801, - 31426415.585400194380614231628318205362874684987640, - 2876370.6289353724412254090516208496135991145378768, - 186056.26539522349504029498971604569928220784236328, - 8071.6720023658162106380029022722506138218516325024, - 210.82427775157934587250973392071336271166969580291, - 2.5066282746310002701649081771338373386264310793408, -]; -const SDEN: [Float64; N + 1] = [ - 0.0, - 39916800.0, - 120543840.0, - 150917976.0, - 105258076.0, - 45995730.0, - 13339535.0, - 2637558.0, - 357423.0, - 32670.0, - 1925.0, - 66.0, - 1.0, -]; -/* n! for small integer n */ -const FACT: [Float64; 23] = [ - 1.0, - 1.0, - 2.0, - 6.0, - 24.0, - 120.0, - 720.0, - 5040.0, - 40320.0, - 362880.0, - 3628800.0, - 39916800.0, - 479001600.0, - 6227020800.0, - 87178291200.0, - 1307674368000.0, - 20922789888000.0, - 355687428096000.0, - 6402373705728000.0, - 121645100408832000.0, - 2432902008176640000.0, - 51090942171709440000.0, - 1124000727777607680000.0, -]; -} - -/* S(x) rational function for positive x */ -fn s(x: Float64) -> Float64 { - let mut num: Float64 = 0.0; - let mut den: Float64 = 0.0; - - /* to avoid overflow handle large x differently */ - if x < 8.0 { - for i in (0..=N).rev() { - num = num * x + i!(SNUM, i); - den = den * x + i!(SDEN, i); - } - } else { - for i in 0..=N { - num = num / x + i!(SNUM, i); - den = den / x + i!(SDEN, i); - } - } - return num / den; -} - -/// Returns the gamma function of `x`. -#[export_name = "__l2math_tgamma"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn tgamma(mut x: Float64) -> Float64 { - let u: u64 = x.to_bits(); - let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; - let sign: bool = (u >> 63) != 0; - - /* special cases */ - if ix >= 0x7ff00000 { - /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ - return x + core::f64::INFINITY; - } - if ix < ((0x3ff - 54) << 20) { - /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ - return 1.0 / x; - } - - /* integer arguments */ - /* raise inexact when non-integer */ - if x == floor(x) { - if sign { - return Float64::NAN; - } - if x <= FACT.len() as Float64 { - return i!(FACT, (x as usize) - 1); - } - } - - /* x >= 172: tgamma(x)=inf with overflow */ - /* x =< -184: tgamma(x)=+-0 with underflow */ - if ix >= 0x40670000 { - /* |x| >= 184 */ - if sign { - let x1p_126 = Float64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 - force_eval!((x1p_126 / x) as Float32); - if floor(x) * 0.5 == floor(x * 0.5) { - return 0.0; - } else { - return -0.0; - } - } - let x1p1023 = Float64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 - x *= x1p1023; - return x; - } - - let absx: Float64 = if sign { -x } else { x }; - - /* handle the error of x + g - 0.5 */ - let mut y = absx + GMHALF; - let mut dy: Float64; - let mut z: Float64; - if absx > GMHALF { - dy = y - absx; - dy -= GMHALF; - } else { - dy = y - GMHALF; - dy -= absx; - } - - z = absx - 0.5; - let mut r = s(absx) * exp(-y); - if x < 0.0 { - /* reflection formula for negative x */ - /* sinpi(absx) is not 0, integers are already handled */ - r = -PI / (sinpi(absx) * absx * r); - dy = -dy; - z = -z; - } - r += dy * (GMHALF + 0.5) * r / y; - z = pow(y, 0.5 * z); - y = r * z * z; - return y; -} diff --git a/helpers/l2math/core/tgammaf.rs b/helpers/l2math/core/tgammaf.rs deleted file mode 100644 index e5ad039..0000000 --- a/helpers/l2math/core/tgammaf.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::{Float64, Float32}; - -use super::tgamma; - -/// Returns the gamma function of `x`. -#[inline] -#[export_name = "__l2math_tgammaf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn tgammaf(x: Float32) -> Float32 { - tgamma(x as Float64) as Float32 -} diff --git a/helpers/l2math/core/trunc.rs b/helpers/l2math/core/trunc.rs deleted file mode 100644 index f40c6fd..0000000 --- a/helpers/l2math/core/trunc.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::Float64; - -/// Returns the integer part of self. -/// This means that non-integer numbers are always truncated towards zero. -#[export_name = "__l2math_trunc"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn trunc(x: Float64) -> Float64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `Float64.trunc` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::truncf64(x) } - } - } - let x1p120 = Float64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 - - let mut i: u64 = x.to_bits(); - let mut e: i64 = (i >> 52 & 0x7ff) as i64 - 0x3ff + 12; - - if e >= 52 + 12 { - return x; - } - if e < 12 { - e = 1; - } - let m: u64 = -1i64 as u64 >> e; - if (i & m) == 0 { - return x; - } - force_eval!(x + x1p120); - i &= !m; - Float64::from_bits(i) -} - -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::trunc(1.1), 1.0); - } -} diff --git a/helpers/l2math/core/truncf.rs b/helpers/l2math/core/truncf.rs deleted file mode 100644 index 3ebeb71..0000000 --- a/helpers/l2math/core/truncf.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::{Float32, Int}; - -/// Returns the integer part of self. -/// This means that non-integer numbers are always truncated towards zero. -#[export_name = "__l2math_truncf"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub extern "C" fn truncf(x: Float32) -> Float32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `Float32.trunc` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::truncf32(x) } - } - } - let x1p120 = Float32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let mut i: u32 = x.to_bits(); - let mut e: Int = (i >> 23 & 0xff) as Int - 0x7f + 9; - - if e >= 23 + 9 { - return x; - } - if e < 9 { - e = 1; - } - let m: u32 = -1i32 as u32 >> e; - if (i & m) == 0 { - return x; - } - force_eval!(x + x1p120); - i &= !m; - Float32::from_bits(i) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::truncf(1.1), 1.0); - } -} diff --git a/helpers/l2math/core/ulp.rs b/helpers/l2math/core/ulp.rs deleted file mode 100644 index 8977a37..0000000 --- a/helpers/l2math/core/ulp.rs +++ /dev/null @@ -1,115 +0,0 @@ -use crate::Float64; - -const MANTISSA_BITS: u64 = 52; -const EXPONENT_BITS: u64 = 11; -const POS_ZERO_BITS: u64 = 0x0000000000000000; -const NEG_ZERO_BITS: u64 = 0x8000000000000000; - -/// Returns the value of the least significant bit of the given floating point number. -/// -/// Note: this function can technically be `const` but we need to wait for: -/// - [`const_fn_floating_point_arithmetic`](https://github.com/rust-lang/rust/issues/57241) -/// - [`const_float_classify`](https://github.com/rust-lang/rust/issues/72505) -/// - [`const_fn_floating_point_arithmetic`](https://github.com/rust-lang/rust/issues/57241) -#[inline] -#[allow(unused_variables)] -#[export_name = "__l2math_ulp"] -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -#[must_use = "This function returns the least significant bit of the argument."] -pub extern "C" fn ulp(x: Float64) -> Float64 { - // SAFETY: x is a normal number, so it is finite and not zero. - if x.is_nan() { - return x; - } - if x.is_infinite() { - return Float64::INFINITY; - } - if x == Float64::MAX || x == -Float64::MAX || - x == Float64::MIN || x == -Float64::MIN || - x == Float64::MIN_POSITIVE || x == -Float64::MIN_POSITIVE { - return x; - } - - // Last sanity check - let bits = x.to_bits(); - - if bits == POS_ZERO_BITS { - return Float64::MIN_POSITIVE; - } - if bits == NEG_ZERO_BITS { - return -Float64::MIN_POSITIVE; - } - - // Actual code - let mant_mask = (1 << MANTISSA_BITS) - 1; - let mantissa = bits & mant_mask; - let exp_mask = (1 << EXPONENT_BITS) - 1; - let exponent = (bits >> MANTISSA_BITS) & exp_mask; - if exponent == 0 { - let result = (exponent << MANTISSA_BITS) | 1; - return Float64::from_bits(result); - }; - let mut new_exponent = exponent - MANTISSA_BITS; - let new_mantissa: u64; - if new_exponent > 0 { - new_mantissa = 0; - } else { - new_mantissa = 1 << -(new_exponent as i64 - 1); - new_exponent = 0; - }; - Float64::from_bits((new_exponent << MANTISSA_BITS) | new_mantissa) -} - -#[test] -fn zero_ulp() { - assert_eq!(ulp(0.0), Float64::MIN_POSITIVE); - assert_eq!(ulp(-0.0), -Float64::MIN_POSITIVE); -} - -#[test] -fn one_ulp() { - assert_eq!(ulp(1.0), Float64::EPSILON); - assert_eq!(ulp(-1.0), Float64::EPSILON); -} - -#[test] -fn two_ulp() { - assert_eq!(ulp(2.0), Float64::EPSILON * 2.0); - assert_eq!(ulp(-2.0), Float64::EPSILON * 2.0); -} - -#[test] -fn half_ulp() { - assert_eq!(ulp(0.5), Float64::EPSILON / 2.0); - assert_eq!(ulp(-0.5), Float64::EPSILON / 2.0); -} - -#[test] -fn max_value_ulp() { - assert_eq!(ulp(Float64::MAX), Float64::MAX); - assert_eq!(ulp(-Float64::MAX), -Float64::MAX); -} - -#[test] -fn min_value_ulp() { - assert_eq!(ulp(Float64::MIN), Float64::MIN); - assert_eq!(ulp(-Float64::MIN), -Float64::MIN); -} - -#[test] -fn infinity_ulp() { - assert_eq!(ulp(Float64::INFINITY), Float64::INFINITY); - assert_eq!(ulp(-Float64::INFINITY), Float64::INFINITY); -} - -#[test] -fn nan_ulp() { - assert!(ulp(Float64::NAN).is_nan()); - assert!(ulp(-Float64::NAN).is_nan()); -} - -#[test] -fn subnormal_ulp() { - assert_eq!(ulp(Float64::MIN_POSITIVE), Float64::MIN_POSITIVE); - assert_eq!(ulp(-Float64::MIN_POSITIVE), -Float64::MIN_POSITIVE); -} diff --git a/helpers/l2math/lib.rs b/helpers/l2math/lib.rs deleted file mode 100644 index 0c66894..0000000 --- a/helpers/l2math/lib.rs +++ /dev/null @@ -1,58 +0,0 @@ -#![doc = include_str!("./README.md")] -#![no_std] -#![cfg_attr(feature = "unstable", feature(core_intrinsics))] -#![warn(missing_docs, unused, clippy::all)] -#![allow(unused_unsafe)] -#![allow(clippy::unreadable_literal)] -#![allow(clippy::many_single_char_names)] -#![allow(clippy::needless_return)] -#![allow(clippy::int_plus_one)] -#![allow(clippy::deprecated_cfg_attr)] -#![allow(clippy::mixed_case_hex_literals)] -#![allow(clippy::float_cmp)] -#![allow(clippy::eq_op)] -#![allow(clippy::assign_op_pattern)] - -mod core; -mod types; -mod consts; - -#[path = "macros.rs"] -mod __macros; - -pub use self::core::*; -pub use self::types::*; -pub use self::consts::*; - -/// Approximate equality with 1 ULP of tolerance -#[inline] -#[doc(hidden)] -pub(crate) fn _eqf(a: Float32, b: Float32) -> Result<(), u32> { - if a.is_nan() && b.is_nan() { - Ok(()) - } else { - let err = (a.to_bits() as Int).wrapping_sub(b.to_bits() as Int).abs(); - - if err <= 1 { - Ok(()) - } else { - Err(err as u32) - } - } -} - -#[inline] -#[doc(hidden)] -pub(crate) fn _eq(a: Float64, b: Float64) -> Result<(), u64> { - if a.is_nan() && b.is_nan() { - Ok(()) - } else { - let err = (a.to_bits() as i64).wrapping_sub(b.to_bits() as i64).abs(); - - if err <= 1 { - Ok(()) - } else { - Err(err as u64) - } - } -} diff --git a/helpers/l2math/macros.rs b/helpers/l2math/macros.rs deleted file mode 100644 index 4bb58f7..0000000 --- a/helpers/l2math/macros.rs +++ /dev/null @@ -1,21 +0,0 @@ -/// Sigma `Σ` macro -/// -/// This is basically a for loop that sums up the values of the expression -#[macro_export] -macro_rules! Σ { - ($finish:expr => $( $tt:tt )*) => ( - $crate::Σ!(0, $finish, 1 => $( $tt )*) - ); - - ($start:expr, $finish:expr, $step:literal => { $( $tt:tt )* }) => {{ - let mut sum = T::from(0.0); - let mut i = $start; - while i < $finish { - sum += { - $( $tt )* - }; - i += $step; - } - sum - }}; -} diff --git a/helpers/l2math/types.rs b/helpers/l2math/types.rs deleted file mode 100644 index 94c831d..0000000 --- a/helpers/l2math/types.rs +++ /dev/null @@ -1,24 +0,0 @@ -type __Float64 = f64; -type __Float32 = f32; -type __Int = i32; - -/// Radians (64bit) -pub type Radian64 = __Float64; - -/// Radians (32bit) -pub type Radian32 = __Float32; - -/// Degrees (64bit) -pub type Degree64 = __Float64; - -/// Degrees (32bit) -pub type Degree32 = __Float32; - -/// A floating point number (64bit) -pub type Float64 = __Float64; - -/// A floating point number (32bit) -pub type Float32 = __Float32; - -/// A signed integer (32bit) -pub type Int = __Int; diff --git a/helpers/libtrig/Cargo.toml b/helpers/libtrig/Cargo.toml deleted file mode 100644 index 3119fb5..0000000 --- a/helpers/libtrig/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "libtrig" -description = "Trigonometry functionality" -repository.workspace = true -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true - -[lib] -path = "lib.rs" - -[dependencies.macros] -path = "../macros" - -[dependencies.l2math] -path = "../l2math" - -[features] -unstable = ["l2math/unstable"] diff --git a/helpers/libtrig/README.md b/helpers/libtrig/README.md deleted file mode 100644 index 8e1b729..0000000 --- a/helpers/libtrig/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# LibTrig - -## Trigonometry functionality (angles, vectors, etc.) - -Uses [`l2math`](../l2math/) for math functions. - -It is primarily intended to be used by other libraries that require trigonometry functionality. Such as [`libodo`](../libodo/) for odometry, and [`libpath`](../libpath/) for pathing. diff --git a/helpers/libtrig/angle.rs b/helpers/libtrig/angle.rs deleted file mode 100644 index db4b809..0000000 --- a/helpers/libtrig/angle.rs +++ /dev/null @@ -1,606 +0,0 @@ -use crate::*; - -/// A wrapper around a `float` value that represents an angle. -/// -/// It can be created from either radians or degrees, and can be converted to either radians or degrees. -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Angle2D(RadianOrDegree64, bool); - -const DEG_TO_RAD_MULTIPLIER: Float64 = 0.0174532925199432957692369076848861271344287188854172545609; -const RAD_TO_DEG_MULTIPLIER: Float64 = 57.29577951308232087679815481410517033240547246656432154916; - -impl Angle2D { - /// Converts the given `deg` value to radians. - #[inline] - #[macros::func_mod(const => feature = "unstable")] - pub fn deg_to_rad(deg: Degree64) -> Radian64 { - deg * DEG_TO_RAD_MULTIPLIER - } - /// Converts the given `rad` value to degrees. - #[inline] - #[macros::func_mod(const => feature = "unstable")] - pub fn rad_to_deg(rad: Radian64) -> Degree64 { - rad * RAD_TO_DEG_MULTIPLIER - } -} - -impl Angle2D { - /// Creates a new `Angle2D` from the given `value` and `is_radians` flag. - #[inline] - #[must_use] - pub const fn new(value: RadianOrDegree64, is_radians: bool) -> Self { - Self(value, is_radians) - } - /// Creates a new `Angle2D` from the given `value` in radians. - #[inline] - #[must_use] - pub const fn from_radians(value: Radian64) -> Self { - Self::new(value, true) - } - /// Creates a new `Angle2D` from the given `value` in degrees. - #[inline] - #[must_use] - pub const fn from_degrees(value: Degree64) -> Self { - Self::new(value, false) - } - /// Creates a new `Angle2D` with a value of `0.0` radians. - #[inline] - #[must_use] - pub const fn zero() -> Self { - Self::new(0.0, true) - } - /// Creates a new `Angle2D` with a value of `0.0` degrees. - #[inline] - #[must_use] - pub const fn zero_deg() -> Self { - Self::new(0.0, false) - } - /// Returns the value of the angle in radians. - #[inline] - #[must_use] - #[macros::func_mod(const => feature = "unstable")] - pub fn to_radians(&self) -> Radian64 { - if self.1 { - return self.0; - } - Self::deg_to_rad(self.0) - } - /// Returns the value of the angle in degrees. - #[inline] - #[must_use] - #[macros::func_mod(const => feature = "unstable")] - pub fn to_degrees(&self) -> Degree64 { - if !self.1 { - return self.0; - } - Self::rad_to_deg(self.0) - } - /// If the angle is in degrees, converts it to radians. - #[inline] - #[macros::func_mod(const => feature = "unstable")] - pub fn set_self_radians(&mut self) { - if !self.1 { - self.0 = Self::deg_to_rad(self.0); - self.1 = true; - } - } - /// If the angle is in radians, converts it to degrees. - #[inline] - #[macros::func_mod(const => feature = "unstable")] - pub fn set_self_degrees(&mut self) { - if self.1 { - self.0 = Self::rad_to_deg(self.0); - self.1 = false; - } - } - /// Sets the mode of self. - /// - /// If `mode` is `true`, then the angle is in radians. - /// If `mode` is `false`, then the angle is in degrees. - /// - /// This is unsafe because it does not convert the internal value. - #[inline(always)] - #[allow(unsafe_code)] - #[macros::func_mod(const => feature = "unstable")] - pub unsafe fn modify_self_mode_unchecked(&mut self, mode: bool) { - self.1 = mode; - } - /// Sets the value of self. - /// - /// This is unsafe because it does not convert the internal value. - #[inline(always)] - #[allow(unsafe_code)] - #[macros::func_mod(const => feature = "unstable")] - pub unsafe fn modify_self_value_unchecked(&mut self, value: RadianOrDegree64) { - self.0 = value; - } -} - -impl From for Angle2D { - /// Creates a new `Angle2D` from the given `Vec2D`. - /// - /// This is equivalent to `Angle2D::from_radians(v.y().atan2(v.x()))`. - #[inline] - #[must_use] - fn from(v: Vec2D) -> Self { - crate::prelude!(); - Self::from_radians(v.y().atan2(v.x())) - } -} - -impl From<(Float64, Float64)> for Angle2D { - /// Creates a new `Angle2D` from the given `(x, y)` pair. - /// - /// This is equivalent to `Angle2D::from_radians(y.atan2(x))`. - #[inline] - #[must_use] - fn from((x, y): (Float64, Float64)) -> Self { - crate::prelude!(); - Self::from_radians(y.atan2(x)) - } -} - -impl From for Vec2D { - /// Creates a new `Vec2D` from the given `Angle2D`. - /// - /// This is equivalent to `Vec2D::new(a.cos(), a.sin())`. - /// - /// THE VECTOR MAY OR MAY NOT BE NORMALIZED. - #[inline] - #[must_use] - fn from(a: Angle2D) -> Self { - crate::prelude!(); - Self::new(a.cos(), a.sin()) - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::Add for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() + rhs.to_radians()) - } else { - Angle2D::from_degrees(self.to_degrees() + rhs.to_degrees()) - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::Add for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() + rhs) - } else { - Angle2D::from_degrees(self.to_degrees() + rhs) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() + rhs.to_radians(); - } else { - self.0 = self.to_degrees() + rhs.to_degrees(); - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() + rhs; - } else { - self.0 = self.to_degrees() + rhs; - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::Sub for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() - rhs.to_radians()) - } else { - Angle2D::from_degrees(self.to_degrees() - rhs.to_degrees()) - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::Sub for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() - rhs) - } else { - Angle2D::from_degrees(self.to_degrees() - rhs) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() - rhs.to_radians(); - } else { - self.0 = self.to_degrees() - rhs.to_degrees(); - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() - rhs; - } else { - self.0 = self.to_degrees() - rhs; - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::Mul for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() * rhs.to_radians()) - } else { - Angle2D::from_degrees(self.to_degrees() * rhs.to_degrees()) - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::Mul for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() * rhs) - } else { - Angle2D::from_degrees(self.to_degrees() * rhs) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() * rhs.to_radians(); - } else { - self.0 = self.to_degrees() * rhs.to_degrees(); - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() * rhs; - } else { - self.0 = self.to_degrees() * rhs; - } - } -} - -#[macros::mass_impl( - $THIS = @ORM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::Div for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() / rhs.to_radians()) - } else { - Angle2D::from_degrees(self.to_degrees() / rhs.to_degrees()) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::Div for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - if self.1 { - Angle2D::from_radians(self.to_radians() / rhs) - } else { - Angle2D::from_degrees(self.to_degrees() / rhs) - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Angle2D -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() / rhs.to_radians(); - } else { - self.0 = self.to_degrees() / rhs.to_degrees(); - } - } -} - -#[macros::mass_impl( - $THIS = @OM Angle2D, - $OTHER = @OR Float64 -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - if self.1 { - self.0 = self.to_radians() / rhs; - } else { - self.0 = self.to_degrees() / rhs; - } - } -} - -#[macros::mass_impl($THIS = @ORM Angle2D)] -impl core::ops::Neg for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn neg(self) -> Self::Output { - if self.1 { - Angle2D::from_radians(-self.to_radians()) - } else { - Angle2D::from_degrees(-self.to_degrees()) - } - } -} - -impl Default for Angle2D { - #[inline] - #[must_use] - fn default() -> Self { - Self::zero() - } -} - -impl core::fmt::Display for Angle2D { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - if self.1 { - return write!(f, "{}rad", self.to_radians()); - } - write!(f, "{}°", self.to_degrees()) - } -} - -impl> From<(F, bool)> for Angle2D { - #[inline] - #[must_use] - fn from((f, r): (F, bool)) -> Self { - if r { - Self::from_radians(f.into()) - } else { - Self::from_degrees(f.into()) - } - } -} - -impl crate::traits::Number for Angle2D {} - -macro_rules! i { - ($n:ident $($t:tt)*) => ( - #[inline] - #[must_use] - fn $n(&self) -> Float64 { - self.0.$n() - } - i!($($t)*); - ); - () => (); -} - -impl From for Angle2D { - #[inline] - #[must_use] - fn from(u: u3) -> Self { - Self::from_radians(u.into()) - } -} - -impl crate::traits::Sin for Angle2D { - #[inline] - #[must_use] - fn sin(&self) -> Float64 { - l2math::sin(self.to_radians()) - } -} - -impl crate::traits::Cos for Angle2D { - #[inline] - #[must_use] - fn cos(&self) -> Float64 { - l2math::cos(self.to_radians()) - } -} - -impl crate::traits::Sqrt for Angle2D { - #[inline] - #[must_use] - fn sqrt(&self) -> Float64 { - self.0.sqrt() - } -} - -impl crate::traits::Float for Angle2D { - #[inline] - #[must_use] - fn mul_add(&self, a: Self, b: Self) -> Float64 { - self.0.mul_add(a.0, b.0) - } - #[inline] - #[must_use] - fn div_euclid(&self, rhs: Self) -> Float64 { - self.0.div_euclid(rhs.0) - } - #[inline] - #[must_use] - fn rem_euclid(&self, rhs: Self) -> Float64 { - self.0.rem_euclid(rhs.0) - } - #[inline] - #[must_use] - fn powi(&self, n: Int) -> Float64 { - self.0.powi(n) - } - #[inline] - #[must_use] - fn powf(&self, n: Self) -> Float64 { - self.0.powf(n.0) - } - #[inline] - #[must_use] - fn log(&self, base: Self) -> Float64 { - self.0.log(base.0) - } - #[inline] - #[must_use] - fn atan2(&self, other: Self) -> Float64 { - self.to_radians().atan2(other.0) - } - #[inline] - #[must_use] - fn hypot(&self, other: Self) -> Float64 { - self.to_radians().hypot(other.0) - } - #[inline] - #[must_use] - fn sin_cos(&self) -> (Float64, Float64) { - self.to_radians().sin_cos() - } - #[inline] - #[must_use] - fn signof(&self, rhs: Self) -> Float64 { - self.0.signof(rhs.0) - } - #[inline] - #[must_use] - fn tan(&self) -> Float64 { - l2math::tan(self.to_radians()) - } - #[inline] - #[must_use] - fn asin(&self) -> Float64 { - l2math::asin(self.to_radians()) - } - #[inline] - #[must_use] - fn acos(&self) -> Float64 { - l2math::acos(self.to_radians()) - } - #[inline] - #[must_use] - fn atan(&self) -> Float64 { - l2math::atan(self.to_radians()) - } - #[inline] - #[must_use] - fn sinh(&self) -> Float64 { - l2math::sinh(self.to_radians()) - } - #[inline] - #[must_use] - fn cosh(&self) -> Float64 { - l2math::cosh(self.to_radians()) - } - #[inline] - #[must_use] - fn tanh(&self) -> Float64 { - l2math::tanh(self.to_radians()) - } - #[inline] - #[must_use] - fn asinh(&self) -> Float64 { - l2math::asinh(self.to_radians()) - } - #[inline] - #[must_use] - fn acosh(&self) -> Float64 { - l2math::acosh(self.to_radians()) - } - #[inline] - #[must_use] - fn atanh(&self) -> Float64 { - l2math::atanh(self.to_radians()) - } - - i!(floor ceil round trunc fract abs signum exp exp2 ln log2 log10 cbrt exp_m1 ln_1p); -} diff --git a/helpers/libtrig/coords/coord2d.rs b/helpers/libtrig/coords/coord2d.rs deleted file mode 100644 index 0396ac8..0000000 --- a/helpers/libtrig/coords/coord2d.rs +++ /dev/null @@ -1,319 +0,0 @@ -use crate::*; - -/// A wrapper around a `float` value that represents a 2D coordinate. -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Coord2D { - x: Float64, - y: Float64, -} - -impl Coord2D { - /// Creates a new `Vec2D` from the given `x` and `y` values. - #[inline] - #[must_use] - pub const fn new(x: Float64, y: Float64) -> Self { - Self { x, y } - } - /// Creates a new `Vec2D` located at the origin. - #[inline] - #[must_use] - pub const fn origin() -> Self { - Self::new(0.0, 0.0) - } - /// Rotates the vector by the given angle in radians. - #[inline] - #[must_use] - pub fn rotate_by(&self, angle: Angle2D) -> Self { - #[allow(unused_imports)] - use crate::traits::Float; - let angle = angle.to_radians(); - let (sin, cos) = angle.sin_cos(); - Self::new(self.x * cos - self.y * sin, self.x * sin + self.y * cos) - } - /// Returns the angle of the vector in radians. - #[inline] - #[must_use] - pub fn angle(&self) -> Angle2D { - #[allow(unused_imports)] - use crate::traits::Float; - Angle2D::from_radians(self.y.atan2(self.x)) - } - /// Returns the inverted position. - /// - /// Same as rotating the position by 180 degrees. - #[inline] - #[must_use] - pub fn inverse(&self) -> Self { - -self - } - /// Returns the x coordinate. - #[inline] - #[must_use] - pub const fn x(&self) -> Float64 { - self.x - } - /// Returns the y coordinate. - #[inline] - #[must_use] - pub const fn y(&self) -> Float64 { - self.y - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::Add for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x + rhs.x(), self.y + rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::Add for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x + rhs.x, self.y + rhs.y) - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.x += rhs.x(); - self.y += rhs.y(); - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.x += rhs.x; - self.y += rhs.y; - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::Sub for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x - rhs.x(), self.y - rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::Sub for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x - rhs.x, self.y - rhs.y) - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.x -= rhs.x(); - self.y -= rhs.y(); - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @ORM Coord2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.x -= rhs.x; - self.y -= rhs.y; - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @OR Float64 -)] -impl core::ops::Mul for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x * rhs, self.y * rhs) - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @OR Vec2D -)] -impl core::ops::Mul for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x * rhs.x(), self.y * rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @OR Float64 -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - self.x *= rhs; - self.y *= rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @OR Vec2D -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - self.x *= rhs.x(); - self.y *= rhs.y(); - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @OR Float64 -)] -impl core::ops::Div for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x / rhs, self.y / rhs) - } -} - -#[macros::mass_impl( - $THIS = @ORM Coord2D, - $OTHER = @OR Vec2D -)] -impl core::ops::Div for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - Coord2D::new(self.x / rhs.x(), self.y / rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @OR Float64 -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - self.x /= rhs; - self.y /= rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Coord2D, - $OTHER = @OR Vec2D -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - self.x /= rhs.x(); - self.y /= rhs.y(); - } -} - -#[macros::mass_impl($THIS = @ORM Coord2D)] -impl core::ops::Neg for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn neg(self) -> Self::Output { - Coord2D::new(-self.x, -self.y) - } -} - -impl core::fmt::Display for Coord2D { - #[inline] - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "[{}, {}]", self.x, self.y) - } -} - -impl Default for Coord2D { - #[inline] - #[must_use] - fn default() -> Self { - Self::origin() - } -} - -impl> From<(F, F)> for Coord2D { - #[inline] - #[must_use] - fn from((x, y): (F, F)) -> Self { - Self::new(x.into(), y.into()) - } -} - -impl From for (Float64, Float64) { - #[inline] - #[must_use] - fn from(Coord2D { x, y }: Coord2D) -> Self { - (x, y) - } -} - -impl From for Coord2D { - #[inline] - #[must_use] - fn from(vec: crate::Vec2D) -> Self { - Self::new(vec.x(), vec.y()) - } -} - -impl From for crate::Vec2D { - #[inline] - #[must_use] - fn from(vec: Coord2D) -> Self { - Self::new(vec.x, vec.y) - } -} diff --git a/helpers/libtrig/coords/coord3d.rs b/helpers/libtrig/coords/coord3d.rs deleted file mode 100644 index 983f41c..0000000 --- a/helpers/libtrig/coords/coord3d.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::*; - -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Coord3D { - pub x: Float, - pub y: Float, - pub z: Float, -} \ No newline at end of file diff --git a/helpers/libtrig/coords/mod.rs b/helpers/libtrig/coords/mod.rs deleted file mode 100644 index 2589cb1..0000000 --- a/helpers/libtrig/coords/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod coord2d; -// mod coord3d; - -pub use coord2d::Coord2D; -// pub use coord3d::Coord3D; diff --git a/helpers/libtrig/lib.rs b/helpers/libtrig/lib.rs deleted file mode 100644 index b2930b5..0000000 --- a/helpers/libtrig/lib.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![no_std] -#![cfg_attr(feature = "unstable", feature(const_fn_floating_point_arithmetic))] -#![cfg_attr(feature = "unstable", feature(const_mut_refs))] -#![cfg_attr(feature = "unstable", feature(const_mut_refs))] -#![warn(missing_docs, unused, clippy::all, unsafe_code)] -#![deny(missing_debug_implementations)] -#![doc = include_str!("./README.md")] - -pub(crate) mod angle; -pub(crate) mod coords; -pub(crate) mod morenums; -pub(crate) mod pos2d; -pub(crate) mod traits; -pub(crate) mod types; -pub(crate) mod vectors; - -pub mod prelude { - //! Re-exports all the traits. - pub use super::traits::*; -} - -pub use angle::Angle2D; -pub use coords::Coord2D; -pub use morenums::{u2, u3}; -pub use pos2d::Pos2D; -pub use types::*; -pub use vectors::{Vec2D, Vec3D}; - -/// Re-exports all the traits. -#[macro_export] -macro_rules! prelude { - () => { - #[allow(unused_imports)] - use $crate::prelude::*; - }; -} diff --git a/helpers/libtrig/morenums/mod.rs b/helpers/libtrig/morenums/mod.rs deleted file mode 100644 index d6c9911..0000000 --- a/helpers/libtrig/morenums/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -#[path = "./u2/mod.rs"] -mod _u2; -#[path = "./u3/mod.rs"] -mod _u3; - -/// A simple type alias for a bit. -#[allow(non_camel_case_types)] -pub type bit = bool; - -pub use _u2::u2; -pub use _u3::u3; - -impl From for u3 { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u3::fromu2(u) - } -} - -impl From for u2 { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u2::fromu3(u) - } -} diff --git a/helpers/libtrig/morenums/u2/impls.rs b/helpers/libtrig/morenums/u2/impls.rs deleted file mode 100644 index 1a8a32a..0000000 --- a/helpers/libtrig/morenums/u2/impls.rs +++ /dev/null @@ -1,173 +0,0 @@ -use super::source::*; - -impl core::fmt::Display for u2 { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", u8::from(*self)) - } -} - -impl core::default::Default for u2 { - #[must_use] - #[inline(always)] - fn default() -> Self { - Self::ZERO - } -} - -impl From for u8 { - /// Convert a `u2` to a `u8`. - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u2::tou8(u) - } -} - -impl From for u2 { - /// Convert a `u8` to a `u3`. - /// - /// # Safety - /// - /// In debug mode, this will panic if the `u8` is out of range. In release - /// mode, this uses `core::hint::unreachable_unchecked` to enable optimizations. - #[must_use] - #[inline(always)] - fn from(u: u8) -> Self { - debug_assert!(u <= 7, "u8 out of range: {}", u); - Self::fromu8(u) - } -} - -impl From for u16 { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u8::from(u) as u16 - } -} - -impl From for u32 { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u8::from(u) as u32 - } -} - -impl From for u64 { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u8::from(u) as u64 - } -} - -impl From for u128 { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u8::from(u) as u128 - } -} - -impl From for usize { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u8::from(u) as usize - } -} - -impl From for i8 { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u8::from(u) as i8 - } -} - -impl From for i16 { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u8::from(u) as i16 - } -} - -impl From for i32 { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u8::from(u) as i32 - } -} - -impl From for i64 { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u8::from(u) as i64 - } -} - -impl From for i128 { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u8::from(u) as i128 - } -} - -impl From for isize { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u8::from(u) as isize - } -} - -impl From for crate::Float32 { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u8::from(u) as crate::Float32 - } -} - -impl From for crate::Float64 { - #[must_use] - #[inline(always)] - fn from(u: u2) -> Self { - u8::from(u) as crate::Float64 - } -} - -impl core::ops::AddAssign for u2 { - #[inline] - fn add_assign(&mut self, rhs: Self) { - *self = *self + rhs; - } -} - -impl core::ops::SubAssign for u2 { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - *self = *self - rhs; - } -} - -impl core::ops::MulAssign for u2 { - #[inline] - fn mul_assign(&mut self, rhs: Self) { - *self = *self * rhs; - } -} - -impl core::ops::DivAssign for u2 { - #[inline] - fn div_assign(&mut self, rhs: Self) { - *self = *self / rhs; - } -} - -impl crate::traits::Number for u2 {} diff --git a/helpers/libtrig/morenums/u2/mod.rs b/helpers/libtrig/morenums/u2/mod.rs deleted file mode 100644 index 1448d7d..0000000 --- a/helpers/libtrig/morenums/u2/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod impls; -mod source; -mod tests; - -pub use source::u2; diff --git a/helpers/libtrig/morenums/u2/source.rs b/helpers/libtrig/morenums/u2/source.rs deleted file mode 100644 index d9b1d3c..0000000 --- a/helpers/libtrig/morenums/u2/source.rs +++ /dev/null @@ -1,387 +0,0 @@ -use crate::morenums::bit; - -/// The 2-bit unsigned integer type. -#[repr(C)] -#[derive(Clone, Copy, Eq, Hash)] -#[allow(non_camel_case_types)] -pub struct u2(pub(crate) bit, pub(crate) bit); - -impl u2 { - /// Maximum value of `u2`. (3) - pub const MAX: Self = Self::new(true, true); - /// Minimum value of `u2`. (0) - pub const MIN: Self = Self::new(false, false); - /// Zero value of `u2`. (0) - pub const ZERO: Self = Self::MIN; - /// One value of `u2`. (1) - pub const ONE: Self = Self::new(true, false); - /// Two value of `u2`. (2) - pub const TWO: Self = Self::new(false, true); - /// Three value of `u2`. (3) - pub const THREE: Self = Self::MAX; - /// Create a new `u2` - #[inline] - #[must_use] - pub const fn new(ones: bit, twos: bit) -> Self { - Self(ones, twos) - } - /// Convert a `u2` to a `u8`. - #[must_use] - #[inline(always)] - pub const fn tou8(self) -> u8 { - if self.0 && self.1 { - 3 - } else if self.0 { - 1 - } else if self.1 { - 2 - } else { - 0 - } - } - /// Convert a `u8` to a `u3`. - /// - /// # Safety - /// - /// This uses `core::hint::unreachable_unchecked` to enable optimizations, so - /// it is unsafe to use in debug mode. Instead, use `u3::fromu8`. - #[must_use] - #[inline(always)] - #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] - pub const fn fromu8(u: u8) -> Self { - match u { - 0 => Self::ZERO, - 1 => Self::ONE, - 2 => Self::TWO, - 3 => Self::THREE, - #[allow(unsafe_code)] - _ => unsafe { core::hint::unreachable_unchecked() }, - } - } - /// Convert a `u2` to a `u3`. - #[must_use] - #[inline(always)] - pub const fn tou3(self) -> crate::u3 { - crate::u3::new(self.0, self.1, false) - } - /// Convert a `u3` to a `u2`. - #[must_use] - #[inline(always)] - pub const fn fromu3(u: crate::u3) -> Self { - Self::new(u.0, u.1) - } - /// Returns `true` if self is `0`. - #[must_use] - #[inline(always)] - pub const fn zero(self) -> bool { - !self.0 && !self.1 - } - /// Returns `true` if self is `1`. - #[must_use] - #[inline(always)] - pub const fn one(self) -> bool { - self.0 && !self.1 - } - /// Returns `true` if self is `2`. - #[must_use] - #[inline(always)] - pub const fn two(self) -> bool { - !self.0 && self.1 - } - /// Returns `true` if self is `3`. - #[must_use] - #[inline(always)] - pub const fn three(self) -> bool { - self.0 && self.1 - } - /// Inverts all bits in a `u2`. - #[must_use] - #[inline(always)] - pub const fn bitnot(self) -> Self { - Self(!self.0, !self.1) - } - /// Adds two `u2`s - /// - /// # Safety - /// - /// This function is unsafe because it may overflow, - /// therefore causing undefined behavior. - /// The developer must ensure that the result is in the range 0..=3. - #[must_use] - #[inline(always)] - #[allow(non_snake_case, unsafe_code)] - pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { - #[cfg(feature = "unstable")] - { - Self::fromu8(self.tou8().unchecked_add(rhs.tou8())) - } - #[cfg(not(feature = "unstable"))] - { - // If either is zero, the result is the other - if self.zero() { - return rhs; - } - if rhs.zero() { - return self; - } - - let ones = self.0 ^ rhs.0; - let carry = self.0 && rhs.0; - let twos = self.1 ^ rhs.1 ^ carry; - Self(ones, twos) - } - } - /// Adds two `u2`s - /// - /// # Safety - /// - /// This function is unsafe because it may overflow, - /// therefore causing undefined behavior. - /// The developer must ensure that the result is in the range 0..=3. - #[must_use] - #[inline(always)] - #[allow(non_snake_case, unsafe_code)] - pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { - #[cfg(feature = "unstable")] - { - Self::fromu8(self.tou8().unchecked_sub(rhs.tou8())) - } - #[cfg(not(feature = "unstable"))] - { - // If either is zero, the result is the other - if self.zero() { - return rhs; - } - if rhs.zero() { - return self; - } - - self.unchecked_add(rhs.bitnot()).unchecked_add(Self::ONE) - } - } - /// Performs an unchecked multiplication of two `u2`s. - /// - /// # Safety - /// - /// This function is unsafe because it may overflow, - /// therefore causing undefined behavior. - #[must_use] - #[inline(always)] - #[allow(unsafe_code)] - pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { - // If either is zero, the result is zero - if self.zero() || rhs.zero() { - return Self::ZERO; - } - // If either is one, the result is the other - if self.one() { - return rhs; - } - if rhs.one() { - return self; - } - - // Otherwise, the result is not allowed - core::hint::unreachable_unchecked() - } - /// Performs an unchecked division of two `u2`s. - /// - /// # Safety - /// - /// This function is unsafe because it may overflow, - /// therefore causing undefined behavior. - #[must_use] - #[inline(always)] - #[allow(unsafe_code)] - pub const unsafe fn unchecked_div(self, rhs: Self) -> Self { - // if rhs is zero, the result is undefined - if rhs.zero() { - core::hint::unreachable_unchecked(); - } - // if this is zero, the result is zero - if self.zero() { - return Self::ZERO; - } - - // if rhs is one, the result is this - if rhs.one() { - return self; - } - - // If they are equal, the result is one - if self.0 == rhs.0 && self.1 == rhs.1 { - return Self::ONE; - } - - // Otherwise, the result is not allowed - core::hint::unreachable_unchecked() - } -} - -impl core::fmt::Debug for u2 { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_set().entry(&self.0).entry(&self.1).finish() - } -} - -impl core::cmp::PartialEq for u2 { - #[inline] - #[must_use] - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 && self.1 == other.1 - } -} - -impl core::cmp::PartialOrd for u2 { - #[inline] - #[must_use] - fn partial_cmp(&self, other: &Self) -> Option { - if self.0 == other.0 && self.1 == other.1 { - return Some(core::cmp::Ordering::Equal); - } - if self.1 && !other.1 { - return Some(core::cmp::Ordering::Greater); - } - if !self.1 && other.1 { - return Some(core::cmp::Ordering::Less); - } - if self.0 && !other.0 { - return Some(core::cmp::Ordering::Greater); - } - if !self.0 && other.0 { - return Some(core::cmp::Ordering::Less); - } - None - } -} - -impl core::cmp::Ord for u2 { - /// Compare two `u2`s. - /// - /// # Safety - /// - /// This is safe because we are comparing two `u2`s, which are guaranteed to - /// be two valid `bool`s. - #[inline] - #[must_use] - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - #[allow(unsafe_code)] - #[cfg(not(debug_assertions))] - unsafe { - self.partial_cmp(other).unwrap_unchecked() - } - #[cfg(debug_assertions)] - self.partial_cmp(other).unwrap() - } -} - -impl core::ops::BitAnd for u2 { - type Output = Self; - #[inline] - #[must_use] - fn bitand(self, rhs: Self) -> Self::Output { - Self::new(self.0 && rhs.0, self.1 && rhs.1) - } -} - -impl core::ops::BitOr for u2 { - type Output = Self; - #[inline] - #[must_use] - fn bitor(self, rhs: Self) -> Self::Output { - Self::new(self.0 || rhs.0, self.1 || rhs.1) - } -} - -impl core::ops::BitXor for u2 { - type Output = Self; - #[inline] - #[must_use] - fn bitxor(self, rhs: Self) -> Self::Output { - Self::new(self.0 ^ rhs.0, self.1 ^ rhs.1) - } -} - -impl core::ops::Not for u2 { - type Output = Self; - #[inline] - #[must_use] - fn not(self) -> Self::Output { - self.bitnot() - } -} - -impl core::ops::Add for u2 { - type Output = Self; - #[cfg(debug_assertions)] - fn add(self, rhs: Self) -> Self::Output { - let new = self.tou8() + rhs.tou8(); - debug_assert!(new <= 3, "u2 out of range: {}", new); - new.into() - } - #[must_use] - #[inline(always)] - #[allow(unsafe_code)] - #[cfg(not(debug_assertions))] - fn add(self, rhs: Self) -> Self::Output { - unsafe { self.unchecked_add(rhs) } - } -} - -impl core::ops::Sub for u2 { - type Output = Self; - #[inline] - #[must_use] - #[cfg(debug_assertions)] - fn sub(self, rhs: Self) -> Self::Output { - let new = self.tou8() - rhs.tou8(); - assert!(new <= 3, "u2 out of range: {}", new); - new.into() - } - #[must_use] - #[inline(always)] - #[allow(unsafe_code)] - #[cfg(not(debug_assertions))] - fn sub(self, rhs: Self) -> Self::Output { - unsafe { self.unchecked_sub(rhs) } - } -} - -impl core::ops::Mul for u2 { - type Output = Self; - #[must_use] - #[inline(always)] - #[cfg(debug_assertions)] - fn mul(self, rhs: Self) -> Self::Output { - let new = self.tou8() * rhs.tou8(); - assert!(new <= 3, "u2 out of range: {}", new); - new.into() - } - #[must_use] - #[inline(always)] - #[allow(unsafe_code)] - #[cfg(not(debug_assertions))] - fn mul(self, rhs: Self) -> Self::Output { - unsafe { self.unchecked_mul(rhs) } - } -} - -impl core::ops::Div for u2 { - type Output = Self; - #[must_use] - #[inline(always)] - #[cfg(debug_assertions)] - fn div(self, rhs: Self) -> Self::Output { - assert_ne!(rhs, Self::ZERO, "u2 division by zero"); - let new = self.tou8() / rhs.tou8(); - assert!(new <= 3, "u2 out of range: {}", new); - new.into() - } - #[must_use] - #[inline(always)] - #[allow(unsafe_code)] - #[cfg(not(debug_assertions))] - fn div(self, rhs: Self) -> Self::Output { - unsafe { self.unchecked_div(rhs) } - } -} diff --git a/helpers/libtrig/morenums/u2/tests.rs b/helpers/libtrig/morenums/u2/tests.rs deleted file mode 100644 index 6c39d3e..0000000 --- a/helpers/libtrig/morenums/u2/tests.rs +++ /dev/null @@ -1,95 +0,0 @@ -#![cfg(test)] - -#[allow(unused)] -use crate::u2; - -#[test] -fn test_partial_cmp() { - assert!(u2::ZERO == u2::ZERO); - assert!(u2::ZERO < u2::ONE); - assert!(u2::ZERO < u2::TWO); - assert!(u2::ZERO < u2::THREE); - assert!(u2::ONE > u2::ZERO); - assert!(u2::ONE == u2::ONE); - assert!(u2::ONE < u2::TWO); - assert!(u2::ONE < u2::THREE); - assert!(u2::TWO > u2::ZERO); - assert!(u2::TWO > u2::ONE); - assert!(u2::TWO == u2::TWO); - assert!(u2::TWO < u2::THREE); - assert!(u2::THREE > u2::ZERO); - assert!(u2::THREE > u2::ONE); - assert!(u2::THREE > u2::TWO); - assert!(u2::THREE == u2::THREE); -} - -#[test] -fn test_add() { - assert_eq!(u2::ZERO + u2::ZERO, u2::ZERO); - assert_eq!(u2::ZERO + u2::ONE, u2::ONE); - assert_eq!(u2::ZERO + u2::TWO, u2::TWO); - assert_eq!(u2::ZERO + u2::THREE, u2::THREE); - assert_eq!(u2::ONE + u2::ZERO, u2::ONE); - assert_eq!(u2::ONE + u2::ONE, u2::TWO); - assert_eq!(u2::ONE + u2::TWO, u2::THREE); - assert_eq!(u2::TWO + u2::ZERO, u2::TWO); - assert_eq!(u2::TWO + u2::ONE, u2::THREE); - assert_eq!(u2::THREE + u2::ZERO, u2::THREE); -} - -#[test] -fn test_sub() { - assert_eq!(u2::ZERO - u2::ZERO, u2::ZERO); - assert_eq!(u2::ONE - u2::ZERO, u2::ONE); - assert_eq!(u2::ONE - u2::ONE, u2::ZERO); - assert_eq!(u2::TWO - u2::ZERO, u2::TWO); - assert_eq!(u2::TWO - u2::ONE, u2::ONE); - assert_eq!(u2::TWO - u2::TWO, u2::ZERO); - assert_eq!(u2::THREE - u2::ZERO, u2::THREE); - assert_eq!(u2::THREE - u2::ONE, u2::TWO); - assert_eq!(u2::THREE - u2::TWO, u2::ONE); - assert_eq!(u2::THREE - u2::THREE, u2::ZERO); -} - -#[test] -fn test_mul() { - assert_eq!(u2::ZERO * u2::ZERO, u2::ZERO); - assert_eq!(u2::ZERO * u2::ONE, u2::ZERO); - assert_eq!(u2::ZERO * u2::TWO, u2::ZERO); - assert_eq!(u2::ZERO * u2::THREE, u2::ZERO); - assert_eq!(u2::ONE * u2::ZERO, u2::ZERO); - assert_eq!(u2::ONE * u2::ONE, u2::ONE); - assert_eq!(u2::ONE * u2::TWO, u2::TWO); - assert_eq!(u2::TWO * u2::ZERO, u2::ZERO); - assert_eq!(u2::TWO * u2::ONE, u2::TWO); - assert_eq!(u2::THREE * u2::ZERO, u2::ZERO); - assert_eq!(u2::THREE * u2::ONE, u2::THREE); -} - -#[test] -fn test_div() { - assert_eq!(u2::ZERO / u2::ONE, u2::ZERO); - assert_eq!(u2::ZERO / u2::TWO, u2::ZERO); - assert_eq!(u2::ZERO / u2::THREE, u2::ZERO); - assert_eq!(u2::ONE / u2::ONE, u2::ONE); - assert_eq!(u2::TWO / u2::ONE, u2::TWO); - assert_eq!(u2::TWO / u2::TWO, u2::ONE); - assert_eq!(u2::THREE / u2::ONE, u2::THREE); - assert_eq!(u2::THREE / u2::THREE, u2::ONE); -} - -#[test] -fn from_u2() { - assert_eq!(u8::from(u2::ZERO), 0); - assert_eq!(u8::from(u2::ONE), 1); - assert_eq!(u8::from(u2::TWO), 2); - assert_eq!(u8::from(u2::THREE), 3); -} - -#[test] -fn from_u8() { - assert_eq!(u2::from(0), u2::ZERO); - assert_eq!(u2::from(1), u2::ONE); - assert_eq!(u2::from(2), u2::TWO); - assert_eq!(u2::from(3), u2::THREE); -} diff --git a/helpers/libtrig/morenums/u3/impls.rs b/helpers/libtrig/morenums/u3/impls.rs deleted file mode 100644 index 9a9a427..0000000 --- a/helpers/libtrig/morenums/u3/impls.rs +++ /dev/null @@ -1,181 +0,0 @@ -use super::source::*; - -impl core::fmt::Display for u3 { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", u8::from(*self)) - } -} - -impl core::default::Default for u3 { - #[must_use] - #[inline(always)] - fn default() -> Self { - Self::ZERO - } -} - -impl core::cmp::Eq for u3 {} - -impl From for u8 { - /// Convert a `u2` to a `u8`. - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u3::tou8(u) - } -} - -impl From for u3 { - /// Convert a `u8` to a `u3`. - /// - /// # Safety - /// - /// In debug mode, this will panic if the `u8` is out of range. In release - /// mode, this uses `core::hint::unreachable_unchecked` to enable optimizations. - #[must_use] - #[inline(always)] - fn from(u: u8) -> Self { - debug_assert!(u <= 7, "u8 out of range: {}", u); - // Safety: u is in range 0..=7 - // In debug mode, this is verified by the debug_assert above. - // In release mode, this uses `core::hint::unreachable_unchecked` to enable optimizations. - #[allow(unsafe_code)] - unsafe { - Self::fromu8(u) - } - } -} - -impl From for u16 { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u8::from(u) as u16 - } -} - -impl From for u32 { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u8::from(u) as u32 - } -} - -impl From for u64 { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u8::from(u) as u64 - } -} - -impl From for u128 { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u8::from(u) as u128 - } -} - -impl From for usize { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u8::from(u) as usize - } -} - -impl From for i8 { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u8::from(u) as i8 - } -} - -impl From for i16 { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u8::from(u) as i16 - } -} - -impl From for i32 { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u8::from(u) as i32 - } -} - -impl From for i64 { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u8::from(u) as i64 - } -} - -impl From for i128 { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u8::from(u) as i128 - } -} - -impl From for isize { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u8::from(u) as isize - } -} - -impl From for crate::Float32 { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u8::from(u) as crate::Float32 - } -} - -impl From for crate::Float64 { - #[must_use] - #[inline(always)] - fn from(u: u3) -> Self { - u8::from(u) as crate::Float64 - } -} - -impl core::ops::AddAssign for u3 { - #[inline] - fn add_assign(&mut self, rhs: Self) { - *self = *self + rhs; - } -} - -impl core::ops::SubAssign for u3 { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - *self = *self - rhs; - } -} - -impl core::ops::MulAssign for u3 { - #[inline] - fn mul_assign(&mut self, rhs: Self) { - *self = *self * rhs; - } -} - -impl core::ops::DivAssign for u3 { - #[inline] - fn div_assign(&mut self, rhs: Self) { - *self = *self / rhs; - } -} - -impl crate::traits::Number for u3 {} diff --git a/helpers/libtrig/morenums/u3/mod.rs b/helpers/libtrig/morenums/u3/mod.rs deleted file mode 100644 index 34be3ab..0000000 --- a/helpers/libtrig/morenums/u3/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod impls; -mod source; -mod tests; - -pub use source::u3; diff --git a/helpers/libtrig/morenums/u3/source.rs b/helpers/libtrig/morenums/u3/source.rs deleted file mode 100644 index b7fd2ba..0000000 --- a/helpers/libtrig/morenums/u3/source.rs +++ /dev/null @@ -1,462 +0,0 @@ -use crate::morenums::bit; - -/// The 3-bit unsigned integer type. -#[repr(C)] -#[derive(Clone, Copy, Hash)] -#[allow(non_camel_case_types)] -pub struct u3(pub(crate) bit, pub(crate) bit, pub(crate) bit); - -impl u3 { - /// Maximum value of `u3`. (7) - pub const MAX: Self = Self::new(true, true, true); - /// Minimum value of `u3`. (0) - pub const MIN: Self = Self::new(false, false, false); - /// Zero value of `u3`. (0) - pub const ZERO: Self = Self::MIN; - /// One value of `u3`. (1) - pub const ONE: Self = Self::new(true, false, false); - /// Two value of `u3`. (2) - pub const TWO: Self = Self::new(false, true, false); - /// Three value of `u3`. (3) - pub const THREE: Self = Self::new(true, true, false); - /// Four value of `u3`. (4) - pub const FOUR: Self = Self::new(false, false, true); - /// Five value of `u3`. (5) - pub const FIVE: Self = Self::new(true, false, true); - /// Six value of `u3`. (6) - pub const SIX: Self = Self::new(false, true, true); - /// Seven value of `u3`. (7) - pub const SEVEN: Self = Self::MAX; - /// Create a new `u3` from three `bit`s. - #[inline] - #[must_use] - pub const fn new(ones: bool, twos: bool, fours: bool) -> Self { - Self(ones, twos, fours) - } - /// Convert a `u3` to a `u8`. - #[must_use] - #[inline(always)] - pub const fn tou8(self) -> u8 { - if self.0 && self.1 && self.2 { - 7 - } else if !self.0 && self.1 && self.2 { - 6 - } else if self.0 && !self.1 && self.2 { - 5 - } else if !self.0 && !self.1 && self.2 { - 4 - } else if self.0 && self.1 && !self.2 { - 3 - } else if !self.0 && self.1 && !self.2 { - 2 - } else if self.0 && !self.1 && !self.2 { - 1 - } else { - 0 - } - } - /// Convert a `u8` to a `u3`. - /// - /// # Safety - /// - /// This uses `core::hint::unreachable_unchecked` to enable optimizations, so - /// it is unsafe to use in debug mode. Instead, use `u3::fromu8`. - #[must_use] - #[inline(always)] - #[allow(unsafe_code)] - pub const unsafe fn fromu8(u: u8) -> Self { - match u { - 0 => Self::ZERO, - 1 => Self::ONE, - 2 => Self::TWO, - 3 => Self::THREE, - 4 => Self::FOUR, - 5 => Self::FIVE, - 6 => Self::SIX, - 7 => Self::SEVEN, - _ => core::hint::unreachable_unchecked(), - } - } - /// Convert a `u3` to a `u2`. - #[must_use] - #[inline(always)] - pub const fn tou2(self) -> crate::u2 { - crate::u2::new(self.0, self.1) - } - /// Convert a `u2` to a `u3`. - #[must_use] - #[inline(always)] - pub const fn fromu2(u: crate::u2) -> Self { - Self::new(u.0, u.1, false) - } - /// Returns `true` if self is `0`. - #[must_use] - #[inline(always)] - pub const fn zero(self) -> bool { - !self.0 && !self.1 && !self.2 - } - /// Returns `true` if self is `1`. - #[must_use] - #[inline(always)] - pub const fn one(self) -> bool { - self.0 && !self.1 && !self.2 - } - /// Returns `true` if self is `2`. - #[must_use] - #[inline(always)] - pub const fn two(self) -> bool { - !self.0 && self.1 && !self.2 - } - /// Returns `true` if self is `3`. - #[must_use] - #[inline(always)] - pub const fn three(self) -> bool { - self.0 && self.1 && !self.2 - } - /// Returns `true` if self is `4`. - #[must_use] - #[inline(always)] - pub const fn four(self) -> bool { - !self.0 && !self.1 && self.2 - } - /// Returns `true` if self is `5`. - #[must_use] - #[inline(always)] - pub const fn five(self) -> bool { - self.0 && !self.1 && self.2 - } - /// Returns `true` if self is `6`. - #[must_use] - #[inline(always)] - pub const fn six(self) -> bool { - !self.0 && self.1 && self.2 - } - /// Returns `true` if self is `7`. - #[must_use] - #[inline(always)] - pub const fn seven(self) -> bool { - self.0 && self.1 && self.2 - } - /// Inverts all bits in a `u3`. - #[must_use] - #[inline(always)] - pub const fn bitnot(self) -> Self { - Self(!self.0, !self.1, !self.2) - } - /// Adds two `u3`s. - /// - /// # Safety - /// - /// This function is unsafe because it may overflow, - /// therefore causing undefined behavior. - /// The developer must ensure that the result is in the range 0..=7. - #[must_use] - #[inline(always)] - #[allow(non_snake_case, unsafe_code)] - pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { - #[cfg(feature = "unstable")] - { - Self::fromu8(self.tou8().unchecked_add(rhs.tou8())) - } - #[cfg(not(feature = "unstable"))] - { - // If either is zero, the result is the other - if rhs.zero() { - return self; - } - if self.zero() { - return rhs; - } - - let ones = self.0 ^ rhs.0; - let carry_ones = self.0 & rhs.0; - let twos = self.1 ^ rhs.1 ^ carry_ones; - let carry_twos = (self.1 & rhs.1) | (self.1 & carry_ones) | (rhs.1 & carry_ones); - let fours = self.2 ^ rhs.2 ^ carry_twos; - Self::new(ones, twos, fours) - } - } - /// Subtracts two `u3`s. - /// - /// # Safety - /// - /// This function is unsafe because it may overflow, - /// therefore causing undefined behavior. - /// The developer must ensure that the result is in the range 0..=7. - #[must_use] - #[inline(always)] - #[allow(non_snake_case, unsafe_code)] - pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { - #[cfg(feature = "unstable")] - { - Self::fromu8(self.tou8().unchecked_sub(rhs.tou8())) - } - #[cfg(not(feature = "unstable"))] - { - // If we are subtracting zero, the result is this - if rhs.zero() { - return self; - } - // If we are subtracting from zero, the result is undefined - if self.zero() { - core::hint::unreachable_unchecked(); - } - - self.unchecked_add(rhs.bitnot()).unchecked_add(Self::ONE) - } - } - /// Performs an unchecked multiplication of two `u3`s. - /// - /// # Safety - /// - /// This function is unsafe because it may overflow, - /// therefore causing undefined behavior. - /// The developer must ensure that the result is in the range 0..=7. - #[must_use] - #[inline(always)] - #[allow(unsafe_code)] - pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { - // If either is zero, the result is zero - if self.zero() || rhs.zero() { - return Self::ZERO; - } - - // If either is one, the result is the other - if self.one() { - return rhs; - } - if rhs.one() { - return self; - } - - // 2 * 2 = 4 - if self.two() && rhs.two() { - return Self::FOUR; - } - - // 2 * 3 = 6 OR 3 * 2 = 6 - if (self.two() && rhs.three()) || (self.three() && rhs.two()) { - return Self::SIX; - } - - // Otherwise, the result is not allowed - core::hint::unreachable_unchecked(); - } - /// Performs an unchecked division of two `u3`s. - /// - /// # Safety - /// - /// This function is unsafe because it may overflow, - /// therefore causing undefined behavior. - /// The developer must ensure that the result is in the range 0..=7. - #[must_use] - #[inline(always)] - #[allow(unsafe_code)] - pub const unsafe fn unchecked_div(self, rhs: Self) -> Self { - // if this is zero, the result is zero - if self.zero() { - return Self::ZERO; - } - - // if rhs is zero, the result is undefined - if rhs.zero() { - core::hint::unreachable_unchecked(); - } - - // if rhs is one, the result is this - if rhs.one() { - return self; - } - - // If they are equal, the result is one - if self.0 == rhs.0 && self.1 == rhs.1 && self.2 == rhs.2 { - return Self::ONE; - } - - // 4 / 2 = 2 - if self.four() && rhs.two() { - return Self::TWO; - } - - // 6 / 2 = 3 OR 6 / 3 = 2 - if self.six() && rhs.two() { - return Self::THREE; - } - if self.six() && rhs.three() { - return Self::TWO; - } - - // Otherwise, the result is not allowed - core::hint::unreachable_unchecked(); - } -} - -impl core::fmt::Debug for u3 { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_set() - .entry(&self.0) - .entry(&self.1) - .entry(&self.2) - .finish() - } -} - -impl core::cmp::PartialEq for u3 { - #[inline] - #[must_use] - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 && self.1 == other.1 && self.2 == other.2 - } -} - -impl core::cmp::PartialOrd for u3 { - #[inline] - #[must_use] - fn partial_cmp(&self, other: &Self) -> Option { - if self.0 == other.0 && self.1 == other.1 && self.2 == other.2 { - Some(core::cmp::Ordering::Equal) - } else if self.2 && !other.2 { - Some(core::cmp::Ordering::Greater) - } else if !self.2 && other.2 { - Some(core::cmp::Ordering::Less) - } else if self.1 && !other.1 { - Some(core::cmp::Ordering::Greater) - } else if !self.1 && other.1 { - Some(core::cmp::Ordering::Less) - } else if self.0 && !other.0 { - Some(core::cmp::Ordering::Greater) - } else if !self.0 && other.0 { - Some(core::cmp::Ordering::Less) - } else { - None - } - } -} - -impl core::cmp::Ord for u3 { - /// Compare two `u3`s. - #[inline] - #[must_use] - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - #[allow(unsafe_code)] - #[cfg(not(debug_assertions))] - unsafe { - self.partial_cmp(other).unwrap_unchecked() - } - #[cfg(debug_assertions)] - self.partial_cmp(other).unwrap() - } -} - -impl core::ops::BitAnd for u3 { - type Output = Self; - #[inline] - #[must_use] - fn bitand(self, rhs: Self) -> Self::Output { - Self::new(self.0 & rhs.0, self.1 & rhs.1, self.2 & rhs.2) - } -} - -impl core::ops::BitOr for u3 { - type Output = Self; - #[inline] - #[must_use] - fn bitor(self, rhs: Self) -> Self::Output { - Self::new(self.0 | rhs.0, self.1 | rhs.1, self.2 | rhs.2) - } -} - -impl core::ops::BitXor for u3 { - type Output = Self; - #[inline] - #[must_use] - fn bitxor(self, rhs: Self) -> Self::Output { - Self::new(self.0 ^ rhs.0, self.1 ^ rhs.1, self.2 ^ rhs.2) - } -} - -impl core::ops::Not for u3 { - type Output = Self; - #[inline] - #[must_use] - fn not(self) -> Self::Output { - self.bitnot() - } -} - -impl core::ops::Add for u3 { - type Output = Self; - #[must_use] - #[inline(always)] - #[cfg(debug_assertions)] - fn add(self, rhs: Self) -> Self::Output { - let new = self.tou8() + rhs.tou8(); - assert!(new <= 7, "u3 out of range: {}", new); - new.into() - } - #[must_use] - #[inline(always)] - #[allow(unsafe_code)] - #[cfg(not(debug_assertions))] - fn add(self, rhs: Self) -> Self::Output { - unsafe { Self::unchecked_add(self, rhs) } - } -} - -impl core::ops::Sub for u3 { - type Output = Self; - #[inline] - #[must_use] - #[cfg(debug_assertions)] - fn sub(self, rhs: Self) -> Self::Output { - let new = self.tou8() - rhs.tou8(); - assert!(new <= 7, "u3 out of range: {}", new); - new.into() - } - #[must_use] - #[inline(always)] - #[allow(unsafe_code)] - #[cfg(not(debug_assertions))] - fn sub(self, rhs: Self) -> Self::Output { - unsafe { Self::unchecked_sub(self, rhs) } - } -} - -impl core::ops::Mul for u3 { - type Output = Self; - #[inline] - #[must_use] - #[cfg(debug_assertions)] - fn mul(self, rhs: Self) -> Self::Output { - let new = self.tou8() * rhs.tou8(); - assert!(new <= 7, "u3 out of range: {}", new); - new.into() - } - #[must_use] - #[inline(always)] - #[allow(unsafe_code)] - #[cfg(not(debug_assertions))] - fn mul(self, rhs: Self) -> Self::Output { - unsafe { self.unchecked_mul(rhs) } - } -} - -impl core::ops::Div for u3 { - type Output = Self; - #[inline] - #[must_use] - #[cfg(debug_assertions)] - fn div(self, rhs: Self) -> Self::Output { - assert_ne!(rhs, Self::ZERO, "u3 division by zero"); - let new = self.tou8() / rhs.tou8(); - assert!(new <= 7, "u3 out of range: {}", new); - new.into() - } - #[must_use] - #[inline(always)] - #[allow(unsafe_code)] - #[cfg(not(debug_assertions))] - fn div(self, rhs: Self) -> Self::Output { - unsafe { self.unchecked_div(rhs) } - } -} diff --git a/helpers/libtrig/morenums/u3/tests.rs b/helpers/libtrig/morenums/u3/tests.rs deleted file mode 100644 index 5b83a6e..0000000 --- a/helpers/libtrig/morenums/u3/tests.rs +++ /dev/null @@ -1,423 +0,0 @@ -#![cfg(test)] - -#[allow(unused)] -use crate::u3; - -#[test] -fn test_partial_cmp() { - assert_eq!( - u3::ZERO.partial_cmp(&u3::ZERO), - Some(core::cmp::Ordering::Equal) - ); - assert_eq!( - u3::ZERO.partial_cmp(&u3::ONE), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::ZERO.partial_cmp(&u3::TWO), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::ZERO.partial_cmp(&u3::THREE), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::ZERO.partial_cmp(&u3::FOUR), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::ZERO.partial_cmp(&u3::FIVE), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::ZERO.partial_cmp(&u3::SIX), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::ZERO.partial_cmp(&u3::SEVEN), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::ONE.partial_cmp(&u3::ZERO), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::ONE.partial_cmp(&u3::ONE), - Some(core::cmp::Ordering::Equal) - ); - assert_eq!( - u3::ONE.partial_cmp(&u3::TWO), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::ONE.partial_cmp(&u3::THREE), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::ONE.partial_cmp(&u3::FOUR), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::ONE.partial_cmp(&u3::FIVE), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::ONE.partial_cmp(&u3::SIX), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::ONE.partial_cmp(&u3::SEVEN), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::TWO.partial_cmp(&u3::ZERO), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::TWO.partial_cmp(&u3::ONE), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::TWO.partial_cmp(&u3::TWO), - Some(core::cmp::Ordering::Equal) - ); - assert_eq!( - u3::TWO.partial_cmp(&u3::THREE), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::TWO.partial_cmp(&u3::FOUR), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::TWO.partial_cmp(&u3::FIVE), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::TWO.partial_cmp(&u3::SIX), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::TWO.partial_cmp(&u3::SEVEN), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::THREE.partial_cmp(&u3::ZERO), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::THREE.partial_cmp(&u3::ONE), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::THREE.partial_cmp(&u3::TWO), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::THREE.partial_cmp(&u3::THREE), - Some(core::cmp::Ordering::Equal) - ); - assert_eq!( - u3::THREE.partial_cmp(&u3::FOUR), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::THREE.partial_cmp(&u3::FIVE), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::THREE.partial_cmp(&u3::SIX), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::THREE.partial_cmp(&u3::SEVEN), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::FOUR.partial_cmp(&u3::ZERO), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::FOUR.partial_cmp(&u3::ONE), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::FOUR.partial_cmp(&u3::TWO), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::FOUR.partial_cmp(&u3::THREE), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::FOUR.partial_cmp(&u3::FOUR), - Some(core::cmp::Ordering::Equal) - ); - assert_eq!( - u3::FOUR.partial_cmp(&u3::FIVE), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::FOUR.partial_cmp(&u3::SIX), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::FOUR.partial_cmp(&u3::SEVEN), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::FIVE.partial_cmp(&u3::ZERO), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::FIVE.partial_cmp(&u3::ONE), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::FIVE.partial_cmp(&u3::TWO), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::FIVE.partial_cmp(&u3::THREE), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::FIVE.partial_cmp(&u3::FOUR), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::FIVE.partial_cmp(&u3::FIVE), - Some(core::cmp::Ordering::Equal) - ); - assert_eq!( - u3::FIVE.partial_cmp(&u3::SIX), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::FIVE.partial_cmp(&u3::SEVEN), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::SIX.partial_cmp(&u3::ZERO), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::SIX.partial_cmp(&u3::ONE), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::SIX.partial_cmp(&u3::TWO), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::SIX.partial_cmp(&u3::THREE), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::SIX.partial_cmp(&u3::FOUR), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::SIX.partial_cmp(&u3::FIVE), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::SIX.partial_cmp(&u3::SIX), - Some(core::cmp::Ordering::Equal) - ); - assert_eq!( - u3::SIX.partial_cmp(&u3::SEVEN), - Some(core::cmp::Ordering::Less) - ); - assert_eq!( - u3::SEVEN.partial_cmp(&u3::ZERO), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::SEVEN.partial_cmp(&u3::ONE), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::SEVEN.partial_cmp(&u3::TWO), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::SEVEN.partial_cmp(&u3::THREE), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::SEVEN.partial_cmp(&u3::FOUR), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::SEVEN.partial_cmp(&u3::FIVE), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::SEVEN.partial_cmp(&u3::SIX), - Some(core::cmp::Ordering::Greater) - ); - assert_eq!( - u3::SEVEN.partial_cmp(&u3::SEVEN), - Some(core::cmp::Ordering::Equal) - ); -} - -#[test] -fn test_add() { - assert_eq!(u3::ZERO + u3::ZERO, u3::ZERO); - assert_eq!(u3::ONE + u3::ZERO, u3::ONE); - assert_eq!(u3::ONE + u3::ONE, u3::TWO); - assert_eq!(u3::ONE + u3::TWO, u3::THREE); - assert_eq!(u3::ONE + u3::THREE, u3::FOUR); - assert_eq!(u3::ONE + u3::FOUR, u3::FIVE); - assert_eq!(u3::ONE + u3::FIVE, u3::SIX); - assert_eq!(u3::ONE + u3::SIX, u3::SEVEN); - assert_eq!(u3::TWO + u3::ZERO, u3::TWO); - assert_eq!(u3::TWO + u3::ONE, u3::THREE); - assert_eq!(u3::TWO + u3::TWO, u3::FOUR); - assert_eq!(u3::TWO + u3::THREE, u3::FIVE); - assert_eq!(u3::TWO + u3::FOUR, u3::SIX); - assert_eq!(u3::TWO + u3::FIVE, u3::SEVEN); - assert_eq!(u3::THREE + u3::ZERO, u3::THREE); - assert_eq!(u3::THREE + u3::ONE, u3::FOUR); - assert_eq!(u3::THREE + u3::TWO, u3::FIVE); - assert_eq!(u3::THREE + u3::THREE, u3::SIX); - assert_eq!(u3::THREE + u3::FOUR, u3::SEVEN); - assert_eq!(u3::FOUR + u3::ZERO, u3::FOUR); - assert_eq!(u3::FOUR + u3::ONE, u3::FIVE); - assert_eq!(u3::FOUR + u3::TWO, u3::SIX); - assert_eq!(u3::FOUR + u3::THREE, u3::SEVEN); - assert_eq!(u3::FIVE + u3::ZERO, u3::FIVE); - assert_eq!(u3::FIVE + u3::ONE, u3::SIX); - assert_eq!(u3::FIVE + u3::TWO, u3::SEVEN); - assert_eq!(u3::SIX + u3::ZERO, u3::SIX); - assert_eq!(u3::SIX + u3::ONE, u3::SEVEN); - assert_eq!(u3::SEVEN + u3::ZERO, u3::SEVEN); -} - -#[test] -fn test_sub() { - assert_eq!(u3::ZERO - u3::ZERO, u3::ZERO); - assert_eq!(u3::ONE - u3::ZERO, u3::ONE); - assert_eq!(u3::ONE - u3::ONE, u3::ZERO); - assert_eq!(u3::TWO - u3::ZERO, u3::TWO); - assert_eq!(u3::TWO - u3::ONE, u3::ONE); - assert_eq!(u3::TWO - u3::TWO, u3::ZERO); - assert_eq!(u3::THREE - u3::ZERO, u3::THREE); - assert_eq!(u3::THREE - u3::ONE, u3::TWO); - assert_eq!(u3::THREE - u3::TWO, u3::ONE); - assert_eq!(u3::THREE - u3::THREE, u3::ZERO); - assert_eq!(u3::FOUR - u3::ZERO, u3::FOUR); - assert_eq!(u3::FOUR - u3::ONE, u3::THREE); - assert_eq!(u3::FOUR - u3::TWO, u3::TWO); - assert_eq!(u3::FOUR - u3::THREE, u3::ONE); - assert_eq!(u3::FOUR - u3::FOUR, u3::ZERO); - assert_eq!(u3::FIVE - u3::ZERO, u3::FIVE); - assert_eq!(u3::FIVE - u3::ONE, u3::FOUR); - assert_eq!(u3::FIVE - u3::TWO, u3::THREE); - assert_eq!(u3::FIVE - u3::THREE, u3::TWO); - assert_eq!(u3::FIVE - u3::FOUR, u3::ONE); - assert_eq!(u3::FIVE - u3::FIVE, u3::ZERO); - assert_eq!(u3::SIX - u3::ZERO, u3::SIX); - assert_eq!(u3::SIX - u3::ONE, u3::FIVE); - assert_eq!(u3::SIX - u3::TWO, u3::FOUR); - assert_eq!(u3::SIX - u3::THREE, u3::THREE); - assert_eq!(u3::SIX - u3::FOUR, u3::TWO); - assert_eq!(u3::SIX - u3::FIVE, u3::ONE); - assert_eq!(u3::SIX - u3::SIX, u3::ZERO); - assert_eq!(u3::SEVEN - u3::ZERO, u3::SEVEN); - assert_eq!(u3::SEVEN - u3::ONE, u3::SIX); - assert_eq!(u3::SEVEN - u3::TWO, u3::FIVE); - assert_eq!(u3::SEVEN - u3::THREE, u3::FOUR); - assert_eq!(u3::SEVEN - u3::FOUR, u3::THREE); - assert_eq!(u3::SEVEN - u3::FIVE, u3::TWO); - assert_eq!(u3::SEVEN - u3::SIX, u3::ONE); - assert_eq!(u3::SEVEN - u3::SEVEN, u3::ZERO); -} - -#[test] -fn test_mult() { - assert_eq!(u3::ZERO * u3::ZERO, u3::ZERO); - assert_eq!(u3::ZERO * u3::ONE, u3::ZERO); - assert_eq!(u3::ZERO * u3::TWO, u3::ZERO); - assert_eq!(u3::ZERO * u3::THREE, u3::ZERO); - assert_eq!(u3::ZERO * u3::FOUR, u3::ZERO); - assert_eq!(u3::ZERO * u3::FIVE, u3::ZERO); - assert_eq!(u3::ZERO * u3::SIX, u3::ZERO); - assert_eq!(u3::ZERO * u3::SEVEN, u3::ZERO); - assert_eq!(u3::ONE * u3::ZERO, u3::ZERO); - assert_eq!(u3::ONE * u3::ONE, u3::ONE); - assert_eq!(u3::ONE * u3::TWO, u3::TWO); - assert_eq!(u3::ONE * u3::THREE, u3::THREE); - assert_eq!(u3::ONE * u3::FOUR, u3::FOUR); - assert_eq!(u3::ONE * u3::FIVE, u3::FIVE); - assert_eq!(u3::ONE * u3::SIX, u3::SIX); - assert_eq!(u3::ONE * u3::SEVEN, u3::SEVEN); - assert_eq!(u3::TWO * u3::ZERO, u3::ZERO); - assert_eq!(u3::TWO * u3::ONE, u3::TWO); - assert_eq!(u3::TWO * u3::TWO, u3::FOUR); - assert_eq!(u3::TWO * u3::THREE, u3::SIX); - assert_eq!(u3::THREE * u3::ZERO, u3::ZERO); - assert_eq!(u3::THREE * u3::ONE, u3::THREE); - assert_eq!(u3::THREE * u3::TWO, u3::SIX); - assert_eq!(u3::FOUR * u3::ZERO, u3::ZERO); - assert_eq!(u3::FOUR * u3::ONE, u3::FOUR); - assert_eq!(u3::FIVE * u3::ZERO, u3::ZERO); - assert_eq!(u3::FIVE * u3::ONE, u3::FIVE); - assert_eq!(u3::SIX * u3::ZERO, u3::ZERO); - assert_eq!(u3::SIX * u3::ONE, u3::SIX); - assert_eq!(u3::SEVEN * u3::ZERO, u3::ZERO); - assert_eq!(u3::SEVEN * u3::ONE, u3::SEVEN); -} - -#[test] -fn test_div() { - assert_eq!(u3::ZERO / u3::ONE, u3::ZERO); - assert_eq!(u3::ZERO / u3::TWO, u3::ZERO); - assert_eq!(u3::ZERO / u3::THREE, u3::ZERO); - assert_eq!(u3::ZERO / u3::FOUR, u3::ZERO); - assert_eq!(u3::ZERO / u3::FIVE, u3::ZERO); - assert_eq!(u3::ZERO / u3::SIX, u3::ZERO); - assert_eq!(u3::ZERO / u3::SEVEN, u3::ZERO); - assert_eq!(u3::ONE / u3::ONE, u3::ONE); - assert_eq!(u3::TWO / u3::ONE, u3::TWO); - assert_eq!(u3::TWO / u3::TWO, u3::ONE); - assert_eq!(u3::THREE / u3::ONE, u3::THREE); - assert_eq!(u3::THREE / u3::THREE, u3::ONE); - assert_eq!(u3::FOUR / u3::ONE, u3::FOUR); - assert_eq!(u3::FOUR / u3::TWO, u3::TWO); - assert_eq!(u3::FOUR / u3::FOUR, u3::ONE); - assert_eq!(u3::FIVE / u3::ONE, u3::FIVE); - assert_eq!(u3::FIVE / u3::FIVE, u3::ONE); - assert_eq!(u3::SIX / u3::ONE, u3::SIX); - assert_eq!(u3::SIX / u3::TWO, u3::THREE); - assert_eq!(u3::SIX / u3::THREE, u3::TWO); - assert_eq!(u3::SIX / u3::SIX, u3::ONE); - assert_eq!(u3::SEVEN / u3::ONE, u3::SEVEN); - assert_eq!(u3::SEVEN / u3::SEVEN, u3::ONE); -} - -#[test] -fn test_from_u3() { - assert_eq!(u8::from(u3::ZERO), 0); - assert_eq!(u8::from(u3::ONE), 1); - assert_eq!(u8::from(u3::TWO), 2); - assert_eq!(u8::from(u3::THREE), 3); - assert_eq!(u8::from(u3::FOUR), 4); - assert_eq!(u8::from(u3::FIVE), 5); - assert_eq!(u8::from(u3::SIX), 6); - assert_eq!(u8::from(u3::SEVEN), 7); -} - -#[test] -fn test_from_u8() { - assert_eq!(u3::from(0), u3::ZERO); - assert_eq!(u3::from(1), u3::ONE); - assert_eq!(u3::from(2), u3::TWO); - assert_eq!(u3::from(3), u3::THREE); - assert_eq!(u3::from(4), u3::FOUR); - assert_eq!(u3::from(5), u3::FIVE); - assert_eq!(u3::from(6), u3::SIX); - assert_eq!(u3::from(7), u3::SEVEN); -} diff --git a/helpers/libtrig/pos2d.rs b/helpers/libtrig/pos2d.rs deleted file mode 100644 index e396f1a..0000000 --- a/helpers/libtrig/pos2d.rs +++ /dev/null @@ -1,265 +0,0 @@ -use l2math::{Float64, Radian64}; - -use crate::{Angle2D, Coord2D, Vec2D}; - -/// A 2D position with rotation. -/// -/// This type is a wrapper around the [`Coord2D`] and [`Angle2D`] types. -/// -/// All logical operations are implemented for this type. -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct Pos2D { - pos: Coord2D, - rot: Angle2D, -} - -impl core::fmt::Display for Pos2D { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{};{} {}", self.x(), self.y(), self.angle()) - } -} - -impl Default for Pos2D { - #[inline] - #[must_use] - fn default() -> Self { - Self::zero() - } -} - -impl Pos2D { - /// Create a new `Pos2D` from a `Coord2D` and an `Angle2D`. - #[inline] - #[must_use] - pub const fn new(pos: Coord2D, rot: Angle2D) -> Self { - Self { pos, rot } - } - /// Create a new `Pos2D` positioned at the origin with no rotation. - #[inline] - #[must_use] - pub const fn zero() -> Self { - Self::new(Coord2D::origin(), Angle2D::zero()) - } - /// Returns the x coordinate of the `Pos2D`. - #[inline] - #[must_use] - pub const fn x(&self) -> Float64 { - self.pos.x() - } - /// Returns the y coordinate of the `Pos2D`. - #[inline] - #[must_use] - pub const fn y(&self) -> Float64 { - self.pos.y() - } - /// Returns the angle of rotation of the `Pos2D`. - #[inline] - #[must_use] - pub const fn angle(&self) -> Angle2D { - self.rot - } - /// Moves the `Pos2D` by the given delta `Pos2D` - #[inline] - pub fn translate(&mut self, delta: Pos2D) { - self.pos += delta.pos; - self.rot += delta.rot; - } -} - -impl From for Pos2D { - fn from(pos: Coord2D) -> Self { - Self::new(pos, Angle2D::zero()) - } -} - -impl From for Pos2D { - fn from(vec: Vec2D) -> Self { - Self::new(vec.into(), Angle2D::zero()) - } -} - -impl From for Pos2D { - fn from(rot: Angle2D) -> Self { - Self::new(Coord2D::origin(), rot) - } -} - -impl From<(Float64, Float64, Radian64)> for Pos2D { - fn from((x, y, rot): (Float64, Float64, Radian64)) -> Self { - Self::new(Coord2D::new(x, y), Angle2D::from_radians(rot)) - } -} - -impl From<(Float64, Float64)> for Pos2D { - fn from((x, y): (Float64, Float64)) -> Self { - Self::new(Coord2D::new(x, y), Angle2D::zero()) - } -} - -#[macros::mass_impl( - $THIS = @ORM Pos2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::Add for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - self.pos + rhs - } -} - -#[macros::mass_impl( - $THIS = @ORM Pos2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::Add for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - self.rot + rhs - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Pos2D -)] -impl core::ops::Add for THIS { - type Output = Pos2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Pos2D::new(self.pos + rhs.pos, self.rot + rhs.rot) - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.pos += rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.rot += rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Pos2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.pos += rhs.pos; - self.rot += rhs.rot; - } -} - -#[macros::mass_impl( - $THIS = @ORM Pos2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::Sub for THIS { - type Output = Coord2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - self.pos - rhs - } -} - -#[macros::mass_impl( - $THIS = @ORM Pos2D, - $OTHER = @ORM Angle2D -)] -impl core::ops::Sub for THIS { - type Output = Angle2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - self.rot - rhs - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Pos2D -)] -impl core::ops::Sub for THIS { - type Output = Pos2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - Pos2D::new(self.pos - rhs.pos, self.rot - rhs.rot) - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.pos -= rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @OR Angle2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.rot -= rhs; - } -} - -#[macros::mass_impl( - $THIS = @OM Pos2D, - $OTHER = @ORM Pos2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.pos -= rhs.pos; - self.rot -= rhs.rot; - } -} - -#[macros::mass_impl( - $THIS = @ORM Pos2D -)] -impl core::ops::Neg for THIS { - type Output = Pos2D; - #[inline] - #[must_use] - fn neg(self) -> Self::Output { - Pos2D::new(-self.pos, -self.rot) - } -} - -impl PartialEq for Pos2D { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.pos == other.pos && self.rot == other.rot - } -} - -impl Eq for Pos2D {} diff --git a/helpers/libtrig/traits/float.rs b/helpers/libtrig/traits/float.rs deleted file mode 100644 index 53f1a9a..0000000 --- a/helpers/libtrig/traits/float.rs +++ /dev/null @@ -1,668 +0,0 @@ -use super::Number; -use crate::Int; - -/// A trait for things that implement the sine function. -pub trait Sin { - /// Computes the sine of a number (in radians). - /// - /// # Examples - /// - /// ``` - /// let x = std::f64::consts::FRAC_PI_2; - /// - /// let abs_difference = (x.sin() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn sin(&self) -> Output; -} - -/// A trait for things that implement the cosine function. -pub trait Cos { - /// Computes the cosine of a number (in radians). - /// - /// # Examples - /// - /// ``` - /// let x = 2.0 * std::f64::consts::PI; - /// - /// let abs_difference = (x.cos() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn cos(&self) -> Output; -} - -/// A trait for things that can be square rooted. -pub trait Sqrt { - /// Returns the square root of a number. - /// - /// Returns NaN if `self` is a negative number other than `-0.0`. - /// - /// # Examples - /// - /// ``` - /// let positive = 4.0_f64; - /// let negative = -4.0_f64; - /// let negative_zero = -0.0_f64; - /// - /// let abs_difference = (positive.sqrt() - 2.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// assert!(negative.sqrt().is_nan()); - /// assert!(negative_zero.sqrt() == negative_zero); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn sqrt(&self) -> Output; -} - -/// A trait for floating point numbers. -pub trait Float: - Number + Sin + Cos + Sqrt -{ - /// Returns the largest integer less than or equal to `self`. - /// - /// # Examples - /// - /// ``` - /// let f = 3.7_f64; - /// let g = 3.0_f64; - /// let h = -3.7_f64; - /// - /// assert_eq!(f.floor(), 3.0); - /// assert_eq!(g.floor(), 3.0); - /// assert_eq!(h.floor(), -4.0); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn floor(&self) -> Output; - - /// Returns the smallest integer greater than or equal to `self`. - /// - /// # Examples - /// - /// ``` - /// let f = 3.01_f64; - /// let g = 4.0_f64; - /// - /// assert_eq!(f.ceil(), 4.0); - /// assert_eq!(g.ceil(), 4.0); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn ceil(&self) -> Output; - - /// Returns the nearest integer to `self`. If a value is half-way between two - /// integers, round away from `0.0`. - /// - /// # Examples - /// - /// ``` - /// let f = 3.3_f64; - /// let g = -3.3_f64; - /// let h = -3.7_f64; - /// let i = 3.5_f64; - /// let j = 4.5_f64; - /// - /// assert_eq!(f.round(), 3.0); - /// assert_eq!(g.round(), -3.0); - /// assert_eq!(h.round(), -4.0); - /// assert_eq!(i.round(), 4.0); - /// assert_eq!(j.round(), 5.0); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn round(&self) -> Output; - - /// Returns the integer part of `self`. - /// This means that non-integer numbers are always truncated towards zero. - /// - /// # Examples - /// - /// ``` - /// let f = 3.7_f64; - /// let g = 3.0_f64; - /// let h = -3.7_f64; - /// - /// assert_eq!(f.trunc(), 3.0); - /// assert_eq!(g.trunc(), 3.0); - /// assert_eq!(h.trunc(), -3.0); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn trunc(&self) -> Output; - - /// Returns the fractional part of `self`. - /// - /// # Examples - /// - /// ``` - /// let x = 3.6_f64; - /// let y = -3.6_f64; - /// let abs_difference_x = (x.fract() - 0.6).abs(); - /// let abs_difference_y = (y.fract() - (-0.6)).abs(); - /// - /// assert!(abs_difference_x < 1e-10); - /// assert!(abs_difference_y < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn fract(&self) -> Output; - - /// Computes the absolute value of `self`. - /// - /// # Examples - /// - /// ``` - /// let x = 3.5_f64; - /// let y = -3.5_f64; - /// - /// let abs_difference_x = (x.abs() - x).abs(); - /// let abs_difference_y = (y.abs() - (-y)).abs(); - /// - /// assert!(abs_difference_x < 1e-10); - /// assert!(abs_difference_y < 1e-10); - /// - /// assert!(f64::NAN.abs().is_nan()); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn abs(&self) -> Output; - - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `INFINITY` - /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` - /// - NaN if the number is NaN - /// - /// # Examples - /// - /// ``` - /// let f = 3.5_f64; - /// - /// assert_eq!(f.signum(), 1.0); - /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0); - /// - /// assert!(f64::NAN.signum().is_nan()); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn signum(&self) -> Output; - - /// Returns `self` with the sign of `rhs`. - /// This method computes `self.abs() * rhs.signum()`. - #[must_use] - fn signof(&self, rhs: Self) -> Output; - - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error, yielding a more accurate result than an unfused multiply-add. - /// - /// Using `mul_add` *may* be more performant than an unfused multiply-add if - /// the target architecture has a dedicated `fma` CPU instruction. However, - /// this is not always true, and will be heavily dependant on designing - /// algorithms with specific target hardware in mind. - /// - /// # Examples - /// - /// ``` - /// let m = 10.0_f64; - /// let x = 4.0_f64; - /// let b = 60.0_f64; - /// - /// // 100.0 - /// let abs_difference = (m.mul_add(x, b) - ((m * x) + b)).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn mul_add(&self, a: Self, b: Self) -> Output; - - /// Calculates Euclidean division, the matching method for `rem_euclid`. - /// - /// This computes the integer `n` such that - /// `self = n * rhs + self.rem_euclid(rhs)`. - /// In other words, the result is `self / rhs` rounded to the integer `n` - /// such that `self >= n * rhs`. - /// - /// # Examples - /// - /// ``` - /// let a: f64 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 - /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 - /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 - /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn div_euclid(&self, rhs: Self) -> Output; - - /// Calculates the least nonnegative remainder of `self (mod rhs)`. - /// - /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in - /// most cases. However, due to a floating point round-off error it can - /// result in `r == rhs.abs()`, violating the mathematical definition, if - /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. - /// This result is not an element of the function's codomain, but it is the - /// closest floating point number in the real numbers and thus fulfills the - /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` - /// approximately. - /// - /// # Examples - /// - /// ``` - /// let a: f64 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.rem_euclid(b), 3.0); - /// assert_eq!((-a).rem_euclid(b), 1.0); - /// assert_eq!(a.rem_euclid(-b), 3.0); - /// assert_eq!((-a).rem_euclid(-b), 1.0); - /// // limitation due to round-off error - /// assert!((-f64::EPSILON).rem_euclid(3.0) != 0.0); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn rem_euclid(&self, rhs: Self) -> Output; - - /// Raises a number to an integer power. - /// - /// Using this function is generally faster than using `powf`. - /// It might have a different sequence of rounding operations than `powf`, - /// so the results are not guaranteed to agree. - /// - /// # Examples - /// - /// ``` - /// let x = 2.0_f64; - /// let abs_difference = (x.powi(2) - (x * x)).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn powi(&self, n: Int) -> Output; - - /// Raises a number to a floating point power. - /// - /// # Examples - /// - /// ``` - /// let x = 2.0_f64; - /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn powf(&self, n: Self) -> Output; - - /// Returns `e^(self)`, (the exponential function). - /// - /// # Examples - /// - /// ``` - /// let one = 1.0_f64; - /// // e^1 - /// let e = one.exp(); - /// - /// // ln(e) - 1 == 0 - /// let abs_difference = (e.ln() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn exp(&self) -> Output; - - /// Returns `2^(self)`. - /// - /// # Examples - /// - /// ``` - /// let f = 2.0_f64; - /// - /// // 2^2 - 4 == 0 - /// let abs_difference = (f.exp2() - 4.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn exp2(&self) -> Output; - - /// Returns the natural logarithm of the number. - /// - /// # Examples - /// - /// ``` - /// let one = 1.0_f64; - /// // e^1 - /// let e = one.exp(); - /// - /// // ln(e) - 1 == 0 - /// let abs_difference = (e.ln() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn ln(&self) -> Output; - - /// Returns the logarithm of the number with respect to an arbitrary base. - /// - /// The result might not be correctly rounded owing to implementation details; - /// `self.log2()` can produce more accurate results for base 2, and - /// `self.log10()` can produce more accurate results for base 10. - /// - /// # Examples - /// - /// ``` - /// let twenty_five = 25.0_f64; - /// - /// // log5(25) - 2 == 0 - /// let abs_difference = (twenty_five.log(5.0) - 2.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn log(&self, base: Self) -> Output; - - /// Returns the base 2 logarithm of the number. - /// - /// # Examples - /// - /// ``` - /// let four = 4.0_f64; - /// - /// // log2(4) - 2 == 0 - /// let abs_difference = (four.log2() - 2.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn log2(&self) -> Output; - - /// Returns the base 10 logarithm of the number. - /// - /// # Examples - /// - /// ``` - /// let hundred = 100.0_f64; - /// - /// // log10(100) - 2 == 0 - /// let abs_difference = (hundred.log10() - 2.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn log10(&self) -> Output; - - /// Returns the cube root of a number. - /// - /// # Examples - /// - /// ``` - /// let x = 8.0_f64; - /// - /// // x^(1/3) - 2 == 0 - /// let abs_difference = (x.cbrt() - 2.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn cbrt(&self) -> Output; - - /// Compute the distance between the origin and a point (`x`, `y`) on the - /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a - /// right-angle triangle with other sides having length `x.abs()` and - /// `y.abs()`. - /// - /// # Examples - /// - /// ``` - /// let x = 2.0_f64; - /// let y = 3.0_f64; - /// - /// // sqrt(x^2 + y^2) - /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn hypot(&self, other: Self) -> Output; - - /// Computes the tangent of a number (in radians). - /// - /// # Examples - /// - /// ``` - /// let x = std::f64::consts::FRAC_PI_4; - /// let abs_difference = (x.tan() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-14); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn tan(&self) -> Output; - - /// Computes the arcsine of a number. Return value is in radians in - /// the range [-pi/2, pi/2] or NaN if the number is outside the range - /// [-1, 1]. - /// - /// # Examples - /// - /// ``` - /// let f = std::f64::consts::FRAC_PI_2; - /// - /// // asin(sin(pi/2)) - /// let abs_difference = (f.sin().asin() - std::f64::consts::FRAC_PI_2).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn asin(&self) -> Output; - - /// Computes the arccosine of a number. Return value is in radians in - /// the range [0, pi] or NaN if the number is outside the range - /// [-1, 1]. - /// - /// # Examples - /// - /// ``` - /// let f = std::f64::consts::FRAC_PI_4; - /// - /// // acos(cos(pi/4)) - /// let abs_difference = (f.cos().acos() - std::f64::consts::FRAC_PI_4).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn acos(&self) -> Output; - - /// Computes the arctangent of a number. Return value is in radians in the - /// range [-pi/2, pi/2]; - /// - /// # Examples - /// - /// ``` - /// let f = 1.0_f64; - /// - /// // atan(tan(1)) - /// let abs_difference = (f.tan().atan() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn atan(&self) -> Output; - - /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. - /// - /// * `x = 0`, `y = 0`: `0` - /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` - /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` - /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` - /// - /// # Examples - /// - /// ``` - /// // Positive angles measured counter-clockwise - /// // from positive x axis - /// // -pi/4 radians (45 deg clockwise) - /// let x1 = 3.0_f64; - /// let y1 = -3.0_f64; - /// - /// // 3pi/4 radians (135 deg counter-clockwise) - /// let x2 = -3.0_f64; - /// let y2 = 3.0_f64; - /// - /// let abs_difference_1 = (y1.atan2(x1) - (-std::f64::consts::FRAC_PI_4)).abs(); - /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * std::f64::consts::FRAC_PI_4)).abs(); - /// - /// assert!(abs_difference_1 < 1e-10); - /// assert!(abs_difference_2 < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn atan2(&self, other: Self) -> Output; - - /// Simultaneously computes the sine and cosine of the number, `x`. Returns - /// `(sin(x), cos(x))`. - /// - /// # Examples - /// - /// ``` - /// let x = std::f64::consts::FRAC_PI_4; - /// let f = x.sin_cos(); - /// - /// let abs_difference_0 = (f.0 - x.sin()).abs(); - /// let abs_difference_1 = (f.1 - x.cos()).abs(); - /// - /// assert!(abs_difference_0 < 1e-10); - /// assert!(abs_difference_1 < 1e-10); - /// ``` - #[inline] - #[must_use = "method returns new numbers and does not mutate the original value"] - fn sin_cos(&self) -> (Output, Output) { - (self.sin(), self.cos()) - } - - /// Returns `e^(self) - 1` in a way that is accurate even if the - /// number is close to zero. - /// - /// # Examples - /// - /// ``` - /// let x = 1e-16_f64; - /// - /// // for very small x, e^x is approximately 1 + x + x^2 / 2 - /// let approx = x + x * x / 2.0; - /// let abs_difference = (x.exp_m1() - approx).abs(); - /// - /// assert!(abs_difference < 1e-20); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn exp_m1(&self) -> Output; - - /// Returns `ln(1+n)` (natural logarithm) more accurately than if - /// the operations were performed separately. - /// - /// # Examples - /// - /// ``` - /// let x = 1e-16_f64; - /// - /// // for very small x, ln(1 + x) is approximately x - x^2 / 2 - /// let approx = x - x * x / 2.0; - /// let abs_difference = (x.ln_1p() - approx).abs(); - /// - /// assert!(abs_difference < 1e-20); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn ln_1p(&self) -> Output; - - /// Hyperbolic sine function. - /// - /// # Examples - /// - /// ``` - /// let e = std::f64::consts::E; - /// let x = 1.0_f64; - /// - /// let f = x.sinh(); - /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` - /// let g = ((e * e) - 1.0) / (2.0 * e); - /// let abs_difference = (f - g).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn sinh(&self) -> Output; - - /// Hyperbolic cosine function. - /// - /// # Examples - /// - /// ``` - /// let e = std::f64::consts::E; - /// let x = 1.0_f64; - /// let f = x.cosh(); - /// // Solving cosh() at 1 gives this result - /// let g = ((e * e) + 1.0) / (2.0 * e); - /// let abs_difference = (f - g).abs(); - /// - /// // Same result - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn cosh(&self) -> Output; - - /// Hyperbolic tangent function. - /// - /// # Examples - /// - /// ``` - /// let e = std::f64::consts::E; - /// let x = 1.0_f64; - /// - /// let f = x.tanh(); - /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` - /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2)); - /// let abs_difference = (f - g).abs(); - /// - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn tanh(&self) -> Output; - - /// Inverse hyperbolic sine function. - /// - /// # Examples - /// - /// ``` - /// let x = 1.0_f64; - /// let f = x.sinh().asinh(); - /// - /// let abs_difference = (f - x).abs(); - /// - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn asinh(&self) -> Output; - - /// Inverse hyperbolic cosine function. - /// - /// # Examples - /// - /// ``` - /// let x = 1.0_f64; - /// let f = x.cosh().acosh(); - /// - /// let abs_difference = (f - x).abs(); - /// - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn acosh(&self) -> Output; - - /// Inverse hyperbolic tangent function. - /// - /// # Examples - /// - /// ``` - /// let e = std::f64::consts::E; - /// let f = e.tanh().atanh(); - /// - /// let abs_difference = (f - e).abs(); - /// - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] - fn atanh(&self) -> Output; -} diff --git a/helpers/libtrig/traits/impls.rs b/helpers/libtrig/traits/impls.rs deleted file mode 100644 index 6044ca8..0000000 --- a/helpers/libtrig/traits/impls.rs +++ /dev/null @@ -1,179 +0,0 @@ -use super::*; -use crate::*; - -macro_rules! n { ($($o:tt)+) => ($(impl Number for $o{})+); } - -n!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize Float32 Float64); - -macro_rules! simpl { - ($n:ident => $m:ident $($t:tt)*) => ( - #[inline] - #[must_use] - fn $n(&self) -> Self { - l2math::$m(*self) - } - simpl!($($t)*); - ); - ($n:ident $($t:tt)*) => (simpl!($n => $n $($t)*);); - () => (); -} - -impl Sin for Float64 { - simpl!(sin); -} -impl Cos for Float64 { - simpl!(cos); -} -impl Sqrt for Float64 { - simpl!(sqrt); -} - -#[allow(unused)] -impl Float for Float64 { - simpl!(floor ceil round trunc abs => fabs exp exp2 ln log2 log10 cbrt - tan asin acos atan exp_m1 => expm1 ln_1p => ln1p - sinh cosh tanh asinh acosh atanh); - #[inline] - #[must_use] - fn mul_add(&self, a: Self, b: Self) -> Self { - l2math::fma(*self, a, b) - } - #[inline] - #[must_use] - fn div_euclid(&self, rhs: Self) -> Self { - todo!("div_euclid") - } - #[inline] - #[must_use] - fn rem_euclid(&self, rhs: Self) -> Self { - todo!("rem_euclid") - } - #[inline] - #[must_use] - fn signum(&self) -> Self { - if *self > 0.0 { - 1.0 - } else if *self < 0.0 { - -1.0 - } else { - Float64::NAN - } - } - #[inline] - #[must_use] - fn signof(&self, rhs: Self) -> Self { - self.abs() * rhs.signum() - } - #[inline] - #[must_use] - fn powi(&self, n: Int) -> Self { - l2math::pow(*self, n as Float64) - } - #[inline] - #[must_use] - fn powf(&self, n: Self) -> Self { - l2math::pow(*self, n) - } - #[inline] - #[must_use] - fn log(&self, base: Self) -> Self { - l2math::log(*self) / l2math::log(base) - } - #[inline] - #[must_use] - fn hypot(&self, other: Self) -> Self { - l2math::hypot(*self, other) - } - #[inline] - #[must_use] - fn atan2(&self, other: Self) -> Self { - l2math::atan2(*self, other) - } - #[inline] - #[must_use] - fn fract(&self) -> Self { - *self - self.floor() - } -} - -impl Sin for Float32 { - simpl!(sin => sinf); -} -impl Cos for Float32 { - simpl!(cos => cosf); -} -impl Sqrt for Float32 { - simpl!(sqrt => sqrtf); -} - -impl Float for Float32 { - simpl!(floor => floorf ceil => ceilf round => roundf trunc => truncf - abs => fabsf exp => expf exp2 => exp2f ln => lnf log2 => log2f - log10 => log10f cbrt => cbrtf tan => tanf asin => asinf - acos => acosf atan => atanf exp_m1 => expm1f ln_1p => ln1pf - sinh => sinhf cosh => coshf tanh => tanhf asinh => asinhf - acosh => acoshf atanh => atanhf); - #[inline] - #[must_use] - fn mul_add(&self, a: Self, b: Self) -> Self { - l2math::fmaf(*self, a, b) - } - #[inline] - #[must_use] - #[allow(unused)] - fn div_euclid(&self, rhs: Self) -> Self { - todo!("div_euclid") - } - #[inline] - #[must_use] - #[allow(unused)] - fn rem_euclid(&self, rhs: Self) -> Self { - todo!("rem_euclid") - } - #[inline] - #[must_use] - fn signum(&self) -> Self { - if *self > 0.0 { - 1.0 - } else if *self < 0.0 { - -1.0 - } else { - Float32::NAN - } - } - #[inline] - #[must_use] - fn signof(&self, rhs: Self) -> Self { - self.abs() * rhs.signum() - } - #[inline] - #[must_use] - fn powi(&self, n: Int) -> Self { - l2math::powf(*self, n as Float32) - } - #[inline] - #[must_use] - fn powf(&self, n: Self) -> Self { - l2math::powf(*self, n) - } - #[inline] - #[must_use] - fn log(&self, base: Self) -> Self { - l2math::logf(*self) / l2math::logf(base) - } - #[inline] - #[must_use] - fn hypot(&self, other: Self) -> Self { - l2math::hypotf(*self, other) - } - #[inline] - #[must_use] - fn atan2(&self, other: Self) -> Self { - l2math::atan2f(*self, other) - } - #[inline] - #[must_use] - fn fract(&self) -> Self { - *self - self.floor() - } -} diff --git a/helpers/libtrig/traits/mod.rs b/helpers/libtrig/traits/mod.rs deleted file mode 100644 index 1ad4b6f..0000000 --- a/helpers/libtrig/traits/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod float; -mod impls; -mod number; - -pub use float::*; -pub use number::*; diff --git a/helpers/libtrig/traits/number.rs b/helpers/libtrig/traits/number.rs deleted file mode 100644 index aaf6e44..0000000 --- a/helpers/libtrig/traits/number.rs +++ /dev/null @@ -1,28 +0,0 @@ -use core::ops; - -/// A trait for types that can be used as numbers. -pub trait Number: - core::fmt::Debug - + Copy - + Clone - + PartialEq - + ops::Add - + ops::AddAssign - + ops::Sub - + ops::SubAssign - + ops::Mul - + ops::MulAssign - + ops::Div - + ops::DivAssign - + From -{ -} - -/// A trait that calculates the dot product of two items. -pub trait Dot { - /// The output type of the dot product. - type Output; - /// Calculate the dot product of two items. - #[must_use] - fn dot(self, rhs: Rhs) -> Self::Output; -} diff --git a/helpers/libtrig/types.rs b/helpers/libtrig/types.rs deleted file mode 100644 index 9bb01b0..0000000 --- a/helpers/libtrig/types.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub use l2math::{Degree32, Degree64, Float32, Float64, Int, Radian32, Radian64}; - -/// A radian or degree. (64bit) -pub type RadianOrDegree64 = Float64; - -/// A radian or degree. (32bit) -pub type RadianOrDegree32 = Float32; diff --git a/helpers/libtrig/vectors/mod.rs b/helpers/libtrig/vectors/mod.rs deleted file mode 100644 index 0078ddd..0000000 --- a/helpers/libtrig/vectors/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod vec2d; -mod vec3d; - -pub use vec2d::Vec2D; -pub use vec3d::Vec3D; diff --git a/helpers/libtrig/vectors/vec2d.rs b/helpers/libtrig/vectors/vec2d.rs deleted file mode 100644 index 3768edd..0000000 --- a/helpers/libtrig/vectors/vec2d.rs +++ /dev/null @@ -1,231 +0,0 @@ -use crate::*; - -/// A 2D vector. -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Vec2D(Float64, Float64); - -impl Vec2D { - /// Creates a new `Vec2D` from the given `x` and `y` values. - #[inline] - #[must_use] - pub const fn new(x: Float64, y: Float64) -> Self { - Self(x, y) - } - /// Creates a new `Vec2D` located at the origin. - #[inline] - #[must_use] - pub const fn origin() -> Self { - Self(0.0, 0.0) - } - /// Returns the x component of the vector. - #[inline] - #[must_use] - pub const fn x(&self) -> Float64 { - self.0 - } - /// Returns the y component of the vector. - #[inline] - #[must_use] - pub const fn y(&self) -> Float64 { - self.1 - } - /// Rotates the vector by the given angle in radians. - #[inline] - #[must_use] - pub fn rotate_by(&self, angle: Angle2D) -> Self { - #[allow(unused_imports)] - use crate::traits::Float; - let angle = angle.to_radians(); - let (sin, cos) = angle.sin_cos(); - Self( - self.x() * cos - self.y() * sin, - self.x() * sin + self.y() * cos, - ) - } - /// Returns the angle of the vector in radians. - #[inline] - #[must_use] - pub fn angle(&self) -> Angle2D { - #[allow(unused_imports)] - use crate::traits::Float; - Angle2D::from_radians(self.y().atan2(self.x())) - } - /// Returns the inverted vector. - /// - /// Same as rotating the vector by 180 degrees. - #[inline] - #[must_use] - pub fn inverse(&self) -> Self { - -self - } - /// Returns the magnitude of the vector. - #[inline] - #[must_use] - pub fn magnitude(&self) -> Float64 { - #[allow(unused_imports)] - use crate::traits::*; - self.dot(*self).sqrt() - } - /// Normalizes this vector. - #[inline] - #[must_use] - pub fn normalize(&self) -> Self { - let magnitude = self.magnitude(); - Self(self.x() / magnitude, self.y() / magnitude) - } -} - -#[macros::mass_impl( - $THIS = @ORM Vec2D, - $OTHER = @ORM Vec2D -)] -impl crate::traits::Dot for THIS { - type Output = Float64; - #[inline] - #[must_use] - fn dot(self, rhs: OTHER) -> Self::Output { - self.x() * rhs.x() + self.y() * rhs.y() - } -} - -#[macros::mass_impl( - $THIS = @ORM Vec2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::Add for THIS { - type Output = Vec2D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Vec2D(self.x() + rhs.x(), self.y() + rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @OM Vec2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.0 += rhs.x(); - self.1 += rhs.y(); - } -} - -#[macros::mass_impl( - $THIS = @ORM Vec2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::Sub for THIS { - type Output = Vec2D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - Vec2D(self.x() - rhs.x(), self.y() - rhs.y()) - } -} - -#[macros::mass_impl( - $THIS = @OM Vec2D, - $OTHER = @ORM Vec2D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.0 -= rhs.x(); - self.1 -= rhs.y(); - } -} - -#[macros::mass_impl( - $THIS = @ORM Vec2D, - $OTHER = @OR Float64 -)] -impl core::ops::Mul for THIS { - type Output = Vec2D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - Vec2D(self.x() * rhs, self.y() * rhs) - } -} - -#[macros::mass_impl( - $THIS = @OM Vec2D, - $OTHER = @OR Float64 -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - self.0 *= rhs; - self.1 *= rhs; - } -} - -#[macros::mass_impl( - $THIS = @ORM Vec2D, - $OTHER = @OR Float64 -)] -impl core::ops::Div for THIS { - type Output = Vec2D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - Vec2D(self.x() / rhs, self.y() / rhs) - } -} - -#[macros::mass_impl( - $THIS = @OM Vec2D, - $OTHER = @OR Float64 -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - self.0 /= rhs; - self.1 /= rhs; - } -} - -#[macros::mass_impl($THIS = @ORM Vec2D)] -impl core::ops::Neg for THIS { - type Output = Vec2D; - #[inline] - #[must_use] - fn neg(self) -> Self::Output { - Vec2D(-self.x(), -self.y()) - } -} - -impl core::fmt::Display for Vec2D { - #[inline] - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "[{}, {}]", self.x(), self.y()) - } -} - -impl Default for Vec2D { - #[inline] - #[must_use] - fn default() -> Self { - Self::origin() - } -} - -impl> From<(F, F)> for Vec2D { - #[inline] - #[must_use] - fn from((x, y): (F, F)) -> Self { - Self::new(x.into(), y.into()) - } -} - -impl From for (Float64, Float64) { - #[inline] - #[must_use] - fn from(Vec2D(x, y): Vec2D) -> Self { - (x, y) - } -} diff --git a/helpers/libtrig/vectors/vec3d.rs b/helpers/libtrig/vectors/vec3d.rs deleted file mode 100644 index f082b09..0000000 --- a/helpers/libtrig/vectors/vec3d.rs +++ /dev/null @@ -1,226 +0,0 @@ -use crate::*; - -/// A 3D vector. -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Vec3D(Float64, Float64, Float64); - -impl Vec3D { - /// Creates a new `Vec3D` from the given `x`, `y` and `z` values. - #[inline] - #[must_use] - pub const fn new(x: Float64, y: Float64, z: Float64) -> Self { - Self(x, y, z) - } - /// Creates a new `Vec3D` located at the origin. - #[inline] - #[must_use] - pub const fn origin() -> Self { - Self(0.0, 0.0, 0.0) - } - /// Returns the x component of the vector. - #[inline] - #[must_use] - pub const fn x(&self) -> Float64 { - self.0 - } - /// Returns the y component of the vector. - #[inline] - #[must_use] - pub const fn y(&self) -> Float64 { - self.1 - } - /// Returns the z component of the vector. - #[inline] - #[must_use] - pub const fn z(&self) -> Float64 { - self.2 - } - /// Returns the inverted vector. - #[inline] - #[must_use] - pub fn inverse(&self) -> Self { - -self - } - /// Returns the dot product of the vector and the given vector. - #[inline] - #[must_use] - pub fn dot(&self, other: Self) -> Float64 { - self.x() * other.x() + self.y() * other.y() + self.z() * other.z() - } - /// Returns the magnitude of the vector. - #[inline] - #[must_use] - pub fn magnitude(&self) -> Float64 { - #[allow(unused_imports)] - use crate::traits::*; - self.dot(*self).sqrt() - } - /// Normalizes this vector. - #[inline] - pub fn normalize(&mut self) { - let magnitude = self.magnitude(); - self.0 /= magnitude; - self.1 /= magnitude; - self.2 /= magnitude; - } -} - -#[macros::mass_impl( - $THIS = @ORM Vec3D, - $OTHER = @ORM Vec3D -)] -impl core::ops::Add for THIS { - type Output = Vec3D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Vec3D(self.x() + rhs.x(), self.y() + rhs.y(), self.z() + rhs.z()) - } -} - -#[macros::mass_impl( - $THIS = @ORM Vec3D, - $OTHER = @ORM Vec2D -)] -impl core::ops::Add for THIS { - type Output = Vec3D; - #[inline] - #[must_use] - fn add(self, rhs: OTHER) -> Self::Output { - Vec3D(self.x() + rhs.x(), self.y() + rhs.y(), self.z()) - } -} - -#[macros::mass_impl( - $THIS = @OM Vec3D, - $OTHER = @ORM Vec3D -)] -impl core::ops::AddAssign for THIS { - #[inline] - fn add_assign(&mut self, rhs: OTHER) { - self.0 += rhs.x(); - self.1 += rhs.y(); - self.2 += rhs.z(); - } -} - -#[macros::mass_impl( - $THIS = @ORM Vec3D, - $OTHER = @ORM Vec3D -)] -impl core::ops::Sub for THIS { - type Output = Vec3D; - #[inline] - #[must_use] - fn sub(self, rhs: OTHER) -> Self::Output { - Vec3D(self.x() - rhs.x(), self.y() - rhs.y(), self.z() - rhs.z()) - } -} - -#[macros::mass_impl( - $THIS = @OM Vec3D, - $OTHER = @ORM Vec3D -)] -impl core::ops::SubAssign for THIS { - #[inline] - fn sub_assign(&mut self, rhs: OTHER) { - self.0 -= rhs.x(); - self.1 -= rhs.y(); - self.2 -= rhs.z(); - } -} - -#[macros::mass_impl( - $THIS = @ORM Vec3D, - $OTHER = @OR Float64 -)] -impl core::ops::Mul for THIS { - type Output = Vec3D; - #[inline] - #[must_use] - fn mul(self, rhs: OTHER) -> Self::Output { - Vec3D(self.x() * rhs, self.y() * rhs, self.z() * rhs) - } -} - -#[macros::mass_impl( - $THIS = @OM Vec3D, - $OTHER = @OR Float64 -)] -impl core::ops::MulAssign for THIS { - #[inline] - fn mul_assign(&mut self, rhs: OTHER) { - self.0 *= rhs; - self.1 *= rhs; - self.2 *= rhs; - } -} - -#[macros::mass_impl( - $THIS = @ORM Vec3D, - $OTHER = @OR Float64 -)] -impl core::ops::Div for THIS { - type Output = Vec3D; - #[inline] - #[must_use] - fn div(self, rhs: OTHER) -> Self::Output { - Vec3D(self.x() / rhs, self.y() / rhs, self.z() / rhs) - } -} - -#[macros::mass_impl( - $THIS = @OM Vec3D, - $OTHER = @OR Float64 -)] -impl core::ops::DivAssign for THIS { - #[inline] - fn div_assign(&mut self, rhs: OTHER) { - self.0 /= rhs; - self.1 /= rhs; - self.2 /= rhs; - } -} - -#[macros::mass_impl($THIS = @ORM Vec3D)] -impl core::ops::Neg for THIS { - type Output = Vec3D; - #[inline] - #[must_use] - fn neg(self) -> Self::Output { - Vec3D(-self.x(), -self.y(), -self.z()) - } -} - -impl core::fmt::Display for Vec3D { - #[inline] - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "[{}, {}, {}]", self.x(), self.y(), self.z()) - } -} - -impl Default for Vec3D { - #[inline] - #[must_use] - fn default() -> Self { - Self::origin() - } -} - -impl> From<(F, F, F)> for Vec3D { - #[inline] - #[must_use] - /// Converts a tuple of 3 Floats into a `Vec3D`. - fn from((x, y, z): (F, F, F)) -> Self { - Self::new(x.into(), y.into(), z.into()) - } -} - -impl From for (Float64, Float64, Float64) { - #[inline] - #[must_use] - fn from(Vec3D(x, y, z): Vec3D) -> Self { - (x, y, z) - } -} diff --git a/helpers/macros/Cargo.toml b/helpers/macros/Cargo.toml deleted file mode 100644 index 91fb4a0..0000000 --- a/helpers/macros/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "macros" -description = "A collection of macros used throughout the project" -repository.workspace = true -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true - -[lib] -proc-macro = true -path = "lib.rs" - -[dependencies.mc] -package = "macros-core" -path = "./macros-core" diff --git a/helpers/macros/lib.rs b/helpers/macros/lib.rs deleted file mode 100644 index 8710131..0000000 --- a/helpers/macros/lib.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![doc = include_str!("./README.md")] -#![warn(missing_docs, unused, clippy::all, unsafe_code)] -#![deny(missing_debug_implementations)] - -use proc_macro::TokenStream; - -/// A macro for implementing a trait for a list of types. -#[proc_macro_attribute] -pub fn mass_impl(cfg: TokenStream, input: TokenStream) -> TokenStream { - mc::mass_impl(cfg, input).into() -} - -/// A macro for generating FFI functions. -#[proc_macro_attribute] -pub fn ffi(cfg: TokenStream, input: TokenStream) -> TokenStream { - mc::ffi(cfg, input).into() -} - -/// A macro for generating function modifications. -#[proc_macro_attribute] -pub fn func_mod(cfg: TokenStream, input: TokenStream) -> TokenStream { - mc::func_mod(cfg, input).into() -} diff --git a/helpers/macros/macros-core/Cargo.toml b/helpers/macros/macros-core/Cargo.toml deleted file mode 100644 index 96f3c28..0000000 --- a/helpers/macros/macros-core/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "macros-core" -description = "Core functionality for the 'macros' crate" -repository.workspace = true -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true - -[lib] -path = "lib.rs" - -[dependencies] -syn = { version = "2.0", features = ["full"] } -proc-macro2 = "1.0" -quote = "1.0" diff --git a/helpers/macros/macros-core/ffi/mod.rs b/helpers/macros/macros-core/ffi/mod.rs deleted file mode 100644 index 13a4bb7..0000000 --- a/helpers/macros/macros-core/ffi/mod.rs +++ /dev/null @@ -1,98 +0,0 @@ -use crate::TokenStream; - -/// Simplifies the creation of FFI functions -/// -/// # Example -/// ```rust,ignore,no_run -/// #[macros::ffi(type = "system")] -/// pub fn Java_Main_greet<'a>( -/// mut env: JNIEnv<'a>, _class: JClass<'a>, input: JString<'a> -/// ) -> jstring { -/// // First, we have to get the string out of Java. Check out the `strings` -/// // module for more info on how this works. -/// let input: String = env.get_string(&input).expect("Couldn't get java string!").into(); -/// -/// // Then we have to create a new Java string to return. Again, more info -/// // in the `strings` module. -/// let output = env.new_string( -/// format!("Hello, {}!", input) -/// ).expect("Couldn't create java string!"); -/// -/// // Finally, extract the raw pointer to return. -/// output.into_raw() -/// } -/// ``` -pub fn ffi>(cfg: T, input: T) -> TokenStream { - let settings = parse_settings(cfg.into()); - let res = parse_func(input.into(), settings.2).to_string(); - let res = res.replace("__FFI_RAW_MODIFIERS__", &settings.0); - let res = res.replace("__FFI_EXTERN_MODIFIER__", &settings.1); - match syn::parse_str::(&res) { - Ok(res) => res, - Err(err) => err.to_compile_error(), - } -} - -/// parses the function it should be attached to -fn parse_func(item: TokenStream, name_override: Option) -> TokenStream { - let input = match syn::parse2::(item) { - Ok(input) => input, - Err(err) => { - return err.to_compile_error(); - } - }; - let ret = &input.sig.output; - let inputs = &input.sig.inputs; - let name = name_override.unwrap_or(input.sig.ident); - let generics = &input.sig.generics; - let body = &input.block; - let attrs = &input.attrs; - let vis = &input.vis; - let result = quote::quote! { - #(#attrs)* - #[no_mangle] - #vis __FFI_RAW_MODIFIERS__ extern __FFI_EXTERN_MODIFIER__ fn #name #generics(#inputs) #ret { - #body - } - }; - result -} - -/// parses the settings (can be none, const, unsafe or both) -fn parse_settings(attr: TokenStream) -> (String, String, Option) { - let modifiers_str = attr.to_string(); - let mut name_override = None; - let mut res = String::new(); - if modifiers_str.contains("const") { - res.push_str("const "); - } - if modifiers_str.contains("unsafe") { - res.push_str("unsafe "); - } - if modifiers_str.contains('@') { - let type_str = modifiers_str.split('@').collect::>()[1]; - let type_str = type_str.trim(); - let mut namespace = String::new(); - let export_name; - if type_str.contains('+') { - let type_str = type_str.split('+').collect::>(); - namespace = type_str[0].to_string(); - export_name = type_str[1].to_string(); - } else { - export_name = type_str.to_string(); - } - let mut export_name = export_name.replace('.', "_"); - if !namespace.is_empty() { - export_name = format!("{}{}", namespace, export_name) - } - export_name = export_name.replace(' ', ""); - name_override = Some(syn::parse_str::(&export_name).unwrap()); - }; - let t = if modifiers_str.contains("type=") { - let type_str = modifiers_str.split("type=").collect::>()[1]; - type_str.split(' ').collect::>()[0] - } else { - "C" - }; - (res, format!("\"{}\"", t), name_override) -} diff --git a/helpers/macros/macros-core/func_mod/mod.rs b/helpers/macros/macros-core/func_mod/mod.rs deleted file mode 100644 index 2fc56c7..0000000 --- a/helpers/macros/macros-core/func_mod/mod.rs +++ /dev/null @@ -1,258 +0,0 @@ -use crate::TokenStream; -use quote::quote; - -/// A macro for changing the Signature of a function. -/// depending on feature flags. -pub fn func_mod>(cfg: T, input: T) -> TokenStream { - let input = input.into(); - let f = match syn::parse2::(input) { - Err(e) => return e.to_compile_error().into(), - Ok(f) => f, - }; - - // Basic info - let name = &f.sig.ident; - let ret = &f.sig.output; - let inputs = &f.sig.inputs; - let body = &f.block; - let attrs = &f.attrs; - let vis = &f.vis; - - // Configuration - let cfg = match Config::parse(cfg) { - Err(e) => return e.to_compile_error().into(), - Ok(cfg) => cfg, - }; - - // Signatures - let abi = &f.sig.abi; - let asyncness = &f.sig.asyncness; - let constness = &f.sig.constness; - let unsafety = &f.sig.unsafety; - let generics = &f.sig.generics; - let where_clause = &f.sig.generics.where_clause; - - let base_sig = quote!( - #constness #asyncness #unsafety #abi fn #name #generics(#inputs) #ret #where_clause { - #body - } - ); - - let mut sig = quote!(#base_sig); - - if let Some(c) = cfg.constness { - let c_token = c.token; - let c_precode = c.precode; - if let Some(a) = cfg.asyncness { - let a_token = a.token; - let a_precode = a.precode; - if let Some(u) = cfg.unsafety { - let u_token = u.token; - let u_precode = u.precode; - sig = quote!( - #(#attrs)* - #[cfg(all(#c_precode, #a_precode, #u_precode))] - #vis #c_token #a_token #u_token #sig - - #(#attrs)* - #[cfg(all(#c_precode, #a_precode, not(#u_precode)))] - #vis #c_token #a_token #sig - - #(#attrs)* - #[cfg(all(#c_precode, not(#a_precode), #u_precode))] - #vis #c_token #u_token #sig - - #(#attrs)* - #[cfg(all(#c_precode, not(#a_precode), not(#u_precode)))] - #vis #c_token #sig - - #(#attrs)* - #[cfg(all(not(#c_precode), #a_precode, #u_precode))] - #vis #a_token #u_token #sig - - #(#attrs)* - #[cfg(all(not(#c_precode), #a_precode, not(#u_precode)))] - #vis #a_token #sig - - #(#attrs)* - #[cfg(all(not(#c_precode), not(#a_precode), #u_precode))] - #vis #u_token #sig - - #(#attrs)* - #[cfg(all(not(#c_precode), not(#a_precode), not(#u_precode)))] - #vis #sig - ); - } else { - sig = quote!( - #(#attrs)* - #[cfg(all(#c_precode, #a_precode))] - #vis #c_token #a_token #sig - - #(#attrs)* - #[cfg(all(#c_precode, not(#a_precode)))] - #vis #c_token #sig - - #(#attrs)* - #[cfg(all(not(#c_precode), #a_precode))] - #vis #a_token #sig - - #(#attrs)* - #[cfg(all(not(#c_precode), not(#a_precode)))] - #vis #sig - ); - } - } else { - if let Some(u) = cfg.unsafety { - let u_token = u.token; - let u_precode = u.precode; - sig = quote!( - #(#attrs)* - #[cfg(all(#c_precode, #u_precode))] - #vis #c_token #u_token #sig - - #(#attrs)* - #[cfg(all(#c_precode, not(#u_precode)))] - #vis #c_token #sig - - #(#attrs)* - #[cfg(all(not(#c_precode), #u_precode))] - #vis #u_token #sig - - #(#attrs)* - #[cfg(all(not(#c_precode), not(#u_precode)))] - #vis #sig - ); - } else { - sig = quote!( - #(#attrs)* - #[cfg(#c_precode)] - #vis #c_token #sig - - #(#attrs)* - #[cfg(not(#c_precode))] - #vis #sig - ); - } - } - } else { - if let Some(a) = cfg.asyncness { - let a_token = a.token; - let a_precode = a.precode; - if let Some(u) = cfg.unsafety { - let u_token = u.token; - let u_precode = u.precode; - sig = quote!( - #(#attrs)* - #[cfg(all(#a_precode, #u_precode))] - #vis #a_token #u_token #sig - - #(#attrs)* - #[cfg(all(#a_precode, not(#u_precode)))] - #vis #a_token #sig - - #(#attrs)* - #[cfg(all(not(#a_precode), #u_precode))] - #vis #u_token #sig - - #(#attrs)* - #[cfg(all(not(#a_precode), not(#u_precode)))] - #vis #sig - ); - } else { - sig = quote!( - #(#attrs)* - #[cfg(#a_precode)] - #vis #a_token #sig - - #(#attrs)* - #[cfg(not(#a_precode))] - #vis #sig - ); - } - } else { - if let Some(u) = cfg.unsafety { - let u_token = u.token; - let u_precode = u.precode; - sig = quote!( - #(#attrs)* - #[cfg(#u_precode)] - #vis #u_token #sig - - #(#attrs)* - #[cfg(not(#u_precode))] - #vis #sig - ); - } else { - sig = quote!( - #(#attrs)* - #vis #sig - ); - } - } - } - - sig.into() -} - -#[derive(Default)] -struct Config { - constness: Option>, - asyncness: Option>, - unsafety: Option>, -} - -struct ConfigItem { - token: Token, - precode: syn::Meta, -} - -impl syn::parse::Parse for ConfigItem { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let token = input.parse::()?; - input.parse::]>()?; - let precode = input.parse::()?; - Ok(ConfigItem { token, precode }) - } -} - -impl Config { - /// Parses the configuration. - /// - /// # Example - /// - /// This example shows how if the feature `"unstable"` is enabled, - /// the function will be marked as `const`. - /// - /// ```rust,no_run,ignore - /// #[inline] - /// #[func_mod( - /// const => #[cfg(feature = "unstable")] - /// )] - /// fn deg_to_rad(deg: f64) -> f64 { - /// deg * 0.017 - /// } - /// ``` - fn parse>(cfg: T) -> syn::Result { - let cfg: TokenStream = cfg.into(); - syn::parse2::(cfg) - } -} - -impl syn::parse::Parse for Config { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let mut cfg = Config::default(); - while !input.is_empty() { - let lookahead = input.lookahead1(); - if lookahead.peek(syn::Token![const]) { - cfg.constness = Some(input.parse::>()?); - } - if lookahead.peek(syn::Token![async]) { - cfg.asyncness = Some(input.parse::>()?); - } - if lookahead.peek(syn::Token![unsafe]) { - cfg.unsafety = Some(input.parse::>()?); - } - } - Ok(cfg) - } -} diff --git a/helpers/macros/macros-core/lib.rs b/helpers/macros/macros-core/lib.rs deleted file mode 100644 index 200f527..0000000 --- a/helpers/macros/macros-core/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! A collection of core functionality for the macros. - -#![warn(missing_docs, unused, clippy::all, unsafe_code)] -#![deny(missing_debug_implementations)] - -use proc_macro2::TokenStream; - -mod ffi; -mod func_mod; -mod mass_impl; - -pub use ffi::ffi; -pub use func_mod::func_mod; -pub use mass_impl::mass_impl; diff --git a/helpers/macros/macros-core/mass_impl/args.rs b/helpers/macros/macros-core/mass_impl/args.rs deleted file mode 100644 index f805e3f..0000000 --- a/helpers/macros/macros-core/mass_impl/args.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! Argument parsing for the `mass_impl` macro. - -pub use super::variants::TypeVariant; - -/// The configuration for the `mass_impl` macro. -pub struct MassImplMacroConfig { - /// The type variants to implement the trait for. - pub type_variants: Vec, -} - -impl std::fmt::Debug for MassImplMacroConfig { - /// Formats a `TypeVariant` - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("MassImplMacroConfig") - .field("type_variants", &self.type_variants) - .field("number_of_passthroughs", &self.number_of_passthroughs()) - .finish() - } -} - -impl MassImplMacroConfig { - /// Returns the number of passthroughs for this type variant. - pub fn number_of_passthroughs(&self) -> i32 { - let mut i = 1; - for variant in &self.type_variants { - i *= variant.number_of_passthroughs(); - } - i - } -} - -// parses this: -// $SELF = @R @M Vec2D, -// $OTHER = @R @M Vec2D -impl syn::parse::Parse for MassImplMacroConfig { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let mut type_variants = Vec::new(); - let vars = - syn::punctuated::Punctuated::::parse_terminated(input)?; - for var in vars { - type_variants.push(var); - } - Ok(MassImplMacroConfig { type_variants }) - } -} diff --git a/helpers/macros/macros-core/mass_impl/mod.rs b/helpers/macros/macros-core/mass_impl/mod.rs deleted file mode 100644 index e60835c..0000000 --- a/helpers/macros/macros-core/mass_impl/mod.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::TokenStream; - -mod args; -mod variants; - -/// A macro for implementing a trait for a list of types. -pub fn mass_impl>(cfg: T, input: T) -> TokenStream { - let cfg: TokenStream = cfg.into(); - let input: TokenStream = input.into(); - let config = match syn::parse2::(cfg) { - Ok(config) => config, - Err(err) => { - return err.to_compile_error(); - } - }; - let mut results = vec![input.to_string()]; - - for tv in &config.type_variants { - let mut temp_results = Vec::new(); - if tv.allow_owned { - for r in &results { - let new = r.replace(&tv.alias.to_string(), &tv.ty.to_string()); - temp_results.push(new); - } - } - if tv.allow_ref { - for r in &results { - let new = r.replace(&tv.alias.to_string(), &format!("&{}", tv.ty)); - temp_results.push(new); - } - } - if tv.allow_mut { - for r in &results { - let new = r.replace(&tv.alias.to_string(), &format!("&mut {}", tv.ty)); - temp_results.push(new); - } - } - results = temp_results; - } - let single_str = results.join("\n"); - match syn::parse_str::(&single_str) { - Ok(ts) => ts, - Err(err) => err.to_compile_error(), - } -} diff --git a/helpers/macros/macros-core/mass_impl/variants.rs b/helpers/macros/macros-core/mass_impl/variants.rs deleted file mode 100644 index a00c4f1..0000000 --- a/helpers/macros/macros-core/mass_impl/variants.rs +++ /dev/null @@ -1,111 +0,0 @@ -/// A type variant, used in the `#[mass_impl(...)]` macro. -/// -/// Input generally looks like this: -/// -/// ```rust,ignore,no_run -/// $NAME = @RM SomeStruct -/// ``` -/// -/// Which essentially means: -/// - `$NAME` is the alias for `SomeStruct` -/// - `@R` means that `SomeStruct` can be passed by reference -/// - `@RM` means that `SomeStruct` can be passed by mutable reference -/// -/// So it will create 3 bodies for the macro: -/// - `impl SomeTrait for SomeStruct` -/// - `impl SomeTrait for &SomeStruct` -/// - `impl SomeTrait for &mut SomeStruct` -pub struct TypeVariant { - /// The alias for the type (e.g. `$NAME`) - pub alias: syn::Ident, - /// The type (e.g. `SomeStruct`) - pub ty: syn::Ident, - /// Whether or not the type can be passed by value - pub allow_owned: bool, - /// Whether or not the type can be passed by reference - pub allow_ref: bool, - /// Whether or not the type can be passed by mutable reference - pub allow_mut: bool, -} - -impl TypeVariant { - /// Returns the number of passthroughs for this type variant. - pub fn number_of_passthroughs(&self) -> i32 { - let mut i = if self.allow_owned { 1 } else { 0 }; - if self.allow_ref { - i += 1 - }; - if self.allow_mut { - i += 1 - }; - i - } -} - -impl std::fmt::Debug for TypeVariant { - /// Formats a `TypeVariant` - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("TypeVariant") - .field("alias", &self.alias) - .field("ty", &self.ty) - .field("allow_owned", &self.allow_owned) - .field("allow_ref", &self.allow_ref) - .field("allow_mut", &self.allow_mut) - .finish() - } -} - -impl syn::parse::Parse for TypeVariant { - /// Turns this: - /// - /// ```rust,ignore,no_run - /// $NAME = @RM SomeStruct, - /// ``` - /// - /// Into this: - /// - /// ```rust,ignore,no_run - /// TypeVariant { - /// alias: "NAME" - /// ty: SomeStruct, - /// allow_owned: true, - /// allow_ref: true, - /// allow_mut: true, - /// } - /// ``` - fn parse(input: syn::parse::ParseStream) -> syn::Result { - use syn::*; - let _ = input.parse::()?; - let alias = input.parse::()?; - input.parse::()?; - let mut allow_owned = false; - let mut allow_ref = false; - let mut allow_mut = false; - loop { - if input.peek(Token![@]) { - let _ = input.parse::()?; - let modifier = input.parse::()?; - let modifier = modifier.to_string(); - if modifier.contains('R') { - allow_ref = true; - } - if modifier.contains('M') { - allow_mut = true; - } - if modifier.contains('O') { - allow_owned = true; - } - } else { - break; - } - } - let ty = input.parse::()?; - Ok(TypeVariant { - alias, - ty, - allow_owned, - allow_ref, - allow_mut, - }) - } -} diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index adf6e02..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,9 +0,0 @@ -[project] -name = "arc" -version = "0.0.1-dev" -description = "Advanced Robot Controller" -requires-python = ">=3.11" - -[build-system] -requires = ["maturin>=1,<2"] -build-backend = "maturin" diff --git a/robot/Cargo.toml b/robot/Cargo.toml index 98e7749..a9581d0 100644 --- a/robot/Cargo.toml +++ b/robot/Cargo.toml @@ -1,27 +1,28 @@ -[package] -name = "arc-robot" -description = "ARC Robot" -repository.workspace = true -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true - -[lib] -name = "arc_robot" -path = "lib.rs" - -[dependencies.pyruntime] -package = "arc-robot-python-runtime" -path = "./pyruntime" - -[dependencies.macros] -path = "../helpers/macros" -package = "macros" - -[dependencies.rocket] -version = "0.5" -features = [] - -[dependencies.log] -version = "0.4" +[package] +name = "dranik" +description = "Dranik Robot" +repository.workspace = true +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true + +[lib] +name = "dranik" +path = "lib.rs" + +[[bin]] +name = "dranik" +path = "../dranik.rs" + +[dependencies] +# Core of the robot (hardware abstraction layer) +dranik-core = { path = "./core" } +# Robot HTTP client, used to control the robot via HTTP +dranik-web = { path = "./web" } +# Python runtime for the robot +dranik-python = { path = "./python" } +# Async runtime +tokio = { version = "1.35", features = ["rt", "signal"] } + +arc = { path = "../arc", package = "arc-pylib" } diff --git a/robot/core/Cargo.toml b/robot/core/Cargo.toml index 2b29b0d..77a3aeb 100644 --- a/robot/core/Cargo.toml +++ b/robot/core/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "arc-robot-core" -description = "ARC Robot Core" +name = "dranik-core" +description = "Dranik Robot Core" repository.workspace = true version.workspace = true edition.workspace = true @@ -8,13 +8,22 @@ authors.workspace = true license.workspace = true [lib] +name = "dranikcore" path = "lib.rs" [dependencies.l2math] -path = "../../helpers/l2math" +git = "https://github.com/DranikiRobotics/librobomath" +package = "l2math" [dependencies.libtrig] -path = "../../helpers/libtrig" +git = "https://github.com/DranikiRobotics/librobomath" +package = "libtrig" + +[dependencies.tokio] +version = "1.35" + +[dependencies.pyo3] +version = "0.20.0" [features] unstable = ["l2math/unstable", "libtrig/unstable"] diff --git a/server/README.md b/robot/core/README.md similarity index 100% rename from server/README.md rename to robot/core/README.md diff --git a/robot/core/config.rs b/robot/core/config.rs new file mode 100644 index 0000000..77bb2c6 --- /dev/null +++ b/robot/core/config.rs @@ -0,0 +1,25 @@ +//! This module contains the [RobotConfig] trait and the [DefaultRobotConfig] struct +//! +//! This is primarily used to configure the robot at a higher level than just changing the +//! entire codebase. +//! +//! This is useful for things like loading rust libraries before the python +//! interpreter is initialized (which is exactly how ARC is loaded). Or for customizing +//! things like the logging system. Or for anything else that needs to be done before +//! the actual robot code is run. + +use pyo3::prelude::*; +use pyo3::types::{PyDict, PyTuple}; + +/// A trait for common functionality that can be used to configure the robot +pub trait RobotConfig { + /// This function is called before the python interpreter is initialized + /// + /// This is useful for loading rust libraries that will then be used by python. + /// In fact, this is exactly how ARC is loaded. + fn python_preload() {} + type Args: IntoPy> + Default; + fn build_python_main_function_args<'a>(_py: &pyo3::Python<'_>, _io: &crate::io::IO) -> (Self::Args, Option<&'a PyDict>) { + (Self::Args::default(), None) + } +} diff --git a/robot/core/gamepad.rs b/robot/core/gamepad.rs index 55343fc..2bb3d7f 100644 --- a/robot/core/gamepad.rs +++ b/robot/core/gamepad.rs @@ -1,4 +1,4 @@ -use crate::HardwareComponent; +use crate::hardware::HardwareComponent; /// A trait that allows for reading from a gamepad /// diff --git a/robot/core/hardware.rs b/robot/core/hardware.rs index 006828d..a64b15f 100644 --- a/robot/core/hardware.rs +++ b/robot/core/hardware.rs @@ -12,7 +12,7 @@ pub use dcmotor::DcMotor; /// /// # Example /// ```rust -/// # use arc_robot_core as robot; +/// # use dranikcore as robot; /// # use robot::HardwareMap; /// # fn example(hardware_map: impl HardwareMap) -> robot::Result<()> { /// let motor = hardware_map.load::("motor")?; @@ -20,5 +20,16 @@ pub use dcmotor::DcMotor; /// # } /// ``` pub trait HardwareMap { + /// Loads a hardware component with the given UUID fn load(&self, uuid: impl Into) -> Result; } + +/// A trait that represents a hardware component +pub trait HardwareComponent: core::fmt::Debug { + /// Returns the UUID of this component + #[allow(non_snake_case)] + fn getUUID(&self) -> HardwareUUID; + /// Internal method used to load a component + #[doc(hidden)] + fn __load_self(_: internals::HardwareComponentLoadMetadata) -> Result where Self: Sized; +} diff --git a/robot/core/hardware/dcmotor.rs b/robot/core/hardware/dcmotor.rs index 3f5bc69..c217eb6 100644 --- a/robot/core/hardware/dcmotor.rs +++ b/robot/core/hardware/dcmotor.rs @@ -1,16 +1,10 @@ -use crate::*; - -#[derive(Debug, Clone)] -pub struct DcMotor { - -} +use super::HardwareComponent; +use l2math::Float64; -impl DcMotor { - -} +use crate::*; -impl HardwareComponent for DcMotor { - fn getUUID(&self) -> HardwareUUID { - todo!() - } +/// A simple DC motor +pub trait DcMotor: HardwareComponent { + /// Sets the power of the motor + fn set_power(&mut self, power: Float64) -> Result<()>; } diff --git a/robot/core/internals/INTERNALS.md b/robot/core/internals/INTERNALS.md new file mode 100644 index 0000000..cc9a822 --- /dev/null +++ b/robot/core/internals/INTERNALS.md @@ -0,0 +1,6 @@ +Internals of the robot + +This contains things like: the impls of [`HardwareMap`] or [`Telemetry`], etc. + +[`HardwareMap`]: crate::HardwareMap +[`Telemetry`]: crate::Telemetry \ No newline at end of file diff --git a/robot/core/internals/impls.rs b/robot/core/internals/impls.rs new file mode 100644 index 0000000..97a19d6 --- /dev/null +++ b/robot/core/internals/impls.rs @@ -0,0 +1,35 @@ +use std::collections::HashMap; + +use super::HardwareComponentLoadMetadata; +use crate::hardware as h; + +mod dcmotor; +mod gamepad; +pub use dcmotor::DcMotorImpl; +pub use gamepad::GamepadImpl; + +pub enum HardwareComponentType { + DcMotor, +} + +pub struct HardwareMapImpl { + components: HashMap, +} + +impl HardwareMapImpl { + pub fn new() -> Self { + Self { components: HashMap::new() } + } +} + +impl h::HardwareMap for HardwareMapImpl { + fn load(&self, uuid: impl Into) -> crate::Result { + let uuid: crate::HardwareUUID = uuid.into(); + if let Some(component) = self.components.get(&uuid) { + return C::__load_self(HardwareComponentLoadMetadata { + uuid: uuid.into(), + }); + } + Err(crate::HardwareError::DeviceNotFound) + } +} diff --git a/robot/core/internals/impls/dcmotor.rs b/robot/core/internals/impls/dcmotor.rs new file mode 100644 index 0000000..54f8293 --- /dev/null +++ b/robot/core/internals/impls/dcmotor.rs @@ -0,0 +1,29 @@ +use crate::hardware as h; +use crate::*; + +struct DcMotorConfig { + +} + +#[derive(Debug)] +pub struct DcMotorImpl { + +} + +impl h::HardwareComponent for DcMotorImpl { + #[allow(non_snake_case)] + fn getUUID(&self) -> HardwareUUID { + todo!() + } + + fn __load_self(_: super::HardwareComponentLoadMetadata) -> Result where Self: Sized { + todo!() + } + +} + +impl h::DcMotor for DcMotorImpl { + fn set_power(&mut self, power: f64) -> Result<()> { + todo!() + } +} diff --git a/robot/core/internals/impls/gamepad.rs b/robot/core/internals/impls/gamepad.rs new file mode 100644 index 0000000..b5af49b --- /dev/null +++ b/robot/core/internals/impls/gamepad.rs @@ -0,0 +1,125 @@ +use crate::hardware as h; +use crate::*; + +#[derive(Default, Debug, Clone)] +pub struct GamepadImpl { + +} + +impl GamepadImpl { + pub(crate) fn init() -> Self { + Self { + + } + } +} + +impl h::HardwareComponent for GamepadImpl { + /// Returns the UUID of the gamepad + /// + /// Note: This will always be "gamepad0" + #[allow(non_snake_case)] + fn getUUID(&self) -> HardwareUUID { + HardwareUUID::new(['g', 'a', 'm', 'e', 'p', 'a', 'd', '0']) + } + /// Loads the gamepad from the hardware map + /// + /// ### This will always panic + /// + /// This is because the gamepad is not supposed to be loaded from the hardware map. + fn __load_self(_: super::HardwareComponentLoadMetadata) -> Result where Self: Sized { + ::core::panic!("Attempted to load gamepad from hardware map"); + } +} + +impl crate::Gamepad for GamepadImpl { + fn dpad(&self) -> crate::Result { + todo!() + } + + fn left_stick(&self) -> crate::Result { + todo!() + } + + fn right_stick(&self) -> crate::Result { + todo!() + } + + fn left_trigger(&self) -> crate::Result { + todo!() + } + + fn right_trigger(&self) -> crate::Result { + todo!() + } + + fn a(&self) -> crate::Result { + todo!() + } + + fn b(&self) -> crate::Result { + todo!() + } + + fn x(&self) -> crate::Result { + todo!() + } + + fn y(&self) -> crate::Result { + todo!() + } + + fn left_bumper(&self) -> crate::Result { + todo!() + } + + fn right_bumper(&self) -> crate::Result { + todo!() + } +} + +impl crate::gamepad::MutableGamepad for GamepadImpl { + fn set_dpad(&mut self, _: gamepad::GamepadDpad) -> crate::Result<()> { + todo!() + } + + fn set_left_stick(&mut self, _: gamepad::GamepadStick) -> crate::Result<()> { + todo!() + } + + fn set_right_stick(&mut self, _: gamepad::GamepadStick) -> crate::Result<()> { + todo!() + } + + fn set_left_trigger(&mut self, _: l2math::Float64) -> crate::Result<()> { + todo!() + } + + fn set_right_trigger(&mut self, _: l2math::Float64) -> crate::Result<()> { + todo!() + } + + fn set_a(&mut self, _: bool) -> crate::Result<()> { + todo!() + } + + fn set_b(&mut self, _: bool) -> crate::Result<()> { + todo!() + } + + fn set_x(&mut self, _: bool) -> crate::Result<()> { + todo!() + } + + fn set_y(&mut self, _: bool) -> crate::Result<()> { + todo!() + } + + fn set_left_bumper(&mut self, _: bool) -> crate::Result<()> { + todo!() + } + + fn set_right_bumper(&mut self, _: bool) -> crate::Result<()> { + todo!() + } +} diff --git a/robot/core/internals/mod.rs b/robot/core/internals/mod.rs new file mode 100644 index 0000000..0699793 --- /dev/null +++ b/robot/core/internals/mod.rs @@ -0,0 +1,11 @@ +#![doc = include_str!("./INTERNALS.md")] + +use super::*; + +pub(crate) mod impls; + +/// Metadata used to load a hardware component +#[derive(Debug, Clone)] +pub struct HardwareComponentLoadMetadata { + pub uuid: HardwareUUID, +} diff --git a/robot/core/io.rs b/robot/core/io.rs new file mode 100644 index 0000000..eb276b6 --- /dev/null +++ b/robot/core/io.rs @@ -0,0 +1,30 @@ +use crate::threadsafe::{ThreadSafe, GetResult, SafeHeld, StandardResult}; +use crate::*; + +#[derive(Debug)] +struct IOHolder { + gamepad: internals::impls::GamepadImpl, +} +impl IOHolder { + fn init() -> Self { + Self { + gamepad: internals::impls::GamepadImpl::init(), + } + } + fn gamepad(&self) -> impl Gamepad { + self.gamepad.clone() + } +} + +#[derive(Debug, Clone)] +pub struct IO(ThreadSafe); + +impl IO { + pub(crate) fn new() -> Self { + Self(ThreadSafe::new(IOHolder::init())) + } + pub fn gamepad(&self) -> StandardResult { + self.0.get().map(|h| h.gamepad()) + } + +} diff --git a/robot/core/lib.rs b/robot/core/lib.rs index 21f5fc5..e166770 100644 --- a/robot/core/lib.rs +++ b/robot/core/lib.rs @@ -1,9 +1,13 @@ -#![doc = include_str!("../README.md")] +#![doc = include_str!("./README.md")] #![warn(missing_docs, unused, clippy::all, unsafe_code)] #![deny(missing_debug_implementations)] +pub mod threadsafe; pub mod hardware; pub mod gamepad; +pub mod config; +pub mod io; + mod telemetry; mod error; @@ -41,9 +45,18 @@ impl OpMode where mod __uuid; pub use __uuid::HardwareUUID; -/// A trait that represents a hardware component -pub trait HardwareComponent: core::fmt::Debug { - /// Returns the UUID of this component - #[allow(non_snake_case)] - fn getUUID(&self) -> HardwareUUID; +#[doc(hidden)] +pub mod internals; + +pub fn setup_io() -> io::IO { + io::IO::new() +} + +/// This function is used to take a blocking piece of code and run it in such a way +/// that it doesn't block the entire runtime. +pub async fn deblock(f: F) -> core::result::Result where + F: FnOnce() -> R + Send + 'static, + R: Send + 'static, +{ + tokio::task::spawn_blocking(f).await } diff --git a/robot/core/telemetry.rs b/robot/core/telemetry.rs index 9678b68..615c995 100644 --- a/robot/core/telemetry.rs +++ b/robot/core/telemetry.rs @@ -1,4 +1,3 @@ -use crate::HardwareComponent; use core::fmt::{Debug, Display}; /// A type that allows sending telemetry data to the driver control station @@ -8,7 +7,7 @@ use core::fmt::{Debug, Display}; /// /// Even though it is marked as `HardwareComponent`, it is not meant to be loaded. /// Infact, it will always return `HardwareError::DeviceNotFound` when loaded. -pub trait Telemetry: HardwareComponent { +pub trait Telemetry { /// Sends a debug message to the driver control station /// /// It will not be displayed to the driver control station if the robot is not in debug mode. diff --git a/arc/threadsafe.rs b/robot/core/threadsafe.rs similarity index 60% rename from arc/threadsafe.rs rename to robot/core/threadsafe.rs index 7f7cf25..0013053 100644 --- a/arc/threadsafe.rs +++ b/robot/core/threadsafe.rs @@ -27,8 +27,10 @@ mod holders { #[derive(Debug, Default)] pub struct ThreadSafeHolder(Arc>); - pub type GetResult<'a, T> = core::result::Result, &'static str>; - pub type GetResultMut<'a, T> = core::result::Result, &'static str>; + pub type StandardResult = ::core::result::Result; + + pub type GetResult<'a, T> = StandardResult>; + pub type GetResultMut<'a, T> = StandardResult>; #[derive(Debug)] #[repr(transparent)] @@ -79,6 +81,8 @@ mod holders { super::thread_safe!(ThreadSafeHolder); } +pub(crate) use holders::{GetResult, GetResultMut, SafeHeld, SafeHeldMut, StandardResult}; + /// A thread-safe value. /// /// This is a wrapper around a value that by default is not thread-safe. @@ -95,114 +99,118 @@ macro_rules! thread_safe_primitive { pub type $name:ident = $primitive:ty; { $thread_safe_mod_name:ident; $default_value:expr } $($rest:tt)* ) => ( -$(#[$outer])* -pub type $name = $thread_safe_mod_name::$name; -mod $thread_safe_mod_name { - use super::*; - - #[repr(transparent)] - #[derive(Default, Debug, Clone)] - pub struct $name(ThreadSafe); - - impl PartialEq for $name { - fn eq(&self, other: &Self) -> bool { - match (self.get(), other.get() ) { - (Ok(a), Ok(b)) => a.get() == b.get(), - _ => false, + $(#[$outer])* + pub type $name = $thread_safe_mod_name::$name; + mod $thread_safe_mod_name { + use super::*; + + #[repr(transparent)] + #[derive(Default, Debug, Clone)] + pub struct $name(ThreadSafe); + + thread_safe!($name); + + impl PartialEq for $name { + fn eq(&self, other: &Self) -> bool { + match (self.get(), other.get() ) { + (Ok(a), Ok(b)) => a.get() == b.get(), + _ => false, + } + } } - } - } - impl Eq for $name {} + impl Eq for $name {} - impl PartialOrd for $name { - fn partial_cmp(&self, other: &Self) -> Option { - match (self.get(), other.get() ) { - (Ok(a), Ok(b)) => a.get().partial_cmp(&b.get()), - _ => None, + impl PartialOrd for $name { + fn partial_cmp(&self, other: &Self) -> Option { + match (self.get(), other.get() ) { + (Ok(a), Ok(b)) => a.get().partial_cmp(&b.get()), + _ => None, + } + } } - } - } - impl Ord for $name { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - match (self.get(), other.get() ) { - (Ok(a), Ok(b)) => a.get().cmp(&b.get()), - _ => std::cmp::Ordering::Equal, + impl Ord for $name { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + match (self.get(), other.get() ) { + (Ok(a), Ok(b)) => a.get().cmp(&b.get()), + _ => std::cmp::Ordering::Equal, + } + } } - } - } - impl $name { - pub fn new(value: $primitive) -> Self { - Self(ThreadSafe::new(Primitive::new(value))) - } - pub fn get(&self) -> holders::GetResult<'_, Primitive> { - self.0.get() - } - pub fn get_mut(&self) -> holders::GetResultMut<'_, Primitive> { - self.0.get_mut() - } - } - - #[repr(transparent)] - #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct Primitive($primitive); + impl $name { + pub fn new(value: $primitive) -> Self { + Self(ThreadSafe::new(Primitive::new(value))) + } + pub fn get(&self) -> holders::GetResult<'_, Primitive> { + self.0.get() + } + pub fn get_mut(&self) -> holders::GetResultMut<'_, Primitive> { + self.0.get_mut() + } + } - impl Primitive { - pub fn new(value: $primitive) -> Self { - Self(value) - } - pub fn get(&self) -> $primitive { - self.0 - } - pub fn set(&mut self, value: $primitive) { - self.0 = value; - } - } + #[repr(transparent)] + #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct Primitive($primitive); + + thread_safe!(Primitive); + + impl Primitive { + pub fn new(value: $primitive) -> Self { + Self(value) + } + pub fn get(&self) -> $primitive { + self.0 + } + pub fn set(&mut self, value: $primitive) { + self.0 = value; + } + } - impl core::ops::Deref for Primitive { - type Target = $primitive; - fn deref(&self) -> &Self::Target { - &self.0 - } - } + impl core::ops::Deref for Primitive { + type Target = $primitive; + fn deref(&self) -> &Self::Target { + &self.0 + } + } - impl core::ops::DerefMut for Primitive { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } - } + impl core::ops::DerefMut for Primitive { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } - impl From<$primitive> for Primitive { - fn from(value: $primitive) -> Self { - Self(value) - } - } + impl From<$primitive> for Primitive { + fn from(value: $primitive) -> Self { + Self(value) + } + } - impl From for $primitive { - fn from(value: Primitive) -> Self { - value.0 - } - } + impl From for $primitive { + fn from(value: Primitive) -> Self { + value.0 + } + } - impl From<$primitive> for $name { - fn from(value: $primitive) -> Self { - Self::new(value) - } - } + impl From<$primitive> for $name { + fn from(value: $primitive) -> Self { + Self::new(value) + } + } - impl From<$name> for $primitive { - fn from(value: $name) -> Self { - match value.get() { - Ok(b) => b.get(), - Err(_) => $default_value, + impl From<$name> for $primitive { + fn from(value: $name) -> Self { + match value.get() { + Ok(b) => b.get(), + Err(_) => $default_value, + } + } } } - } -} -thread_safe_primitive!($($rest)*); + thread_safe_primitive!($($rest)*); ); () => (); } diff --git a/robot/lib.rs b/robot/lib.rs index 6ddece5..200cc74 100644 --- a/robot/lib.rs +++ b/robot/lib.rs @@ -1,6 +1,124 @@ #![doc = include_str!("./README.md")] - #![warn(missing_docs, unused, clippy::all, unsafe_code)] #![deny(missing_debug_implementations)] -pub use pyruntime; +/// Helps with loading robot configurations. +/// +/// ## Example using the default config +/// +/// ```rust +/// dranik::use_config!(); +/// dranik::main!(); +/// ``` +/// +/// ## Example using ARC +/// +/// ```rust +/// dranik::use_config!(arc); +/// dranik::main!(); +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! use_config { + () => ( $crate::use_config!($crate); ); + ($namespace: path) => ( + use $namespace::{__dranik_config as __DranikRobotConfig}; + ); +} + +/// Creates the main function for the robot. +/// +/// ## Example +/// +/// ```rust +/// dranik::use_config!(); +/// dranik::main!(); +/// ``` +/// +/// This macro is used to create the main function for the robot. +/// It is guaranteed to be stable and it's API will not change. +/// +/// The reason this macro exists is because the main function +/// is not guaranteed to be stable and may change at any time. +/// That mostly includes the generic parameters. +#[macro_export(local_inner_macros)] +macro_rules! main { + () => ( fn main() { + $crate::main::<__DranikRobotConfig>(); + } ); +} + +pub use dranikcore::config::RobotConfig; +use std::sync::atomic::AtomicU8; +use std::sync::atomic::Ordering; +use tokio::runtime::Builder; + +static ID: AtomicU8 = AtomicU8::new(0); + +/// This is the actual main function that is called by the robot. +/// +/// It isn't recommended to call this function directly. +/// However, if you do, be careful as this function is not +/// guaranteed to be stable and may change at any time. +/// See [`main!`] for more information. +/// +/// ## Recommended Usage +/// +/// ```rust +/// dranik::use_config!(); +/// dranik::main!(); +/// ``` +/// +/// ## Example using ARC +/// +/// ```rust +/// dranik::use_config!(arc); +/// dranik::main!(); +/// ``` +/// +/// ## Internal workings +/// +/// What it does in a nutshell is: +/// 1. Initialize the async runtime. +/// 2. Setup the IO. +/// 3. Spawn the web server. +/// 4. Spawn the python thread. +/// 5. inject shutdown handler. +/// 6. Block until shutdown. +/// 7. Shutdown the runtime. +/// 8. Exit. +/// +/// [`main!`]: crate::main +pub fn main() { + let runtime = Builder::new_multi_thread() + .enable_all() + .worker_threads(4) + .thread_name_fn(|| { + let id = ID.fetch_add(1, Ordering::SeqCst); + format!("Dranik worker#{}", id) + }) + .build() + .expect("Failed to initialize runtime"); + + let io = dranikcore::setup_io(); + + // runtime.spawn(dranikweb::main()); + runtime.spawn(dranikpy::main::(io.clone())); + runtime.block_on(async { + tokio::signal::ctrl_c().await.expect("Failed to listen for ctrl-c"); + print!("Exiting..."); + }); + runtime.shutdown_timeout(std::time::Duration::from_secs(5)); + drop(io); + std::process::exit(0); +} + +/// Internal struct that is used to hold the robot config. +/// +/// This contains the default config. +#[doc(hidden)] +#[allow(non_camel_case_types)] +#[derive(Default, Debug, Clone, Copy)] +pub struct __dranik_config; +impl dranikcore::config::RobotConfig for __dranik_config { + type Args = (); +} diff --git a/robot/pyruntime/Cargo.toml b/robot/pyruntime/Cargo.toml deleted file mode 100644 index cb3be4c..0000000 --- a/robot/pyruntime/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "arc-robot-python-runtime" -description = "ARC Robot Server Python Runtime" -repository.workspace = true -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true - -[lib] -name = "arc_robot_server_python_runtime" -path = "lib.rs" - -[dependencies.arc_core] -package = "arc-robot-core" -path = "../core" - -[dependencies.pylib] -package = "arc-pylib" -path = "../../arc" - -[dependencies.pyo3] -version = "0.20.0" -features = ["extension-module"] diff --git a/robot/python/Cargo.toml b/robot/python/Cargo.toml new file mode 100644 index 0000000..2e4b052 --- /dev/null +++ b/robot/python/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "dranik-python" +description = "Dranik Robot Python Runtime" +repository.workspace = true +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true + +[lib] +name = "dranikpy" +path = "lib.rs" + +[dependencies.dranikcore] +package = "dranik-core" +path = "../core" + +[dependencies.pyo3] +version = "0.20.0" diff --git a/robot/python/README.md b/robot/python/README.md new file mode 100644 index 0000000..e69de29 diff --git a/robot/pyruntime/lib.rs b/robot/python/lib.rs similarity index 65% rename from robot/pyruntime/lib.rs rename to robot/python/lib.rs index a4d0b5e..dc8b31e 100644 --- a/robot/pyruntime/lib.rs +++ b/robot/python/lib.rs @@ -1,8 +1,49 @@ -#![doc = include_str!("../README.md")] +#![doc = include_str!("./README.md")] #![warn(missing_docs, unused, clippy::all, unsafe_code)] #![deny(missing_debug_implementations)] +const PY_OK: pyo3::PyResult<()> = Ok(()); + +use dranikcore::config::RobotConfig; +use pyo3::prelude::*; +use pyo3::Python; + +pub async fn main(io: dranikcore::io::IO) where + A: IntoPy> + Default, + C: RobotConfig, +{ + C::python_preload(); + + pyo3::prepare_freethreaded_python(); + + dranikcore::deblock(move || Python::with_gil(|py| { + // add files to sys.path + let syspath = py.import("sys")? + .getattr("path")? + .downcast::()?; + syspath.insert(0, "./examples")?; + + let args = C::build_python_main_function_args(&py, &io); + + // import main module + let main = py.import("tank_drive_teleop")?; + let mainfunc = main.getattr("main")?; + mainfunc.call(args.0, args.1)?; + PY_OK + })) + .await + .expect("Failed to run python main") + .expect("Python main returned an error"); +} + +// fn pymain(py: Python) -> PyResult<()> { +// let main_func: pyo3::Py = PyModule::from_code(py, &code, "auto.py", "")? +// .getattr("main")? +// .into(); +// main_func.call1(py, (op_wrapper,))?; +// } + // use pyo3::prelude::*; // #[derive(Debug, Clone)] diff --git a/robot/web/Cargo.toml b/robot/web/Cargo.toml new file mode 100644 index 0000000..5db70e0 --- /dev/null +++ b/robot/web/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "dranik-web" +description = "Dranik HTTP Server" +repository.workspace = true +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true + +[lib] +name = "dranikweb" +path = "lib.rs" + +[dependencies.rocket] +version = "0.5" +features = [] + +[dependencies.log] +version = "0.4" diff --git a/robot/web/README.md b/robot/web/README.md new file mode 100644 index 0000000..e69de29 diff --git a/robot/web/assets/logo.png b/robot/web/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8a14d8c4e58651cdf9484fa331675df6059b36dd GIT binary patch literal 17222 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 literal 0 HcmV?d00001 diff --git a/robot/web/assets/logo.svg b/robot/web/assets/logo.svg new file mode 100644 index 0000000..6ff0791 --- /dev/null +++ b/robot/web/assets/logo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/robot/web/assets/logo192.ico b/robot/web/assets/logo192.ico new file mode 100644 index 0000000000000000000000000000000000000000..d1ed52f79450dc5ef6af8f44ae70b98901394c6b GIT binary patch literal 152126 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 literal 0 HcmV?d00001 diff --git a/robot/web/assets/logo256.ico b/robot/web/assets/logo256.ico new file mode 100644 index 0000000000000000000000000000000000000000..13f18226b9340d88f8ca182737bf293a9573edb8 GIT binary patch literal 12847 zcmX}T1z1$i8#cT_F5TVIDWEhts*A z{!#ncO}lh!y!?mqI;g3i_KyEgCHiF>{b#m5Wb>^U;K7Y4J3I>_Q z&?dKd|CQzI{!dlzPshjBPLHn#_ho#X#Kp2(o7*cr_0XNQ0tv_aH5D~J6$ih{eOTd1 ztHc+85*<#+YIXZ_;FaB<8U+|f6)wH|J1fpQwScdnBW`^FN*PGN6nLU^xCE4E$5g*E zW}d=*_RJ@Vk!0Z@B+ED)gqzjeAyR3DwG`r*Y?R1YcehWZT4)OqW0*|mo;YNkp0sSyM zr1+H-AVE;i{B%l(W@e9Wo8cY!mdmh>pBiCJA07aPzIrFz-lfdw=qpOFnBW7kX}%=R zd&wRm*W@8L)ZEJQdd^}HP*9lMeL;$(7wOwRsb`tC*hq)d&;4=FFy#zXtS^I0M<6eo&EL_-Wx@|81tPl^xRYY_{{+=MT<{NDC z>!9evIQxOz++Q7{W6>&k9jfQ2x$HOO>(b+RQ_l$Mtyi(WeOK3*05Vv3#LRL7r1d~g zO+sAMA7S^5q!1l)#ZeX>M_3~OG<=^Aeeg^d% zppXxz7i15M6MQdqLL^kG2k`D6Pld(K#n9od_(13g#6D#mDf&U^#&m4~1%UOP7s0!m zW1NNG#Z6DWBLmn%{%lJg<4&~yVxD}QN~J(jH@+G03v3Pk+&-1>(9*CRYjWzHy`!-) zCv%@~{KlUhDK2IT%!D@#Sxspgfvn*{!io}tE4p2k_7hM35EbrG2r>rMxA=#7bYlA^S%=UL`-0$(sQ!jI= zG?FKFG%{=6w=h&YJwe(b@TQ248c>}ylHrTSUt-V4eP07Q<7FiH*OozVv$JXd3itiN zZw4bmagmj97SUF(C^GK!{@CPNr5^9e<^$9BR{wPHT4SKxryCArMW>2saQVJXN0#5= z0l+ssS$NEk^ve&0Jw!i`sSQt|*ML z8k@0Kq(B4eE9ACG(Xmigsf{0IK@`G5s$PrTNsO<0X*{HWkEE%FuMH*ibquLKV&bvE zCy&~FB=)Y|6!#s0REAvCcHV4CwSyq}-o$WUw&IzZrrE~Z>gYG~5%Fir8eVB#s`fT& zpD0lGz81XOH8;YW6QZ&aQGcZ4QQ>ry0i(8uEA3J56z<<#(`bZ@CH ze6yiZ*1RH0HrZ{i2 zY7Dzqt!ClB|3cctct3@+^J8IKBz)6f@x1QM(;!*Leuq7L$t+?x!e_It)pC{R)vq(v zsuG2E(mSj%eLj|$cDB>h%J{7B#@QFPhx2wRHI{tRF)r+8tO%G=&J+urd77&aXr$cL zd;)&1zkucH5qWvtQ}0?>GrjE2xA;JxD__Sp>YaY9j4MN+x{h4%)^n6=T?Y5RcBzzSSRZX(O>l@d zuAJb?IDjP~gn(wi&cvnmha$?cY}^1e;Im^Q@ z8aZ5sYOzF5hBs|(Hvw2oiXqVDPAu$e~5w6a|#!>j;$oLK~ z4PG44g|aGh#uAh1e7}L$9qx|YI#n#WNL}o!H$ACw{WgJ@K;PZkds3pG$xz_}R`ueg z2^VI!ib31(nRL*kM-RJiS2_NM+CH7)EJo>7A{x2U(+E- z=qOfIUS;d7I@eOoT#5Jemv|v1qc&G;j@Z0OrqXISnufdqPL@lpMX`u4&W4&5vfpVmiA4*f-+bqU?>ge3~-%Q!NKFiWXU(L#KDbmSI{=cY3>efaVo z$u%UBiVanvOEu~&2EFWzblLIg=rNJ3pg72WgP_^$+(<5lK3mHg#Op>?Bag1%eZQYf z5z#rRcK^2Aa-Tf9gtwcP?i1_|woHK#bK6}w%(Uff;?N;hhGxRx`x&i`0(z`kg#;}# z#Q|-4s!vvLF%Dnb&gs}hRhx#<^MI{F3H?2OtQ56i3uH zkY1fG01MjA#9h^g&o^3>P|}AGwY5T;bl{P7OsnUQl14y6pGBfizA% z9Wm$DMCQOH5`@%5#O4Uk*=9}hhBppbXLB+~qH!GH$xU51R)=+2{m1(w9#3b9aKn6?lme}8GT9aVUd z*+9#DC%x*;qB2s_wZK9{VRZv!TrFw$OH3ZhwlFa4{rIusi=zhxkHN>r^e0tiWsb)0 z%F>##V#tJ{f*-W~^2ZAR{%p_nwYBl9+VD~TBy5+Y|2euiC|s`~|5*1ZB%M%8N8rC? zV0-#&-fq#i-CxmEO2TN)hlg&jI<3Yx4BLm+^s1|@64aLGlgN%5Z+;F@BuyZ7yHULv z>Jlg!b4qwObmyeVpaZ>CfDgmHJ^;4MxA-4)lXV((JK zBP724X)Vzj1fYUX$i4zRZ6l0P@*0fU?6r=*a}0jZ!kQCa+DXKHweL~>6%$j`8OHTB z6$4Mf`S`!+*gVQ=zCu$S_1F*mwh*caZMa<<|8Hz;fVb>ojPWVa%ekI^P?FPI7JXB@ z*-$7+u}vLI{w?<(nbP*gL@}8c{-(9?{a2tJtv8m2OpR)>3wFv@mo!7S*Jv=Y#YvWs z)pI~=FqkGh0HHfDU;f+_%yJJ}J%2p9xCfUQwM3m|U2mxLakntO6zCo3uAp~OW@}Qx z?I^+e5{pF35#L?w;R?6zI3_uH@u!{k#=@v?}*c7$Lb%t^1Aq zD3+**u}oni;ifmi{eH4Z*QEsU_K3YS^_OCBvhU5B7{N%D6=9A z*&+-AyTztNw#!bhNTh`CrTo#9(RY^aj>=D}vT${t)O7l1_6|!1|9(!0d(9@riR_Lx zVt(!BcVRhONI-W;KW~-sn+n^D1_@kC2OyY8;KC?kl@UwHBx6#Bw1=)y-={qXx+XFk zm&RbyamOV|U$WUv`H4K@dw*AM7MItTBQP}JE%~lR1kK%7$c?yx-rx~qr3d*2s=_QF z_YEOf_vroCb_>sgx$~l8=Jl{VW*Go{peS@griEz87StHsy=S)P<&%K2jgG(66T7^) zO5DW8_G&l05OsQdKf3$!e?_V z3y-?OF_9X)1jxQhJcsU8X(&0+D(hH4a#kb#fu9tX8;INAekJ@3p*p{rj6V9Rt~#yBti(=i;5gig{8TZWq$SK%d{|w1AG|lwV8HU z>*4t$K2$15tf-N?CigH@VtbJy$y+|pJ4D3sS?Y@GL2Fl$s`b|U9I`AgCMJji8)_<> zxB&LPlJjk?kak_kD3rBlV;#+&B7jbpo)y81~L`xAJ6lkEgiZ;*KJ4TZgKdOnG6gBxc+e6u03@!()rAC-G*j1idaLP_hE{N94LJ4y1?1u8H2SiuPM9$z@9hs*lYQN9pkET|tdQ*pGVOo=~fJ zglkhNa3i}?zA>4q5&V4hLrEkYtie-zUl4pADsL;N%q9h@RdaHwBO)1^E)d$B3_>%l zmG2yDJANRi)pOW80zhxF^7Dsn{=RjK4RDptnat#>WEyh+ z#U3lW`^7#TXlxRetuZlP96w~Ci||SH*JY#CxF44Zw`-+IGz1*Nf;7tNk}u5xu?A)^&OkUj__K6^V*$S?Q0V;QuR6Q2sdj&@eztg{sx$vFb z{R0Te5+^FEYqAMqDf8Uq28SGdbls0~LDZ7jj`PAur^YmH> zf=sYq-`^A4M%kZQZ&XNZM%%(~n-Mowg0-GC;k#yB5=&;4QON_db%N7C9Lt}K;?$br zato8g(m&35PDs1>y2&GlWytF zUKqD_#uM}DaW$s*Rl;_5((j~uq+EvLG&2nVY&IPy*-|}E0`?0Ye2Ti7^ z2Kz23eMWPWX#6E1`Z3>QXaq4$|7&{v9i^O~vGKC4yB_@K;-lQB_%|X&K@5N~e*V3^3OO?6 zDUUYNEEXex>)8sb>kDLlgF{VW?a`K(O=Z(UZ61^e8bURTNOL6va=afCM+EGkO!>M%2=V2x1jqvPIdPYPV7J(wv1$z>TT^ zkmtsDu<({1@QUzf#h2(x{)Z9WA5uD07TM|k(nVZjVe8jVO zoL5-z848b1H>;2t3s;FZD1W5&6(SP8tREZf!qB+F!H94vTvE74%lIt}7|}cRRxq3? zTsaJV<2+9)`G-qk1;{1@dsr3;TLa+leLo(52NI5da?18H@MCIVcj$+XnfrqBaOyy& z*f%kpu7%aw8|fRiX;=@Eej3)s&%A-JmFkTUqzR=qTy;<~A3^(@K1*9si5C;uTF2kP z$0c+owyfGfbeTkP-<@>{Z=0%o>nN0)Sfvg52qVoa z4;vSH9Y6-kEAwF{p2qec6FNuF(jrXHoK+k{qrb|Lxt&s#sS3V*?9?(Pjk z-I#(0^KDEJf1zIuYNrc>#K7hSb4Ksy&E6af_ECOO@>*jLxdkZ*;mV0kX)klEz^G6@ zL{@G#Qdl?9R0~0Nx3z?=*I`PNYhjrs;3<=5nk?&OL5J5p019>3u;zu=_?qs%=It<%|1o-O5!U(oYgdDV)xYo;sK;$S_YC92gXqb zvGHg+_Va5xI4M#LK>%lhbBCjC-lk}FC@y&81>2~9C0y)MU0DlDW(e`2=Ut}Ja_WRJ zwr@QrZqHTll^sdzuK)Wfp7K}R&;>Uc9U8=bu6)~RWs0Cg$|1p* zU!QhY$Ok%l8u;x~T|mQp`jCz`+Y21ZE!gXx3SE?Y;V;TMPsej^2gI|P!Hy|(X80N#@HmRw(t&T{?{k4=%)|= z!W@QS0(%_rWrh8!3GpYS*+THLFNZFo6=V|B#^^*BC2A4Z9zo<2Mvhje67vr{! z-b;z2xcMvZJ`PfQg(VCkiTiW8U7Av^d!)^uApTg&WcOloi>esq0u%MU*NVM zp~A1!axA8ANg~K}Cx*^l%(P?S6a}Mwo5>2SAPPWMY<$!t~_6Rgf8~1__2Kx9pOnDq)cgkH#uUsgkT-RseLc z_~Z4+!EbsJ3zCz`Z@0E#%~!GAp{)9V{x4~a=sdZaMtc8Mbe91087^QkCzfp7(Jv=d zo0;U@2)R0)myL|Y(Y#qgx=&#T&?!Kf%R-9AOqP`X)P{Y4jHC~b#}9<9FR-81hnoG# zXxT+NlGh2b{rG9$ZD#o;W<)#wNaB2r68g`GQ0lbn!Tg6&@7Y5baT2DJoz-K;At)&i z>=hDr&C>D%J^5sb;|)mhCup+7pqo`FqVV)1TWZAdr0XRL{O>nfXD`GGi5n=Bx7}D2 zXVwAIW-8zT5P=owrhJS<(JqdXr~-z}AbfT4)W-8fdnps zm?Fjpd`T&xZ*ibIxmC(C8u{L8mLoToxJb(V0)IglOevB!K9#3?=+P!9Sp*PmVWRu< zN}}&;OB=aHDIy_bTQ8w1*Uob0%^PyU_toFNG9%phhCi1DKL)7)?e`~IP-_O1G+RLy z7}9VJ)~@(%d^4;iQvC!Ki5J!wZU3ZMV75Sl^r8=M$`=t#nIdR@HVCmPV-d>r_as1& z9d^C&dLY-gwRiEZ1jIS^{x&tsfyU>Q0=0N`OUW;sERycFham6|l^ljGOe7-du$H)| zFgK&WDCZ`W#2ox5mt@fTgWDgi?uypBo!EIH0K!drc;bfC(qSi2#(t*>fPa0i_mZ{V z!PU*Noe~E8!J(+QL1J<0vS2@hY|?H|T-{+w_yG03P~ZHzF~5~l3qxg|Fq8g&XnWQ2 zP}leF>u^irn8E@W4Uzqrpr{yU2rz^j!h@&tl&a7XGAAt~kcaA}JCfuHIPdAMi+8%^ z8PCK2GSsiZ7gfC7nosmUL;<@}Q_`$4OqRY%6V)v1j z=AYAU`87e}p)D1@Zu4?1oz2*<3sDA+pOrNO?A8<6KmyGp+^~WdDrLxh9>D3?)z-9+ z+B={NeXb?`H-lx0Ff0qLFs|{Mz?Y)9Qc)lb1G7Hw_HXzrndW&24R#Ggs1)#1Y9&ei z+F5hx`O2SMkUq{u?tJJix6L~%=7T-d9rfU=D}Kto8Qyi>U^U=2PoSYl3J7`S24#*6 z@!F;Jt%g6Yr7gDEQw!3A?JY7g*@v+Yq*Kk=GuC0zLK3+tE*xZ!u_dbw6+1yZc}t

bMZpHq#}M`xu2V^AQ)Y@Y6SUTL^t`dnh*VI~}<@@x=af$f>IAt_Ep_#8YW zZNv>q#(gE_g!dBXA}`!7*tc2KhP-J2=Vr$(2a_Uv%W??ox!RWX5LvH4ys>dwyc>N2 z!~Ok}a`;0CCcz+bzghvxdSiU@_Rff;&M^Gc_=c_!mhYP#f}bP_rBp*zAhzH};Au#) z@I7lZyg6ya&0S)N@Mxpr;jbQiJ6Eq5gGHA^rH1rB+6_yV8sM+#{D|X12!WBgnhiF; zmB|YxJ<=k=t@JEV_?fwcT(!iOj~uQcQ&Gp?6{GK|f?1sbxPA*gMpqu6#4Y{55K4C9 z>N3r&wZVAnIHloIITW!2;{rKfz->8>61WegfJF1=3ql5Hmvc{!u(C5f%#jfjlKy?s zZUj`0g@OF(HlEI>=)tW*AmfxJf%(21I9OuE2^TrFQvfSZ5!JDxKWZN5T-2|xkUV4} zQD~R60n~1B%fOsROgk)B01ohQcdr@iw=<_dsXJc3hw$eIJ{{FoepnXMUw%d&xCXfT zt?-Skn(;^C;n5;arfJs0r4;}_lZ!i5b3LAjDo;VY`F?|JHsjMOTU&Ssj@Jwys^~ht z(O%e_gw_PDP2H{wPKz*(5xRSG8%8ea%$kkxTWkDIH5)ZPso-1K!lO8nT#VlDZ8N9T z2dun`^er{O)&oOm$Lw#;6lymUw8?(gQxGIp}Yrk4f1%nbQpw9@7MTdVI!@$D{dWNx=M7B(^o- zNG6xwRlw}&@k-cxk=UX8x|9o61eE()!YZO+kiZ<92YfeyJC7#c!_XFIAW$Iv(A-8w zj9WtYK9#P`EqeRWmMpU5#B6C|X$yIf`u?HD7M>!(i3(E~u9qO&ss@ST@)igB7iMf} zZrq^u&bipndm*ggo7rC-J5qn3&=5PDryMC^5u;Gf@z$3g*D$lgH`w_;wsf7?woL%Fp&;Jm@WKdK?NTxP1gKtBxWWq{XsM|jzZ4|tWW>x zp}W3K@k8&BetI+TG& z5%~G{-@D@fKypKD{~4ASp=4s>>c=HQ+4CeXM@Y9)bO$EIor;gr zJC(|7Km!q^9Ns>VSTS~k{#?xxQaToo)x|RS3Mrc<42y`-rcbDlG+f^4VeJRsip=g_ z=g$H?lSzG}{sp%Egj|Akd9qUC?t#Hg)T9my&8tivh82Jg>Bm5Qr&&$u9*5L{_|R|Y z2;IQ~HiTGghE>+(DTZxOBh7LFd=_Q5ORx*A!EU2Hi>y`M9#^mrHb)T*^1)K!!eZn^ zlGX^@A4&kSgZ;7*+B%9BMeXa(8_&8EU6a6_ZDOT=&4Ifo=$^wBQ!iy)$0pw<4lTu_ zSD%iPm|5i!L@aly zP3b-hE>Jjr*P8M8I&^>!CXURGBsx-km3H_XuvY58kNi-p{4H18FXPjZ5_9YQSHk{A z7PIc`f1i_eGIV+PiYdW+Um2GJN5mkk&e?7siR+3=P&0R+?{3jy2U5Mx9T}ndh!>k( zj9g!vk9pPfW>RX_5l;EGZ~uJ-qbcc{c({GvSNi#W)EyJ6qRZWNHU(5{USNGJ2ecv zr~6^hw-dzE%CL%G>u-1K;PdL%=$*I=By!JOzPuN-q+uBrFu7-g?{Qh z^Mp@2O^ZA}&T#Yt@i+-PSj`Bsk3f<*LZ$6VXOW&WP(s z8$B^tF)ME8>&1{Gm|2L$0gPFs+c=i$)$Ndw55^FH56Xx70M?)ptLY1m&0=-i!E+AN zDDQc+a;3#UcNAq7=T))VJU1LectIBSM<{REK@xy`SzFmV62JCymby|CS^ zmQ{39x=qcP@Wm?@z;vH@+D>;r2>c8_J{T=tLK@-Gz*86f_3H>nP|h zAT64c_n$X(Z5jeOJLYSihgNryj#79u=-7y1=gyTB-|e?IOJO~~8|!ZPCQZ;qKd#Ze znOw*GIptOS-1Db-u8j;acjY34%%=;T7Ym)_{;UZnKO{c{;tI_gMLsh#0)^~t{?VPh zL0g}ripQ*>EBtf3nO;Ge55oC2h+GNANKGX}kD{5f4^0f(u*Ik{FXTIu;_2?k9C z5QpCN{_crc(r{3gIeI=48%2zaAWjr57J8%md>=Uc-bVYpIkLvY(E)vP+-nEGIe7 z)Ys+LSHzxV2Yv{(A9LNH2~q?CWN~G`w3A!G@fduobKcj>ba!x#RcT^gni=&k8ng%+ zi6^?-xJ8AXtS0^i%}$}0S~1`~`mjJU+jUe`K|hk!Q1K&#-fbI8bY70kb(J3ic=Td8 z07foQJrS5C2#EtR!xZt7d zeb$q#j-M$NC6G14>2Wgq_+T7i40nk1C{zwm^(7M`m=1Cv2o=l9DbZ9`Cu)%0rLGDm zwvRu&>Y^Lqhp=M3gWPcVzQuMaX)BNT{GO=O3CQe9F6W`{^1#VOrpD<3zlSS5X4i&ibCm0;*^f5VU(&wlb%eZX}OJ~j*B_J z91V*CN8Zq4myQ#sFCQ!?g(F2(S_aN9?)wrGy+3NvR*4!8nG=;}e#X7p0!sD>M@uRU z!%xljuTbGe@ZFn-Yi}OaL8@_D+cg3`y&^+u-*@=OW|MJaR`W0GH@iwcVgfARSl!UB z^`s(@$i33GSv{BgO3tbmkKu=)du}M?oV-_DhhExs--5{vJh1sx1z*7Tyx4;eFli#+ zp=M|&C3ya@g@&?Wc(K1SZN3YAm8&@S@FOEd?m1YgeMuE6kb zScUHTT8aQJ)i^-||At-1I+oS1(ZZ3K8_6}-HZZQn+(>$^@lgS5{T7cdMsH)s%ub4W z^H}Ml>F7fj2Ircsz}lAP+A4oLD8-IR$~#M!1H60C!5S`Gus3Dy)n7s!8qnA1peS~n zWB%-qVaZ(|FfEmlduah_;|1&-f5x5Kk6BHt*f|}?zW`|QO4qs&onTw!=N=y!NIt66 z<%P+F$KXey>&5-&UPTebCx>SPR{+J7Bl~NXMiBE)Kl)2WYsB9Qyb=9O`3Ag-xHa2?8Eop`v@8@)5%5ZAH zR)C3>TO00@T%kvkw`P0)`k^X(JwIw+zv|CBHwm=Eb=Rint^Ht=UE)TfrK3y9qg<56 zPNnDLA0`}QE!Dq{mY!G%4%Xl3D-kTcGQvdwDsR0AV4e#jg{J?!)QO_yd zca%3pYb5?!z$j9J-P0oU$eZCWgsKkibjQZxVyD@rW9|M=-L)CYJt|lk@xzriAc{Nq zKk@fpMi=Ev?h#*jzZ<1X^pqQ2X>b2P^vEeKd=^*_XEE!)`emqVmS>g%hz*dsN&Fzf z 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 literal 0 HcmV?d00001 diff --git a/robot/web/assets/logo_white.png b/robot/web/assets/logo_white.png new file mode 100644 index 0000000000000000000000000000000000000000..821a899c05647a9d0ee6423c06475a056694dfe4 GIT binary patch literal 14084 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 literal 0 HcmV?d00001 diff --git a/robot/web/assets/logo_white_gear.png b/robot/web/assets/logo_white_gear.png new file mode 100644 index 0000000000000000000000000000000000000000..f75d5016f18fbe1399e10b45a154bffe03091c32 GIT binary patch literal 14766 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 ( + ::core::include_str!($file) + .handlebars("debug", $crate::html::SERVER) + ) +} + +pub async fn main() { + +} diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index 07ade69..0000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly \ No newline at end of file diff --git a/scripts/__init__.py b/scripts/__init__.py deleted file mode 100644 index ebd3e8b..0000000 --- a/scripts/__init__.py +++ /dev/null @@ -1,42 +0,0 @@ -from scripts.build import build -from scripts.clean import clean -from scripts.doc import doc -from scripts.fmt import fmt -from scripts.run import run -from scripts.test import test - -def run_cmd(cmd: str, cwd: str, args: list[str]) -> str | int | None: - if cmd == "help" or cmd == "--help" or cmd == "-h": return hlp() - if cmd == "build": return build(cwd, args) - if cmd == "clean": return clean(cwd, args) - if cmd == "doc": return doc(cwd, args) - if cmd == "fmt": return fmt(cwd, args) - if cmd == "run": return run(cwd, args) - if cmd == "test": return test(cwd, args) - - return f"Unknown command: {cmd}" - -def hlp() -> str | int | None: - print("""\033[35mUsage: \033[36m./epearl \033[32m \033[96m[args]\033[0m -\033[35mCommands: - \033[32mbuild \033[0mBuild the project - \033[96m--release\033[0m Build in release mode - \033[32mrun \033[0mRun an OpMode - \033[32m \033[0mThe file to run - \033[32mtest \033[0mRun the tests - \033[96m--tarpaulin\033[0m Run the tests with tarpaulin - \033[96m--llvm \033[0m Run the tests with llvm coverage - \033[96m--all \033[0m Run the tests with both tarpaulin and llvm coverage - \033[32mclean \033[0mClean the project - \033[96m--deep \033[0mRemoves all generated files and folders - \033[32mdoc \033[0mGenerate the documentation - \033[96m--open \033[0mOpen the documentation in the browser - \033[32mfmt \033[0mFix formatting issues in the code - \033[96m--check \033[0mCheck if the code is formatted correctly - \033[32mhelp \033[0mDisplay this message -\033[35mExamples: - \033[0mRun the example OpMode: \033[36m./epearl \033[32mrun \033[32m./examples/auto.py - \033[0mBuild the project: \033[36m./epearl \033[32mbuild \033[96m--release - \033[0mRun the tests: \033[36m./epearl \033[32mtest \033[96m--all -\033[0m""") - return \ No newline at end of file diff --git a/scripts/build.py b/scripts/build.py deleted file mode 100644 index 715ca0f..0000000 --- a/scripts/build.py +++ /dev/null @@ -1,12 +0,0 @@ -import subprocess, os - -def build(cd: str, args: list[str]) -> str | int | None: - if "--android" in args: - print("Android builds are currently halted.") - print("Hopefully they will be back soon.") - return 0 - - cmd = ["cargo", "build", "-p", "arc-pylib", "-F", "extension-module", "--workspace"] - cmd.extend(args) - res = subprocess.run(cmd, cwd=cd) - if res.returncode != 0: return res.returncode diff --git a/scripts/clean.py b/scripts/clean.py deleted file mode 100644 index e43d1ba..0000000 --- a/scripts/clean.py +++ /dev/null @@ -1,42 +0,0 @@ -def clean(cd: str, args: list[str]) -> str | int | None: - import subprocess - - DEEP = False - if '--deep' in args: DEEP = True - - if not DEEP: - print("Cleaning...") - else: print("Deep cleaning...") - - cmd = ["cargo", "clean"] - res = subprocess.run(cmd, cwd=cd) - if res.returncode != 0: return res.returncode - - if not DEEP: - print("Done!") - return - - import shutil, os - - CLEAN_DIRS = ["target", ".build", "__pycache__"] - CLEAN_DIRS_EXTENSIONS = [] - CLEAN_FILES = ["Cargo.lock"] - CLEAN_FILES_EXTENSIONS = [".dylib", ".dll", ".lib", ".so"] - KEEP_FILES = [] - - for full_dir_path, _, files in os.walk(cd): - for file in files: - if file in CLEAN_FILES: - if file not in KEEP_FILES: - os.remove(os.path.join(full_dir_path, file)) - elif os.path.splitext(file)[1] in CLEAN_FILES_EXTENSIONS: - if file not in KEEP_FILES: - os.remove(os.path.join(full_dir_path, file)) - for dr in CLEAN_DIRS_EXTENSIONS: - if os.path.basename(full_dir_path).startswith(dr): - try: shutil.rmtree(full_dir_path) - except Exception: os.remove(full_dir_path) - if os.path.basename(full_dir_path) in CLEAN_DIRS: - shutil.rmtree(full_dir_path) - - print("Done!") diff --git a/scripts/doc.py b/scripts/doc.py deleted file mode 100644 index 15dff69..0000000 --- a/scripts/doc.py +++ /dev/null @@ -1,22 +0,0 @@ -def doc(cd: str, args: list[str]) -> str | int | None: - import subprocess - - cmd = ["cargo", "doc", "--no-deps"] - - PACKAGES = [ - "arc-pylib", - "arc-robot-core", - # "libodo", - # "libpath", - "libtrig", - "l2math", - "macros" - ] - - for p in PACKAGES: - cmd.append("--package") - cmd.append(p) - - cmd.extend(args) - res = subprocess.run(cmd, cwd=cd) - if res.returncode != 0: return res.returncode diff --git a/scripts/fmt.py b/scripts/fmt.py deleted file mode 100644 index 19fd85c..0000000 --- a/scripts/fmt.py +++ /dev/null @@ -1,7 +0,0 @@ -def fmt(cd: str, args: list[str]) -> str | int | None: - import subprocess - - cmd = ["cargo", "fmt"] - if '--check' in args: cmd.extend(['--', '--check']) - res = subprocess.run(cmd, cwd=cd) - if res.returncode != 0: return res.returncode diff --git a/scripts/run.py b/scripts/run.py deleted file mode 100644 index 1d25a23..0000000 --- a/scripts/run.py +++ /dev/null @@ -1,14 +0,0 @@ -def run(cd: str, args: list[str]) -> str | int | None: - import subprocess - - binary = "arc" - for i in range(len(args)): - arg = args[i] - if '--bin=' in arg: - binary = arg.split('=')[1] - args.pop(i) - - cmd = ["cargo", "run", "--bin", binary] - cmd.extend(args) - res = subprocess.run(cmd, cwd=cd) - if res.returncode != 0: return res.returncode diff --git a/scripts/test.py b/scripts/test.py deleted file mode 100644 index 8f006fc..0000000 --- a/scripts/test.py +++ /dev/null @@ -1,90 +0,0 @@ -def test(cd: str, args: list[str]) -> str | int | None: - if len(args) == 0: return "No test type specified" - - if '--release' in args: - return "Release mode is not supported for tests" - - if '--tarpaulin' in args: - args.pop(0) - return tarpaulin_test(cd, args) - elif '--llvm' in args: - args.pop(0) - return llvm_test(cd, args) - elif '--all' in args: - args.pop(0) - tarpaulin_test_res = tarpaulin_test(cd, args) - if tarpaulin_test_res != None: return tarpaulin_test_res - llvm_test_res = llvm_test(cd, args) - if llvm_test_res != None: return llvm_test_res - else: return "Invalid test type" - -def llvm_test(cd: str, args: list[str]) -> str | int | None: - print("LLVM tests are currently broken") - return - - import subprocess - - print("Running tests with llvm coverage") - - # Run the tests - res = subprocess.run( - ["cargo", "test"], - cwd = cd, - env = { - "RUSTFLAGS": "-Cinstrument-coverage", - "LLVM_PROFILE_FILE": "./target/cargo-test-%p-%m.profraw" - } - ) - - if res.returncode != 0: return res.returncode - - print("Generating coverage report") - - # Generate the coverage report - def cov(t: str) -> list[str]: - out = [ - "grcov", ".", - "--binary-path", "./target/debug/deps/", - "-s", ".", - "--branch", - "--ignore-not-existing", - "--ignore", "'../*'", - "--ignore", "'/*'" - ] - if t == "html": - out.extend(["-t", "html", "-o", "target/coverage/html"]) - elif t == "lcov": - out.extend(["-t", "lcov", "-o", "target/coverage/tests.lcov"]) - else: return "Invalid coverage type" - return out - - - # Generate the coverage report - res = subprocess.run( - cov("html"), - cwd = cd - ) - -def tarpaulin_test(cd: str, args: list[str]) -> int | str | None: - import subprocess - - # Check if tarpaulin is installed - def is_tarpaulin_installed() -> bool: - res = subprocess.run(["cargo", "tarpaulin", "--version"], capture_output=True) - return res.returncode == 0 - - # Install tarpaulin - def install_tarpaulin() -> int | None: - res = subprocess.run(["cargo", "binstall", "--no-confirm", "cargo-tarpaulin"]) - if res.returncode != 0: return res.returncode - - # Check if tarpaulin is installed and install it if it isn't - if not is_tarpaulin_installed(): - res = install_tarpaulin() - if res != None: return res - - # Run tarpaulin - cmd = ["cargo", "tarpaulin"] - cmd.extend(args) - res = subprocess.run(cmd, cwd=cd) - if res.returncode != 0: return res.returncode diff --git a/server/Cargo.toml b/server/Cargo.toml deleted file mode 100644 index f4f72bf..0000000 --- a/server/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -[package] -name = "arc-robot-server" -description = "ARC Robot Server" -repository.workspace = true -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true -build = "comptime.rs" - -[lib] -name = "arc_rs" -path = "lib.rs" - -[[bin]] -name = "arc-robot-server" -path = "main.rs" - -[dependencies.robot] -package = "arc-robot" -path = "../robot" - -# [dependencies.pyruntime] -# package = "arc-robot-python-runtime" -# path = "./runtime" - -# [dependencies.pylib] -# package = "arc-pylib" -# path = "../../arc" -# -# [dependencies.pyo3] -# version = "0.20.0" -# features = ["extension-module"] - -[dependencies.rocket] -version = "0.5" -features = [] - -[dependencies.log] -version = "0.4" diff --git a/server/comptime.rs b/server/comptime.rs deleted file mode 100644 index 545d1db..0000000 --- a/server/comptime.rs +++ /dev/null @@ -1,7 +0,0 @@ -use std::process::Command; - -fn main() { - let output = Command::new("git").args(&["rev-parse", "HEAD"]).output().unwrap(); - let git_hash = String::from_utf8(output.stdout).unwrap(); - println!("cargo:rustc-env=GIT_HASH={}", git_hash); -} \ No newline at end of file diff --git a/server/html/.gitignore b/server/html/.gitignore deleted file mode 100644 index e66d9fc..0000000 --- a/server/html/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Duplicates that I have here for the sake of simplicity -/*.ico -/*.png diff --git a/server/html/SourceCodePro-Bold.ttf b/server/html/SourceCodePro-Bold.ttf deleted file mode 100644 index 4653b76c80383cbce2452ddbdab318ab3fdab83c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120316 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"; -/// let html = HTML.handlebars("title", "Hello, World!"); -/// assert_eq!(html, "

Hello, World!

"); -/// ``` -pub trait HtmlHandlebarsInjector { - /// Replaces `{{__KEY__}}` with the value of `key`. - fn handlebars, V: AsRef>(self, key: K, value: V) -> Output; -} - -impl HtmlHandlebarsInjector for &str { - fn handlebars, V: AsRef>(self, key: K, value: V) -> String { - self.replace(&format!("{{{{__{}__}}}}", key.as_ref().to_uppercase()), value.as_ref()) - } -} - -impl HtmlHandlebarsInjector for String { - fn handlebars, V: AsRef>(self, key: K, value: V) -> String { - self.replace(&format!("{{{{__{}__}}}}", key.as_ref().to_uppercase()), value.as_ref()) - } -} - -/// `style.css` file. -#[get("/style.css")] -pub fn style() -> crate::html::Response<&'static str> { - res!(@CSS #200 include_str!("./style.css")) -} - -/// `SourceCodePro-Bold.ttf` file. -#[get("/SourceCodePro-Bold.ttf")] -pub fn font() -> crate::html::Response<&'static [u8]> { - res!(@TTF #200 include_bytes!("./SourceCodePro-Bold.ttf")) -} - -/// `favicon.ico` file. -#[get("/favicon.ico?")] -pub fn favicon(s: Option) -> crate::html::Response<&'static [u8]> { - let s256 = include_bytes!("../../docs/logo256.ico"); - let s192 = include_bytes!("../../docs/logo192.ico"); - let s64 = include_bytes!("../../docs/logo64.ico"); - res!(@Icon #200 match s { - Some(192) => s192, - Some(64) => s64, - _ => s256, - }) -} - -/// `logo_white_a.png` file. -#[get("/logo_white_a.png")] -pub fn logo_white_a() -> crate::html::Response<&'static [u8]> { - res!(@PNG #200 include_bytes!("../../docs/logo_white_a.png")) -} diff --git a/server/html/code/index.html b/server/html/code/index.html deleted file mode 100644 index 8ad9869..0000000 --- a/server/html/code/index.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - ARC - - -
- -
- - -
- -
-
-
{{__DEBUG__}}
- - diff --git a/server/html/error.html b/server/html/error.html deleted file mode 100644 index 09a39f3..0000000 --- a/server/html/error.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - ARC: Error - - -

{{__MESSAGE__}}: {{__ERROR__}}

-
{{__DEBUG__}}
- - \ No newline at end of file diff --git a/server/html/error.rs b/server/html/error.rs deleted file mode 100644 index 9c13289..0000000 --- a/server/html/error.rs +++ /dev/null @@ -1,83 +0,0 @@ -use crate::prelude::*; - -/// The result type used by this crate. -pub type Result = core::result::Result; - -/// An enum of all possible errors that can occur in this crate. -#[non_exhaustive] -pub enum Error { - /// An IO error occurred. - Io(std::io::Error), - /// A UTF-8 parsing error occurred. - Utf8(std::string::FromUtf8Error), - /// An error occurred that isn't covered by the other variants. - Other(Box) -} - -impl From for Error { - fn from(e: std::io::Error) -> Self { - Self::Io(e) - } -} - -impl From for Error { - fn from(e: std::string::FromUtf8Error) -> Self { - Self::Utf8(e) - } -} - -impl From> for Error { - fn from(e: Box) -> Self { - Self::Other(e) - } -} - -impl<'a> From<&'a str> for Error { - fn from(e: &'a str) -> Self { - Self::Other(Box::new(e.to_string())) - } -} - -impl From for Error { - fn from(e: String) -> Self { - Self::Other(Box::new(e)) - } -} - -impl core::fmt::Debug for Error { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::Io(e) => write!(f, "Io({:?})", e), - Self::Utf8(e) => write!(f, "Utf8({:?})", e), - Self::Other(e) => write!(f, "Other({:?})", e.to_string()), - } - } -} - -impl core::fmt::Display for Error { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::Other(e) => write!(f, "{}", e.to_string()), - other => write!(f, "{}", other), - } - } -} - -impl std::error::Error for Error {} - -/// The HTML for the error page. -pub const ERROR_HTML: &'static str = include_str!("./error.html"); - -impl<'r, 'o: 'r> rocket::response::Responder<'r, 'o> for Error { - fn respond_to(self, request: &'r rocket::Request<'_>) -> rocket::response::Result<'o> { - let error = format!("{}", self); - let html = ERROR_HTML - .handlebars("message", "An Internal Server Error Occurred") - .handlebars("error", &error) - .handlebars("debug", &super::SERVER); - rocket::Response::build_from(html.respond_to(request)?) - .header(rocket::http::ContentType::HTML) - .status(rocket::http::Status::InternalServerError) - .ok() - } -} diff --git a/server/html/index.html b/server/html/index.html deleted file mode 100644 index 8c2bf54..0000000 --- a/server/html/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - ARC - - -
- -

ARC LogoRC: - Advanced - Robot - Controller -

- - ARC is a feature complete framework for writing robot code.
- It is designed to be easy to use, and easy to understand.
- It is also designed to be modular, so that you can use only the parts you need.
- ARC is also designed to be easy to extend, - so that you can add your own functionality to it. -
-
{{__DEBUG__}}
- - diff --git a/server/html/macros.rs b/server/html/macros.rs deleted file mode 100644 index 1609c57..0000000 --- a/server/html/macros.rs +++ /dev/null @@ -1,177 +0,0 @@ -/// A macro to create a new error. -/// -/// This macro is used to create a new error and return it from a function. -/// -/// # Example -/// -/// ```rust -/// -#[macro_export] -macro_rules! err { - ($($args:tt)*) => {{ - $crate::__internals::log::error!($($args)*); - return Err(format!($($args)*).into()); - }}; -} - -pub use err; - -#[macro_export] -macro_rules! res { - (@$content_type:expr; #$code:expr; $body:expr) => ($crate::res!(! - $content_type; $code; $body - )); - (@$content_type:expr; #$code:literal $body:expr) => ($crate::res!(! - $content_type; $crate::html::macros::get_status($code); $body - )); - (@$content_type:expr; #$code:ident $body:expr) => ($crate::res!(! - $content_type; $crate::html::macros::Status::$code; $body - )); - - (@$content_type:ident #$code:expr; $body:expr) => ($crate::res!(! - $crate::html::macros::ContentType::$content_type; - $code; $body - )); - (@$content_type:ident #$code:literal $body:expr) => ($crate::res!(! - $crate::html::macros::ContentType::$content_type; - $crate::html::macros::get_status($code); $body - )); - (@$content_type:ident #$code:ident $body:expr) => ($crate::res!(! - $crate::html::macros::ContentType::$content_type; - $crate::html::macros::Status::$code; $body - )); - - - (#$code:expr; @$content_type:expr; $body:expr) => ($crate::res!(@@ - $content_type; $code; $body - )); - (#$code:literal @$content_type:expr; $body:expr) => ($crate::res!(@@ - $content_type; $crate::html::macros::get_status($code); $body - )); - (#$code:ident @$content_type:expr; $body:expr) => ($crate::res!(! - $content_type; $crate::html::macros::Status::$code; $body - )); - - (#$code:expr; @$content_type:ident $body:expr) => ($crate::res!(! - $crate::html::macros::ContentType::$content_type; $code; $body - )); - (#$code:literal @$content_type:ident $body:expr) => ($crate::res!(! - $crate::html::macros::ContentType::$content_type; - $crate::html::macros::get_status($code); $body - )); - (#$code:ident @$content_type:ident $body:expr) => ($crate::res!(! - $crate::html::macros::ContentType::$content_type; - $crate::html::macros::Status::$code; $body - )); - - (#$code:expr; $body:expr) => ($crate::res!(! - $crate::html::macros::ContentType::Plain; $code; $body - )); - (#$code:literal $body:expr) => ($crate::res!(! - $crate::html::macros::ContentType::Plain; - $crate::html::macros::get_status($code); $body - )); - (#$code:ident $body:expr) => ($crate::res!(! - $crate::html::macros::ContentType::Plain; - $crate::html::macros::Status::$code; $body - )); - - - (@$content_type:ident $body:expr) => ($crate::res!(! - $crate::html::macros::ContentType::$content_type; - $crate::html::macros::Status::Ok; $body - )); - (@$content_type:expr; $body:expr) => ($crate::res!(! - $content_type; $crate::html::macros::Status::Ok; $body - )); - - - ($body:expr) => ($crate::res!(! - $crate::html::macros::ContentType::Plain; - $crate::html::macros::Status::Ok; - $body - )); - (! $content_type: expr; $code: expr; $body: expr ) => ( - ($content_type, ($code, $body)) - ) -} - -pub use res; - -pub use rocket::http::ContentType; -pub use rocket::http::Status; -pub const fn get_status(code: u16) -> Status { - match code { - 100 => Status::Continue, - 101 => Status::SwitchingProtocols, - 102 => Status::Processing, - // 103 => Status::EarlyHints, - - 200 => Status::Ok, - 201 => Status::Created, - 202 => Status::Accepted, - 203 => Status::NonAuthoritativeInformation, - 204 => Status::NoContent, - 205 => Status::ResetContent, - 206 => Status::PartialContent, - 207 => Status::MultiStatus, - 208 => Status::AlreadyReported, - 226 => Status::ImUsed, - - 300 => Status::MultipleChoices, - 301 => Status::MovedPermanently, - 302 => Status::Found, - 303 => Status::SeeOther, - 304 => Status::NotModified, - 305 => Status::UseProxy, - // 306 => Status::SwitchProxy, - 307 => Status::TemporaryRedirect, - 308 => Status::PermanentRedirect, - - 400 => Status::BadRequest, - 401 => Status::Unauthorized, - 402 => Status::PaymentRequired, - 403 => Status::Forbidden, - 404 => Status::NotFound, - 405 => Status::MethodNotAllowed, - 406 => Status::NotAcceptable, - 407 => Status::ProxyAuthenticationRequired, - 408 => Status::RequestTimeout, - 409 => Status::Conflict, - 410 => Status::Gone, - 411 => Status::LengthRequired, - 412 => Status::PreconditionFailed, - 413 => Status::PayloadTooLarge, - 414 => Status::UriTooLong, - 415 => Status::UnsupportedMediaType, - 416 => Status::RangeNotSatisfiable, - 417 => Status::ExpectationFailed, - 418 => Status::ImATeapot, - 421 => Status::MisdirectedRequest, - 422 => Status::UnprocessableEntity, - 423 => Status::Locked, - 424 => Status::FailedDependency, - // 425 => Status::TooEarly, - 426 => Status::UpgradeRequired, - 428 => Status::PreconditionRequired, - 429 => Status::TooManyRequests, - 431 => Status::RequestHeaderFieldsTooLarge, - 451 => Status::UnavailableForLegalReasons, - - 500 => Status::InternalServerError, - 501 => Status::NotImplemented, - 502 => Status::BadGateway, - 503 => Status::ServiceUnavailable, - 504 => Status::GatewayTimeout, - 505 => Status::HttpVersionNotSupported, - 506 => Status::VariantAlsoNegotiates, - 507 => Status::InsufficientStorage, - 508 => Status::LoopDetected, - 510 => Status::NotExtended, - 511 => Status::NetworkAuthenticationRequired, - - _ => Status::new(code) - } -} - -pub use ::log; diff --git a/server/html/mod.rs b/server/html/mod.rs deleted file mode 100644 index f60e6ec..0000000 --- a/server/html/mod.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::prelude::*; - -#[doc(hidden)] -pub mod assets; -#[doc(hidden)] -pub mod macros; -#[doc(hidden)] -pub mod error; - -#[cfg(debug_assertions)] -const __SERVER: &str = concat!( - "ARC v", env!("CARGO_PKG_VERSION"), - "-", env!("GIT_HASH") -); -#[cfg(not(debug_assertions))] -const __SERVER: &str = concat!( - "ARC v", env!("CARGO_PKG_VERSION") -); - -/// Version of the software. -/// -/// In debug builds, this is the version number and git hash. -/// In release builds, this is just the version number. -pub const SERVER: &str = __SERVER; - -pub fn make_server_identifier() -> rocket::config::Ident { - rocket::config::Ident::try_new(SERVER) - .expect("Failed to create rocket ident") -} - -pub type Response = (rocket::http::ContentType, (rocket::http::Status, T)); - -pub type Result = error::Result; - -#[doc(hidden)] -const SERVER_ERR: &str = concat!("The server encountered an internal", -" error and was unable to complete your request."); - -#[rocket::catch(default)] -pub fn error_catcher(status: rocket::http::Status, _req: &rocket::Request) -> Response { - // If it is a server error (500+) - if (status.code - 400) >= 100 { - return crate::res!(@HTML #500 error::ERROR_HTML - .handlebars("message", "An Internal Server Error Occurred") - .handlebars("error", SERVER_ERR) - .handlebars("debug", SERVER) - ); - } - // Otherwise client error - let error = format!("{}", status); - crate::res!(@HTML #status; error::ERROR_HTML - .handlebars("message", &error) - .handlebars("error", &error) - .handlebars("debug", SERVER) - ) -} diff --git a/server/html/style.css b/server/html/style.css deleted file mode 100644 index 7afec65..0000000 --- a/server/html/style.css +++ /dev/null @@ -1,66 +0,0 @@ -:root { - --footer-height: 30px; - --scrollbar-width: 20px; - - --c-complete-black: #000000; - --c-black: #06070E; - --c-gray: #2d2d2d; - --c-dark-white: #cccccc; - --c-blue: #00A7E1; - --c-green: #84DD63; - --c-red: #DF2935; - --c-yellow: #FFA400; - --c-transparent: #0000; -} - -@font-face { - font-family: 'SourceCodePro-Bold'; - src: url('./SourceCodePro-Bold.ttf') format('truetype'); - font-weight: bold; - font-style: normal; -} - -::-webkit-scrollbar { - width: var(--scrollbar-width); -} - -::-webkit-scrollbar-track { - background: var(--c-transparent) -} - -::-webkit-scrollbar-thumb { - background: var(--c-dark-white) -} - -body { - font-family: 'SourceCodePro-Bold'; - background-color: var(--c-gray); - color: var(--c-dark-white); - position: relative; - top: 0px; - left: 0px; - min-height: calc(99vh - var(--footer-height)); -} - -footer { - position: absolute; - bottom: 0px; - width: 100%; - align-self: center; - align-items: center; - text-align: center; -} - -h1 { - font-size: 2.5em; -} - -main { - position: relative; - padding-top: 0px; - padding-left: 0px; - padding-right: 0px; - padding-bottom: var(--footer-height); - width: 50%; - left: 25%; -} diff --git a/server/lib.rs b/server/lib.rs deleted file mode 100644 index 32944d9..0000000 --- a/server/lib.rs +++ /dev/null @@ -1,32 +0,0 @@ -pub mod html; - -#[macro_export] -macro_rules! inc { () => (use $crate::prelude::*; use $crate::*; ) } - -pub mod prelude { - pub use crate::html::assets::HtmlHandlebarsInjector; - pub use crate::html::macros::{err, res}; - pub use ::rocket::{ - async_main, async_run, async_test, async_trait, - build, - catch, catchers, - delete, - export, - get, - head, - launch, - main, - options, - patch, post, put, - routes, route, - uri, - }; - #[macro_export(local_inner_macros)] - macro_rules! include_hbs { - ($file:expr $(,)?) => ( - ::core::include_str!($file) - .handlebars("debug", $crate::html::SERVER) - ) - } - pub use include_hbs; -} diff --git a/server/main.rs b/server/main.rs deleted file mode 100644 index c7dc86f..0000000 --- a/server/main.rs +++ /dev/null @@ -1,69 +0,0 @@ -use arc_rs::html::*; -arc_rs::inc!(); - -#[cfg(debug_assertions)] -const SAVE_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/code"); -#[cfg(not(debug_assertions))] -const SAVE_DIR: &str = "/arc/code"; - -#[cfg(debug_assertions)] -const TEMP_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tmp"); -#[cfg(not(debug_assertions))] -const TEMP_DIR: &str = "/arc/tmp"; - -#[get("/")] -fn index() -> Response { - res!(@HTML #200 include_hbs!("./html/index.html")) -} - -#[get("/")] -fn code() -> Response { - res!(@HTML #200 include_hbs!("./html/code/index.html")) -} - -#[post("/upload?", format = "plain", data = "")] -async fn upload<'a>(name: &'a str, input: rocket::Data<'_>) -> Result { - use rocket::data::ToByteUnit; - let location = format!("{SAVE_DIR}/{}", name); - let file = match rocket::tokio::fs::File::create(location).await { - Err(e) => return Ok(res!(@JSON #500 format!( - "{{\"ok\":false,\"msg\":\"Failed to create file: {e}\"}}" - ))), - Ok(file) => file, - }; - if let Err(e) = input.open(1.megabytes()).stream_to(file).await { - return Ok(res!(@JSON #500 format!( - "{{\"ok\":false,\"msg\":\"Failed to write to file: {e}\"}}" - ))); - } - Ok(res!("{\"ok\":true}".into())) -} - -fn main() { - // let mut python_runtime = PyRuntime::init(); - - // python_runtime.start("auto").unwrap(); -} - -// #[rocket::main] -// async fn main() { -// let python_runtime = PyRuntime::init(); -// -// let config = rocket::Config { -// temp_dir: TEMP_DIR.into(), -// ident: make_server_identifier(), -// ..Default::default() -// }; -// -// let rocket = rocket::custom(&config) -// .mount("/", routes![index]) -// .mount("/", routes![assets::style, assets::favicon, assets::font, assets::logo_white_a]) -// .mount("/code", routes![code, upload]) -// .register("/", catchers![error_catcher]) -// .ignite() -// .await -// .expect("Failed to start server"); -// rocket.launch() -// .await -// .expect("Failed to launch server"); -// } \ No newline at end of file diff --git a/uploader/Cargo.toml b/uploader/Cargo.toml deleted file mode 100644 index bb70bc3..0000000 --- a/uploader/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "arc-uploader" -description = "ARC Robot Code Uploader" -repository.workspace = true -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true - -[[bin]] -name = "arc-uploader" -path = "main.rs" diff --git a/uploader/main.rs b/uploader/main.rs deleted file mode 100644 index 281eb0e..0000000 --- a/uploader/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Code Uploader") -} From dbca55bd1dbaf575ddebc8d5621b9d090b5ac39a Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sat, 30 Dec 2023 10:19:24 -0800 Subject: [PATCH 91/93] License update --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 17b03cf..eda5deb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 2-Clause License -Copyright (c) 2023 AtomicGamer9523 +Copyright (c) 2023 AtomicGamer9523 and members of the Draniki Team Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From 7b4a98b06ec74dd908f7c5f1195abf571bd7c1fa Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sat, 30 Dec 2023 10:19:33 -0800 Subject: [PATCH 92/93] More changes, bindings are WIP --- arc/Cargo.toml | 14 +- arc/__init__.rs | 83 ++----- arc/hardware/dcmotor.rs | 0 arc/hardware/gamepad.rs | 98 ++++---- arc/hardware/telemetry.rs | 0 arc/lib.rs | 34 +-- arc/macros.rs | 12 + examples/auto.py | 26 +++ examples/mecanum_basic_teleop.py | 2 +- examples/tank_drive_teleop.py | 2 +- robot/Cargo.toml | 16 +- robot/core/Cargo.toml | 10 + robot/core/config.rs | 38 ++- robot/core/hardware.rs | 7 +- robot/core/internals/impls.rs | 22 ++ robot/core/internals/impls/dcmotor.rs | 2 +- robot/core/internals/impls/gamepad.rs | 4 +- robot/core/internals/mod.rs | 10 + robot/core/io.rs | 30 --- robot/core/lib.rs | 86 ++++--- robot/core/op.rs | 320 ++++++++++++++++++++++++++ robot/core/tests/rust_only_robot.rs | 5 + robot/core/threadsafe.rs | 35 ++- robot/lib.rs | 13 +- robot/python/Cargo.toml | 3 + robot/python/lib.rs | 150 +++++------- 26 files changed, 707 insertions(+), 315 deletions(-) create mode 100644 arc/hardware/dcmotor.rs create mode 100644 arc/hardware/telemetry.rs create mode 100644 examples/auto.py delete mode 100644 robot/core/io.rs create mode 100644 robot/core/op.rs create mode 100644 robot/core/tests/rust_only_robot.rs diff --git a/arc/Cargo.toml b/arc/Cargo.toml index 5a246ca..3a61182 100644 --- a/arc/Cargo.toml +++ b/arc/Cargo.toml @@ -14,19 +14,23 @@ crate-type = ["cdylib", "rlib"] [dependencies.dranikcore] package = "dranik-core" path = "../robot/core" +features = [ + "reveal_modules", # More items + "internals", # Internal modules +] [dependencies.libtrig] git = "https://github.com/DranikiRobotics/librobomath" package = "libtrig" +optional = true [dependencies.pyo3] -#!!! Important - DO NOT ENABLE extension-module FEATURE HERE!!! -version = "0.20.0" +version = "0.20" features = [ + "extension-module", # for standalone extension module "abi3-py311" # for python 3.11 ] [features] -# instead extension-module feature for pyo3 is enabled conditionally -# when we want to build a standalone extension module to test our plugins without "main" program -extension-module = ["pyo3/extension-module"] +dranik-only-builtins = ["dranikcore/only_builtins"] +math = ["dep:libtrig"] diff --git a/arc/__init__.rs b/arc/__init__.rs index 2a2d6c1..9ea5f53 100644 --- a/arc/__init__.rs +++ b/arc/__init__.rs @@ -5,7 +5,7 @@ //! //! [`Op`]: struct.Op.html -use crate::threadsafe::{self, ThreadSafe}; +use dranikcore::RuntimeOp; use pyo3::prelude::*; /// Hardware submodule @@ -16,51 +16,8 @@ pub mod hardware; #[path = "math/__init__.rs"] pub mod math; -/// The struct that actually contains the necessary data for the op mode -/// to run. -/// -/// This struct should only be used for mutating the data outside of the -/// op mode thread. For reading the up to date data, use the `Op` struct. -#[derive(Debug)] -pub struct OpHolder { - running: threadsafe::ThreadSafeBool, - start_time: std::time::Instant, - io: dranikcore::io::IO, -} - -impl OpHolder { - /// Returns whether the op mode is running - /// - /// This call aquires a lock on the data - pub fn running(&self) -> bool { - match self.running.get() { - Ok(r) => **r, - Err(_) => false, - } - } - /// Returns a reference to the gamepad - /// - /// This call aquires a lock on the data - pub fn gamepad(&self) -> &hardware::gamepad::Gamepad { - &self.io.gamepad - } - /// Stops the op mode - /// - /// DO NOT CALL THIS FROM THE PYTHON THREAD - pub fn stop(&self) -> core::result::Result<(), &'static str> { - self.running.get_mut()?.set(false); - Ok(()) - } - /// Returns the running time of the op mode - /// - /// This call does not aquire a lock on the data, - /// nor does it need to. - pub fn running_time(&self) -> core::time::Duration { - std::time::Instant::now() - self.start_time - } -} - -threadsafe::thread_safe!(OpHolder); +#[cfg(feature = "dranik-only-builtins")] +type OpImpl = RuntimeOp; /// The struct that is used to access the data in the op mode /// @@ -98,17 +55,27 @@ threadsafe::thread_safe!(OpHolder); /// ``` #[pyclass] #[derive(Default, Debug, Clone)] -pub struct Op(ThreadSafe); - -impl From for Op { - fn from(io: dranikcore::io::IO) -> Self { - let gamepad = hardware::gamepad::Gamepad::new(io.gamepad); - let holder = OpHolder { - running: threadsafe::ThreadSafeBool::new(true), - gamepad, - start_time: std::time::Instant::now(), - }; - Self(ThreadSafe::new(holder)) +pub struct Op(OpImpl); + +impl From for Op { + #[inline(always)] + #[cfg(feature = "dranik-only-builtins")] + fn from(op: OpImpl) -> Self { + Self(op) + } +} + +impl From for OpImpl { + #[inline(always)] + #[cfg(feature = "dranik-only-builtins")] + fn from(op: Op) -> Self { + op.0 + } +} + +impl pyo3::IntoPy> for Op { + fn into_py(self, py: Python<'_>) -> pyo3::Py { + (self, ).into_py(py) } } @@ -119,7 +86,7 @@ impl Op { /// /// [`Gamepad`]: _hardware/gamepad/struct.Gamepad.html pub fn get_gamepad(&self) -> core::result::Result { - self.0.get().map(|g| g.gamepad().clone()) + self.0.get().map(|g| g.get_gamepad().into()) } /// Returns whether the op mode is running /// diff --git a/arc/hardware/dcmotor.rs b/arc/hardware/dcmotor.rs new file mode 100644 index 0000000..e69de29 diff --git a/arc/hardware/gamepad.rs b/arc/hardware/gamepad.rs index a20dda7..b77f9ff 100644 --- a/arc/hardware/gamepad.rs +++ b/arc/hardware/gamepad.rs @@ -2,22 +2,10 @@ //! //! Python identifier: `arc.hardware.gamepad` -use crate::threadsafe::ThreadSafe; -use dranikcore::gamepad as gp; +use dranikcore::{gamepad as gp, threadsafe::ThreadSafe}; +use gp::Gamepad as _; use pyo3::prelude::*; -/// The struct that actually contains the necessary data for the gamepad -/// to function. -/// -/// This struct should only be used for mutating the data outside of the -/// gamepad thread. For reading the up to date data, use the `Gamepad` struct. -#[derive(Debug)] -pub struct GamepadHolder { - gamepad: Box, -} - -crate::threadsafe::thread_safe!(GamepadHolder); - /// A struct that holds the state of a gamepad stick #[pyclass] #[derive(Debug, Clone)] @@ -25,22 +13,29 @@ pub struct GamepadStick(gp::GamepadStick); impl GamepadStick { /// Returns the x value of the stick. + #[inline(always)] pub fn get_x(&self) -> f64 { self.0.x } /// Returns the y value of the stick. + #[inline(always)] pub fn get_y(&self) -> f64 { self.0.y } /// Returns whether or not the stick is pressed. + #[inline(always)] pub fn get_pressed(&self) -> bool { self.0.pressed } /// Converts the stick into an angle. + #[inline] + #[must_use = "This returns a new angle"] pub fn into_angle(&self) -> libtrig::Angle2D { libtrig::Angle2D::from((self.get_x(), self.get_y())) } /// Converts the stick into a vector. + #[inline] + #[must_use = "This returns a new vector"] pub fn into_vector(&self) -> libtrig::Vec2D { libtrig::Vec2D::from((self.get_x(), self.get_y())) } @@ -83,20 +78,25 @@ impl From for GamepadStick { #[pymethods] impl GamepadStick { #[getter] + #[inline(always)] fn x(&self) -> PyResult { Ok(self.get_x()) } #[getter] + #[inline(always)] fn y(&self) -> PyResult { Ok(self.get_y()) } #[getter] + #[inline(always)] fn pressed(&self) -> PyResult { Ok(self.get_pressed()) } + #[inline(always)] fn as_angle(&self) -> PyResult { Ok(self.into_angle().into()) } + #[inline(always)] fn as_vec2d(&self) -> PyResult { Ok(self.into_vector().into()) } @@ -139,49 +139,34 @@ impl GamepadDpad { } } +#[cfg(feature = "dranik-only-builtins")] +type GImpl = ThreadSafe; + /// The struct that is used to access the gamepad data from python. /// /// This struct is thread safe, and can be used to read the gamepad data /// from any thread. /// -/// This struct should not be used to modify the gamepad data. For that, -/// use the `GamepadHolder` struct. +/// This struct should not be used to modify the gamepad data. #[pyclass] #[derive(Debug, Clone)] -pub struct Gamepad(ThreadSafe); +pub struct Gamepad(GImpl); -impl crate::PyWrappedComponent for Gamepad { - type Holder = GamepadHolder; - fn new(gamepad: G) -> ThreadSafe { - ThreadSafe::new(GamepadHolder { - gamepad: Box::new(gamepad), - }) - } - fn wrap(gamepad: &ThreadSafe) -> Self { - Self(gamepad.clone()) +impl From for Gamepad { + #[inline(always)] + #[cfg(feature = "dranik-only-builtins")] + fn from(gamepad: GImpl) -> Self { + Self(gamepad) } } impl Gamepad { - /// This creates a new `ThreadSafe` struct. NOT a `Gamepad` struct. - /// - /// You then need to wrap it in a `Gamepad` struct using the [`Gamepad::wrap()`] method. - pub fn new(gamepad: G) -> ThreadSafe { - ThreadSafe::new(GamepadHolder { - gamepad: Box::new(gamepad), - }) - } - /// Wraps a `ThreadSafe` in a `Gamepad` struct. - pub fn wrap(gamepad: &ThreadSafe) -> Self { - Self(gamepad.clone()) - } /// Returns the state of the dpad /// /// Includes up, down, left, and right pub fn get_dpad(&self) -> core::result::Result { self.0 .get()? - .gamepad .dpad() .map(|d| GamepadDpad(d)) .map_err(|e| e.into()) @@ -192,7 +177,6 @@ impl Gamepad { pub fn get_left_stick(&self) -> core::result::Result { self.0 .get()? - .gamepad .left_stick() .map(|d| GamepadStick(d)) .map_err(|e| e.into()) @@ -203,106 +187,118 @@ impl Gamepad { pub fn get_right_stick(&self) -> core::result::Result { self.0 .get()? - .gamepad .right_stick() .map(|d| GamepadStick(d)) .map_err(|e| e.into()) } /// Returns the state of the left trigger pub fn get_left_trigger(&self) -> core::result::Result { - self.0.get()?.gamepad.left_trigger().map_err(|e| e.into()) + self.0.get()?.left_trigger().map_err(|e| e.into()) } /// Returns the state of the right trigger pub fn get_right_trigger(&self) -> core::result::Result { - self.0.get()?.gamepad.right_trigger().map_err(|e| e.into()) + self.0.get()?.right_trigger().map_err(|e| e.into()) } /// Is the 'x' button pressed? pub fn get_x(&self) -> core::result::Result { - self.0.get()?.gamepad.x().map_err(|e| e.into()) + self.0.get()?.x().map_err(|e| e.into()) } /// Is the 'y' button pressed? pub fn get_y(&self) -> core::result::Result { - self.0.get()?.gamepad.y().map_err(|e| e.into()) + self.0.get()?.y().map_err(|e| e.into()) } /// Is the 'a' button pressed? pub fn get_a(&self) -> core::result::Result { - self.0.get()?.gamepad.a().map_err(|e| e.into()) + self.0.get()?.a().map_err(|e| e.into()) } /// Is the 'b' button pressed? pub fn get_b(&self) -> core::result::Result { - self.0.get()?.gamepad.b().map_err(|e| e.into()) + self.0.get()?.b().map_err(|e| e.into()) } /// Is the left bumper pressed? pub fn get_left_bumper(&self) -> core::result::Result { - self.0.get()?.gamepad.left_bumper().map_err(|e| e.into()) + self.0.get()?.left_bumper().map_err(|e| e.into()) } /// Is the right bumper pressed? pub fn get_right_bumper(&self) -> core::result::Result { - self.0.get()?.gamepad.right_bumper().map_err(|e| e.into()) + self.0.get()?.right_bumper().map_err(|e| e.into()) } /// A non-standard 'back' button pub fn get_back(&self) -> core::result::Result { - self.0.get()?.gamepad.back().map_err(|e| e.into()) + self.0.get()?.back().map_err(|e| e.into()) } /// A non-standard 'start' button pub fn get_start(&self) -> core::result::Result { - self.0.get()?.gamepad.start().map_err(|e| e.into()) + self.0.get()?.start().map_err(|e| e.into()) } } #[pymethods] impl Gamepad { #[getter] + #[inline(always)] fn dpad(&self) -> PyResult { self.get_dpad().map_err(crate::make_err) } #[getter] + #[inline(always)] fn left_stick(&self) -> PyResult { self.get_left_stick().map_err(crate::make_err) } #[getter] + #[inline(always)] fn right_stick(&self) -> PyResult { self.get_right_stick().map_err(crate::make_err) } #[getter] + #[inline(always)] fn left_trigger(&self) -> PyResult { self.get_left_trigger().map_err(crate::make_err) } #[getter] + #[inline(always)] fn right_trigger(&self) -> PyResult { self.get_right_trigger().map_err(crate::make_err) } #[getter] + #[inline(always)] fn x(&self) -> PyResult { self.get_x().map_err(crate::make_err) } #[getter] + #[inline(always)] fn y(&self) -> PyResult { self.get_y().map_err(crate::make_err) } #[getter] + #[inline(always)] fn a(&self) -> PyResult { self.get_a().map_err(crate::make_err) } #[getter] + #[inline(always)] fn b(&self) -> PyResult { self.get_b().map_err(crate::make_err) } #[getter] + #[inline(always)] fn left_bumper(&self) -> PyResult { self.get_left_bumper().map_err(crate::make_err) } #[getter] + #[inline(always)] fn right_bumper(&self) -> PyResult { self.get_right_bumper().map_err(crate::make_err) } #[getter] + #[inline(always)] fn back(&self) -> PyResult { self.get_back().map_err(crate::make_err) } #[getter] + #[inline(always)] fn start(&self) -> PyResult { self.get_start().map_err(crate::make_err) } diff --git a/arc/hardware/telemetry.rs b/arc/hardware/telemetry.rs new file mode 100644 index 0000000..e69de29 diff --git a/arc/lib.rs b/arc/lib.rs index a3b18c1..ffbcee4 100644 --- a/arc/lib.rs +++ b/arc/lib.rs @@ -2,30 +2,16 @@ #![warn(missing_docs, unused, clippy::all, unsafe_code)] #![deny(missing_debug_implementations)] +#[cfg(any( + not(feature = "dranik-only-builtins"), + not(feature = "math") +))] +compile_error!("The `dranik-only-builtins` feature is required to use this crate, as well as the `math` feature."); + pub mod __init__; #[doc(hidden)] pub mod macros; -pub use threadsafe::{ThreadSafe, ThreadSafeError}; - -/// A trait for hardware components that can be used in the robot. -pub trait PyWrappedComponent { - /// The type that holds the hardware component. - /// - /// This type isn't required to be `Send` or `Sync`. - /// - /// The holder is what will be written to by the python thread. - type Holder; - /// Creates a new hardware component. - /// - /// This function should be called before the python main thread is started. - fn new(hardware: Input) -> crate::ThreadSafe; - /// Wraps the hardware component in a `ThreadSafe` type. - /// - /// The wrapper is what will be read from by the python thread. - fn wrap(hardware_component: &crate::ThreadSafe) -> Self; -} - /// Internal function to translate a static string into a PyIOError. #[doc(hidden)] fn make_err(e: &'static str) -> pyo3::PyErr { @@ -61,16 +47,16 @@ impl PyFunction { #[derive(Default, Debug, Clone, Copy)] pub struct __dranik_config; -impl dranikcore::config::RobotConfig for __dranik_config { +impl dranikcore::prelude::RobotConfig for __dranik_config { fn python_preload() { use crate::__init__::arc as __arc_pylib; pyo3::append_to_inittab!(__arc_pylib); } type Args = __init__::Op; fn build_python_main_function_args<'a>( - py: &pyo3::Python<'_>, - io: &dranikcore::io::IO + _py: &pyo3::Python<'_>, + op: &dranikcore::RuntimeOp ) -> (Self::Args, Option<&'a pyo3::types::PyDict>) { - (__init__::Op::from(io), None) + (__init__::Op::from(op.clone()), None) } } diff --git a/arc/macros.rs b/arc/macros.rs index 08cfa15..dd3e538 100644 --- a/arc/macros.rs +++ b/arc/macros.rs @@ -106,3 +106,15 @@ macro_rules! setup_wrapped_component { __setup_wrapped_component_internal::<_, _, $component>($value) }}; } + +#[macro_export(local_inner_macros)] +macro_rules! pyimpl { + ($strcut: ident { $($body: tt)* }) => ( + impl $strcut { + $crate::pyimpl!(@INNER $($body)*); + } + ); + (@INNER) => ( + + ) +} diff --git a/examples/auto.py b/examples/auto.py new file mode 100644 index 0000000..a1d6428 --- /dev/null +++ b/examples/auto.py @@ -0,0 +1,26 @@ +from arc.hardware import * +from arc import * + +# You are REQUIRED to have a main() function in your program. +# and you MUST NOT call it yourself. +@Teleop("Tank Drive Example", config = "tank_drive") +def main(op: Op): + op.log("Starting...") + + # Create a tank drive with the left and right motors. + leftMotor = op.hardwareMap[DcMotor]("motor0") + rightMotor = op.hardwareMap[DcMotor]("motor1") + + # While the op is running... + while op.running: + # Get the left and right stick values. + l = op.gamepad.left_stick.y + r = op.gamepad.right_stick.y + op.debug("Left: ", l, "Right: ", r) + + # Drive the robot with the left and right sticks. + leftMotor.power(l) + rightMotor.power(r) + + op.log("Done!") + return OK \ No newline at end of file diff --git a/examples/mecanum_basic_teleop.py b/examples/mecanum_basic_teleop.py index 42825b5..54b47fe 100644 --- a/examples/mecanum_basic_teleop.py +++ b/examples/mecanum_basic_teleop.py @@ -15,7 +15,7 @@ def main(op: Op): br = op.hardwareMap[DcMotor]("motor3") drive = MechanumDrive(fl, fr, bl, br) - # While the opmode is running... + # While the op is running... while op.running: # Drive the robot using the gamepad. drive.moveUsingDefaultSheme(op.gamepad) diff --git a/examples/tank_drive_teleop.py b/examples/tank_drive_teleop.py index 5f9c156..a1d6428 100644 --- a/examples/tank_drive_teleop.py +++ b/examples/tank_drive_teleop.py @@ -11,7 +11,7 @@ def main(op: Op): leftMotor = op.hardwareMap[DcMotor]("motor0") rightMotor = op.hardwareMap[DcMotor]("motor1") - # While the opmode is running... + # While the op is running... while op.running: # Get the left and right stick values. l = op.gamepad.left_stick.y diff --git a/robot/Cargo.toml b/robot/Cargo.toml index a9581d0..3386e75 100644 --- a/robot/Cargo.toml +++ b/robot/Cargo.toml @@ -25,4 +25,18 @@ dranik-python = { path = "./python" } # Async runtime tokio = { version = "1.35", features = ["rt", "signal"] } -arc = { path = "../arc", package = "arc-pylib" } +[dependencies.arc] +path = "../arc" +package = "arc-pylib" +features = [ + "dranik-only-builtins", + "math" +] + +[features] +default = ["only-builtins"] + +only-builtins = [ + "dranik-core/only_builtins", + "dranik-python/dranik-only-builtins", +] diff --git a/robot/core/Cargo.toml b/robot/core/Cargo.toml index 77a3aeb..36e5a9b 100644 --- a/robot/core/Cargo.toml +++ b/robot/core/Cargo.toml @@ -25,5 +25,15 @@ version = "1.35" [dependencies.pyo3] version = "0.20.0" +[[test]] +name = "rust_only_robot" +path = "tests/rust_only_robot.rs" + [features] unstable = ["l2math/unstable", "libtrig/unstable"] + +only_builtins = [] +allow_external_impls = [] + +reveal_modules = [] +internals = [] diff --git a/robot/core/config.rs b/robot/core/config.rs index 77bb2c6..8161e13 100644 --- a/robot/core/config.rs +++ b/robot/core/config.rs @@ -10,16 +10,52 @@ use pyo3::prelude::*; use pyo3::types::{PyDict, PyTuple}; +use crate::prelude::*; +use crate::internals::impls; +use impls::HardwareMapImpl as BuiltInHardwareMapImpl; +use impls::TelemetryImpl as BuiltInTelemetryImpl; +use impls::GamepadImpl as BuiltInGamepadImpl; /// A trait for common functionality that can be used to configure the robot +#[cfg(not(feature = "only_builtins"))] +pub trait RobotConfig< + H = BuiltInHardwareMapImpl, + T = BuiltInTelemetryImpl, + G = BuiltInGamepadImpl +> where + H: HardwareMap, + T: Telemetry, + G: Gamepad +{ + /// This function is called before the python interpreter is initialized + /// + /// This is useful for loading rust libraries that will then be used by python. + /// In fact, this is exactly how ARC is loaded. + fn python_preload() {} + /// The type that will be passed to the python main function + type Args: IntoPy> + Default; + /// This function is called to build the arguments that will be passed to the python main function + fn build_python_main_function_args<'a>( + _py: &pyo3::Python<'_>, _op: &crate::RuntimeOp + ) -> (Self::Args, Option<&'a PyDict>) { + (Self::Args::default(), None) + } +} + +/// A trait for common functionality that can be used to configure the robot +#[cfg(feature = "only_builtins")] pub trait RobotConfig { /// This function is called before the python interpreter is initialized /// /// This is useful for loading rust libraries that will then be used by python. /// In fact, this is exactly how ARC is loaded. fn python_preload() {} + /// The type that will be passed to the python main function type Args: IntoPy> + Default; - fn build_python_main_function_args<'a>(_py: &pyo3::Python<'_>, _io: &crate::io::IO) -> (Self::Args, Option<&'a PyDict>) { + /// This function is called to build the arguments that will be passed to the python main function + fn build_python_main_function_args<'a>( + _py: &pyo3::Python<'_>, _op: &crate::RuntimeOp + ) -> (Self::Args, Option<&'a PyDict>) { (Self::Args::default(), None) } } diff --git a/robot/core/hardware.rs b/robot/core/hardware.rs index a64b15f..9cfa3f4 100644 --- a/robot/core/hardware.rs +++ b/robot/core/hardware.rs @@ -25,11 +25,14 @@ pub trait HardwareMap { } /// A trait that represents a hardware component -pub trait HardwareComponent: core::fmt::Debug { +pub trait HardwareComponent: core::fmt::Debug + Send { /// Returns the UUID of this component #[allow(non_snake_case)] fn getUUID(&self) -> HardwareUUID; /// Internal method used to load a component + #[inline] #[doc(hidden)] - fn __load_self(_: internals::HardwareComponentLoadMetadata) -> Result where Self: Sized; + fn __load_self(_: internals::HardwareComponentLoadMetadata) -> Result where Self: Sized { + Err(HardwareError::Other { message: "This component does not support loading" }) + } } diff --git a/robot/core/internals/impls.rs b/robot/core/internals/impls.rs index 97a19d6..7502d0c 100644 --- a/robot/core/internals/impls.rs +++ b/robot/core/internals/impls.rs @@ -2,16 +2,19 @@ use std::collections::HashMap; use super::HardwareComponentLoadMetadata; use crate::hardware as h; +use crate::prelude::*; mod dcmotor; mod gamepad; pub use dcmotor::DcMotorImpl; pub use gamepad::GamepadImpl; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum HardwareComponentType { DcMotor, } +#[derive(Default, Debug, Clone)] pub struct HardwareMapImpl { components: HashMap, } @@ -33,3 +36,22 @@ impl h::HardwareMap for HardwareMapImpl { Err(crate::HardwareError::DeviceNotFound) } } + +#[derive(Default, Debug, Clone)] +pub struct TelemetryImpl; + +impl TelemetryImpl { + pub fn new() -> Self { + Self {} + } +} + +impl Telemetry for TelemetryImpl { + fn debug(&self, message: T) { + todo!() + } + fn send(&self, message: T) { + todo!() + } +} + diff --git a/robot/core/internals/impls/dcmotor.rs b/robot/core/internals/impls/dcmotor.rs index 54f8293..115ed06 100644 --- a/robot/core/internals/impls/dcmotor.rs +++ b/robot/core/internals/impls/dcmotor.rs @@ -5,7 +5,7 @@ struct DcMotorConfig { } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct DcMotorImpl { } diff --git a/robot/core/internals/impls/gamepad.rs b/robot/core/internals/impls/gamepad.rs index b5af49b..38f807b 100644 --- a/robot/core/internals/impls/gamepad.rs +++ b/robot/core/internals/impls/gamepad.rs @@ -7,7 +7,7 @@ pub struct GamepadImpl { } impl GamepadImpl { - pub(crate) fn init() -> Self { + pub(crate) fn new() -> Self { Self { } @@ -32,7 +32,7 @@ impl h::HardwareComponent for GamepadImpl { } } -impl crate::Gamepad for GamepadImpl { +impl crate::prelude::Gamepad for GamepadImpl { fn dpad(&self) -> crate::Result { todo!() } diff --git a/robot/core/internals/mod.rs b/robot/core/internals/mod.rs index 0699793..3883e2f 100644 --- a/robot/core/internals/mod.rs +++ b/robot/core/internals/mod.rs @@ -9,3 +9,13 @@ pub(crate) mod impls; pub struct HardwareComponentLoadMetadata { pub uuid: HardwareUUID, } + +pub mod builtins { + use super::*; + + pub type BuiltInHardwareMapImpl = impls::HardwareMapImpl; + pub type BuiltInTelemetryImpl = impls::TelemetryImpl; + pub type BuiltInGamepadImpl = impls::GamepadImpl; + + pub type BuiltInDcMotorImpl = impls::DcMotorImpl; +} diff --git a/robot/core/io.rs b/robot/core/io.rs deleted file mode 100644 index eb276b6..0000000 --- a/robot/core/io.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::threadsafe::{ThreadSafe, GetResult, SafeHeld, StandardResult}; -use crate::*; - -#[derive(Debug)] -struct IOHolder { - gamepad: internals::impls::GamepadImpl, -} -impl IOHolder { - fn init() -> Self { - Self { - gamepad: internals::impls::GamepadImpl::init(), - } - } - fn gamepad(&self) -> impl Gamepad { - self.gamepad.clone() - } -} - -#[derive(Debug, Clone)] -pub struct IO(ThreadSafe); - -impl IO { - pub(crate) fn new() -> Self { - Self(ThreadSafe::new(IOHolder::init())) - } - pub fn gamepad(&self) -> StandardResult { - self.0.get().map(|h| h.gamepad()) - } - -} diff --git a/robot/core/lib.rs b/robot/core/lib.rs index e166770..29a9082 100644 --- a/robot/core/lib.rs +++ b/robot/core/lib.rs @@ -2,59 +2,75 @@ #![warn(missing_docs, unused, clippy::all, unsafe_code)] #![deny(missing_debug_implementations)] +#[cfg(any( + all( + feature = "only_builtins", + feature = "allow_external_impls" + ), + all( + not(feature = "only_builtins"), + not(feature = "allow_external_impls") + ) +))] +compile_error!("The `only_builtins` and `allow_external_impls` features are mutually exclusive."); + +#[cfg(not(feature = "reveal_modules"))] +mod threadsafe; +#[cfg(not(feature = "reveal_modules"))] +mod hardware; +#[cfg(not(feature = "reveal_modules"))] +mod gamepad; +#[cfg(feature = "reveal_modules")] pub mod threadsafe; +#[cfg(feature = "reveal_modules")] pub mod hardware; +#[cfg(feature = "reveal_modules")] pub mod gamepad; -pub mod config; -pub mod io; + +#[cfg(all( + feature = "reveal_modules", + feature = "internals" +))] +#[doc(hidden)] +pub mod internals; +#[cfg(not(all( + feature = "reveal_modules", + feature = "internals" +)))] +mod internals; mod telemetry; +mod config; mod error; +mod op; -pub use error::{HardwareError, Result, IO_OK}; -pub use hardware::HardwareMap; -pub use telemetry::Telemetry; - -use gamepad::Gamepad; - -#[derive(Debug, Clone)] -pub struct OpMode where - H: HardwareMap, - T: Telemetry, - G: Gamepad, -{ - hardware_map: H, - telemetry: T, - gamepad: G, +/// The prelude for the `arc` crate. +/// +/// This prelude re-exports all of the important types and traits +pub mod prelude { + pub use super::hardware::*; + pub use super::config::RobotConfig; + pub use super::gamepad::{Gamepad, MutableGamepad}; + pub use super::telemetry::Telemetry; + pub use super::threadsafe::ThreadSafeError; + pub use super::thread_safe; } -impl OpMode where - H: HardwareMap, - T: Telemetry, - G: Gamepad, -{ - /// Creates a new `OpMode` with the given hardware map, telemetry, and gamepad - #[inline(always)] - #[must_use = "This returns a new OpMode"] - pub const fn new(hardware_map: H, telemetry: T, gamepad: G) -> Self { - Self { hardware_map, telemetry, gamepad } - } -} +pub use op::{Op, RuntimeOp}; +pub use error::{HardwareError, Result, IO_OK}; #[path = "hardware/uuid.rs"] mod __uuid; pub use __uuid::HardwareUUID; #[doc(hidden)] -pub mod internals; - -pub fn setup_io() -> io::IO { - io::IO::new() -} +type DeblockResult = core::result::Result; +/// Deblocks a blocking piece of code. +/// /// This function is used to take a blocking piece of code and run it in such a way /// that it doesn't block the entire runtime. -pub async fn deblock(f: F) -> core::result::Result where +pub async fn deblock(f: F) -> DeblockResult where F: FnOnce() -> R + Send + 'static, R: Send + 'static, { diff --git a/robot/core/op.rs b/robot/core/op.rs new file mode 100644 index 0000000..b3f4d78 --- /dev/null +++ b/robot/core/op.rs @@ -0,0 +1,320 @@ +use crate::prelude::*; +use crate::threadsafe::*; +use crate::{Result, HardwareUUID}; + +#[cfg(not(feature = "only_builtins"))] +#[derive(Debug, Clone)] +pub struct Op where + H: HardwareMap, + T: Telemetry, + G: Gamepad, +{ + running: ThreadSafeBool, + start_time: std::time::Instant, + hardware_map: ThreadSafe, + telemetry: ThreadSafe, + gamepad: ThreadSafe, +} + +#[cfg(feature = "only_builtins")] +#[derive(Debug, Clone)] +pub struct Op { + running: ThreadSafeBool, + start_time: std::time::Instant, + hardware_map: ThreadSafe, + telemetry: ThreadSafe, + gamepad: ThreadSafe, +} + +#[cfg(feature = "only_builtins")] +impl Default for Op { + #[inline(always)] + fn default() -> Self { + Self::new( + crate::internals::builtins::BuiltInHardwareMapImpl::default(), + crate::internals::builtins::BuiltInTelemetryImpl::default(), + crate::internals::builtins::BuiltInGamepadImpl::default() + ) + } +} + +use crate::internals::impls; +use impls::HardwareMapImpl as BuiltInHardwareMapImpl; +use impls::TelemetryImpl as BuiltInTelemetryImpl; +use impls::GamepadImpl as BuiltInGamepadImpl; + +#[cfg(not(feature = "only_builtins"))] +pub type RuntimeOp< + H: HardwareMap, + T: Telemetry, + G: Gamepad, +> = ThreadSafe>; + +#[cfg(feature = "only_builtins")] +pub type RuntimeOp = ThreadSafe; + +#[cfg(not(feature = "only_builtins"))] +impl Op where + H: HardwareMap, + T: Telemetry, + G: Gamepad, +{ + /// Creates a new `Op` with the given hardware map, telemetry, and gamepad + #[inline(always)] + #[must_use = "This returns a new Op"] + pub fn new(hardware_map: H, telemetry: T, gamepad: G) -> Self { + Self { + hardware_map: ThreadSafe::new(hardware_map), + telemetry: ThreadSafe::new(telemetry), + gamepad: ThreadSafe::new(gamepad), + running: ThreadSafeBool::new(false), + start_time: std::time::Instant::now() + } + } + + /// Returns if the op mode is running + /// + /// If the mutex is poisoned, this will return false + #[inline] + pub fn running(&self) -> bool { + match self.running.get() { + Ok(r) => **r, + Err(_) => false, + } + } + /// Returns if the op mode is running + /// + /// The result is wrapped in a `Result` because + /// internally, the value is wrapped in a `Mutex` + /// + /// If the [`Mutex`] is poisoned, this will return an error + /// + /// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html + #[inline] + pub fn running_result(&self) -> Result { + Ok(self.running.get().map(|r| **r)?) + } + /// Returns a reference to the [`HardwareMap`] of the op mode. + /// + /// It is mostly used for loading hardware components. + /// However, you may use this struct to load hardware components as well. + /// + /// See [`HardwareMap`] for more information. + /// + /// [`HardwareMap`]: ./trait.HardwareMap.html + #[inline] + pub fn hardware_map(&self) -> GetResult<'_, H> { + self.hardware_map.get() + } + /// Returns a cloned version of the [`HardwareMap`] of the op mode. + /// + /// This doesn't do bit for bit cloning, but instead, it clones the + /// internal [`Arc`] that holds the data. + /// + /// See [`HardwareMap`] for more information. + /// + /// [`HardwareMap`]: ./trait.HardwareMap.html + /// [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html + #[inline] + pub fn get_hardware_map(&self) -> ThreadSafe { + self.hardware_map.clone() + } + /// Returns the [`Telemetry`] of the op mode. + /// + /// It is mostly used for sending log messages to the driver control station. + /// + /// See [`Telemetry`] for more information. + /// + /// [`Telemetry`]: ./trait.Telemetry.html + #[inline] + pub fn telemetry(&self) -> GetResult<'_, T> { + self.telemetry.get() + } + /// Returns a cloned version of the [`Telemetry`] of the op mode. + /// + /// This doesn't do bit for bit cloning, but instead, it clones the + /// internal [`Arc`] that holds the data. + /// + /// See [`Telemetry`] for more information. + /// + /// [`Telemetry`]: ./trait.Telemetry.html + /// [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html + #[inline] + pub fn get_telemetry(&self) -> ThreadSafe { + self.telemetry.clone() + } + /// Returns the [`Gamepad`] of the op mode. + /// + /// Used for controlling the in TeleOp Modes. + /// + /// See [`Gamepad`] for more information. + /// + /// [`Gamepad`]: ./trait.Gamepad.html + #[inline] + pub fn gamepad(&self) -> GetResult<'_, G> { + self.gamepad.get() + } + /// Returns a cloned version of the [`Gamepad`] of the op mode. + /// + /// This doesn't do bit for bit cloning, but instead, it clones the + /// internal [`Arc`] that holds the data. + /// + /// See [`Gamepad`] for more information. + /// + /// [`Gamepad`]: ./trait.Gamepad.html + /// [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html + #[inline] + pub fn get_gamepad(&self) -> ThreadSafe { + self.gamepad.clone() + } +} + +#[cfg(feature = "only_builtins")] +impl Op { + pub fn init() -> RuntimeOp { + let hardware_map = crate::internals::builtins::BuiltInHardwareMapImpl::default(); + let telemetry = crate::internals::builtins::BuiltInTelemetryImpl::default(); + let gamepad = crate::internals::builtins::BuiltInGamepadImpl::default(); + let op = Self::new(hardware_map, telemetry, gamepad); + ThreadSafe::new(op) + } + + /// Creates a new `Op` with the given hardware map, telemetry, and gamepad + #[inline(always)] + #[must_use = "This returns a new Op"] + pub fn new( + hardware_map: BuiltInHardwareMapImpl, + telemetry: BuiltInTelemetryImpl, + gamepad: BuiltInGamepadImpl + ) -> Self { + Self { + hardware_map: ThreadSafe::new(hardware_map), + telemetry: ThreadSafe::new(telemetry), + gamepad: ThreadSafe::new(gamepad), + running: ThreadSafeBool::new(false), + start_time: std::time::Instant::now() + } + } + + /// Returns if the op mode is running + /// + /// If the mutex is poisoned, this will return false + #[inline] + pub fn running(&self) -> bool { + match self.running.get() { + Ok(r) => **r, + Err(_) => false, + } + } + /// Returns if the op mode is running + /// + /// The result is wrapped in a `Result` because + /// internally, the value is wrapped in a `Mutex` + /// + /// If the [`Mutex`] is poisoned, this will return an error + /// + /// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html + #[inline] + pub fn running_result(&self) -> Result { + Ok(self.running.get().map(|r| **r)?) + } + /// Returns a reference to the [`HardwareMap`] of the op mode. + /// + /// It is mostly used for loading hardware components. + /// However, you may use this struct to load hardware components as well. + /// + /// See [`HardwareMap`] for more information. + /// + /// [`HardwareMap`]: ./trait.HardwareMap.html + #[inline] + pub fn hardware_map(&self) -> GetResult<'_, BuiltInHardwareMapImpl> { + self.hardware_map.get() + } + /// Returns a cloned version of the [`HardwareMap`] of the op mode. + /// + /// This doesn't do bit for bit cloning, but instead, it clones the + /// internal [`Arc`] that holds the data. + /// + /// See [`HardwareMap`] for more information. + /// + /// [`HardwareMap`]: ./trait.HardwareMap.html + /// [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html + #[inline] + pub fn get_hardware_map(&self) -> ThreadSafe { + self.hardware_map.clone() + } + /// Returns the [`Telemetry`] of the op mode. + /// + /// It is mostly used for sending log messages to the driver control station. + /// + /// See [`Telemetry`] for more information. + /// + /// [`Telemetry`]: ./trait.Telemetry.html + #[inline] + pub fn telemetry(&self) -> GetResult<'_, BuiltInTelemetryImpl> { + self.telemetry.get() + } + /// Returns a cloned version of the [`Telemetry`] of the op mode. + /// + /// This doesn't do bit for bit cloning, but instead, it clones the + /// internal [`Arc`] that holds the data. + /// + /// See [`Telemetry`] for more information. + /// + /// [`Telemetry`]: ./trait.Telemetry.html + /// [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html + #[inline] + pub fn get_telemetry(&self) -> ThreadSafe { + self.telemetry.clone() + } + /// Returns the [`Gamepad`] of the op mode. + /// + /// Used for controlling the in TeleOp Modes. + /// + /// See [`Gamepad`] for more information. + /// + /// [`Gamepad`]: ./trait.Gamepad.html + #[inline] + pub fn gamepad(&self) -> GetResult<'_, BuiltInGamepadImpl> { + self.gamepad.get() + } + /// Returns a cloned version of the [`Gamepad`] of the op mode. + /// + /// This doesn't do bit for bit cloning, but instead, it clones the + /// internal [`Arc`] that holds the data. + /// + /// See [`Gamepad`] for more information. + /// + /// [`Gamepad`]: ./trait.Gamepad.html + /// [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html + #[inline] + pub fn get_gamepad(&self) -> ThreadSafe { + self.gamepad.clone() + } +} + +#[cfg(not(feature = "only_builtins"))] +impl HardwareMap for Op where + H: HardwareMap, + T: Telemetry, + G: Gamepad, +{ + /// Loads a hardware component with the given UUID + /// + /// This is just a shortcut for `self.hardware_map.load(uuid)` + #[inline] + fn load(&self, uuid: impl Into) -> Result { + self.hardware_map.get()?.load(uuid) + } +} + +#[cfg(feature = "only_builtins")] +impl HardwareMap for Op { + /// Loads a hardware component with the given UUID + /// + /// This is just a shortcut for `self.hardware_map.load(uuid)` + #[inline] + fn load(&self, uuid: impl Into) -> Result { + self.hardware_map()?.load(uuid) + } +} diff --git a/robot/core/tests/rust_only_robot.rs b/robot/core/tests/rust_only_robot.rs new file mode 100644 index 0000000..b476064 --- /dev/null +++ b/robot/core/tests/rust_only_robot.rs @@ -0,0 +1,5 @@ +#[test] +fn rust_only_robot() -> ::core::result::Result<(), Box> { + + Ok(()) +} \ No newline at end of file diff --git a/robot/core/threadsafe.rs b/robot/core/threadsafe.rs index 0013053..6a21948 100644 --- a/robot/core/threadsafe.rs +++ b/robot/core/threadsafe.rs @@ -3,6 +3,8 @@ //! This module contains thread-safe values that can be used in a //! multi-threaded environment. +/// Macro for implementing [`Send`] and [`Sync`] for a struct. +#[macro_export] macro_rules! thread_safe { ($struct: ident < $($generics: ident),* >) => { #[allow(unsafe_code)] @@ -17,7 +19,6 @@ macro_rules! thread_safe { unsafe impl Sync for $struct {} }; } -pub(crate) use thread_safe; mod holders { use std::sync::{Arc, Mutex, MutexGuard}; @@ -27,21 +28,27 @@ mod holders { #[derive(Debug, Default)] pub struct ThreadSafeHolder(Arc>); + /// The Standard Result type retuned by the thread-safe holders. pub type StandardResult = ::core::result::Result; + /// The result type returned when borrowing from a thread-safe holder. pub type GetResult<'a, T> = StandardResult>; + /// The result type returned when mutably borrowing from a thread-safe holder. pub type GetResultMut<'a, T> = StandardResult>; + /// A Holder for immutable thread-safe values. #[derive(Debug)] #[repr(transparent)] pub struct SafeHeld<'a, T>(MutexGuard<'a, T>); + /// A Holder for mutable thread-safe values. #[derive(Debug)] #[repr(transparent)] pub struct SafeHeldMut<'a, T>(MutexGuard<'a, T>); impl<'a, T> std::ops::Deref for SafeHeld<'a, T> { type Target = T; + #[inline] fn deref(&self) -> &Self::Target { &*self.0 } @@ -49,24 +56,28 @@ mod holders { impl<'a, T> std::ops::Deref for SafeHeldMut<'a, T> { type Target = T; + #[inline] fn deref(&self) -> &Self::Target { &*self.0 } } impl<'a, T> std::ops::DerefMut for SafeHeldMut<'a, T> { + #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut *self.0 } } impl Clone for ThreadSafeHolder { + #[inline] fn clone(&self) -> Self { Self(self.0.clone()) } } impl ThreadSafeHolder { + #[inline] pub fn new(value: T) -> Self { ThreadSafeHolder(Arc::new(Mutex::new(value))) } @@ -78,10 +89,13 @@ mod holders { } } - super::thread_safe!(ThreadSafeHolder); + crate::prelude::thread_safe!(ThreadSafeHolder); } +#[cfg(not(feature = "internals"))] pub(crate) use holders::{GetResult, GetResultMut, SafeHeld, SafeHeldMut, StandardResult}; +#[cfg(feature = "internals")] +pub use holders::{GetResult, GetResultMut, SafeHeld, SafeHeldMut, StandardResult}; /// A thread-safe value. /// @@ -111,6 +125,7 @@ macro_rules! thread_safe_primitive { thread_safe!($name); impl PartialEq for $name { + #[inline] fn eq(&self, other: &Self) -> bool { match (self.get(), other.get() ) { (Ok(a), Ok(b)) => a.get() == b.get(), @@ -122,6 +137,7 @@ macro_rules! thread_safe_primitive { impl Eq for $name {} impl PartialOrd for $name { + #[inline] fn partial_cmp(&self, other: &Self) -> Option { match (self.get(), other.get() ) { (Ok(a), Ok(b)) => a.get().partial_cmp(&b.get()), @@ -131,6 +147,7 @@ macro_rules! thread_safe_primitive { } impl Ord for $name { + #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { match (self.get(), other.get() ) { (Ok(a), Ok(b)) => a.get().cmp(&b.get()), @@ -140,12 +157,15 @@ macro_rules! thread_safe_primitive { } impl $name { + #[inline] pub fn new(value: $primitive) -> Self { Self(ThreadSafe::new(Primitive::new(value))) } + #[inline] pub fn get(&self) -> holders::GetResult<'_, Primitive> { self.0.get() } + #[inline] pub fn get_mut(&self) -> holders::GetResultMut<'_, Primitive> { self.0.get_mut() } @@ -158,12 +178,15 @@ macro_rules! thread_safe_primitive { thread_safe!(Primitive); impl Primitive { - pub fn new(value: $primitive) -> Self { + #[inline] + pub const fn new(value: $primitive) -> Self { Self(value) } + #[inline] pub fn get(&self) -> $primitive { self.0 } + #[inline] pub fn set(&mut self, value: $primitive) { self.0 = value; } @@ -171,36 +194,42 @@ macro_rules! thread_safe_primitive { impl core::ops::Deref for Primitive { type Target = $primitive; + #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl core::ops::DerefMut for Primitive { + #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl From<$primitive> for Primitive { + #[inline] fn from(value: $primitive) -> Self { Self(value) } } impl From for $primitive { + #[inline] fn from(value: Primitive) -> Self { value.0 } } impl From<$primitive> for $name { + #[inline] fn from(value: $primitive) -> Self { Self::new(value) } } impl From<$name> for $primitive { + #[inline] fn from(value: $name) -> Self { match value.get() { Ok(b) => b.get(), diff --git a/robot/lib.rs b/robot/lib.rs index 200cc74..9f0d85c 100644 --- a/robot/lib.rs +++ b/robot/lib.rs @@ -47,7 +47,7 @@ macro_rules! main { } ); } -pub use dranikcore::config::RobotConfig; +pub use dranikcore::prelude::RobotConfig; use std::sync::atomic::AtomicU8; use std::sync::atomic::Ordering; use tokio::runtime::Builder; @@ -99,16 +99,19 @@ pub fn main() { .build() .expect("Failed to initialize runtime"); - let io = dranikcore::setup_io(); + // This isn't how it's supposed to be done, but it works for now + // + // In the future the http server will be the one creating the OpMode + // and then feeding it to the Python thread. + let op = dranikcore::Op::init(); // runtime.spawn(dranikweb::main()); - runtime.spawn(dranikpy::main::(io.clone())); + runtime.spawn(dranikpy::main::(op)); runtime.block_on(async { tokio::signal::ctrl_c().await.expect("Failed to listen for ctrl-c"); print!("Exiting..."); }); runtime.shutdown_timeout(std::time::Duration::from_secs(5)); - drop(io); std::process::exit(0); } @@ -119,6 +122,6 @@ pub fn main() { #[allow(non_camel_case_types)] #[derive(Default, Debug, Clone, Copy)] pub struct __dranik_config; -impl dranikcore::config::RobotConfig for __dranik_config { +impl dranikcore::prelude::RobotConfig for __dranik_config { type Args = (); } diff --git a/robot/python/Cargo.toml b/robot/python/Cargo.toml index 2e4b052..e6949c5 100644 --- a/robot/python/Cargo.toml +++ b/robot/python/Cargo.toml @@ -17,3 +17,6 @@ path = "../core" [dependencies.pyo3] version = "0.20.0" + +[features] +dranik-only-builtins = ["dranikcore/only_builtins"] diff --git a/robot/python/lib.rs b/robot/python/lib.rs index dc8b31e..9366dac 100644 --- a/robot/python/lib.rs +++ b/robot/python/lib.rs @@ -5,15 +5,36 @@ const PY_OK: pyo3::PyResult<()> = Ok(()); -use dranikcore::config::RobotConfig; +use dranikcore::prelude::*; use pyo3::prelude::*; use pyo3::Python; -pub async fn main(io: dranikcore::io::IO) where - A: IntoPy> + Default, - C: RobotConfig, +#[cfg(not(feature = "dranik-only-builtins"))] +pub async fn main< + PyArgs, + RoboConf, + HardwareMapImpl, + TelemetryImpl, + GamepadImpl, +>( + op: dranikcore::RuntimeOp< + HardwareMapImpl, + TelemetryImpl, + GamepadImpl, + >, +) where + PyArgs: IntoPy> + Default, + RoboConf: RobotConfig< + HardwareMapImpl, + TelemetryImpl, + GamepadImpl, + Args = PyArgs + >, + HardwareMapImpl: HardwareMap + 'static, + TelemetryImpl: Telemetry + 'static, + GamepadImpl: Gamepad + 'static, { - C::python_preload(); + RoboConf::python_preload(); pyo3::prepare_freethreaded_python(); @@ -24,10 +45,10 @@ pub async fn main(io: dranikcore::io::IO) where .downcast::()?; syspath.insert(0, "./examples")?; - let args = C::build_python_main_function_args(&py, &io); + let args = RoboConf::build_python_main_function_args(&py, &op); // import main module - let main = py.import("tank_drive_teleop")?; + let main = py.import("auto")?; let mainfunc = main.getattr("main")?; mainfunc.call(args.0, args.1)?; PY_OK @@ -37,95 +58,34 @@ pub async fn main(io: dranikcore::io::IO) where .expect("Python main returned an error"); } -// fn pymain(py: Python) -> PyResult<()> { -// let main_func: pyo3::Py = PyModule::from_code(py, &code, "auto.py", "")? -// .getattr("main")? -// .into(); -// main_func.call1(py, (op_wrapper,))?; -// } - -// use pyo3::prelude::*; +#[cfg(feature = "dranik-only-builtins")] +pub async fn main< + PyArgs, + RoboConf, +>(op: dranikcore::RuntimeOp) where + PyArgs: IntoPy> + Default, + RoboConf: RobotConfig +{ + RoboConf::python_preload(); -// #[derive(Debug, Clone)] -// struct RuntimeOpMode { -// hardware: hardware::HardwareMap, -// name: String -// } -// -// impl RuntimeOpMode { -// fn start(&mut self, hardware: &mut hardware::HardwareMap) -> Result<()> { -// Ok(()) -// } -// } -// -// #[derive(Debug, Clone)] -// pub enum Error { -// OpNotFound, -// } -// -// pub type Result = core::result::Result; -// -// #[derive(Debug)] -// pub struct PyRuntime { -// ops: Vec, -// thread: Option>, -// } -// -// impl PyRuntime { -// pub fn init() -> Self { -// Self { -// ops: Vec::new(), -// thread: None, -// } -// } -// pub fn start(&mut self, name: Name) -> Result<()> { -// let name = name.to_string(); -// let op = self.ops.iter_mut() -// .find(|op| op.name == name) -// .ok_or(Error::OpNotFound)?; -// op.start(&mut self.hardware) -// } -// } + pyo3::prepare_freethreaded_python(); -// fn main() -> PyResult<()> { - // Setup hardware components - // let (gamepad, gamepad_wrapper) = pylib::setup_wrapped_component!( - // pylib::arc_robot_hardware::gamepad::impls::LogitechF310::default(); - // pylib::__init__::hardware::gamepad::Gamepad - // ); - // let (op, op_wrapper) = pylib::setup_wrapped_component!(gamepad_wrapper; pylib::__init__::Op); + dranikcore::deblock(move || Python::with_gil(|py| { + // add files to sys.path + let syspath = py.import("sys")? + .getattr("path")? + .downcast::()?; + syspath.insert(0, "./examples")?; - // IO Thread -// std::thread::spawn(move || { -// use hardware::gamepad::MutableGamepad as _; -// -// std::thread::sleep(std::time::Duration::from_secs(1)); -// gamepad.get_mut()?.set_a(true)?; -// -// std::thread::sleep(std::time::Duration::from_secs(1)); -// gamepad.get_mut()?.set_a(false)?; -// -// std::thread::sleep(std::time::Duration::from_secs(1)); -// gamepad.get_mut()?.set_a(true)?; -// -// std::thread::sleep(std::time::Duration::from_secs(1)); -// op.get_mut()?.stop()?; -// -// op.get_mut()?.running_time(); -// -// IO_OK -// }); + let args = RoboConf::build_python_main_function_args(&py, &op); - // Main Thread -// let mut code = String::new(); -// std::fs::File::open("./examples/auto.py")?.read_to_string(&mut code)?; -// -// // Python (Main Thread) -// Python::with_gil(move |py| { -// let main_func: pyo3::Py = PyModule::from_code(py, &code, "auto.py", "")? -// .getattr("main")? -// .into(); -// main_func.call1(py, (op_wrapper,))?; -// Ok(()) -// }) -// } + // import main module + let main = py.import("auto")?; + let mainfunc = main.getattr("main")?; + mainfunc.call(args.0, args.1)?; + PY_OK + })) + .await + .expect("Failed to run python main") + .expect("Python main returned an error"); +} From 1774431def8ac13c25ffad0fbbf204ee2bece684 Mon Sep 17 00:00:00 2001 From: AtomicGamer9523 Date: Sat, 30 Dec 2023 10:27:10 -0800 Subject: [PATCH 93/93] Added docs to pymod function --- arc/macros.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arc/macros.rs b/arc/macros.rs index dd3e538..0925005 100644 --- a/arc/macros.rs +++ b/arc/macros.rs @@ -21,9 +21,13 @@ /// ``` #[macro_export] macro_rules! pymod { - ( - $module_name: ident -> $submodule_func: path, $module_path: literal, $py:ident, $m: ident - ) => { + // Explanation: + // + // 1. We create the submodule via PyModule::new + // 2. Call that the function that represents the submodule (providing py, so this module) + // 3. Then we add the submodule to the parent module. (m.add_submodule(module_name)) + // 4. Finally, run a python script to add the submodule to sys.modules. + ($module_name: ident -> $submodule_func: path, $module_path: literal, $py:ident, $m: ident) => { let $module_name = PyModule::new($py, ::core::stringify!($module_name))?; $submodule_func($py, $module_name)?; $m.add_submodule($module_name)?;