@@ -1382,7 +1382,12 @@ macro_rules! to_primitive_small {
13821382 }
13831383
13841384 fn to_f64( & self ) -> Option <f64 > {
1385- Some ( self . numer. to_f64( ) . unwrap( ) / self . denom. to_f64( ) . unwrap( ) )
1385+ let float = self . numer. to_f64( ) . unwrap( ) / self . denom. to_f64( ) . unwrap( ) ;
1386+ if float. is_nan( ) {
1387+ None
1388+ } else {
1389+ Some ( float)
1390+ }
13861391 }
13871392 }
13881393 ) * )
@@ -1415,10 +1420,15 @@ macro_rules! to_primitive_64 {
14151420 }
14161421
14171422 fn to_f64( & self ) -> Option <f64 > {
1418- Some ( ratio_to_f64(
1423+ let float = ratio_to_f64(
14191424 self . numer as i128 ,
14201425 self . denom as i128
1421- ) )
1426+ ) ;
1427+ if float. is_nan( ) {
1428+ None
1429+ } else {
1430+ Some ( float)
1431+ }
14221432 }
14231433 }
14241434 ) * )
@@ -1449,16 +1459,21 @@ impl<T: Clone + Integer + ToPrimitive + ToBigInt> ToPrimitive for Ratio<T> {
14491459 }
14501460
14511461 fn to_f64 ( & self ) -> Option < f64 > {
1452- match ( self . numer . to_i64 ( ) , self . denom . to_i64 ( ) ) {
1453- ( Some ( numer) , Some ( denom) ) => Some ( ratio_to_f64 (
1462+ let float = match ( self . numer . to_i64 ( ) , self . denom . to_i64 ( ) ) {
1463+ ( Some ( numer) , Some ( denom) ) => ratio_to_f64 (
14541464 <i128 as From < _ > >:: from ( numer) ,
14551465 <i128 as From < _ > >:: from ( denom) ,
1456- ) ) ,
1466+ ) ,
14571467 _ => {
14581468 let numer: BigInt = self . numer . to_bigint ( ) ?;
14591469 let denom: BigInt = self . denom . to_bigint ( ) ?;
1460- Some ( ratio_to_f64 ( numer, denom) )
1470+ ratio_to_f64 ( numer, denom)
14611471 }
1472+ } ;
1473+ if float. is_nan ( ) {
1474+ None
1475+ } else {
1476+ Some ( float)
14621477 }
14631478 }
14641479}
@@ -1498,10 +1513,9 @@ fn ratio_to_f64<T: Bits + Clone + Integer + Signed + ShlAssign<usize> + ToPrimit
14981513 const MAX_EXACT_INT : i64 = 1i64 << core:: f64:: MANTISSA_DIGITS ;
14991514 const MIN_EXACT_INT : i64 = -MAX_EXACT_INT ;
15001515
1501- let flo_sign = numer. signum ( ) . to_f64 ( ) . unwrap ( ) * denom. signum ( ) . to_f64 ( ) . unwrap ( ) ;
1502-
1503- if numer. is_zero ( ) {
1504- return 0.0 * flo_sign;
1516+ let flo_sign = numer. signum ( ) . to_f64 ( ) . unwrap ( ) / denom. signum ( ) . to_f64 ( ) . unwrap ( ) ;
1517+ if !flo_sign. is_normal ( ) {
1518+ return flo_sign;
15051519 }
15061520
15071521 // Fast track: both sides can losslessly be converted to f64s. In this case, letting the
@@ -2890,47 +2904,67 @@ mod test {
28902904 . unwrap( ) ,
28912905 "3" . parse( ) . unwrap( )
28922906 )
2893- . to_f64( )
2894- . unwrap( ) ,
2895- 411522630329218100000000000000000000000000000f64
2907+ . to_f64( ) ,
2908+ Some ( 411522630329218100000000000000000000000000000f64 )
2909+ ) ;
2910+ assert_eq ! (
2911+ BigRational :: new( BigInt :: one( ) , BigInt :: one( ) << 1050 ) . to_f64( ) ,
2912+ Some ( 0f64 )
28962913 ) ;
28972914 assert_eq ! (
2898- BigRational :: new( 1 . into( ) , BigInt :: one( ) << 1050 , )
2899- . to_f64( )
2900- . unwrap( ) ,
2901- 0f64
2915+ BigRational :: from( BigInt :: one( ) << 1050 ) . to_f64( ) ,
2916+ Some ( core:: f64 :: INFINITY )
2917+ ) ;
2918+ assert_eq ! (
2919+ BigRational :: from( ( -BigInt :: one( ) ) << 1050 ) . to_f64( ) ,
2920+ Some ( core:: f64 :: NEG_INFINITY )
29022921 ) ;
29032922 assert_eq ! (
29042923 BigRational :: new(
29052924 "1234567890987654321234567890" . parse( ) . unwrap( ) ,
29062925 "987654321234567890987654321" . parse( ) . unwrap( )
29072926 )
2908- . to_f64( )
2909- . unwrap( ) ,
2910- 1.2499999893125f64
2927+ . to_f64( ) ,
2928+ Some ( 1.2499999893125f64 )
2929+ ) ;
2930+ assert_eq ! (
2931+ BigRational :: new_raw( BigInt :: one( ) , BigInt :: zero( ) ) . to_f64( ) ,
2932+ Some ( core:: f64 :: INFINITY )
2933+ ) ;
2934+ assert_eq ! (
2935+ BigRational :: new_raw( -BigInt :: one( ) , BigInt :: zero( ) ) . to_f64( ) ,
2936+ Some ( core:: f64 :: NEG_INFINITY )
2937+ ) ;
2938+ assert_eq ! (
2939+ BigRational :: new_raw( BigInt :: zero( ) , BigInt :: zero( ) ) . to_f64( ) ,
2940+ None
29112941 ) ;
29122942 }
29132943
29142944 #[ test]
29152945 fn test_ratio_to_f64 ( ) {
2916- assert_eq ! ( 0.5f64 , Ratio :: <u8 >:: new( 1 , 2 ) . to_f64( ) . unwrap( ) ) ;
2917- assert_eq ! ( 0.5f64 , Rational64 :: new( 1 , 2 ) . to_f64( ) . unwrap( ) ) ;
2918- assert_eq ! ( -0.5f64 , Rational64 :: new( 1 , -2 ) . to_f64( ) . unwrap( ) ) ;
2919- assert_eq ! ( 0.0f64 , Rational64 :: new( 0 , 2 ) . to_f64( ) . unwrap( ) ) ;
2920- assert_eq ! ( -0.0f64 , Rational64 :: new( 0 , -2 ) . to_f64( ) . unwrap( ) ) ;
2946+ assert_eq ! ( Ratio :: <u8 >:: new( 1 , 2 ) . to_f64( ) , Some ( 0.5f64 ) ) ;
2947+ assert_eq ! ( Rational64 :: new( 1 , 2 ) . to_f64( ) , Some ( 0.5f64 ) ) ;
2948+ assert_eq ! ( Rational64 :: new( 1 , -2 ) . to_f64( ) , Some ( -0.5f64 ) ) ;
2949+ assert_eq ! ( Rational64 :: new( 0 , 2 ) . to_f64( ) , Some ( 0.0f64 ) ) ;
2950+ assert_eq ! ( Rational64 :: new( 0 , -2 ) . to_f64( ) , Some ( -0.0f64 ) ) ;
2951+ assert_eq ! ( Rational64 :: new( ( 1 << 57 ) + 1 , 1 << 54 ) . to_f64( ) , Some ( 8f64 ) ) ;
29212952 assert_eq ! (
2922- 8f64 ,
2923- Rational64 :: new ( ( 1 << 57 ) + 1 , 1 << 54 ) . to_f64 ( ) . unwrap ( )
2953+ Rational64 :: new ( ( 1 << 52 ) + 1 , 1 << 52 ) . to_f64 ( ) ,
2954+ Some ( 1.0000000000000002f64 ) ,
29242955 ) ;
29252956 assert_eq ! (
2926- 1.0000000000000002f64 ,
2927- Rational64 :: new ( ( 1 << 52 ) + 1 , 1 << 52 ) . to_f64 ( ) . unwrap ( )
2957+ Rational64 :: new ( ( 1 << 60 ) + ( 1 << 8 ) , 1 << 60 ) . to_f64 ( ) ,
2958+ Some ( 1.0000000000000002f64 ) ,
29282959 ) ;
29292960 assert_eq ! (
2930- 1.0000000000000002f64 ,
2931- Rational64 :: new( ( 1 << 60 ) + ( 1 << 8 ) , 1 << 60 )
2932- . to_f64( )
2933- . unwrap( )
2961+ Ratio :: <i32 >:: new_raw( 1 , 0 ) . to_f64( ) ,
2962+ Some ( core:: f64 :: INFINITY )
2963+ ) ;
2964+ assert_eq ! (
2965+ Ratio :: <i32 >:: new_raw( -1 , 0 ) . to_f64( ) ,
2966+ Some ( core:: f64 :: NEG_INFINITY )
29342967 ) ;
2968+ assert_eq ! ( Ratio :: <i32 >:: new_raw( 0 , 0 ) . to_f64( ) , None ) ;
29352969 }
29362970}
0 commit comments