77
88// spell-checker:ignore powf copysign prec ilog inity infinit infs bigdecimal extendedbigdecimal biguint underflowed muls
99
10- use std:: num:: NonZeroU64 ;
11-
1210use bigdecimal:: {
13- BigDecimal , Context ,
11+ BigDecimal ,
1412 num_bigint:: { BigInt , BigUint , Sign } ,
1513} ;
1614use num_traits:: Signed ;
@@ -398,71 +396,6 @@ fn make_error(overflow: bool, negative: bool) -> ExtendedParserError<ExtendedBig
398396 }
399397}
400398
401- /// Compute bd**exp using exponentiation by squaring algorithm, while maintaining the
402- /// precision specified in ctx (the number of digits would otherwise explode).
403- ///
404- /// Algorithm comes from <https://en.wikipedia.org/wiki/Exponentiation_by_squaring>
405- ///
406- /// TODO: Still pending discussion in <https://github.com/akubera/bigdecimal-rs/issues/147>,
407- /// we do lose a little bit of precision, and the last digits may not be correct.
408- /// Note: This has been copied from the latest revision in <https://github.com/akubera/bigdecimal-rs/pull/148>,
409- /// so it's using minimum Rust version of `bigdecimal-rs`.
410- fn pow_with_context ( bd : & BigDecimal , exp : i64 , ctx : & Context ) -> BigDecimal {
411- if exp == 0 {
412- return 1 . into ( ) ;
413- }
414-
415- // When performing a multiplication between 2 numbers, we may lose up to 2 digits
416- // of precision.
417- // "Proof": https://github.com/akubera/bigdecimal-rs/issues/147#issuecomment-2793431202
418- const MARGIN_PER_MUL : u64 = 2 ;
419- // When doing many multiplication, we still introduce additional errors, add 1 more digit
420- // per 10 multiplications.
421- const MUL_PER_MARGIN_EXTRA : u64 = 10 ;
422-
423- fn trim_precision ( bd : BigDecimal , ctx : & Context , margin : u64 ) -> BigDecimal {
424- let prec = ctx. precision ( ) . get ( ) + margin;
425- if bd. digits ( ) > prec {
426- bd. with_precision_round ( NonZeroU64 :: new ( prec) . unwrap ( ) , ctx. rounding_mode ( ) )
427- } else {
428- bd
429- }
430- }
431-
432- // Count the number of multiplications we're going to perform, one per "1" binary digit
433- // in exp, and the number of times we can divide exp by 2.
434- let mut n = exp. unsigned_abs ( ) ;
435- // Note: 63 - n.leading_zeros() == n.ilog2, but that's only available in recent Rust versions.
436- let muls = ( n. count_ones ( ) + ( 63 - n. leading_zeros ( ) ) - 1 ) as u64 ;
437- // Note: div_ceil would be nice to use here, but only available in recent Rust versions.
438- // (see note above about minimum Rust version in use)
439- let margin_extra = ( muls + MUL_PER_MARGIN_EXTRA / 2 ) / MUL_PER_MARGIN_EXTRA ;
440- let mut margin = margin_extra + MARGIN_PER_MUL * muls;
441-
442- let mut bd_y: BigDecimal = 1 . into ( ) ;
443- let mut bd_x = if exp >= 0 {
444- bd. clone ( )
445- } else {
446- bd. inverse_with_context ( & ctx. with_precision (
447- NonZeroU64 :: new ( ctx. precision ( ) . get ( ) + margin + MARGIN_PER_MUL ) . unwrap ( ) ,
448- ) )
449- } ;
450-
451- while n > 1 {
452- if n % 2 == 1 {
453- bd_y = trim_precision ( & bd_x * bd_y, ctx, margin) ;
454- margin -= MARGIN_PER_MUL ;
455- n -= 1 ;
456- }
457- bd_x = trim_precision ( bd_x. square ( ) , ctx, margin) ;
458- margin -= MARGIN_PER_MUL ;
459- n /= 2 ;
460- }
461- debug_assert_eq ! ( margin, margin_extra) ;
462-
463- trim_precision ( bd_x * bd_y, ctx, 0 )
464- }
465-
466399/// Construct an [`ExtendedBigDecimal`] based on parsed data
467400fn construct_extended_big_decimal (
468401 digits : BigUint ,
@@ -510,7 +443,7 @@ fn construct_extended_big_decimal(
510443 let bd = BigDecimal :: from_bigint ( signed_digits, 0 )
511444 / BigDecimal :: from_bigint ( BigInt :: from ( 16 ) . pow ( scale as u32 ) , 0 ) ;
512445
513- // pow_with_context "only" supports i64 values. Just overflow/underflow if the value provided
446+ // powi "only" supports i64 values. Just overflow/underflow if the value provided
514447 // is > 2**64 or < 2**-64.
515448 let Some ( exponent) = exponent. to_i64 ( ) else {
516449 return Err ( make_error ( exponent. is_positive ( ) , negative) ) ;
@@ -520,7 +453,7 @@ fn construct_extended_big_decimal(
520453 let base: BigDecimal = 2 . into ( ) ;
521454 // Note: We cannot overflow/underflow BigDecimal here, as we will not be able to reach the
522455 // maximum/minimum scale (i64 range).
523- let pow2 = pow_with_context ( & base, exponent , & Context :: default ( ) ) ;
456+ let pow2 = base. powi ( exponent ) ;
524457
525458 bd * pow2
526459 } else {
0 commit comments