Skip to content

Commit ac69ee4

Browse files
committed
auto merge of #6048 : bjz/rust/numeric-traits, r=pcwalton
As part of the numeric trait reform (see issue #4819), I have added the following traits to `core::num` and implemented them for floating point types: ~~~rust pub trait Round { fn floor(&self) -> Self; fn ceil(&self) -> Self; fn round(&self) -> Self; fn trunc(&self) -> Self; fn fract(&self) -> Self; } pub trait Fractional: Num + Ord + Round + Quot<Self,Self> { fn recip(&self) -> Self; } pub trait Real: Signed + Fractional { // Common Constants 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 log_2() -> Self; fn log_10() -> Self; // Exponential functions fn pow(&self, n: Self) -> Self; fn exp(&self) -> Self; fn exp2(&self) -> Self; fn expm1(&self) -> Self; fn ldexp(&self, n: int) -> Self; fn log(&self) -> Self; fn log2(&self) -> Self; fn log10(&self) -> Self; fn log_radix(&self) -> Self; fn ilog_radix(&self) -> int; fn sqrt(&self) -> Self; fn rsqrt(&self) -> Self; fn cbrt(&self) -> Self; // Angular conversions fn to_degrees(&self) -> Self; fn to_radians(&self) -> Self; // Triganomic functions fn hypot(&self, other: Self) -> Self; fn sin(&self) -> Self; fn cos(&self) -> Self; fn tan(&self) -> Self; // Inverse triganomic functions fn asin(&self) -> Self; fn acos(&self) -> Self; fn atan(&self) -> Self; fn atan2(&self, other: Self) -> Self; // Hyperbolic triganomic functions fn sinh(&self) -> Self; fn cosh(&self) -> Self; fn tanh(&self) -> Self; } /// Methods that are harder to implement and not commonly used. pub trait RealExt: Real { // Gamma functions fn lgamma(&self) -> (int, Self); fn tgamma(&self) -> Self; // Bessel functions fn j0(&self) -> Self; fn j1(&self) -> Self; fn jn(&self, n: int) -> Self; fn y0(&self) -> Self; fn y1(&self) -> Self; fn yn(&self, n: int) -> Self; } ~~~ The constants in `Real` could be [associated items](http://smallcultfollowing.com/babysteps/blog/2013/04/03/associated-items-continued/) in the future (see issue #5527). At the moment I have left the constants in `{float|f32|f64}::consts` in case folks need to access these at compile time. There are also instances of `int` in `Real` and `RealExt`. In the future these could be replaced with an associated `INTEGER` type on `Real`. `Natural` has also been renamed to `Integer`. This is because `Natural` normally means 'positive integer' in mathematics. It is therefore strange to implement it on signed integer types. `Integer` is probably a better choice. I have also switched some of the `Integer` methods to take borrowed pointers as arguments. This brings them in line with the `Quot` and `Rem` traits, and is be better for large Integer types like `BigInt` and `BigUint` because they don't need to be copied unnecessarily. There has also been considerable discussion on the mailing list and IRC about the renaming of the `Div` and `Modulo` traits to `Quot` and `Rem`. Depending on the outcome of these discussions they might be renamed again.
2 parents 1d53bab + 225ac21 commit ac69ee4

File tree

12 files changed

+1148
-319
lines changed

12 files changed

+1148
-319
lines changed

Diff for: src/libcore/core.rc

+4-4
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,7 @@ pub use kinds::{Const, Copy, Owned, Durable};
7777
pub use ops::{Drop};
7878
#[cfg(stage0)]
7979
pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not};
80-
#[cfg(stage1)]
81-
#[cfg(stage2)]
82-
#[cfg(stage3)]
80+
#[cfg(not(stage0))]
8381
pub use ops::{Add, Sub, Mul, Quot, Rem, Neg, Not};
8482
pub use ops::{BitAnd, BitOr, BitXor};
8583
pub use ops::{Shl, Shr, Index};
@@ -105,7 +103,9 @@ pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter};
105103
pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times};
106104
pub use iter::{ExtendedMutableIter};
107105

108-
pub use num::{Num, Signed, Unsigned, Natural, NumCast};
106+
pub use num::{Num, NumCast};
107+
pub use num::{Signed, Unsigned, Integer};
108+
pub use num::{Round, Fractional, Real, RealExt};
109109
pub use ptr::Ptr;
110110
pub use to_str::ToStr;
111111
pub use clone::Clone;

Diff for: src/libcore/num/f32.rs

+289-41
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,10 @@
1010

1111
//! Operations and constants for `f32`
1212
13-
use num::strconv;
14-
use num::Signed;
15-
use num;
16-
use option::Option;
1713
use from_str;
18-
use to_str;
19-
20-
#[cfg(notest)] use cmp::{Eq, Ord};
21-
#[cfg(stage0,notest)]
22-
use ops::{Add, Sub, Mul, Div, Modulo, Neg};
23-
#[cfg(stage1,notest)]
24-
#[cfg(stage2,notest)]
25-
#[cfg(stage3,notest)]
26-
use ops::{Add, Sub, Mul, Quot, Rem, Neg};
14+
use libc::c_int;
15+
use num::strconv;
16+
use prelude::*;
2717

2818
pub use cmath::c_float_targ_consts::*;
2919

@@ -233,6 +223,8 @@ pub fn logarithm(n: f32, b: f32) -> f32 {
233223
return log2(n) / log2(b);
234224
}
235225

226+
impl Num for f32 {}
227+
236228
#[cfg(notest)]
237229
impl Eq for f32 {
238230
#[inline(always)]
@@ -286,10 +278,7 @@ impl Div<f32,f32> for f32 {
286278
#[inline(always)]
287279
fn div(&self, other: &f32) -> f32 { *self / *other }
288280
}
289-
290-
#[cfg(stage1,notest)]
291-
#[cfg(stage2,notest)]
292-
#[cfg(stage3,notest)]
281+
#[cfg(not(stage0),notest)]
293282
impl Quot<f32,f32> for f32 {
294283
#[inline(always)]
295284
fn quot(&self, other: &f32) -> f32 { *self / *other }
@@ -300,10 +289,7 @@ impl Modulo<f32,f32> for f32 {
300289
#[inline(always)]
301290
fn modulo(&self, other: &f32) -> f32 { *self % *other }
302291
}
303-
304-
#[cfg(stage1,notest)]
305-
#[cfg(stage2,notest)]
306-
#[cfg(stage3,notest)]
292+
#[cfg(not(stage0),notest)]
307293
impl Rem<f32,f32> for f32 {
308294
#[inline(always)]
309295
fn rem(&self, other: &f32) -> f32 { *self % *other }
@@ -341,31 +327,188 @@ impl Signed for f32 {
341327
fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity }
342328
}
343329

344-
impl num::Round for f32 {
345-
#[inline(always)]
346-
fn round(&self, mode: num::RoundMode) -> f32 {
347-
match mode {
348-
num::RoundDown => floor(*self),
349-
num::RoundUp => ceil(*self),
350-
num::RoundToZero if self.is_negative() => ceil(*self),
351-
num::RoundToZero => floor(*self),
352-
num::RoundFromZero if self.is_negative() => floor(*self),
353-
num::RoundFromZero => ceil(*self)
354-
}
355-
}
356-
330+
impl Round for f32 {
331+
/// Round half-way cases toward `neg_infinity`
357332
#[inline(always)]
358333
fn floor(&self) -> f32 { floor(*self) }
334+
335+
/// Round half-way cases toward `infinity`
359336
#[inline(always)]
360337
fn ceil(&self) -> f32 { ceil(*self) }
338+
339+
/// Round half-way cases away from `0.0`
361340
#[inline(always)]
362-
fn fract(&self) -> f32 {
363-
if self.is_negative() {
364-
(*self) - ceil(*self)
365-
} else {
366-
(*self) - floor(*self)
367-
}
368-
}
341+
fn round(&self) -> f32 { round(*self) }
342+
343+
/// The integer part of the number (rounds towards `0.0`)
344+
#[inline(always)]
345+
fn trunc(&self) -> f32 { trunc(*self) }
346+
347+
///
348+
/// The fractional part of the number, satisfying:
349+
///
350+
/// ~~~
351+
/// assert!(x == trunc(x) + fract(x))
352+
/// ~~~
353+
///
354+
#[inline(always)]
355+
fn fract(&self) -> f32 { *self - self.trunc() }
356+
}
357+
358+
impl Fractional for f32 {
359+
/// The reciprocal (multiplicative inverse) of the number
360+
#[inline(always)]
361+
fn recip(&self) -> f32 { 1.0 / *self }
362+
}
363+
364+
impl Real for f32 {
365+
/// Archimedes' constant
366+
#[inline(always)]
367+
fn pi() -> f32 { 3.14159265358979323846264338327950288 }
368+
369+
/// 2.0 * pi
370+
#[inline(always)]
371+
fn two_pi() -> f32 { 6.28318530717958647692528676655900576 }
372+
373+
/// pi / 2.0
374+
#[inline(always)]
375+
fn frac_pi_2() -> f32 { 1.57079632679489661923132169163975144 }
376+
377+
/// pi / 3.0
378+
#[inline(always)]
379+
fn frac_pi_3() -> f32 { 1.04719755119659774615421446109316763 }
380+
381+
/// pi / 4.0
382+
#[inline(always)]
383+
fn frac_pi_4() -> f32 { 0.785398163397448309615660845819875721 }
384+
385+
/// pi / 6.0
386+
#[inline(always)]
387+
fn frac_pi_6() -> f32 { 0.52359877559829887307710723054658381 }
388+
389+
/// pi / 8.0
390+
#[inline(always)]
391+
fn frac_pi_8() -> f32 { 0.39269908169872415480783042290993786 }
392+
393+
/// 1 .0/ pi
394+
#[inline(always)]
395+
fn frac_1_pi() -> f32 { 0.318309886183790671537767526745028724 }
396+
397+
/// 2.0 / pi
398+
#[inline(always)]
399+
fn frac_2_pi() -> f32 { 0.636619772367581343075535053490057448 }
400+
401+
/// 2.0 / sqrt(pi)
402+
#[inline(always)]
403+
fn frac_2_sqrtpi() -> f32 { 1.12837916709551257389615890312154517 }
404+
405+
/// sqrt(2.0)
406+
#[inline(always)]
407+
fn sqrt2() -> f32 { 1.41421356237309504880168872420969808 }
408+
409+
/// 1.0 / sqrt(2.0)
410+
#[inline(always)]
411+
fn frac_1_sqrt2() -> f32 { 0.707106781186547524400844362104849039 }
412+
413+
/// Euler's number
414+
#[inline(always)]
415+
fn e() -> f32 { 2.71828182845904523536028747135266250 }
416+
417+
/// log2(e)
418+
#[inline(always)]
419+
fn log2_e() -> f32 { 1.44269504088896340735992468100189214 }
420+
421+
/// log10(e)
422+
#[inline(always)]
423+
fn log10_e() -> f32 { 0.434294481903251827651128918916605082 }
424+
425+
/// log(2.0)
426+
#[inline(always)]
427+
fn log_2() -> f32 { 0.693147180559945309417232121458176568 }
428+
429+
/// log(10.0)
430+
#[inline(always)]
431+
fn log_10() -> f32 { 2.30258509299404568401799145468436421 }
432+
433+
#[inline(always)]
434+
fn pow(&self, n: f32) -> f32 { pow(*self, n) }
435+
436+
#[inline(always)]
437+
fn exp(&self) -> f32 { exp(*self) }
438+
439+
#[inline(always)]
440+
fn exp2(&self) -> f32 { exp2(*self) }
441+
442+
#[inline(always)]
443+
fn expm1(&self) -> f32 { expm1(*self) }
444+
445+
#[inline(always)]
446+
fn ldexp(&self, n: int) -> f32 { ldexp(*self, n as c_int) }
447+
448+
#[inline(always)]
449+
fn log(&self) -> f32 { ln(*self) }
450+
451+
#[inline(always)]
452+
fn log2(&self) -> f32 { log2(*self) }
453+
454+
#[inline(always)]
455+
fn log10(&self) -> f32 { log10(*self) }
456+
457+
#[inline(always)]
458+
fn log_radix(&self) -> f32 { log_radix(*self) as f32 }
459+
460+
#[inline(always)]
461+
fn ilog_radix(&self) -> int { ilog_radix(*self) as int }
462+
463+
#[inline(always)]
464+
fn sqrt(&self) -> f32 { sqrt(*self) }
465+
466+
#[inline(always)]
467+
fn rsqrt(&self) -> f32 { self.sqrt().recip() }
468+
469+
#[inline(always)]
470+
fn cbrt(&self) -> f32 { cbrt(*self) }
471+
472+
/// Converts to degrees, assuming the number is in radians
473+
#[inline(always)]
474+
fn to_degrees(&self) -> f32 { *self * (180.0 / Real::pi::<f32>()) }
475+
476+
/// Converts to radians, assuming the number is in degrees
477+
#[inline(always)]
478+
fn to_radians(&self) -> f32 { *self * (Real::pi::<f32>() / 180.0) }
479+
480+
#[inline(always)]
481+
fn hypot(&self, other: f32) -> f32 { hypot(*self, other) }
482+
483+
#[inline(always)]
484+
fn sin(&self) -> f32 { sin(*self) }
485+
486+
#[inline(always)]
487+
fn cos(&self) -> f32 { cos(*self) }
488+
489+
#[inline(always)]
490+
fn tan(&self) -> f32 { tan(*self) }
491+
492+
#[inline(always)]
493+
fn asin(&self) -> f32 { asin(*self) }
494+
495+
#[inline(always)]
496+
fn acos(&self) -> f32 { acos(*self) }
497+
498+
#[inline(always)]
499+
fn atan(&self) -> f32 { atan(*self) }
500+
501+
#[inline(always)]
502+
fn atan2(&self, other: f32) -> f32 { atan2(*self, other) }
503+
504+
#[inline(always)]
505+
fn sinh(&self) -> f32 { sinh(*self) }
506+
507+
#[inline(always)]
508+
fn cosh(&self) -> f32 { cosh(*self) }
509+
510+
#[inline(always)]
511+
fn tanh(&self) -> f32 { tanh(*self) }
369512
}
370513

371514
/**
@@ -588,6 +731,111 @@ impl num::FromStrRadix for f32 {
588731
#[cfg(test)]
589732
mod tests {
590733
use f32::*;
734+
use super::*;
735+
use prelude::*;
736+
737+
macro_rules! assert_fuzzy_eq(
738+
($a:expr, $b:expr) => ({
739+
let a = $a, b = $b;
740+
if !((a - b).abs() < 1.0e-6) {
741+
fail!(fmt!("The values were not approximately equal. Found: %? and %?", a, b));
742+
}
743+
})
744+
)
745+
746+
#[test]
747+
fn test_num() {
748+
num::test_num(10f32, 2f32);
749+
}
750+
751+
#[test]
752+
fn test_floor() {
753+
assert_fuzzy_eq!(1.0f32.floor(), 1.0f32);
754+
assert_fuzzy_eq!(1.3f32.floor(), 1.0f32);
755+
assert_fuzzy_eq!(1.5f32.floor(), 1.0f32);
756+
assert_fuzzy_eq!(1.7f32.floor(), 1.0f32);
757+
assert_fuzzy_eq!(0.0f32.floor(), 0.0f32);
758+
assert_fuzzy_eq!((-0.0f32).floor(), -0.0f32);
759+
assert_fuzzy_eq!((-1.0f32).floor(), -1.0f32);
760+
assert_fuzzy_eq!((-1.3f32).floor(), -2.0f32);
761+
assert_fuzzy_eq!((-1.5f32).floor(), -2.0f32);
762+
assert_fuzzy_eq!((-1.7f32).floor(), -2.0f32);
763+
}
764+
765+
#[test]
766+
fn test_ceil() {
767+
assert_fuzzy_eq!(1.0f32.ceil(), 1.0f32);
768+
assert_fuzzy_eq!(1.3f32.ceil(), 2.0f32);
769+
assert_fuzzy_eq!(1.5f32.ceil(), 2.0f32);
770+
assert_fuzzy_eq!(1.7f32.ceil(), 2.0f32);
771+
assert_fuzzy_eq!(0.0f32.ceil(), 0.0f32);
772+
assert_fuzzy_eq!((-0.0f32).ceil(), -0.0f32);
773+
assert_fuzzy_eq!((-1.0f32).ceil(), -1.0f32);
774+
assert_fuzzy_eq!((-1.3f32).ceil(), -1.0f32);
775+
assert_fuzzy_eq!((-1.5f32).ceil(), -1.0f32);
776+
assert_fuzzy_eq!((-1.7f32).ceil(), -1.0f32);
777+
}
778+
779+
#[test]
780+
fn test_round() {
781+
assert_fuzzy_eq!(1.0f32.round(), 1.0f32);
782+
assert_fuzzy_eq!(1.3f32.round(), 1.0f32);
783+
assert_fuzzy_eq!(1.5f32.round(), 2.0f32);
784+
assert_fuzzy_eq!(1.7f32.round(), 2.0f32);
785+
assert_fuzzy_eq!(0.0f32.round(), 0.0f32);
786+
assert_fuzzy_eq!((-0.0f32).round(), -0.0f32);
787+
assert_fuzzy_eq!((-1.0f32).round(), -1.0f32);
788+
assert_fuzzy_eq!((-1.3f32).round(), -1.0f32);
789+
assert_fuzzy_eq!((-1.5f32).round(), -2.0f32);
790+
assert_fuzzy_eq!((-1.7f32).round(), -2.0f32);
791+
}
792+
793+
#[test]
794+
fn test_trunc() {
795+
assert_fuzzy_eq!(1.0f32.trunc(), 1.0f32);
796+
assert_fuzzy_eq!(1.3f32.trunc(), 1.0f32);
797+
assert_fuzzy_eq!(1.5f32.trunc(), 1.0f32);
798+
assert_fuzzy_eq!(1.7f32.trunc(), 1.0f32);
799+
assert_fuzzy_eq!(0.0f32.trunc(), 0.0f32);
800+
assert_fuzzy_eq!((-0.0f32).trunc(), -0.0f32);
801+
assert_fuzzy_eq!((-1.0f32).trunc(), -1.0f32);
802+
assert_fuzzy_eq!((-1.3f32).trunc(), -1.0f32);
803+
assert_fuzzy_eq!((-1.5f32).trunc(), -1.0f32);
804+
assert_fuzzy_eq!((-1.7f32).trunc(), -1.0f32);
805+
}
806+
807+
#[test]
808+
fn test_fract() {
809+
assert_fuzzy_eq!(1.0f32.fract(), 0.0f32);
810+
assert_fuzzy_eq!(1.3f32.fract(), 0.3f32);
811+
assert_fuzzy_eq!(1.5f32.fract(), 0.5f32);
812+
assert_fuzzy_eq!(1.7f32.fract(), 0.7f32);
813+
assert_fuzzy_eq!(0.0f32.fract(), 0.0f32);
814+
assert_fuzzy_eq!((-0.0f32).fract(), -0.0f32);
815+
assert_fuzzy_eq!((-1.0f32).fract(), -0.0f32);
816+
assert_fuzzy_eq!((-1.3f32).fract(), -0.3f32);
817+
assert_fuzzy_eq!((-1.5f32).fract(), -0.5f32);
818+
assert_fuzzy_eq!((-1.7f32).fract(), -0.7f32);
819+
}
820+
821+
#[test]
822+
fn test_real_consts() {
823+
assert_fuzzy_eq!(Real::two_pi::<f32>(), 2f32 * Real::pi::<f32>());
824+
assert_fuzzy_eq!(Real::frac_pi_2::<f32>(), Real::pi::<f32>() / 2f32);
825+
assert_fuzzy_eq!(Real::frac_pi_3::<f32>(), Real::pi::<f32>() / 3f32);
826+
assert_fuzzy_eq!(Real::frac_pi_4::<f32>(), Real::pi::<f32>() / 4f32);
827+
assert_fuzzy_eq!(Real::frac_pi_6::<f32>(), Real::pi::<f32>() / 6f32);
828+
assert_fuzzy_eq!(Real::frac_pi_8::<f32>(), Real::pi::<f32>() / 8f32);
829+
assert_fuzzy_eq!(Real::frac_1_pi::<f32>(), 1f32 / Real::pi::<f32>());
830+
assert_fuzzy_eq!(Real::frac_2_pi::<f32>(), 2f32 / Real::pi::<f32>());
831+
assert_fuzzy_eq!(Real::frac_2_sqrtpi::<f32>(), 2f32 / Real::pi::<f32>().sqrt());
832+
assert_fuzzy_eq!(Real::sqrt2::<f32>(), 2f32.sqrt());
833+
assert_fuzzy_eq!(Real::frac_1_sqrt2::<f32>(), 1f32 / 2f32.sqrt());
834+
assert_fuzzy_eq!(Real::log2_e::<f32>(), Real::e::<f32>().log2());
835+
assert_fuzzy_eq!(Real::log10_e::<f32>(), Real::e::<f32>().log10());
836+
assert_fuzzy_eq!(Real::log_2::<f32>(), 2f32.log());
837+
assert_fuzzy_eq!(Real::log_10::<f32>(), 10f32.log());
838+
}
591839

592840
#[test]
593841
pub fn test_signed() {

0 commit comments

Comments
 (0)