@@ -408,3 +408,192 @@ pub fn pow(x: f64, y: f64) -> f64 {
408
408
409
409
return s * z;
410
410
}
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