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