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