@@ -408,3 +408,227 @@ pub fn pow(x: f64, y: f64) -> f64 {
408408
409409 return s * z;
410410}
411+
412+ #[ cfg( test) ]
413+ mod tests {
414+ extern crate core;
415+
416+ use self :: core:: f64:: consts:: { E , PI } ;
417+ use self :: core:: f64:: { EPSILON , INFINITY , MAX , MIN , MIN_POSITIVE , NAN , NEG_INFINITY } ;
418+ use super :: pow;
419+
420+ const POS_ZERO : & [ f64 ] = & [ 0.0 ] ;
421+ const NEG_ZERO : & [ f64 ] = & [ -0.0 ] ;
422+ const POS_ONE : & [ f64 ] = & [ 1.0 ] ;
423+ const NEG_ONE : & [ f64 ] = & [ -1.0 ] ;
424+ const POS_FLOATS : & [ f64 ] = & [ 99.0 / 70.0 , E , PI ] ;
425+ const NEG_FLOATS : & [ f64 ] = & [ -99.0 / 70.0 , -E , -PI ] ;
426+ const POS_SMALL_FLOATS : & [ f64 ] = & [ ( 1.0 / 2.0 ) , MIN_POSITIVE , EPSILON ] ;
427+ const NEG_SMALL_FLOATS : & [ f64 ] = & [ -( 1.0 / 2.0 ) , -MIN_POSITIVE , -EPSILON ] ;
428+ const POS_EVENS : & [ f64 ] = & [ 2.0 , 6.0 , 8.0 , 10.0 , 22.0 , 100.0 , MAX ] ;
429+ const NEG_EVENS : & [ f64 ] = & [ MIN , -100.0 , -22.0 , -10.0 , -8.0 , -6.0 , -2.0 ] ;
430+ const POS_ODDS : & [ f64 ] = & [ 3.0 , 7.0 ] ;
431+ const NEG_ODDS : & [ f64 ] = & [ -7.0 , -3.0 ] ;
432+ const NANS : & [ f64 ] = & [ NAN ] ;
433+ const POS_INF : & [ f64 ] = & [ INFINITY ] ;
434+ const NEG_INF : & [ f64 ] = & [ NEG_INFINITY ] ;
435+
436+ const ALL : & [ & [ f64 ] ] = & [
437+ POS_ZERO ,
438+ NEG_ZERO ,
439+ NANS ,
440+ NEG_SMALL_FLOATS ,
441+ POS_SMALL_FLOATS ,
442+ NEG_FLOATS ,
443+ POS_FLOATS ,
444+ NEG_EVENS ,
445+ POS_EVENS ,
446+ NEG_ODDS ,
447+ POS_ODDS ,
448+ NEG_INF ,
449+ POS_INF ,
450+ NEG_ONE ,
451+ POS_ONE ,
452+ ] ;
453+ const POS : & [ & [ f64 ] ] = & [ POS_ZERO , POS_ODDS , POS_ONE , POS_FLOATS , POS_EVENS , POS_INF ] ;
454+ const NEG : & [ & [ f64 ] ] = & [ NEG_ZERO , NEG_ODDS , NEG_ONE , NEG_FLOATS , NEG_EVENS , NEG_INF ] ;
455+
456+ fn pow_test ( base : f64 , exponent : f64 , expected : f64 ) {
457+ let res = pow ( base, exponent) ;
458+ assert ! (
459+ if expected. is_nan( ) {
460+ res. is_nan( )
461+ } else {
462+ pow( base, exponent) == expected
463+ } ,
464+ "{} ** {} was {} instead of {}" ,
465+ base,
466+ exponent,
467+ res,
468+ expected
469+ ) ;
470+ }
471+
472+ fn test_sets_as_base ( sets : & [ & [ f64 ] ] , exponent : f64 , expected : f64 ) {
473+ sets. iter ( )
474+ . for_each ( |s| s. iter ( ) . for_each ( |val| pow_test ( * val, exponent, expected) ) ) ;
475+ }
476+
477+ fn test_sets_as_exponent ( base : f64 , sets : & [ & [ f64 ] ] , expected : f64 ) {
478+ sets. iter ( )
479+ . for_each ( |s| s. iter ( ) . for_each ( |val| pow_test ( base, * val, expected) ) ) ;
480+ }
481+
482+ fn test_sets ( sets : & [ & [ f64 ] ] , computed : & Fn ( f64 ) -> f64 , expected : & Fn ( f64 ) -> f64 ) {
483+ sets. iter ( ) . for_each ( |s| {
484+ s. iter ( ) . for_each ( |val| {
485+ let exp = expected ( * val) ;
486+ let res = computed ( * val) ;
487+
488+ assert ! (
489+ if exp. is_nan( ) {
490+ res. is_nan( )
491+ } else {
492+ exp == res
493+ } ,
494+ "test for {} was {} instead of {}" ,
495+ val,
496+ res,
497+ exp
498+ ) ;
499+ } )
500+ } ) ;
501+ }
502+
503+ #[ test]
504+ fn zero_as_exponent ( ) {
505+ test_sets_as_base ( ALL , 0.0 , 1.0 ) ;
506+ test_sets_as_base ( ALL , -0.0 , 1.0 ) ;
507+ }
508+
509+ #[ test]
510+ fn one_as_base ( ) {
511+ test_sets_as_exponent ( 1.0 , ALL , 1.0 ) ;
512+ }
513+
514+ #[ test]
515+ fn nan_inputs ( ) {
516+ // NAN as the base:
517+ // (NAN ^ anything *but 0* should be NAN)
518+ test_sets_as_exponent ( NAN , & ALL [ 2 ..] , NAN ) ;
519+
520+ // NAN as the exponent:
521+ // (anything *but 1* ^ NAN should be NAN)
522+ test_sets_as_base ( & ALL [ ..( ALL . len ( ) - 2 ) ] , NAN , NAN ) ;
523+ }
524+
525+ #[ test]
526+ fn infinity_as_base ( ) {
527+ // Positive Infinity as the base:
528+ // (+Infinity ^ positive anything but 0 and NAN should be +Infinity)
529+ test_sets_as_exponent ( INFINITY , & POS [ 1 ..] , INFINITY ) ;
530+
531+ // (+Infinity ^ negative anything except 0 and NAN should be 0.0)
532+ test_sets_as_exponent ( INFINITY , & NEG [ 1 ..] , 0.0 ) ;
533+
534+ // Negative Infinity as the base:
535+ // (-Infinity ^ positive odd ints should be -Infinity)
536+ test_sets_as_exponent ( NEG_INFINITY , & [ POS_ODDS ] , NEG_INFINITY ) ;
537+
538+ // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything))
539+ // We can lump in pos/neg odd ints here because they don't seem to
540+ // cause panics (div by zero) in release mode (I think).
541+ test_sets ( ALL , & |v : f64 | pow ( NEG_INFINITY , v) , & |v : f64 | pow ( -0.0 , -v) ) ;
542+ }
543+
544+ #[ test]
545+ fn infinity_as_exponent ( ) {
546+ // Positive/Negative base greater than 1:
547+ // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes NAN as the base)
548+ test_sets_as_base ( & ALL [ 5 ..( ALL . len ( ) - 2 ) ] , INFINITY , INFINITY ) ;
549+
550+ // (pos/neg > 1 ^ -Infinity should be 0.0)
551+ test_sets_as_base ( & ALL [ 5 ..ALL . len ( ) - 2 ] , NEG_INFINITY , 0.0 ) ;
552+
553+ // Positive/Negative base less than 1:
554+ let base_below_one = & [ POS_ZERO , NEG_ZERO , NEG_SMALL_FLOATS , POS_SMALL_FLOATS ] ;
555+
556+ // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes NAN as the base)
557+ test_sets_as_base ( base_below_one, INFINITY , 0.0 ) ;
558+
559+ // (pos/neg < 1 ^ -Infinity should be Infinity)
560+ test_sets_as_base ( base_below_one, NEG_INFINITY , INFINITY ) ;
561+
562+ // Positive/Negative 1 as the base:
563+ // (pos/neg 1 ^ Infinity should be 1)
564+ test_sets_as_base ( & [ NEG_ONE , POS_ONE ] , INFINITY , 1.0 ) ;
565+
566+ // (pos/neg 1 ^ -Infinity should be 1)
567+ test_sets_as_base ( & [ NEG_ONE , POS_ONE ] , NEG_INFINITY , 1.0 ) ;
568+ }
569+
570+ #[ test]
571+ fn zero_as_base ( ) {
572+ // Positive Zero as the base:
573+ // (+0 ^ anything positive but 0 and NAN should be +0)
574+ test_sets_as_exponent ( 0.0 , & POS [ 1 ..] , 0.0 ) ;
575+
576+ // (+0 ^ anything negative but 0 and NAN should be Infinity)
577+ // (this should panic because we're dividing by zero)
578+ test_sets_as_exponent ( 0.0 , & NEG [ 1 ..] , INFINITY ) ;
579+
580+ // Negative Zero as the base:
581+ // (-0 ^ anything positive but 0, NAN, and odd ints should be +0)
582+ test_sets_as_exponent ( -0.0 , & POS [ 3 ..] , 0.0 ) ;
583+
584+ // (-0 ^ anything negative but 0, NAN, and odd ints should be Infinity)
585+ // (should panic because of divide by zero)
586+ test_sets_as_exponent ( -0.0 , & NEG [ 3 ..] , INFINITY ) ;
587+
588+ // (-0 ^ positive odd ints should be -0)
589+ test_sets_as_exponent ( -0.0 , & [ POS_ODDS ] , -0.0 ) ;
590+
591+ // (-0 ^ negative odd ints should be -Infinity)
592+ // (should panic because of divide by zero)
593+ test_sets_as_exponent ( -0.0 , & [ NEG_ODDS ] , NEG_INFINITY ) ;
594+ }
595+
596+ #[ test]
597+ fn special_cases ( ) {
598+ // One as the exponent:
599+ // (anything ^ 1 should be anything - i.e. the base)
600+ test_sets ( ALL , & |v : f64 | pow ( v, 1.0 ) , & |v : f64 | v) ;
601+
602+ // Negative One as the exponent:
603+ // (anything ^ -1 should be 1/anything)
604+ test_sets ( ALL , & |v : f64 | pow ( v, -1.0 ) , & |v : f64 | 1.0 / v) ;
605+
606+ // Factoring -1 out:
607+ // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer))
608+ & [ POS_ZERO , NEG_ZERO , POS_ONE , NEG_ONE , POS_EVENS , NEG_EVENS ]
609+ . iter ( )
610+ . for_each ( |int_set| {
611+ int_set. iter ( ) . for_each ( |int| {
612+ test_sets ( ALL , & |v : f64 | pow ( -v, * int) , & |v : f64 | {
613+ pow ( -1.0 , * int) * pow ( v, * int)
614+ } ) ;
615+ } )
616+ } ) ;
617+
618+ // Negative base (imaginary results):
619+ // (-anything except 0 and Infinity ^ non-integer should be NAN)
620+ & NEG [ 1 ..( NEG . len ( ) - 1 ) ] . iter ( ) . for_each ( |set| {
621+ set. iter ( ) . for_each ( |val| {
622+ test_sets ( & ALL [ 3 ..7 ] , & |v : f64 | pow ( * val, v) , & |_| NAN ) ;
623+ } )
624+ } ) ;
625+ }
626+
627+ #[ test]
628+ fn normal_cases ( ) {
629+ assert_eq ! ( pow( 2.0 , 20.0 ) , ( 1 << 20 ) as f64 ) ;
630+ assert_eq ! ( pow( -1.0 , 9.0 ) , -1.0 ) ;
631+ assert ! ( pow( -1.0 , 2.2 ) . is_nan( ) ) ;
632+ assert ! ( pow( -1.0 , -1.14 ) . is_nan( ) ) ;
633+ }
634+ }
0 commit comments