bigdecimal/arithmetic/
mod.rs1use crate::*;
4use num_traits::CheckedSub;
5use num_traits::AsPrimitive;
6
7pub(crate) mod decimal;
8
9pub(crate) mod addition;
10pub(crate) mod division;
11pub(crate) mod multiplication;
12pub(crate) mod modulo;
13pub(crate) mod sqrt;
14pub(crate) mod cbrt;
15pub(crate) mod inverse;
16pub(crate) mod pow;
17pub(crate) mod exp;
18
19pub(crate) use self::decimal::{
20 count_digits_bigint as count_decimal_digits,
21 count_digits_biguint as count_decimal_digits_uint,
22};
23
24#[cfg(not(feature = "std"))]
25mod funcs {
26 pub fn exp2(x: f64) -> f64 {
28 libm::exp2(x)
29 }
30
31 pub fn log10(x: f64) -> f64 {
33 libm::log10(x)
34 }
35}
36
37#[cfg(feature = "std")]
38mod funcs {
39 pub fn exp2(x: f64) -> f64 {
40 x.exp2()
41 }
42
43 pub fn log10(x: f64) -> f64 {
44 x.log10()
45 }
46}
47
48pub(crate) use self::funcs::*;
50
51pub(crate) fn ten_to_the(pow: u64) -> BigInt {
56 ten_to_the_uint(pow).into()
57}
58
59pub(crate) fn ten_to_the_u64(pow: u8) -> u64 {
61 if true {
if !(pow < 20) { ::core::panicking::panic("assertion failed: pow < 20") };
};debug_assert!(pow < 20);
62 10u64.pow(pow as u32)
63}
64
65pub(crate) fn ten_to_the_t<T>(pow: u8) -> T
67where
68 T: From<u8> + num_traits::Pow<u8, Output = T>
69{
70 if true {
if !((pow as f64) < stdlib::mem::size_of::<T>() as f64 * 8.0 / LOG2_10) {
::core::panicking::panic("assertion failed: (pow as f64) < stdlib::mem::size_of::<T>() as f64 * 8.0 / LOG2_10")
};
};debug_assert!((pow as f64) < stdlib::mem::size_of::<T>() as f64 * 8.0 / LOG2_10);
71 T::from(10u8).pow(pow)
72}
73
74pub(crate) fn ten_to_the_uint(pow: u64) -> BigUint {
76 if pow < 20 {
77 return BigUint::from(10u64.pow(pow as u32));
78 }
79
80 if pow < 590 {
82 let ten_to_nineteen = 10u64.pow(19);
83
84 let (count, rem) = pow.div_rem(&19);
86
87 let mut res = BigUint::from(ten_to_nineteen);
88 for _ in 1..count {
89 res *= ten_to_nineteen;
90 }
91 if rem != 0 {
92 res *= 10u64.pow(rem as u32);
93 }
94
95 return res;
96 }
97
98 let (quotient, rem) = pow.div_rem(&16);
100 let x = ten_to_the_uint(quotient);
101
102 let x2 = &x * &x;
103 let x4 = &x2 * &x2;
104 let x8 = &x4 * &x4;
105 let res = &x8 * &x8;
106
107 if rem == 0 {
108 res
109 } else {
110 res * 10u64.pow(rem as u32)
111 }
112}
113
114pub(crate) fn multiply_by_ten_to_the_uint<T, P>(n: &mut T, pow: P)
115where
116 T: MulAssign<u64> + MulAssign<BigUint>,
117 P: ToPrimitive,
118{
119 let pow = pow.to_u64().expect("exponent overflow error");
120 if pow < 20 {
121 *n *= 10u64.pow(pow as u32);
122 } else {
123 *n *= ten_to_the_uint(pow);
124 }
125}
126
127pub(crate) fn diff<T>(a: T, b: T) -> (Ordering, u64)
129where
130 T: ToPrimitive + CheckedSub + stdlib::cmp::Ord,
131{
132 use stdlib::cmp::Ordering::*;
133
134 let (ord, diff) = checked_diff(a, b);
135
136 (ord, diff.expect("subtraction overflow"))
137}
138
139pub(crate) fn checked_diff<T>(a: T, b: T) -> (Ordering, Option<u64>)
141where
142 T: ToPrimitive + CheckedSub + stdlib::cmp::Ord,
143{
144 use stdlib::cmp::Ordering::*;
145
146 let _try_subtracting = |x: T, y: T| x.checked_sub(&y).and_then(|diff| diff.to_u64());
147
148 match a.cmp(&b) {
149 Less => (Less, _try_subtracting(b, a)),
150 Greater => (Greater, _try_subtracting(a, b)),
151 Equal => (Equal, Some(0)),
152 }
153}
154
155#[allow(dead_code)]
157pub(crate) fn diff_usize<T>(a: T, b: T) -> (Ordering, usize)
158where
159 T: AsPrimitive<usize> + stdlib::ops::Sub<Output = T> + stdlib::cmp::Ord,
160{
161 use stdlib::cmp::Ordering::*;
162
163 match a.cmp(&b) {
164 Less => (Less, (b - a).as_()),
165 Greater => (Greater, (a - b).as_()),
166 Equal => (Equal, 0),
167 }
168}
169
170#[cfg(rustc_1_60)]
172#[allow(clippy::incompatible_msrv)]
173#[allow(dead_code)]
174pub(crate) fn abs_diff(x: i64, y: i64) -> u64 {
175 x.abs_diff(y)
176}
177
178#[cfg(not(rustc_1_60))]
179#[allow(dead_code)]
180pub(crate) fn abs_diff(x: i64, y: i64) -> u64 {
181 (x as i128 - y as i128).to_u64().unwrap_or(0)
182}
183
184pub(crate) fn add_carry(n: u8, carry: &mut u8) -> u8 {
187 let s = n + *carry;
188 if s < 10 {
189 *carry = 0;
190 s
191 } else {
192 if true {
if !(s < 20) { ::core::panicking::panic("assertion failed: s < 20") };
};debug_assert!(s < 20);
193 *carry = 1;
194 s - 10
195 }
196}
197
198pub(crate) fn store_carry(n: u8, carry: &mut u8) -> u8 {
205 if n < 10 {
206 n
207 } else {
208 if true {
if !(n < 20) { ::core::panicking::panic("assertion failed: n < 20") };
};debug_assert!(n < 20);
209 if true {
{
match (&carry, &&0) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};
};debug_assert_eq!(carry, &0);
210 *carry = 1;
211 n - 10
212 }
213}
214
215pub(crate) fn extend_adding_with_carry<D: Iterator<Item = u8>>(
220 dest: &mut Vec<u8>,
221 mut digits: D,
222 carry: &mut u8,
223) {
224 while *carry != 0 {
225 match digits.next() {
226 Some(d) => {
227 dest.push(add_carry(d, carry))
228 }
229 None => {
230 return;
231 }
232 }
233 }
234 dest.extend(digits);
235}