@@ -33,7 +33,7 @@ use std::str::FromStr;
33
33
use bigint:: { BigInt , BigUint , Sign } ;
34
34
35
35
use integer:: Integer ;
36
- use traits:: { FromPrimitive , Float , PrimInt , Num , Signed , Zero , One , Bounded , NumCast } ;
36
+ use traits:: { FromPrimitive , Float , PrimInt , Num , Signed , Zero , One , Bounded , NumCast , CheckedAdd , CheckedSub , CheckedMul , CheckedDiv } ;
37
37
38
38
/// Represents the ratio between 2 numbers.
39
39
#[ derive( Copy , Clone , Debug ) ]
@@ -442,7 +442,7 @@ impl<'a, 'b, T> Div<&'b Ratio<T>> for &'a Ratio<T>
442
442
}
443
443
}
444
444
445
- // Abstracts the a/b `op` c/d = (a*d `op` b*d ) / (b*d) pattern
445
+ // Abstracts the a/b `op` c/d = (a*d `op` b*c ) / (b*d) pattern
446
446
macro_rules! arith_impl {
447
447
( impl $imp: ident, $method: ident) => {
448
448
forward_all_binop!( impl $imp, $method) ;
@@ -467,6 +467,53 @@ arith_impl!(impl Sub, sub);
467
467
// a/b % c/d = (a*d % b*c)/(b*d)
468
468
arith_impl ! ( impl Rem , rem) ;
469
469
470
+ // a/b * c/d = (a*c)/(b*d)
471
+ impl < T > CheckedMul for Ratio < T >
472
+ where T : Clone + Integer + CheckedMul
473
+ {
474
+ #[ inline]
475
+ fn checked_mul ( & self , rhs : & Ratio < T > ) -> Option < Ratio < T > > {
476
+ Some ( Ratio :: new ( self . numer . checked_mul ( & rhs. numer ) ?,
477
+ self . denom . checked_mul ( & rhs. denom ) ?) )
478
+ }
479
+ }
480
+
481
+ // (a/b) / (c/d) = (a*d)/(b*c)
482
+ impl < T > CheckedDiv for Ratio < T >
483
+ where T : Clone + Integer + CheckedMul
484
+ {
485
+ #[ inline]
486
+ fn checked_div ( & self , rhs : & Ratio < T > ) -> Option < Ratio < T > > {
487
+ let bc = self . denom . checked_mul ( & rhs. numer ) ?;
488
+ if bc. is_zero ( ) {
489
+ None
490
+ } else {
491
+ Some ( Ratio :: new ( self . numer . checked_mul ( & rhs. denom ) ?, bc) )
492
+ }
493
+ }
494
+ }
495
+
496
+ // As arith_impl! but for Checked{Add,Sub} traits
497
+ macro_rules! checked_arith_impl {
498
+ ( impl $imp: ident, $method: ident) => {
499
+ impl <T : Clone + Integer + CheckedMul + $imp> $imp for Ratio <T > {
500
+ #[ inline]
501
+ fn $method( & self , rhs: & Ratio <T >) -> Option <Ratio <T >> {
502
+ let ad = self . numer. checked_mul( & rhs. denom) ?;
503
+ let bc = self . denom. checked_mul( & rhs. numer) ?;
504
+ let bd = self . denom. checked_mul( & rhs. denom) ?;
505
+ Some ( Ratio :: new( ad. $method( & bc) ?, bd) )
506
+ }
507
+ }
508
+ }
509
+ }
510
+
511
+ // a/b + c/d = (a*d + b*c)/(b*d)
512
+ checked_arith_impl ! ( impl CheckedAdd , checked_add) ;
513
+
514
+ // a/b - c/d = (a*d - b*c)/(b*d)
515
+ checked_arith_impl ! ( impl CheckedSub , checked_sub) ;
516
+
470
517
impl < T > Neg for Ratio < T >
471
518
where T : Clone + Integer + Neg < Output = T >
472
519
{
@@ -1102,12 +1149,15 @@ mod test {
1102
1149
mod arith {
1103
1150
use super :: { _0, _1, _2, _1_2, _3_2, _NEG1_2, to_big} ;
1104
1151
use super :: super :: { Ratio , Rational } ;
1152
+ use traits:: { CheckedAdd , CheckedSub , CheckedMul , CheckedDiv } ;
1105
1153
1106
1154
#[ test]
1107
1155
fn test_add ( ) {
1108
1156
fn test ( a : Rational , b : Rational , c : Rational ) {
1109
1157
assert_eq ! ( a + b, c) ;
1110
1158
assert_eq ! ( to_big( a) + to_big( b) , to_big( c) ) ;
1159
+ assert_eq ! ( a. checked_add( & b) , Some ( c) ) ;
1160
+ assert_eq ! ( to_big( a) . checked_add( & to_big( b) ) , Some ( to_big( c) ) ) ;
1111
1161
}
1112
1162
1113
1163
test ( _1, _1_2, _3_2) ;
@@ -1120,7 +1170,9 @@ mod test {
1120
1170
fn test_sub ( ) {
1121
1171
fn test ( a : Rational , b : Rational , c : Rational ) {
1122
1172
assert_eq ! ( a - b, c) ;
1123
- assert_eq ! ( to_big( a) - to_big( b) , to_big( c) )
1173
+ assert_eq ! ( to_big( a) - to_big( b) , to_big( c) ) ;
1174
+ assert_eq ! ( a. checked_sub( & b) , Some ( c) ) ;
1175
+ assert_eq ! ( to_big( a) . checked_sub( & to_big( b) ) , Some ( to_big( c) ) ) ;
1124
1176
}
1125
1177
1126
1178
test ( _1, _1_2, _1_2) ;
@@ -1132,7 +1184,9 @@ mod test {
1132
1184
fn test_mul ( ) {
1133
1185
fn test ( a : Rational , b : Rational , c : Rational ) {
1134
1186
assert_eq ! ( a * b, c) ;
1135
- assert_eq ! ( to_big( a) * to_big( b) , to_big( c) )
1187
+ assert_eq ! ( to_big( a) * to_big( b) , to_big( c) ) ;
1188
+ assert_eq ! ( a. checked_mul( & b) , Some ( c) ) ;
1189
+ assert_eq ! ( to_big( a) . checked_mul( & to_big( b) ) , Some ( to_big( c) ) ) ;
1136
1190
}
1137
1191
1138
1192
test ( _1, _1_2, _1_2) ;
@@ -1144,7 +1198,9 @@ mod test {
1144
1198
fn test_div ( ) {
1145
1199
fn test ( a : Rational , b : Rational , c : Rational ) {
1146
1200
assert_eq ! ( a / b, c) ;
1147
- assert_eq ! ( to_big( a) / to_big( b) , to_big( c) )
1201
+ assert_eq ! ( to_big( a) / to_big( b) , to_big( c) ) ;
1202
+ assert_eq ! ( a. checked_div( & b) , Some ( c) ) ;
1203
+ assert_eq ! ( to_big( a) . checked_div( & to_big( b) ) , Some ( to_big( c) ) ) ;
1148
1204
}
1149
1205
1150
1206
test ( _1, _1_2, _2) ;
@@ -1188,6 +1244,17 @@ mod test {
1188
1244
fn test_div_0 ( ) {
1189
1245
let _a = _1 / _0;
1190
1246
}
1247
+
1248
+ #[ test]
1249
+ fn test_checked_failures ( ) {
1250
+ let big = Ratio :: new ( 128u8 , 1 ) ;
1251
+ let small = Ratio :: new ( 1 , 128u8 ) ;
1252
+ assert_eq ! ( big. checked_add( & big) , None ) ;
1253
+ assert_eq ! ( small. checked_sub( & big) , None ) ;
1254
+ assert_eq ! ( big. checked_mul( & big) , None ) ;
1255
+ assert_eq ! ( small. checked_div( & big) , None ) ;
1256
+ assert_eq ! ( _1. checked_div( & _0) , None ) ;
1257
+ }
1191
1258
}
1192
1259
1193
1260
#[ test]
0 commit comments