@@ -94,28 +94,27 @@ pub fn pow(
94
94
/// The exponent of the power. Must be non-negative.
95
95
exponent : Spanned < Num > ,
96
96
) -> Value {
97
- let Spanned { v : exp, span } = exponent;
98
- match exp {
99
- _ if exp. float ( ) == 0.0 && base. float ( ) == 0.0 => {
97
+ match exponent. v {
98
+ _ if exponent. v . float ( ) == 0.0 && base. float ( ) == 0.0 => {
100
99
bail ! ( args. span, "zero to the power of zero is undefined" )
101
100
}
102
101
Num :: Int ( i) if i32:: try_from ( i) . is_err ( ) => {
103
- bail ! ( span, "exponent is too large" )
102
+ bail ! ( exponent . span, "exponent is too large" )
104
103
}
105
104
Num :: Float ( f) if !f. is_normal ( ) && f != 0.0 => {
106
- bail ! ( span, "exponent may not be infinite, subnormal, or NaN" )
105
+ bail ! ( exponent . span, "exponent may not be infinite, subnormal, or NaN" )
107
106
}
108
107
_ => { }
109
108
} ;
110
109
111
- let result = match ( base, exp ) {
110
+ let result = match ( base, exponent . v ) {
112
111
( Num :: Int ( a) , Num :: Int ( b) ) if b >= 0 => Num :: Int ( a. pow ( b as u32 ) ) ,
113
112
( a, Num :: Int ( b) ) => Num :: Float ( a. float ( ) . powi ( b as i32 ) ) ,
114
113
( a, b) => Num :: Float ( a. float ( ) . powf ( b. float ( ) ) ) ,
115
114
} ;
116
115
117
116
if result. float ( ) . is_nan ( ) {
118
- bail ! ( span, "the result is not a real number" )
117
+ bail ! ( args . span, "the result is not a real number" )
119
118
}
120
119
121
120
result. value ( )
@@ -381,28 +380,28 @@ pub fn log(
381
380
value : Spanned < Num > ,
382
381
/// The base of the logarithm. Defaults to `{10}` and may not be zero.
383
382
#[ named]
384
- #[ default( 10.0 ) ]
385
- base : f64 ,
383
+ #[ default( Spanned :: new ( 10.0 , Span :: detached ( ) ) ) ]
384
+ base : Spanned < f64 > ,
386
385
) -> Value {
387
386
let number = value. v . float ( ) ;
388
387
if number <= 0.0 {
389
388
bail ! ( value. span, "value must be strictly positive" )
390
389
}
391
390
392
- if !base. is_normal ( ) {
393
- bail ! ( value . span, "base may not be zero, NaN, infinite, or subnormal" )
391
+ if !base. v . is_normal ( ) {
392
+ bail ! ( base . span, "base may not be zero, NaN, infinite, or subnormal" )
394
393
}
395
394
396
- let result = if base == 2.0 {
395
+ let result = if base. v == 2.0 {
397
396
number. log2 ( )
398
- } else if base == 10.0 {
397
+ } else if base. v == 10.0 {
399
398
number. log10 ( )
400
399
} else {
401
- number. log ( base)
400
+ number. log ( base. v )
402
401
} ;
403
402
404
403
if result. is_infinite ( ) || result. is_nan ( ) {
405
- bail ! ( value . span, "the result is not a real number" )
404
+ bail ! ( args . span, "the result is not a real number" )
406
405
}
407
406
408
407
Value :: Float ( result)
@@ -420,114 +419,103 @@ pub fn log(
420
419
/// Returns: integer
421
420
#[ func]
422
421
pub fn fact (
423
- /// The number whose factorial to calculate. Must be positive .
424
- number : Spanned < u64 > ,
422
+ /// The number whose factorial to calculate. Must be non-negative .
423
+ number : u64 ,
425
424
) -> Value {
426
- let result = factorial_range ( 1 , number. v ) . and_then ( |r| i64:: try_from ( r) . ok ( ) ) ;
427
-
428
- match result {
429
- None => bail ! ( number. span, "the factorial result is too large" ) ,
430
- Some ( s) => Value :: Int ( s) ,
431
- }
425
+ factorial_range ( 1 , number)
426
+ . map ( Value :: Int )
427
+ . ok_or ( "the result is too large" )
428
+ . at ( args. span ) ?
432
429
}
433
430
434
- /// Calculates the product of a range of numbers. Used to calculate permutations.
435
- /// Returns None if the result is larger than `u64 ::MAX`
436
- fn factorial_range ( start : u64 , end : u64 ) -> Option < u64 > {
431
+ /// Calculates the product of a range of numbers. Used to calculate
432
+ /// permutations. Returns None if the result is larger than `i64 ::MAX`
433
+ fn factorial_range ( start : u64 , end : u64 ) -> Option < i64 > {
437
434
// By convention
438
435
if end + 1 < start {
439
436
return Some ( 0 ) ;
440
437
}
441
438
442
- let mut count: u64 = 1 ;
443
439
let real_start: u64 = cmp:: max ( 1 , start) ;
444
-
440
+ let mut count : u64 = 1 ;
445
441
for i in real_start..=end {
446
442
count = count. checked_mul ( i) ?;
447
443
}
448
- Some ( count)
444
+
445
+ i64:: try_from ( count) . ok ( )
449
446
}
450
447
451
448
/// Calculate a permutation.
452
449
///
453
450
/// ## Example
454
451
/// ```example
455
- /// #calc.perm(10,5)
452
+ /// #calc.perm(10, 5)
456
453
/// ```
457
454
///
458
455
/// Display: Permutation
459
456
/// Category: calculate
460
457
/// Returns: integer
461
458
#[ func]
462
459
pub fn perm (
463
- /// The base number. Must be positive .
464
- base : Spanned < u64 > ,
465
- /// The number of permutations. Must be positive .
466
- numbers : Spanned < u64 > ,
460
+ /// The base number. Must be non-negative .
461
+ base : u64 ,
462
+ /// The number of permutations. Must be non-negative .
463
+ numbers : u64 ,
467
464
) -> Value {
468
- let base_parsed = base. v ;
469
- let numbers_parsed = numbers. v ;
470
-
471
- let result = if base_parsed + 1 > numbers_parsed {
472
- factorial_range ( base_parsed - numbers_parsed + 1 , base_parsed)
473
- . and_then ( |value| i64:: try_from ( value) . ok ( ) )
474
- } else {
475
- // By convention
476
- Some ( 0 )
477
- } ;
478
-
479
- match result {
480
- None => bail ! ( base. span, "the permutation result is too large" ) ,
481
- Some ( s) => Value :: Int ( s) ,
465
+ // By convention.
466
+ if base + 1 <= numbers {
467
+ return Ok ( Value :: Int ( 0 ) ) ;
482
468
}
469
+
470
+ factorial_range ( base - numbers + 1 , base)
471
+ . map ( Value :: Int )
472
+ . ok_or ( "the result is too large" )
473
+ . at ( args. span ) ?
483
474
}
484
475
485
476
/// Calculate a binomial coefficient.
486
477
///
487
478
/// ## Example
488
479
/// ```example
489
- /// #calc.binom(10,5)
480
+ /// #calc.binom(10, 5)
490
481
/// ```
491
482
///
492
- /// Display: Permutation
483
+ /// Display: Binomial
493
484
/// Category: calculate
494
485
/// Returns: integer
495
486
#[ func]
496
487
pub fn binom (
497
- /// The upper coefficient. Must be positive
498
- n : Spanned < u64 > ,
499
- /// The lower coefficient. Must be positive .
500
- k : Spanned < u64 > ,
488
+ /// The upper coefficient. Must be non-negative.
489
+ n : u64 ,
490
+ /// The lower coefficient. Must be non-negative .
491
+ k : u64 ,
501
492
) -> Value {
502
- let result = binomial ( n. v , k. v ) . and_then ( |raw| i64:: try_from ( raw) . ok ( ) ) ;
503
-
504
- match result {
505
- None => bail ! ( n. span, "the binomial result is too large" ) ,
506
- Some ( r) => Value :: Int ( r) ,
507
- }
493
+ binomial ( n, k)
494
+ . map ( Value :: Int )
495
+ . ok_or ( "the result is too large" )
496
+ . at ( args. span ) ?
508
497
}
509
498
510
- /// Calculates a binomial coefficient, with `n` the upper coefficient and `k` the lower coefficient.
511
- /// Returns `None` if the result is larger than `u64::MAX`
512
- fn binomial ( n : u64 , k : u64 ) -> Option < u64 > {
499
+ /// Calculates a binomial coefficient, with `n` the upper coefficient and `k`
500
+ /// the lower coefficient. Returns `None` if the result is larger than
501
+ /// `i64::MAX`
502
+ fn binomial ( n : u64 , k : u64 ) -> Option < i64 > {
513
503
if k > n {
514
504
return Some ( 0 ) ;
515
505
}
516
506
517
507
// By symmetry
518
508
let real_k = cmp:: min ( n - k, k) ;
519
-
520
509
if real_k == 0 {
521
510
return Some ( 1 ) ;
522
511
}
523
512
524
513
let mut result: u64 = 1 ;
525
-
526
514
for i in 0 ..real_k {
527
- result = result. checked_mul ( n - i) . and_then ( |r| r . checked_div ( i + 1 ) ) ?;
515
+ result = result. checked_mul ( n - i) ? . checked_div ( i + 1 ) ?;
528
516
}
529
517
530
- Some ( result)
518
+ i64 :: try_from ( result) . ok ( )
531
519
}
532
520
533
521
/// Round a number down to the nearest integer.
0 commit comments