Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

infinity-related functions shouldn't be generic over Num #4788

Closed
brson opened this issue Feb 4, 2013 · 9 comments
Closed

infinity-related functions shouldn't be generic over Num #4788

brson opened this issue Feb 4, 2013 · 9 comments

Comments

@brson
Copy link
Contributor

brson commented Feb 4, 2013

num::is_infinity, etc. are generic functions on the Num, One and Zero traits and do divides by zero. This doesn't make sense for integers.

@brendanzab
Copy link
Member

Yeah, I'm concerned about this. Warnings about failure is always worrying - it would be better if this could be enforced via the type system. I've been working hard at a refactor of the numeric modules, but this design issue is making it hard to merge: https://github.com/bjz/rust/tree/incoming/src/libcore/num

From my perspective, infinities and NaNs should be defined in a separate Float trait like so:

pub trait Float: Num {
    static pure fn NaN() -> Self;
    static pure fn infinity() -> Self;
    static pure fn neg_infinity() -> Self;

    pure fn is_infinite(&self) -> bool;
    pure fn is_finite(&self) -> bool;
    pure fn is_NaN(&self) -> bool;
    ...
}

@brendanzab
Copy link
Member

Related: #4789

@brendanzab
Copy link
Member

The current implementation:

libcore/num/num.rs

// Generic math functions:

/// Dynamically calculates the value `inf` (`1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn infinity<T: Num One Zero>() -> T {
    let _0: T = Zero::zero();
    let _1: T = One::one();
    _1 / _0
}

/// Dynamically calculates the value `-inf` (`-1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn neg_infinity<T: Num One Zero>() -> T {
    let _0: T = Zero::zero();
    let _1: T = One::one();
    - _1 / _0
}

/// Dynamically calculates the value `NaN` (`0/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn NaN<T: Num Zero>() -> T {
    let _0: T = Zero::zero();
    _0 / _0
}

/// Returns `true` if `num` has the value `inf` (`1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn is_infinity<T: Num One Zero Eq>(num: &T) -> bool {
    (*num) == (infinity::<T>())
}

/// Returns `true` if `num` has the value `-inf` (`-1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn is_neg_infinity<T: Num One Zero Eq>(num: &T) -> bool {
    (*num) == (neg_infinity::<T>())
}

/// Returns `true` if `num` has the value `NaN` (is not equal to itself).
#[inline(always)]
pub pure fn is_NaN<T: Num Eq>(num: &T) -> bool {
    (*num) != (*num)
}

/// Returns `true` if `num` has the value `-0` (`1/num == -1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn is_neg_zero<T: Num One Zero Eq>(num: &T) -> bool {
    let _1: T = One::one();
    let _0: T = Zero::zero();
    *num == _0 && is_neg_infinity(&(_1 / *num))
}

@kud1ing
Copy link

kud1ing commented Feb 5, 2013

Haskell uses a typeclass RealFloat: http://www.bucephalus.org/text/Haskell98numbers/Haskell98numbers.png

@brendanzab
Copy link
Member

Thanks for that, that's very useful.

@Kimundi
Copy link
Member

Kimundi commented Feb 6, 2013

Just as in #4789, as the writer of these functions I'm aware that they are bad solution, but I needed them for being able to handle both integers and floats correctly in the string conversion functions. The problem is simple: If the inf and NaN functions are only reachable for Floats, then the only two options for a function that works with all numbers but has to special case inf and NaN are:

  • Not to require the trait bound, thus not check for them, and because of that possible failing because calculations on inf and NaN don't work like on normal values.
  • Require the trait bound, being able to check for them, thus not being able to use integers numbers even thought the operation would be even safer on them, because the special values don't exist there.

A possible solution might be a 'SpecialValue' trait where NaN, inf and -inf are an Option, depending on whether the numeric type has them or not, but that again would mean unnecessary impls...

Really, maybe I'm being an Idiot here, or not giving it enough time, but I don't see how it's possible with the proposed system to write generic functions that can work with both integers and floats. :(

@kud1ing
Copy link

kud1ing commented Feb 6, 2013

See #4819

@Kimundi
Copy link
Member

Kimundi commented Feb 19, 2013

This can be closed now, those functions got removed again.

@catamorphism
Copy link
Contributor

Fixed in 3edc7c0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants