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