1use crate::constants::{MAX_SCALE_U32, POWERS_10, U32_MASK};
2
3#[inline]
6pub(crate) fn rescale_internal(value: &mut [u32; 3], value_scale: &mut u32, new_scale: u32) {
7 rescale::<true>(value, value_scale, new_scale);
8}
9
10#[inline(always)]
11fn rescale<const ROUND: bool>(value: &mut [u32; 3], value_scale: &mut u32, new_scale: u32) {
12 if *value_scale == new_scale {
13 return;
15 }
16
17 if is_all_zero(value) {
18 *value_scale = new_scale.min(MAX_SCALE_U32);
19 return;
20 }
21
22 if *value_scale > new_scale {
23 let mut diff = value_scale.wrapping_sub(new_scale);
24 let mut remainder = 0;
29 while let Some(diff_minus_one) = diff.checked_sub(1) {
30 if is_all_zero(value) {
31 *value_scale = new_scale;
32 return;
33 }
34
35 diff = diff_minus_one;
36
37 remainder = div_by_u32(value, 10);
39 }
40 if ROUND && remainder >= 5 {
41 for part in value.iter_mut() {
42 let digit = u64::from(*part) + 1u64;
43 remainder = if digit > U32_MASK { 1 } else { 0 };
44 *part = (digit & U32_MASK) as u32;
45 if remainder == 0 {
46 break;
47 }
48 }
49 }
50 *value_scale = new_scale;
51 } else {
52 let mut diff = new_scale.wrapping_sub(*value_scale);
53 let mut working = [value[0], value[1], value[2]];
54 while let Some(diff_minus_one) = diff.checked_sub(1) {
55 if mul_by_10(&mut working) == 0 {
56 value.copy_from_slice(&working);
57 diff = diff_minus_one;
58 } else {
59 break;
60 }
61 }
62 *value_scale = new_scale.wrapping_sub(diff);
63 }
64}
65
66#[inline]
67pub(crate) fn truncate_internal(value: &mut [u32; 3], value_scale: &mut u32, desired_scale: u32) {
68 rescale::<false>(value, value_scale, desired_scale);
69}
70
71#[cfg(feature = "legacy-ops")]
72pub(crate) fn add_by_internal(value: &mut [u32], by: &[u32]) -> u32 {
73 let mut carry: u64 = 0;
74 let vl = value.len();
75 let bl = by.len();
76 if vl >= bl {
77 let mut sum: u64;
78 for i in 0..bl {
79 sum = u64::from(value[i]) + u64::from(by[i]) + carry;
80 value[i] = (sum & U32_MASK) as u32;
81 carry = sum >> 32;
82 }
83 if vl > bl && carry > 0 {
84 for i in value.iter_mut().skip(bl) {
85 sum = u64::from(*i) + carry;
86 *i = (sum & U32_MASK) as u32;
87 carry = sum >> 32;
88 if carry == 0 {
89 break;
90 }
91 }
92 }
93 } else if vl + 1 == bl {
94 let mut sum: u64;
96 for i in 0..vl {
97 sum = u64::from(value[i]) + u64::from(by[i]) + carry;
98 value[i] = (sum & U32_MASK) as u32;
99 carry = sum >> 32;
100 }
101 if by[vl] > 0 {
102 carry += u64::from(by[vl]);
103 }
104 } else {
105 panic!("Internal error: add using incompatible length arrays. {} <- {}", vl, bl);
106 }
107 carry as u32
108}
109
110pub(crate) fn add_by_internal_flattened(value: &mut [u32; 3], by: u32) -> u32 {
111 manage_add_by_internal(by, value)
112}
113
114#[inline]
115pub(crate) fn add_one_internal(value: &mut [u32; 3]) -> u32 {
116 manage_add_by_internal(1, value)
117}
118
119#[inline]
121pub(crate) fn manage_add_by_internal<const N: usize>(initial_carry: u32, value: &mut [u32; N]) -> u32 {
122 let mut carry = u64::from(initial_carry);
123 let mut iter = 0..value.len();
124 let mut sum = 0;
125
126 let mut sum_fn = |local_carry: &mut u64, idx| {
127 sum = u64::from(value[idx]).wrapping_add(*local_carry);
128 value[idx] = (sum & U32_MASK) as u32;
129 *local_carry = sum.wrapping_shr(32);
130 };
131
132 if let Some(idx) = iter.next() {
133 sum_fn(&mut carry, idx);
134 }
135
136 for idx in iter {
137 if carry > 0 {
138 sum_fn(&mut carry, idx);
139 }
140 }
141
142 carry as u32
143}
144
145pub(crate) fn sub_by_internal(value: &mut [u32], by: &[u32]) -> u32 {
146 let mut overflow = 0;
175 let vl = value.len();
176 let bl = by.len();
177 for i in 0..vl {
178 if i >= bl {
179 break;
180 }
181 let (lo, hi) = sub_part(value[i], by[i], overflow);
182 value[i] = lo;
183 overflow = hi;
184 }
185 overflow
186}
187
188fn sub_part(left: u32, right: u32, overflow: u32) -> (u32, u32) {
189 let part = 0x1_0000_0000u64 + u64::from(left) - (u64::from(right) + u64::from(overflow));
190 let lo = part as u32;
191 let hi = 1 - ((part >> 32) as u32);
192 (lo, hi)
193}
194
195#[inline]
197pub(crate) fn mul_by_10(bits: &mut [u32; 3]) -> u32 {
198 let mut overflow = 0u64;
199 for b in bits.iter_mut() {
200 let result = u64::from(*b) * 10u64 + overflow;
201 let hi = (result >> 32) & U32_MASK;
202 let lo = (result & U32_MASK) as u32;
203 *b = lo;
204 overflow = hi;
205 }
206
207 overflow as u32
208}
209
210pub(crate) fn mul_by_u32(bits: &mut [u32], m: u32) -> u32 {
212 let mut overflow = 0;
213 for b in bits.iter_mut() {
214 let (lo, hi) = mul_part(*b, m, overflow);
215 *b = lo;
216 overflow = hi;
217 }
218 overflow
219}
220
221pub(crate) fn mul_part(left: u32, right: u32, high: u32) -> (u32, u32) {
222 let result = u64::from(left) * u64::from(right) + u64::from(high);
223 let hi = ((result >> 32) & U32_MASK) as u32;
224 let lo = (result & U32_MASK) as u32;
225 (lo, hi)
226}
227
228pub(crate) fn div_by_u32<const N: usize>(bits: &mut [u32; N], divisor: u32) -> u32 {
230 if divisor == 0 {
231 panic!("Internal error: divide by zero");
233 } else if divisor == 1 {
234 0
236 } else {
237 let mut remainder = 0u32;
238 let divisor = u64::from(divisor);
239 for part in bits.iter_mut().rev() {
240 let temp = (u64::from(remainder) << 32) + u64::from(*part);
241 remainder = (temp % divisor) as u32;
242 *part = (temp / divisor) as u32;
243 }
244
245 remainder
246 }
247}
248
249pub(crate) fn div_by_power<const POWER: usize>(bits: &mut [u32; 3]) -> u32 {
252 let mut remainder = 0u32;
253 let divisor = POWERS_10[POWER] as u64;
254 let temp = ((remainder as u64) << 32) + (bits[2] as u64);
255 remainder = (temp % divisor) as u32;
256 bits[2] = (temp / divisor) as u32;
257 let temp = ((remainder as u64) << 32) + (bits[1] as u64);
258 remainder = (temp % divisor) as u32;
259 bits[1] = (temp / divisor) as u32;
260 let temp = ((remainder as u64) << 32) + (bits[0] as u64);
261 remainder = (temp % divisor) as u32;
262 bits[0] = (temp / divisor) as u32;
263 remainder
264}
265
266#[inline]
267pub(crate) fn shl1_internal(bits: &mut [u32], carry: u32) -> u32 {
268 let mut carry = carry;
269 for part in bits.iter_mut() {
270 let b = *part >> 31;
271 *part = (*part << 1) | carry;
272 carry = b;
273 }
274 carry
275}
276
277#[inline]
278pub(crate) fn cmp_internal(left: &[u32; 3], right: &[u32; 3]) -> core::cmp::Ordering {
279 let left_hi: u32 = left[2];
280 let right_hi: u32 = right[2];
281 let left_lo: u64 = (u64::from(left[1]) << 32) | u64::from(left[0]);
282 let right_lo: u64 = (u64::from(right[1]) << 32) | u64::from(right[0]);
283 if left_hi < right_hi || (left_hi <= right_hi && left_lo < right_lo) {
284 core::cmp::Ordering::Less
285 } else if left_hi == right_hi && left_lo == right_lo {
286 core::cmp::Ordering::Equal
287 } else {
288 core::cmp::Ordering::Greater
289 }
290}
291
292#[inline]
293pub(crate) fn is_all_zero<const N: usize>(bits: &[u32; N]) -> bool {
294 bits.iter().all(|b| *b == 0)
295}
296
297#[cfg(test)]
298mod test {
299 use super::*;
304 use crate::prelude::*;
305
306 fn to_mantissa_array_with_scale(value: &str) -> ([u32; 3], u32) {
307 let v = Decimal::from_str(value).unwrap();
308 (v.mantissa_array3(), v.scale())
309 }
310
311 #[test]
312 fn it_can_rescale_internal() {
313 let tests = &[
314 ("1", 0, "1", 0),
315 ("1", 1, "1.0", 1),
316 ("1", 5, "1.00000", 5),
317 ("1", 10, "1.0000000000", 10),
318 ("1", 20, "1.00000000000000000000", 20),
319 (
320 "0.6386554621848739495798319328",
321 27,
322 "0.638655462184873949579831933",
323 27,
324 ),
325 (
326 "843.65000000", 25,
328 "843.6500000000000000000000000",
329 25,
330 ),
331 (
332 "843.65000000", 30,
334 "843.6500000000000000000000000",
335 25, ),
337 ("0", 130, "0.000000000000000000000000000000", 28),
338 ];
339
340 for &(value_raw, new_scale, expected_value, expected_scale) in tests {
341 let (expected_value, _) = to_mantissa_array_with_scale(expected_value);
342 let (mut value, mut value_scale) = to_mantissa_array_with_scale(value_raw);
343 rescale_internal(&mut value, &mut value_scale, new_scale);
344 assert_eq!(value, expected_value);
345 assert_eq!(
346 value_scale, expected_scale,
347 "value: {value_raw}, requested scale: {new_scale}"
348 );
349 }
350 }
351
352 #[test]
353 fn test_shl1_internal() {
354 struct TestCase {
355 given: [u32; 3],
359 given_carry: u32,
360 expected: [u32; 3],
361 expected_carry: u32,
362 }
363 let tests = [
364 TestCase {
365 given: [1, 0, 0],
366 given_carry: 0,
367 expected: [2, 0, 0],
368 expected_carry: 0,
369 },
370 TestCase {
371 given: [1, 0, 2147483648],
372 given_carry: 1,
373 expected: [3, 0, 0],
374 expected_carry: 1,
375 },
376 ];
377 for case in &tests {
378 let mut test = [case.given[0], case.given[1], case.given[2]];
379 let carry = shl1_internal(&mut test, case.given_carry);
380 assert_eq!(
381 test, case.expected,
382 "Bits: {:?} << 1 | {}",
383 case.given, case.given_carry
384 );
385 assert_eq!(
386 carry, case.expected_carry,
387 "Carry: {:?} << 1 | {}",
388 case.given, case.given_carry
389 )
390 }
391 }
392}