Description
I am growing increasingly concerned that we are locking ourselves into a substandard numeric API heading toward 1.0 that will be hard to alter in the future without breaking a significant amount of client code.
Perhaps we could investigate simplifying the numeric trait hierarchy to be centered around built-in types. Perhaps the traits could be removed from the prelude as default instead using free, method wrapper functions as the primary form of using the numeric functions. This would make the API more amenable to being extended by users in the future. Perhaps an algebraic hierarchy could be included in extra
.
For example the Round
, Fractional
, Algebraic
, Trigonometric
, Exponential
, Hyperbolic
, Real
and Float
could be consolidated into a single Float
trait. Then the primary way of accessing the functions would be via the wrapper functions, eg. num::atan2(x, y)
.
pub trait Float {
fn floor(x: Self) -> Self;
fn ceil(x: Self) -> Self;
fn round(x: Self) -> Self;
fn trunc(x: Self) -> Self;
fn fract(x: Self) -> Self;
fn recip(x: Self) -> Self;
fn pow(x: Self, n: Self) -> Self;
fn sqrt(x: Self) -> Self;
fn rsqrt(x: Self) -> Self;
fn cbrt(x: Self) -> Self;
fn hypot(x: Self, other: Self) -> Self;
fn sin(x: Self) -> Self;
fn cos(x: Self) -> Self;
fn tan(x: Self) -> Self;
fn asin(x: Self) -> Self;
fn acos(x: Self) -> Self;
fn atan(x: Self) -> Self;
fn atan2(x: Self, y: Self) -> Self;
fn sin_cos(x: Self) -> (Self, Self);
fn sinh(x: Self) -> Self;
fn cosh(x: Self) -> Self;
fn tanh(x: Self) -> Self;
fn asinh(x: Self) -> Self;
fn acosh(x: Self) -> Self;
fn atanh(x: Self) -> Self;
fn exp(x: Self) -> Self;
fn exp2(x: Self) -> Self;
fn ln(x: Self) -> Self;
fn log(x: Self, base: Self) -> Self;
fn log2(x: Self) -> Self;
fn log10(x: Self) -> Self;
fn pi() -> Self;
fn two_pi() -> Self;
fn frac_pi_2() -> Self;
fn frac_pi_3() -> Self;
fn frac_pi_4() -> Self;
fn frac_pi_6() -> Self;
fn frac_pi_8() -> Self;
fn frac_1_pi() -> Self;
fn frac_2_pi() -> Self;
fn frac_2_sqrtpi() -> Self;
fn sqrt2() -> Self;
fn frac_1_sqrt2() -> Self;
fn e() -> Self;
fn log2_e() -> Self;
fn log10_e() -> Self;
fn ln_2() -> Self;
fn ln_10() -> Self;
fn to_degrees(x: Self) -> Self;
fn to_radians(x: Self) -> Self;
fn nan() -> Self;
fn infinity() -> Self;
fn neg_infinity() -> Self;
fn neg_zero() -> Self;
fn is_nan(self) -> bool;
fn is_infinite(self) -> bool;
fn is_finite(self) -> bool;
fn is_normal(self) -> bool;
fn classify(self) -> FPCategory;
fn mantissa_digits(_: Option<Self>) -> uint;
fn digits(_: Option<Self>) -> uint;
fn epsilon() -> Self;
fn min_exp(_: Option<Self>) -> int;
fn max_exp(_: Option<Self>) -> int;
fn min_10_exp(_: Option<Self>) -> int;
fn max_10_exp(_: Option<Self>) -> int;
fn ldexp(x: Self, exp: int) -> Self;
fn frexp(x: Self) -> (Self, int);
fn exp_m1(x: Self) -> Self;
fn ln_1p(x: Self) -> Self;
fn mul_add(x: Self, a: Self, b: Self) -> Self;
fn next_after(x: Self, other: Self) -> Self;
}
#[inline] fn floor<T:Float>(x: T) -> T { Float::floor(x) }
#[inline] fn ceil<T:Float>(x: T) -> T { Float::ceil(x) }
#[inline] fn round<T:Float>(x: T) -> T { Float::round(x) }
#[inline] fn trunc<T:Float>(x: T) -> T { Float::trunc(x) }
#[inline] fn fract<T:Float>(x: T) -> T { Float::fract(x) }
#[inline] fn recip<T:Float>(x: T) -> T { Float::recip(x) }
#[inline] fn pow<T:Float>(x: T, n: T) -> T { Float::pow(x, n) }
#[inline] fn sqrt<T:Float>(x: T) -> T { Float::sqrt(x) }
#[inline] fn rsqrt<T:Float>(x: T) -> T { Float::rsqrt(x) }
#[inline] fn cbrt<T:Float>(x: T) -> T { Float::cbrt(x) }
#[inline] fn hypot<T:Float>(x: T, y: T) -> T { Float::hypot(x, y) }
#[inline] fn sin<T:Float>(x: T) -> T { Float::sin(x) }
#[inline] fn cos<T:Float>(x: T) -> T { Float::cos(x) }
#[inline] fn tan<T:Float>(x: T) -> T { Float::tan(x) }
// ...
This is related to the numeric trait reform tracked at #4819