Skip to content

Commit f39152e

Browse files
committed
Implement Natural trait
This adds the following methods to ints and uints: - div - modulo - div_mod - quot_rem - gcd - lcm - divisible_by - is_even - is_odd I have not implemented Natural for BigInt and BigUInt because they're a little over my head.
1 parent aef2490 commit f39152e

File tree

5 files changed

+335
-2
lines changed

5 files changed

+335
-2
lines changed

src/libcore/core.rc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter};
105105
pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times};
106106
pub use iter::{ExtendedMutableIter};
107107

108-
pub use num::{Num, Signed, Unsigned, NumCast};
108+
pub use num::{Num, Signed, Unsigned, Natural, NumCast};
109109
pub use ptr::Ptr;
110110
pub use to_str::ToStr;
111111
pub use clone::Clone;

src/libcore/num/int-template.rs

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,24 @@ impl Div<T,T> for T {
191191
#[cfg(stage2,notest)]
192192
#[cfg(stage3,notest)]
193193
impl Quot<T,T> for T {
194+
/**
195+
* Returns the integer quotient, truncated towards 0. As this behaviour reflects
196+
* the underlying machine implementation it is more efficient than `Natural::div`.
197+
*
198+
* # Examples
199+
*
200+
* ~~~
201+
* assert!( 8 / 3 == 2);
202+
* assert!( 8 / -3 == -2);
203+
* assert!(-8 / 3 == -2);
204+
* assert!(-8 / -3 == 2);
205+
206+
* assert!( 1 / 2 == 0);
207+
* assert!( 1 / -2 == 0);
208+
* assert!(-1 / 2 == 0);
209+
* assert!(-1 / -2 == 0);
210+
* ~~~
211+
*/
194212
#[inline(always)]
195213
fn quot(&self, other: &T) -> T { *self / *other }
196214
}
@@ -205,6 +223,27 @@ impl Modulo<T,T> for T {
205223
#[cfg(stage2,notest)]
206224
#[cfg(stage3,notest)]
207225
impl Rem<T,T> for T {
226+
/**
227+
* Returns the integer remainder after division, satisfying:
228+
*
229+
* ~~~
230+
* assert!((n / d) * d + (n % d) == n)
231+
* ~~~
232+
*
233+
* # Examples
234+
*
235+
* ~~~
236+
* assert!( 8 % 3 == 2);
237+
* assert!( 8 % -3 == 2);
238+
* assert!(-8 % 3 == -2);
239+
* assert!(-8 % -3 == -2);
240+
241+
* assert!( 1 % 2 == 1);
242+
* assert!( 1 % -2 == 1);
243+
* assert!(-1 % 2 == -1);
244+
* assert!(-1 % -2 == -1);
245+
* ~~~
246+
*/
208247
#[inline(always)]
209248
fn rem(&self, other: &T) -> T { *self % *other }
210249
}
@@ -247,6 +286,123 @@ impl Signed for T {
247286
fn is_negative(&self) -> bool { *self < 0 }
248287
}
249288
289+
impl Natural for T {
290+
/**
291+
* Floored integer division
292+
*
293+
* # Examples
294+
*
295+
* ~~~
296+
* assert!(( 8).div( 3) == 2);
297+
* assert!(( 8).div(-3) == -3);
298+
* assert!((-8).div( 3) == -3);
299+
* assert!((-8).div(-3) == 2);
300+
*
301+
* assert!(( 1).div( 2) == 0);
302+
* assert!(( 1).div(-2) == -1);
303+
* assert!((-1).div( 2) == -1);
304+
* assert!((-1).div(-2) == 0);
305+
* ~~~
306+
*/
307+
#[inline(always)]
308+
fn div(&self, other: T) -> T {
309+
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
310+
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
311+
match self.quot_rem(other) {
312+
(q, r) if (r > 0 && other < 0)
313+
|| (r < 0 && other > 0) => q - 1,
314+
(q, _) => q,
315+
}
316+
}
317+
318+
/**
319+
* Integer modulo, satisfying:
320+
*
321+
* ~~~
322+
* assert!(n.div(d) * d + n.modulo(d) == n)
323+
* ~~~
324+
*
325+
* # Examples
326+
*
327+
* ~~~
328+
* assert!(( 8).modulo( 3) == 2);
329+
* assert!(( 8).modulo(-3) == -1);
330+
* assert!((-8).modulo( 3) == 1);
331+
* assert!((-8).modulo(-3) == -2);
332+
*
333+
* assert!(( 1).modulo( 2) == 1);
334+
* assert!(( 1).modulo(-2) == -1);
335+
* assert!((-1).modulo( 2) == 1);
336+
* assert!((-1).modulo(-2) == -1);
337+
* ~~~
338+
*/
339+
#[inline(always)]
340+
fn modulo(&self, other: T) -> T {
341+
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
342+
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
343+
match *self % other {
344+
r if (r > 0 && other < 0)
345+
|| (r < 0 && other > 0) => r + other,
346+
r => r,
347+
}
348+
}
349+
350+
/// Calculates `div` and `modulo` simultaneously
351+
#[inline(always)]
352+
fn div_mod(&self, other: T) -> (T,T) {
353+
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
354+
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
355+
match self.quot_rem(other) {
356+
(q, r) if (r > 0 && other < 0)
357+
|| (r < 0 && other > 0) => (q - 1, r + other),
358+
(q, r) => (q, r),
359+
}
360+
}
361+
362+
/// Calculates `quot` (`\`) and `rem` (`%`) simultaneously
363+
#[inline(always)]
364+
fn quot_rem(&self, other: T) -> (T,T) {
365+
(*self / other, *self % other)
366+
}
367+
368+
/**
369+
* Calculates the Greatest Common Divisor (GCD) of the number and `other`
370+
*
371+
* The result is always positive
372+
*/
373+
#[inline(always)]
374+
fn gcd(&self, other: T) -> T {
375+
// Use Euclid's algorithm
376+
let mut m = *self, n = other;
377+
while m != 0 {
378+
let temp = m;
379+
m = n % temp;
380+
n = temp;
381+
}
382+
n.abs()
383+
}
384+
385+
/**
386+
* Calculates the Lowest Common Multiple (LCM) of the number and `other`
387+
*/
388+
#[inline(always)]
389+
fn lcm(&self, other: T) -> T {
390+
((*self * other) / self.gcd(other)).abs() // should not have to recaluculate abs
391+
}
392+
393+
/// Returns `true` if the number can be divided by `other` without leaving a remainder
394+
#[inline(always)]
395+
fn divisible_by(&self, other: T) -> bool { *self % other == 0 }
396+
397+
/// Returns `true` if the number is divisible by `2`
398+
#[inline(always)]
399+
fn is_even(&self) -> bool { self.divisible_by(2) }
400+
401+
/// Returns `true` if the number is not divisible by `2`
402+
#[inline(always)]
403+
fn is_odd(&self) -> bool { !self.is_even() }
404+
}
405+
250406
#[cfg(notest)]
251407
impl BitOr<T,T> for T {
252408
#[inline(always)]
@@ -388,6 +544,95 @@ mod tests {
388544
assert!((-1 as T).is_negative());
389545
}
390546
547+
/**
548+
* Checks that the division rule holds for:
549+
*
550+
* - `n`: numerator (dividend)
551+
* - `d`: denominator (divisor)
552+
* - `qr`: quotient and remainder
553+
*/
554+
#[cfg(test)]
555+
fn test_division_rule(nd: (T,T), qr: (T,T)) {
556+
let (n,d) = nd,
557+
(q,r) = qr;
558+
559+
assert_eq!(d * q + r, n);
560+
}
561+
562+
#[test]
563+
fn test_quot_rem() {
564+
fn test_nd_qr(nd: (T,T), qr: (T,T)) {
565+
let (n,d) = nd;
566+
let separate_quot_rem = (n / d, n % d);
567+
let combined_quot_rem = n.quot_rem(d);
568+
569+
assert_eq!(separate_quot_rem, qr);
570+
assert_eq!(combined_quot_rem, qr);
571+
572+
test_division_rule(nd, separate_quot_rem);
573+
test_division_rule(nd, combined_quot_rem);
574+
}
575+
576+
test_nd_qr(( 8, 3), ( 2, 2));
577+
test_nd_qr(( 8, -3), (-2, 2));
578+
test_nd_qr((-8, 3), (-2, -2));
579+
test_nd_qr((-8, -3), ( 2, -2));
580+
581+
test_nd_qr(( 1, 2), ( 0, 1));
582+
test_nd_qr(( 1, -2), ( 0, 1));
583+
test_nd_qr((-1, 2), ( 0, -1));
584+
test_nd_qr((-1, -2), ( 0, -1));
585+
}
586+
587+
#[test]
588+
fn test_div_mod() {
589+
fn test_nd_dm(nd: (T,T), dm: (T,T)) {
590+
let (n,d) = nd;
591+
let separate_div_mod = (n.div(d), n.modulo(d));
592+
let combined_div_mod = n.div_mod(d);
593+
594+
assert_eq!(separate_div_mod, dm);
595+
assert_eq!(combined_div_mod, dm);
596+
597+
test_division_rule(nd, separate_div_mod);
598+
test_division_rule(nd, combined_div_mod);
599+
}
600+
601+
test_nd_dm(( 8, 3), ( 2, 2));
602+
test_nd_dm(( 8, -3), (-3, -1));
603+
test_nd_dm((-8, 3), (-3, 1));
604+
test_nd_dm((-8, -3), ( 2, -2));
605+
606+
test_nd_dm(( 1, 2), ( 0, 1));
607+
test_nd_dm(( 1, -2), (-1, -1));
608+
test_nd_dm((-1, 2), (-1, 1));
609+
test_nd_dm((-1, -2), ( 0, -1));
610+
}
611+
612+
#[test]
613+
fn test_gcd() {
614+
assert_eq!((10 as T).gcd(2), 2 as T);
615+
assert_eq!((10 as T).gcd(3), 1 as T);
616+
assert_eq!((0 as T).gcd(3), 3 as T);
617+
assert_eq!((3 as T).gcd(3), 3 as T);
618+
assert_eq!((56 as T).gcd(42), 14 as T);
619+
assert_eq!((3 as T).gcd(-3), 3 as T);
620+
assert_eq!((-6 as T).gcd(3), 3 as T);
621+
assert_eq!((-4 as T).gcd(-2), 2 as T);
622+
}
623+
624+
#[test]
625+
fn test_lcm() {
626+
assert_eq!((1 as T).lcm(0), 0 as T);
627+
assert_eq!((0 as T).lcm(1), 0 as T);
628+
assert_eq!((1 as T).lcm(1), 1 as T);
629+
assert_eq!((-1 as T).lcm(1), 1 as T);
630+
assert_eq!((1 as T).lcm(-1), 1 as T);
631+
assert_eq!((-1 as T).lcm(-1), 1 as T);
632+
assert_eq!((8 as T).lcm(9), 72 as T);
633+
assert_eq!((11 as T).lcm(5), 55 as T);
634+
}
635+
391636
#[test]
392637
fn test_bitwise_ops() {
393638
assert_eq!(0b1110 as T, (0b1100 as T).bitor(&(0b1010 as T)));

src/libcore/num/num.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,22 @@ pub fn abs<T:Ord + Zero + Neg<T>>(v: T) -> T {
7575
if v < Zero::zero() { v.neg() } else { v }
7676
}
7777

78+
pub trait Natural: Num
79+
+ Ord
80+
+ Quot<Self,Self>
81+
+ Rem<Self,Self> {
82+
fn div(&self, other: Self) -> Self;
83+
fn modulo(&self, other: Self) -> Self;
84+
fn div_mod(&self, other: Self) -> (Self,Self);
85+
fn quot_rem(&self, other: Self) -> (Self,Self);
86+
87+
fn gcd(&self, other: Self) -> Self;
88+
fn lcm(&self, other: Self) -> Self;
89+
fn divisible_by(&self, other: Self) -> bool;
90+
fn is_even(&self) -> bool;
91+
fn is_odd(&self) -> bool;
92+
}
93+
7894
pub trait Round {
7995
fn round(&self, mode: RoundMode) -> Self;
8096

src/libcore/num/uint-template.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,59 @@ impl Neg<T> for T {
184184
185185
impl Unsigned for T {}
186186
187+
impl Natural for T {
188+
/// Unsigned integer division. Returns the same result as `quot` (`/`).
189+
#[inline(always)]
190+
fn div(&self, other: T) -> T { *self / other }
191+
192+
/// Unsigned integer modulo operation. Returns the same result as `rem` (`%`).
193+
#[inline(always)]
194+
fn modulo(&self, other: T) -> T { *self / other }
195+
196+
/// Calculates `div` and `modulo` simultaneously
197+
#[inline(always)]
198+
fn div_mod(&self, other: T) -> (T,T) {
199+
(*self / other, *self % other)
200+
}
201+
202+
/// Calculates `quot` (`\`) and `rem` (`%`) simultaneously
203+
#[inline(always)]
204+
fn quot_rem(&self, other: T) -> (T,T) {
205+
(*self / other, *self % other)
206+
}
207+
208+
/// Calculates the Greatest Common Divisor (GCD) of the number and `other`
209+
#[inline(always)]
210+
fn gcd(&self, other: T) -> T {
211+
// Use Euclid's algorithm
212+
let mut m = *self, n = other;
213+
while m != 0 {
214+
let temp = m;
215+
m = n % temp;
216+
n = temp;
217+
}
218+
n
219+
}
220+
221+
/// Calculates the Lowest Common Multiple (LCM) of the number and `other`
222+
#[inline(always)]
223+
fn lcm(&self, other: T) -> T {
224+
(*self * other) / self.gcd(other)
225+
}
226+
227+
/// Returns `true` if the number can be divided by `other` without leaving a remainder
228+
#[inline(always)]
229+
fn divisible_by(&self, other: T) -> bool { *self % other == 0 }
230+
231+
/// Returns `true` if the number is divisible by `2`
232+
#[inline(always)]
233+
fn is_even(&self) -> bool { self.divisible_by(2) }
234+
235+
/// Returns `true` if the number is not divisible by `2`
236+
#[inline(always)]
237+
fn is_odd(&self) -> bool { !self.is_even() }
238+
}
239+
187240
#[cfg(notest)]
188241
impl BitOr<T,T> for T {
189242
#[inline(always)]
@@ -303,6 +356,25 @@ mod tests {
303356
use super::inst::T;
304357
use prelude::*;
305358
359+
#[test]
360+
fn test_gcd() {
361+
assert_eq!((10 as T).gcd(2), 2 as T);
362+
assert_eq!((10 as T).gcd(3), 1 as T);
363+
assert_eq!((0 as T).gcd(3), 3 as T);
364+
assert_eq!((3 as T).gcd(3), 3 as T);
365+
assert_eq!((56 as T).gcd(42), 14 as T);
366+
}
367+
368+
#[test]
369+
fn test_lcm() {
370+
assert_eq!((1 as T).lcm(0), 0 as T);
371+
assert_eq!((0 as T).lcm(1), 0 as T);
372+
assert_eq!((1 as T).lcm(1), 1 as T);
373+
assert_eq!((8 as T).lcm(9), 72 as T);
374+
assert_eq!((11 as T).lcm(5), 55 as T);
375+
assert_eq!((99 as T).lcm(17), 1683 as T);
376+
}
377+
306378
#[test]
307379
fn test_bitwise_ops() {
308380
assert_eq!(0b1110 as T, (0b1100 as T).bitor(&(0b1010 as T)));

src/libcore/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub use hash::Hash;
3939
pub use iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter};
4040
pub use iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter};
4141
pub use iter::{Times, ExtendedMutableIter};
42-
pub use num::{Num, Signed, Unsigned, NumCast};
42+
pub use num::{Num, Signed, Unsigned, Natural, NumCast};
4343
pub use path::GenericPath;
4444
pub use path::Path;
4545
pub use path::PosixPath;

0 commit comments

Comments
 (0)