Code Monkey home page Code Monkey logo

num-traits's Introduction

num-traits

crate documentation minimum rustc 1.60 build status

Numeric traits for generic mathematics in Rust.

Usage

Add this to your Cargo.toml:

[dependencies]
num-traits = "0.2"

Features

This crate can be used without the standard library (#![no_std]) by disabling the default std feature. Use this in Cargo.toml:

[dependencies.num-traits]
version = "0.2"
default-features = false
# features = ["libm"]    # <--- Uncomment if you wish to use `Float` and `Real` without `std`

The Float and Real traits are only available when either std or libm is enabled.

The FloatCore trait is always available. MulAdd and MulAddAssign for f32 and f64 also require std or libm, as do implementations of signed and floating- point exponents in Pow.

Releases

Release notes are available in RELEASES.md.

Compatibility

The num-traits crate is tested for rustc 1.60 and greater.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

num-traits's People

Contributors

alexcrichton avatar aliddell avatar bluss avatar bors[bot] avatar clarfonthey avatar cuviper avatar darksonn avatar dbarella avatar donsheddow avatar enet4 avatar feadoor avatar gifnksm avatar hauleth avatar homu avatar huonw avatar jbcrail avatar koverstreet avatar lcnr avatar mbrubeck avatar mitchmindtree avatar ocstl avatar ollie27 avatar regexident avatar sparrowlii avatar superfluffy avatar tarcieri avatar termoshtt avatar vks avatar xaeroxe avatar yoanlcq avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

num-traits's Issues

Bound FloatCore by Bounded?

Both traits are in this crate, and it seems highly redundant to me to have min_value() and max_value() duplicated between FloatCore and Bounded. Any objections to just having trait FloatCore: Bounded?

Documentation for checked operations says "instead of wrapping around on underflow"

From @kryptan on July 30, 2015 21:50

Documentation for CheckedAdd, CheckedDiv, CheckedMul, CheckedSub says: Performs operation that returns None instead of wrapping around on underflow.

"instead of wrapping around on underflow" sounds like wrapping on overflow is the default behaviour but it is not.

P.S. there are traits for checked and saturating operations but no trait for wrapped operations, why?

Copied from original issue: rust-num/num#107

Add rsqrt method to Float trait

From @davll on November 9, 2017 8:48

rsqrt is a widely used math function in game development, and is faster than combining the two functions: recip(sqrt(x)) thanks to x86 SSE instructions RSQRTSS, RSQRTPS, RSQRTSD, and RSQRTPD. Should we consider add rsqrt to Float trait?

  • x86/x86_64 SSE: _mm_rsqrt_ps (note that RSQRT instruction is approximate, less accurate than SQRT)
  • ARM Neon VRSQRTE
  • PowerPC Altivec: vec_rsqrte

Copied from original issue: rust-num/num#343

Unusual breaking change introduced in 0.2.6

The following code builds fine on 0.2.5, but fails to compile on 0.2.6. Extremely unusually, testing seems to indicate that was introduced in d2bf4e0, a rustfmt commit.

extern crate num_traits;
use num_traits::*;

pub trait Trait {
    type Num: PrimInt + CheckedShl;
}
pub fn function<T: Trait>(b: usize) -> T::Num {
  T::Num::one() << b
}

Error encountered:

error[E0308]: mismatched types
 --> src/lib.rs:8:20
  |
8 |   T::Num::one() << b
  |                    ^ expected u32, found usize

Moving the associated type's bounds directly into the trait bounds for T, as well as removing the bound on CheckedShl both seem to clear this error.

Changing the body of function to Shl::<usize>::shl(T::Num::one(), b) also clears the error, proving that an implementation of Shl<usize> does exist for T::Repr.

This seems to be due a bug in rustc, where the order that traits are declared in influences their resolution in operators.

Interest in generic nonzero and nonzeroable traits?

Hey there, huge fan of the num_traits crate. I just needed traits to represent generic non-zero integer types (as opposed to the concrete core::num::NonZeroU8 type), and figured this might be a good fit for this crate! In the meantime I made https://crates.io/crates/nonzero_ext, but would love to just fold it into this one (:

Happy to make the PR to add these! If you are interested, let me know!

No `.abs()` on integers, any reason?

There are some method on Float which aren't on any of the integer traits (PrimInt? Num Itself). e.g. .abs(). A i32 can defintely have an .abs() method. (.abs() on a u8 makes sense (ish)). Something I'm doing would benefit from more generic numeric traits.

Is there any reason why Float has methods which could be applied to more generic numbers? I don't want to submit a patch if there's some good reason I'm not aware of

pow(0, 0) returns 1.

pow(0, 0) should be undefined. Should probably panic in pow(0, 0), and return None in checked_pow(0, 0).

Remove default `epsilon` implementation for `Float`

From @AtheMathmo on September 22, 2016 19:57

With #231 we introduced a new epsilon() function which returns the EPSILON constant for f32 and f64. In order to prevent breaking the API we provided a default implementation here - using NumCast to return f32::EPSILON.

When we are ready to release breaking changes we should consider removing this default implementation.

Copied from original issue: rust-num/num#232

Allow classification of Float and FloatCore values without taking ownership

The .is_nan(), .is_infinite(), .is_finite(), .is_normal(), .classify(), .is_sign_positive(), and .is_sign_negative() methods of the Float and FloatCore traits take ownership of self. This is problematic when writing generic code for container types which contain T: Float because in many cases, only &T is available and it's not guaranteed that T implements Copy or Clone. Taking ownership is also problematic for arbitrary precision floating point types which are expensive to clone. I can't think of any reasonable case where taking ownership would be necessary to implement these methods.

Taking &self instead of self should not incur any performance penalty for f32 and f64 as long as the call is inlined; the #[inline] attribute is already included on all of those methods. As a demonstration, call() and call_with_ref() generate the same assembly after optimization in this example (is_nan() and is_nan_ref() are inlined):

fn is_nan(num: f32) -> bool {
    num.is_nan()
}

fn is_nan_ref(num: &f32) -> bool {
    num.is_nan()
}

pub fn call(num: f32) -> bool {
    is_nan(num)
}

pub fn call_with_ref(num: f32) -> bool {
    is_nan_ref(&num)
}

I propose doing either one of the of the following for .is_nan(), .is_infinite(), .is_finite(), .is_normal(), .classify(), .is_sign_positive(), and .is_sign_negative():

  1. Change the existing methods to take &self instead of self.

  2. Add methods (e.g. .is_nan_ref() or .is_nan_borrowed()) which take &self instead of self.

More features for `Float`

From @bluss on March 7, 2016 15:19

If Float truly is for f32 and f64 (it should be), we can frontload it with as much features as possible.

Wishlist:

  • 'static
  • Display + Debug + LowerExp + UpperExp
  • Send + Sync

Copied from original issue: rust-num/num#178

All bit twiddling functions in num::traits::PrimInt should take or return usize instead of u32

From @octurion on April 10, 2015 10:12

The trait num::traits::PrimInt mandates that any type implementing it must also implement Shl<usize, Output=Self> and Shr<usize, Output=Self> (in other words, PrimInt mandates that the shift amount be of type usize).

Thus all bit twiddling functions (trailing_zeros, rotate_left, count_zeros etc.) in PrimInt should take or return a usize instead of u32 as the number of bits for the sake of consistency with what the implementation restrictions on Shl and Shr mandate.

Copied from original issue: rust-num/num#80

Idea: Pow trait

I've been working on a crate which works with runtime-level units, and I think that having a generic Pow trait would be useful.

Essentially, it would be very similar to the other unary op traits, namely:

pub trait Pow<RHS> {
    type Output;
    fn pow(self, rhs: RHS) -> Self::Output;
}

And in most cases, this would simply do exponentiation by squaring as included in the existing pow functions. However, it may be easier to implement for some types, namely a unit could simply multiply a field that indicates what power of the given unit you have. Another example is that a type which constrains which values it has, e.g. a matrix which specifically performs scaling operations, could be modified to do less work.

This would be weird to implement and may cause confusion with the existing pow function, which is why I haven't offered a PR for it. But it might be nice to have in this crate.

Tracking issue for potential breaking changes

num-traits is somewhat of a de facto stable crate. Since these traits are often found in the public API of other crates, we really want to avoid the sort of ecosystem split that a breaking-change semver bump might cause.

Nevertheless, it's a good idea to track what breaking changes we might want to make someday, now found in the list below. Links are included to postponed issues, which often have more details. They will be closed in the meantime, but discussion can continue.

  • Remove default epsilon implementation for Float #4
  • Num::FromStrRadixErr should have Trait bound #6
  • More features for Float #8
  • All bit twiddling functions in num::traits::PrimInt should take or return usize instead of u32 #14
  • std::num::Checked{Add,Sub,Mul,Div} should have type parameters #15
  • Use Mul by reference in pow #18
  • Make the Float trait depend on FloatConst. #20
  • Add Default, Display, and Debug trait bounds to PrimInt #44
  • Easy conversions between Signed and Unsigned #46
  • Blanket impl for Real trait prevents parameterized implementations. #49
  • Functions to distinguish signaling from non-signaling NaN's #51
  • Bound FloatCore by Bounded? #55
  • Implement traits for Reverse (rust 1.19+) #65
  • Make One::is_one a required method and remove its Self: PartialEq #5 (comment)
  • LowerBounded and UpperBounded (#210) should be super-traits of Bounded

Feature Request: Add "Maximum" and "Minimum" traits (or a combined `MiniMax` trait)

Often times, it is useful to know the maximum and minimum values allowed by a numeric type.

I'm hoping we could see a fairly simple trait that looks someting like this:

pub trait MiniMax {
    fn maximum() -> Self;
    fn minimum() -> Self;
}

Some examples:

  1. u32.maximum() would return std::u32::MAX
  2. u32.minimum() would return 0
  3. f64.maximum() would return std::f64::INFINITY
  4. f64.minimum() would return std::f64::NEG_INFINITY

Unbounded finite types like BigInt simply wouldn't implement this trait.

Make the Float trait depend on FloatConst.

In my (arguably limited) experience with using the num traits, FloatConst is most of the time used along with Float. It would simplify a lot of type signatures if the Float trait bound implied FloatConst.
I'll happily submit a PR if the idea is sound.

Functions to distinguish signaling from non-signaling NaN's

From @icefoxen on March 6, 2018 16:14

It'd be nice to be able to distinguish signaling from non-signaling NaN's in some cases. In particular, writing a WebAssembly interpreter; WebAssembly disallows signaling NaN's, so one needs some way to detect and filter them out. Easy to do with bit masks, but it would be nice to be a little more abstract.

Thank you!

Copied from original issue: rust-num/num#364

Add trait that allows using `as` operator for generic code

From @bluss on March 23, 2016 21:26

The as operator does unchecked conversion between numerical types, without error cases. It's a core part of the language, so it would be useful to have it available for generic code as well.

Often it can be used very sensibly because you know your input is well behaved. For example, it can be small magnitude floating point numbers that you want to cast to/from f32/f64.

Copied from original issue: rust-num/num#183

Feature request: Recip trait

Essentially, a pair to Neg for multiplication. Anything which can have its reciprocal taken would implement this. Useful in the context of Mul + Recip + One, for example.

`saturating_mul` missing

Is the lack of saturating_mul in num::Saturating on purpose, or a mistake, or should it live somewhere else?

Document PrimInt

From @gnzlbg on December 17, 2015 12:10

It took me a bit to realize that PrimInt is the trait that provides the bit manipulation operations on primitive types (nothing more, nothing less). The methods are documented but the Trait itself is not documented.

Copied from original issue: rust-num/num#140

Documentation for checked shifts is misleading

Excerpt from the CheckedShl trait:

///Performs a left shift that returns `None` on overflow.
pub trait CheckedShl: Sized + Shl<u32, Output=Self> {
    /// Shifts a number to the left, checking for overflow. If overflow happens,
    /// `None` is returned.
...
    fn checked_shl(&self, rhs: u32) -> Option<Self>;

The current wording seems to imply that if bits are shifted past the integer's range, then None is returned. This is not the case, the primitive checked_shl explicitly documents this:

        /// Checked shift left. Computes `self << rhs`, returning `None`
        /// if `rhs` is larger than or equal to the number of bits in `self`.
...
        #[stable(feature = "wrapping", since = "1.7.0")]
        #[inline]
        pub fn checked_shl(self, rhs: u32) -> Option<Self> {
            let (a, b) = self.overflowing_shl(rhs);
            if b {None} else {Some(a)}
        }

None is only returned if rhs is larger than the number of bits in the numeric type.
E.g.

0x88u8.checked_shl(4) == Some(0x80)
0x88u8.cheched_shl(8) == None

Implement numerically stable sum of floats

From @vks on June 27, 2017 12:29

Here is an implementation based on the (hidden) one in the standard library:

use std::mem;

/// Numerically stable sum.
///
/// See http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps for a proof of
/// correctness.
struct Sum {
    partials: Vec<f64>,
}

impl Sum {
    fn new() -> Sum {
        Sum {
            partials: vec![],
        }
    }

    fn add(&mut self, mut x: f64) {
        let mut j = 0;
        // This inner loop applies `hi`/`lo` summation to each
        // partial so that the list of partial sums remains exact.
        for i in 0..self.partials.len() {
            let mut y: f64 = self.partials[i];
            if x.abs() < y.abs() {
                mem::swap(&mut x, &mut y);
            }
            // Rounded `x+y` is stored in `hi` with round-off stored in
            // `lo`. Together `hi+lo` are exactly equal to `x+y`.
            let hi = x + y;
            let lo = y - (hi - x);
            if lo != 0.0 {
                self.partials[j] = lo;
                j += 1;
            }
            x = hi;
        }
        if j >= self.partials.len() {
            self.partials.push(x);
        } else {
            self.partials[j] = x;
            self.partials.truncate(j + 1);
        }
    }

    fn sum(&self) -> f64 {
        self.partials.iter().fold(0., |p, q| p + *q)
    }
}

impl std::iter::FromIterator<f64> for Sum {
    fn from_iter<T>(iter: T) -> Sum
        where T: IntoIterator<Item=f64>
    {
        let mut e = Sum::new();
        for i in iter {
            e.add(i);
        }
        e
    }
}

fn main() {
    const N: usize = 10_000;
    let mut v = Vec::with_capacity(4 * N);
    for _ in 0..N {
        v.push(1.);
        v.push(1e100);
        v.push(1.);
        v.push(-1e100);
    }
    let stable_sum: Sum = v.iter().map(|x| *x).collect();
    assert_eq!(stable_sum.sum(), (2 * N) as f64);
}

I'm not sure how the interface should ideally look like.

Copied from original issue: rust-num/num#309

Split general functions in the `Float` trait into one or more general math traits

The Float trait does not only cover float specific functions, but also some general math functions, which are applicable for many number types.
For example fixed point number types could define functions like sqrt, log and sin, but not the float specific functions like infinity, neg_zero, ǹan.
So I propose to outsorce some functions of the float trait into another trait.

This trait should also be applicable to more complicated kinds of numbers, where such functions make sence, like complex numbers, quaternions, matrices or similar.

I also could implement it myself, but I think, it's good to talk about this before.

I'll define the trait, As I'd implement it:

pub trait Math: Add<Output=Self>+Sub<Output=Self>+Mul+Neg<Output=Self>+Sized

The name of the trait may be different, I just called it Math.
Addition, Subtraction and Negation should result in the same output type.
Multiplication may also result in different output types.
For example, if you implement real numbers and imaginary numbers as seperate types, multiplication of two imaginary numbers will result in real numbers.
Or multiplication of matrices of different sizes will result in another matrix of a size depending on the matrix size.
Division is not required for this trait. For many mathematical types, where multiplication is not symmetric (for example for matrices) division seems not that useful. Instead you would normally multiply by the inverse.
The type doesn't even need to implement One or Zero, because some types may be useful, which don't have a identity element for multiplication (for example the imaginary numbers).
Implementing at least Zero may be useful.

A list of functions will follow, I would include into the trait.
The functions are just the functions from the float trait, that seem useful for most mathematical types, which can represent more then whole numbers.
Maybe the output value has to be more general for some of these functions, because of the low restrictions on multiplication. (for example exp on imaginary numbers would need complex numbers as output type).

    fn recip(self) -> Self;

    fn powi(self, n: i32) -> Self;

    fn powf(self, n: Self) -> Self;

    fn sqrt(self) -> Self;

    fn exp(self) -> Self;

    fn exp2(self) -> Self;

    fn ln(self) -> Self;

    fn log(self, base: Self) -> Self;

    fn log2(self) -> Self;

    fn log10(self) -> Self;

    fn cbrt(self) -> Self;

    fn sin(self) -> Self;

    fn cos(self) -> Self;

    fn tan(self) -> Self;

    fn asin(self) -> Self;

    fn acos(self) -> Self;

    fn atan(self) -> Self;

    fn sin_cos(self) -> (Self, Self);

    fn exp_m1(self) -> Self;

    fn ln_1p(self) -> Self;

    fn sinh(self) -> Self;

    fn cosh(self) -> Self;

    fn tanh(self) -> Self;

    fn asinh(self) -> Self;

    fn acosh(self) -> Self;

    fn atanh(self) -> Self;

Default implementations may also be useful, because for most function there is some definition, that can be used for every type, often as an infinite sum.

Another soulution may also be to add some more specific traits, which only implement some functions:

trait Trigonometric {
    fn sin(self) -> Self;
    fn cos(self) -> Self;
    fn tan(self) -> Self;
    fn asin(self) -> Self;
    fn acos(self) -> Self;
    fn atan(self) -> Self;
}

trait Power {
    fn powi(self, n: i32) -> Self;
    fn powf(self, self) -> Self;
    fn exp(self) -> Self;
    fn exp2(self) -> Self;
    fn ln(self) -> Self;
    fn log2(self) -> Self;
    fn log10(self) -> Self;
    fn sqrt(self) -> Self;
    fn cbrt(self) -> Self;
}

But I doubt, this more detailled split really is useful, since you can normally define trigonometric functions in terms of exp and the other way round, and also implement the default impelmentations that way.

So I'm interested, how you would implement such traits, so I don't require to use floats in order to use a generic sqrt and exponential functions.
Are there arleady plans in this crate?

Blanket `impl` for `Real` trait prevents parameterized implementations.

I'm working on stabilizing a crate for constraints and total orderings of floating-point types. My crate integrates with num-traits, and has introduced subsets of the Float trait: Encoding, Infinite, Nan, and Real. The 0.2.* series of num-traits introduces a Real trait of its own, which I would prefer to use instead, but the blanket impl<T> Real for T where T: Float makes this difficult. See this issue.

I know this is a long shot, since this would likely involve breaking changes, but is there any chance this impl and the relationship between Real and Float could be reconsidered? Just a few thoughts:

  • Today, Real does not really behave as a subset given the blanket implementation. Users either implement Real xor Float, rather than implementing Real and any additional traits to satisfy Float. That relationship seems a bit backwards to me.
  • The blanket implementation makes it difficult to generically implement Real and Float. In my crate, this is a problem, because I implement both based on constraints on a wrapped type T. Attempting an implementation of Float will always clash with an implementation of Real regardless of the constraints. This is the difficulty I'm referencing in the title of this issue.

My guess is that the second point will almost always be a problem for parameterized types (i.e., wrappers) that may want to implement Float and/or Real.

The most obvious workaround for my crate is to remove the parameterized impls for Real and Float and duplicate a lot of code to implement them for the concrete type definitions that the crate re-exports. I can reduce duplication with a macro, but it makes the code more fragile, because type definitions that should pick up such implementations based on the input types alone would no longer get them implicitly.

Thanks for taking a look at this. Thoughts?

Support for SIMD types

I am creating a library where I would like to abstract math over scalar (f32) or packed SIMD types (f32x8) as defined in RFC 2366.

For example, I would like to express:

fn kernel<F>(a: F, b: F) -> F
where
    F: Float,
{
    (a - b) * (a - b)
}

And then call either kernel(1.0, 2.0) or kernel(f32x8::splat(1.0), f32x8::splat(2.0)), depending on what data structure I am operating with.

As part of that I was looking into num-traits, in particular I was about to create a num-packed crate, that implements Num & friends for RFC 2366 packed types.

The problem, however, is that many traits such as Integer, Float, Signed, ... not only provide f(Self) -> Self mathematical functions, but also f(Self) -> bool utilities, such as is_even or integer_decode, which do not directly make sense anymore.

Two questions:

  • Do you think it would be feasible to either split out these utility functions into separate traits, or generalize them to be compatible with packed types?
  • More generally, does num-packed make sense as an addition to num, or am I on the wrong path?

Wrapping neg is not implemented for PrimInt

From @gnzlbg on December 23, 2015 18:40

When constraining on PrimInt there is no way of performing wrapping neg in a generic way.

The "generic" way to do this seems to be to call the .wrapping_neg() method which is offered by all primitive integers (but not by PrimInt).

Copied from original issue: rust-num/num#146

Easy conversions between `Signed` and `Unsigned`

It would be nice if Signed and Unsigned had a way to convert between each other, presumably via:

  • Signed::abs_unsigned, which would losslessly convert the signed version to an unsigned version of the same size (wrapping_abs + as for primitives, and just extracting the inner BigUint for BigInt)
  • Unsigned::try_signed, which would allow casting to the signed version if available.
  • Signed::Unsigned and Unsigned::Signed, two associated types that would do the job.

This would be a breaking change but a useful one. For example, a Pow implementation for Ratio could leverage these methods so that the signed and unsigned versions relied on each others' implementations, instead of duplicating code.

Should `num::{ToPrimitive,FromPrimitive}` be implemented in terms of `std::convert::{Into,TryFrom}`?

std::convert supplies Into and TryFrom traits which seem applicable to the existing num::ToPrimitive and num::FromPrimitive traits.

In theory, the std::convert traits are the more future-proof way to implement all of this. That said, I stared at cast.rs for a while trying to figure out a good way to make this change, and I haven't got anything useful so far -- the problem is that num reprovides ToPrimitive and FromPrimitive to the world, which means that they can't be removed without breaking current users (at least, as far as I can tell).

Add method `is_one` to `One` trait

From @pyfisch on August 5, 2016 17:15

The Zero trait contains two methods: zero returns the number 0 for the given type and is_zero is provided and can be used to check if a number is 0.

The One trait is similar but contains only the method one to create the number 1. Please also add a method to check if a number is one.

Copied from original issue: rust-num/num#214

Idea: Log Trait

With #38 's suggestion about a Pow trait, it would be useful to add the inverse of exponentiation as a trait. The proposed syntax is similar to the one for Pow

pub trait Log<RHS> {
    type Output;
    fn log(self, rhs: RHS) -> Self::Output;
}

This would most likely be necessary for impl Pow<Complex<T>> for Complex<T>.

Relevent issue on num-complex

rust-num/num-complex#18

Use the libm crate for a full Float on no_std

Currently, num_traits::Float is only available with std, and no_std only has the more limited FloatCore without all of transcendental functions like sqrt, sin, etc. The new libm crate might be the way out of this, as an optional dependency to get Float on no_std too!

There's also Real and the signed and floating-point Pow (mapping to powi and powf) which all require std now, and should be feasible with libm. I'm not sure about MulAdd and MulAddAssign though.

Associated constants for One and Zero

Any reason we can't have ONE and ZERO implemented as constants rather than methods? Given that num_traits is a low level crate, it effectively forbids any higher level constructs with associated constants atm.

Extract some kind of RealNumber trait out of Float and make Float require it

Greetings,

This proposal isn't supposed to be a breaking change, but I suspect it would end up like one anyway.
I've searched for similar issues and the closest one I could find is Option 2 presented in #321.

The problem
I'm writing yet-another generic vector/matrix math library.
It also provides a Lerp<Factor> trait where Factor is expected to behave like a real number; And, as of today, everywhere I require a T to be a real number, I write where T: Float.
Often, I find that my only use case is either to call trigonometric functions on T, or guarantee that T can represent numbers between 0 and 1.

Here's the thing: I would like my library to work with less common real number types such as fixed-point; And today, fixed-point numbers cannot meaningfully implement Float, because infinity(), classify() and some others make no sense for them, however I know they have trigonometric functions which is what I actually use Float for.
Essentially, Float forcefully ties together two concepts that should be separate IMO: "something that behaves like a floating-point number", and "something that behaves like a real number, regardless of the underlying representation".

The proposal
Extract floating-point-agnostic items of Float into a new RealNum trait (not sure about the name), and make Float require RealNum.

pub trait Float: RealNum {
    fn nan() -> Self;
    fn infinity() -> Self;
    fn neg_infinity() -> Self;
    fn neg_zero() -> Self; // Not sure about this one. Does it belong to RealNum instead ?
    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 integer_decode(self) -> (u64, i16, i8);
}
pub trait RealNum: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
    fn min_value() -> Self;
    fn min_positive_value() -> Self;
    fn max_value() -> Self;
    fn floor(self) -> Self;
    fn ceil(self) -> Self;
    fn round(self) -> Self;
    fn trunc(self) -> Self;
    fn fract(self) -> Self;
    fn abs(self) -> Self;
    fn signum(self) -> Self;
    fn is_sign_positive(self) -> bool;
    fn is_sign_negative(self) -> bool;
    fn mul_add(self, a: Self, b: Self) -> Self;
    fn recip(self) -> Self;
    fn powi(self, n: i32) -> Self;
    fn powf(self, n: Self) -> Self;
    fn sqrt(self) -> Self;
    fn exp(self) -> Self;
    fn exp2(self) -> Self;
    fn ln(self) -> Self;
    fn log(self, base: Self) -> Self;
    fn log2(self) -> Self;
    fn log10(self) -> Self;
    fn max(self, other: Self) -> Self;
    fn min(self, other: Self) -> Self;
    fn abs_sub(self, other: Self) -> Self;
    fn cbrt(self) -> Self;
    fn hypot(self, other: Self) -> Self;
    fn sin(self) -> Self;
    fn cos(self) -> Self;
    fn tan(self) -> Self;
    fn asin(self) -> Self;
    fn acos(self) -> Self;
    fn atan(self) -> Self;
    fn atan2(self, other: Self) -> Self;
    fn sin_cos(self) -> (Self, Self);
    fn exp_m1(self) -> Self;
    fn ln_1p(self) -> Self;
    fn sinh(self) -> Self;
    fn cosh(self) -> Self;
    fn tanh(self) -> Self;
    fn asinh(self) -> Self;
    fn acosh(self) -> Self;
    fn atanh(self) -> Self;
    fn epsilon() -> Self { ... }
    fn to_degrees(self) -> Self { ... }
    fn to_radians(self) -> Self { ... }
}

That's pretty much the idea, but I suspect this would break existing impl Float for T in the wild.

An (uglier, IMO) alternative would be to duplicate appropriate Float items instead (into RealNum), then make an universal impl so that T: Float implements RealNum.

I'm pretty sure I haven't foreseen all problems. Thanks in advance for considering anyway! :)

`std::num::Checked{Add,Sub,Mul,Div}` should have type parameters

From @steveklabnik on February 11, 2015 1:35

Issue by lifthrasiir
Monday Apr 14, 2014 at 12:33 GMT

For earlier discussion, see rust-lang/rust#13510

This issue was labelled with: A-libs in the Rust repository


The corresponding std::ops traits have both the type of right hand side operand and the type of result, while Checked* traits do not (and always assume that both operands and result have the same type). There is no real reason to make Checked* traits behave differently from std::ops traits, and having them as is hampers advanced uses of operator overloading: for example, if the scalar type (e.g. DateTime) and difference type (e.g. Duration) are distinct from each other then the current scheme wouldn't work at all.

Copied from original issue: rust-num/num#59

Feature request: 'One' and 'Zero' traits for bool

Could we get the One and Zero traits implemented for booleans, as true and false respectively? It would be useful, for example, in the context or ndarray where arrays often are initialized using either trait, e.g. let arr: Array1<usize> = Array::zeroes(5) which in turn uses the Zero trait for usize. I would like to be able to do the same with booleans.

Thank you

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.