@@ -1391,7 +1391,12 @@ macro_rules! to_primitive_small {
13911391 }
13921392
13931393 fn to_f64( & self ) -> Option <f64 > {
1394- Some ( self . numer. to_f64( ) . unwrap( ) / self . denom. to_f64( ) . unwrap( ) )
1394+ let float = self . numer. to_f64( ) . unwrap( ) / self . denom. to_f64( ) . unwrap( ) ;
1395+ if float. is_nan( ) {
1396+ None
1397+ } else {
1398+ Some ( float)
1399+ }
13951400 }
13961401 }
13971402 ) * )
@@ -1424,10 +1429,15 @@ macro_rules! to_primitive_64 {
14241429 }
14251430
14261431 fn to_f64( & self ) -> Option <f64 > {
1427- Some ( ratio_to_f64(
1432+ let float = ratio_to_f64(
14281433 self . numer as i128 ,
14291434 self . denom as i128
1430- ) )
1435+ ) ;
1436+ if float. is_nan( ) {
1437+ None
1438+ } else {
1439+ Some ( float)
1440+ }
14311441 }
14321442 }
14331443 ) * )
@@ -1458,16 +1468,21 @@ impl<T: Clone + Integer + ToPrimitive + ToBigInt> ToPrimitive for Ratio<T> {
14581468 }
14591469
14601470 fn to_f64 ( & self ) -> Option < f64 > {
1461- match ( self . numer . to_i64 ( ) , self . denom . to_i64 ( ) ) {
1462- ( Some ( numer) , Some ( denom) ) => Some ( ratio_to_f64 (
1471+ let float = match ( self . numer . to_i64 ( ) , self . denom . to_i64 ( ) ) {
1472+ ( Some ( numer) , Some ( denom) ) => ratio_to_f64 (
14631473 <i128 as From < _ > >:: from ( numer) ,
14641474 <i128 as From < _ > >:: from ( denom) ,
1465- ) ) ,
1475+ ) ,
14661476 _ => {
14671477 let numer: BigInt = self . numer . to_bigint ( ) ?;
14681478 let denom: BigInt = self . denom . to_bigint ( ) ?;
1469- Some ( ratio_to_f64 ( numer, denom) )
1479+ ratio_to_f64 ( numer, denom)
14701480 }
1481+ } ;
1482+ if float. is_nan ( ) {
1483+ None
1484+ } else {
1485+ Some ( float)
14711486 }
14721487 }
14731488}
@@ -1507,10 +1522,9 @@ fn ratio_to_f64<T: Bits + Clone + Integer + Signed + ShlAssign<usize> + ToPrimit
15071522 const MAX_EXACT_INT : i64 = 1i64 << core:: f64:: MANTISSA_DIGITS ;
15081523 const MIN_EXACT_INT : i64 = -MAX_EXACT_INT ;
15091524
1510- let flo_sign = numer. signum ( ) . to_f64 ( ) . unwrap ( ) * denom. signum ( ) . to_f64 ( ) . unwrap ( ) ;
1511-
1512- if numer. is_zero ( ) {
1513- return 0.0 * flo_sign;
1525+ let flo_sign = numer. signum ( ) . to_f64 ( ) . unwrap ( ) / denom. signum ( ) . to_f64 ( ) . unwrap ( ) ;
1526+ if !flo_sign. is_normal ( ) {
1527+ return flo_sign;
15141528 }
15151529
15161530 // Fast track: both sides can losslessly be converted to f64s. In this case, letting the
@@ -2899,47 +2913,67 @@ mod test {
28992913 . unwrap( ) ,
29002914 "3" . parse( ) . unwrap( )
29012915 )
2902- . to_f64( )
2903- . unwrap( ) ,
2904- 411522630329218100000000000000000000000000000f64
2916+ . to_f64( ) ,
2917+ Some ( 411522630329218100000000000000000000000000000f64 )
2918+ ) ;
2919+ assert_eq ! (
2920+ BigRational :: new( BigInt :: one( ) , BigInt :: one( ) << 1050 ) . to_f64( ) ,
2921+ Some ( 0f64 )
29052922 ) ;
29062923 assert_eq ! (
2907- BigRational :: new( 1 . into( ) , BigInt :: one( ) << 1050 , )
2908- . to_f64( )
2909- . unwrap( ) ,
2910- 0f64
2924+ BigRational :: from( BigInt :: one( ) << 1050 ) . to_f64( ) ,
2925+ Some ( core:: f64 :: INFINITY )
2926+ ) ;
2927+ assert_eq ! (
2928+ BigRational :: from( ( -BigInt :: one( ) ) << 1050 ) . to_f64( ) ,
2929+ Some ( core:: f64 :: NEG_INFINITY )
29112930 ) ;
29122931 assert_eq ! (
29132932 BigRational :: new(
29142933 "1234567890987654321234567890" . parse( ) . unwrap( ) ,
29152934 "987654321234567890987654321" . parse( ) . unwrap( )
29162935 )
2917- . to_f64( )
2918- . unwrap( ) ,
2919- 1.2499999893125f64
2936+ . to_f64( ) ,
2937+ Some ( 1.2499999893125f64 )
2938+ ) ;
2939+ assert_eq ! (
2940+ BigRational :: new_raw( BigInt :: one( ) , BigInt :: zero( ) ) . to_f64( ) ,
2941+ Some ( core:: f64 :: INFINITY )
2942+ ) ;
2943+ assert_eq ! (
2944+ BigRational :: new_raw( -BigInt :: one( ) , BigInt :: zero( ) ) . to_f64( ) ,
2945+ Some ( core:: f64 :: NEG_INFINITY )
2946+ ) ;
2947+ assert_eq ! (
2948+ BigRational :: new_raw( BigInt :: zero( ) , BigInt :: zero( ) ) . to_f64( ) ,
2949+ None
29202950 ) ;
29212951 }
29222952
29232953 #[ test]
29242954 fn test_ratio_to_f64 ( ) {
2925- assert_eq ! ( 0.5f64 , Ratio :: <u8 >:: new( 1 , 2 ) . to_f64( ) . unwrap( ) ) ;
2926- assert_eq ! ( 0.5f64 , Rational64 :: new( 1 , 2 ) . to_f64( ) . unwrap( ) ) ;
2927- assert_eq ! ( -0.5f64 , Rational64 :: new( 1 , -2 ) . to_f64( ) . unwrap( ) ) ;
2928- assert_eq ! ( 0.0f64 , Rational64 :: new( 0 , 2 ) . to_f64( ) . unwrap( ) ) ;
2929- assert_eq ! ( -0.0f64 , Rational64 :: new( 0 , -2 ) . to_f64( ) . unwrap( ) ) ;
2955+ assert_eq ! ( Ratio :: <u8 >:: new( 1 , 2 ) . to_f64( ) , Some ( 0.5f64 ) ) ;
2956+ assert_eq ! ( Rational64 :: new( 1 , 2 ) . to_f64( ) , Some ( 0.5f64 ) ) ;
2957+ assert_eq ! ( Rational64 :: new( 1 , -2 ) . to_f64( ) , Some ( -0.5f64 ) ) ;
2958+ assert_eq ! ( Rational64 :: new( 0 , 2 ) . to_f64( ) , Some ( 0.0f64 ) ) ;
2959+ assert_eq ! ( Rational64 :: new( 0 , -2 ) . to_f64( ) , Some ( -0.0f64 ) ) ;
2960+ assert_eq ! ( Rational64 :: new( ( 1 << 57 ) + 1 , 1 << 54 ) . to_f64( ) , Some ( 8f64 ) ) ;
29302961 assert_eq ! (
2931- 8f64 ,
2932- Rational64 :: new ( ( 1 << 57 ) + 1 , 1 << 54 ) . to_f64 ( ) . unwrap ( )
2962+ Rational64 :: new ( ( 1 << 52 ) + 1 , 1 << 52 ) . to_f64 ( ) ,
2963+ Some ( 1.0000000000000002f64 ) ,
29332964 ) ;
29342965 assert_eq ! (
2935- 1.0000000000000002f64 ,
2936- Rational64 :: new ( ( 1 << 52 ) + 1 , 1 << 52 ) . to_f64 ( ) . unwrap ( )
2966+ Rational64 :: new ( ( 1 << 60 ) + ( 1 << 8 ) , 1 << 60 ) . to_f64 ( ) ,
2967+ Some ( 1.0000000000000002f64 ) ,
29372968 ) ;
29382969 assert_eq ! (
2939- 1.0000000000000002f64 ,
2940- Rational64 :: new( ( 1 << 60 ) + ( 1 << 8 ) , 1 << 60 )
2941- . to_f64( )
2942- . unwrap( )
2970+ Ratio :: <i32 >:: new_raw( 1 , 0 ) . to_f64( ) ,
2971+ Some ( core:: f64 :: INFINITY )
2972+ ) ;
2973+ assert_eq ! (
2974+ Ratio :: <i32 >:: new_raw( -1 , 0 ) . to_f64( ) ,
2975+ Some ( core:: f64 :: NEG_INFINITY )
29432976 ) ;
2977+ assert_eq ! ( Ratio :: <i32 >:: new_raw( 0 , 0 ) . to_f64( ) , None ) ;
29442978 }
29452979}
0 commit comments