rust_decimal/ops/
div.rs

1use crate::constants::{MAX_SCALE_I32, POWERS_10};
2use crate::decimal::{CalculationResult, Decimal};
3use crate::ops::common::{Buf12, Buf16, Dec64};
4
5use core::cmp::Ordering;
6use core::ops::BitXor;
7
8impl Buf12 {
9    // Returns true if successful, else false for an overflow
10    fn add32(&mut self, value: u32) -> Result<(), DivError> {
11        let value = value as u64;
12        let new = self.low64().wrapping_add(value);
13        self.set_low64(new);
14        if new < value {
15            self.data[2] = self.data[2].wrapping_add(1);
16            if self.data[2] == 0 {
17                return Err(DivError::Overflow);
18            }
19        }
20        Ok(())
21    }
22
23    // Divide a Decimal union by a 32 bit divisor.
24    // Self is overwritten with the quotient.
25    // Return value is a 32 bit remainder.
26    fn div32(&mut self, divisor: u32) -> u32 {
27        let divisor64 = divisor as u64;
28        // See if we can get by using a simple u64 division
29        if self.data[2] != 0 {
30            let mut temp = self.high64();
31            let q64 = temp / divisor64;
32            self.set_high64(q64);
33
34            // Calculate the "remainder"
35            temp = ((temp - q64 * divisor64) << 32) | (self.data[0] as u64);
36            if temp == 0 {
37                return 0;
38            }
39            let q32 = (temp / divisor64) as u32;
40            self.data[0] = q32;
41            (temp as u32).wrapping_sub(q32.wrapping_mul(divisor))
42        } else {
43            // Super easy divisor
44            let low64 = self.low64();
45            if low64 == 0 {
46                // Nothing to do
47                return 0;
48            }
49            // Do the calc
50            let quotient = low64 / divisor64;
51            self.set_low64(quotient);
52            // Remainder is the leftover that wasn't used
53            (low64.wrapping_sub(quotient.wrapping_mul(divisor64))) as u32
54        }
55    }
56
57    // Divide the number by a power constant
58    // Returns true if division was successful
59    fn div32_const(&mut self, pow: u32) -> bool {
60        let pow64 = pow as u64;
61        let high64 = self.high64();
62        let lo = self.data[0] as u64;
63        let div64: u64 = high64 / pow64;
64        let div = ((((high64 - div64 * pow64) << 32) + lo) / pow64) as u32;
65        if self.data[0] == div.wrapping_mul(pow) {
66            self.set_high64(div64);
67            self.data[0] = div;
68            true
69        } else {
70            false
71        }
72    }
73}
74
75impl Buf16 {
76    // Does a partial divide with a 64 bit divisor. The divisor in this case must be 64 bits
77    // otherwise various assumptions fail (e.g. 32 bit quotient).
78    // To assist, the upper 64 bits must be greater than the divisor for this to succeed.
79    // Consequently, it will return the quotient as a 32 bit number and overwrite self with the
80    // 64 bit remainder.
81    pub(super) fn partial_divide_64(&mut self, divisor: u64) -> u32 {
82        // We make this assertion here, however below we pivot based on the data
83        debug_assert!(divisor > self.mid64());
84
85        // If we have an empty high bit, then divisor must be greater than the dividend due to
86        // the assumption that the divisor REQUIRES 64 bits.
87        if self.data[2] == 0 {
88            let low64 = self.low64();
89            if low64 < divisor {
90                // We can't divide at at all so result is 0. The dividend remains untouched since
91                // the full amount is the remainder.
92                return 0;
93            }
94
95            let quotient = low64 / divisor;
96            self.set_low64(low64 - (quotient * divisor));
97            return quotient as u32;
98        }
99
100        // Do a simple check to see if the hi portion of the dividend is greater than the hi
101        // portion of the divisor.
102        let divisor_hi32 = (divisor >> 32) as u32;
103        if self.data[2] >= divisor_hi32 {
104            // We know that the divisor goes into this at MOST u32::max times.
105            // So we kick things off, with that assumption
106            let mut low64 = self.low64();
107            low64 = low64.wrapping_sub(divisor << 32).wrapping_add(divisor);
108            let mut quotient = u32::MAX;
109
110            // If we went negative then keep adding it back in
111            loop {
112                if low64 < divisor {
113                    break;
114                }
115                quotient = quotient.wrapping_sub(1);
116                low64 = low64.wrapping_add(divisor);
117            }
118            self.set_low64(low64);
119            return quotient;
120        }
121
122        let mid64 = self.mid64();
123        let divisor_hi32_64 = divisor_hi32 as u64;
124        if mid64 < divisor_hi32_64 {
125            // similar situation as above where we've got nothing left to divide
126            return 0;
127        }
128
129        let mut quotient = mid64 / divisor_hi32_64;
130        let mut remainder = self.data[0] as u64 | ((mid64 - quotient * divisor_hi32_64) << 32);
131
132        // Do quotient * lo divisor
133        let product = quotient * (divisor & 0xFFFF_FFFF);
134        remainder = remainder.wrapping_sub(product);
135
136        // Check if we've gone negative. If so, add it back
137        if remainder > product.bitxor(u64::MAX) {
138            loop {
139                quotient = quotient.wrapping_sub(1);
140                remainder = remainder.wrapping_add(divisor);
141                if remainder < divisor {
142                    break;
143                }
144            }
145        }
146
147        self.set_low64(remainder);
148        quotient as u32
149    }
150
151    // Does a partial divide with a 96 bit divisor. The divisor in this case must require 96 bits
152    // otherwise various assumptions fail (e.g. 32 bit quotient).
153    pub(super) fn partial_divide_96(&mut self, divisor: &Buf12) -> u32 {
154        let dividend = self.high64();
155        let divisor_hi = divisor.data[2];
156        if dividend < divisor_hi as u64 {
157            // Dividend is too small - entire number is remainder
158            return 0;
159        }
160
161        let mut quo = (dividend / divisor_hi as u64) as u32;
162        let mut remainder = (dividend as u32).wrapping_sub(quo.wrapping_mul(divisor_hi));
163
164        // Compute full remainder
165        let mut prod1 = quo as u64 * divisor.data[0] as u64;
166        let mut prod2 = quo as u64 * divisor.data[1] as u64;
167        prod2 += prod1 >> 32;
168        prod1 = (prod1 & 0xFFFF_FFFF) | (prod2 << 32);
169        prod2 >>= 32;
170
171        let mut num = self.low64();
172        num = num.wrapping_sub(prod1);
173        remainder = remainder.wrapping_sub(prod2 as u32);
174
175        // If there are carries make sure they are propagated
176        if num > prod1.bitxor(u64::MAX) {
177            remainder = remainder.wrapping_sub(1);
178            if remainder < (prod2 as u32).bitxor(u32::MAX) {
179                self.set_low64(num);
180                self.data[2] = remainder;
181                return quo;
182            }
183        } else if remainder <= (prod2 as u32).bitxor(u32::MAX) {
184            self.set_low64(num);
185            self.data[2] = remainder;
186            return quo;
187        }
188
189        // Remainder went negative, add divisor back until it's positive
190        prod1 = divisor.low64();
191        loop {
192            quo = quo.wrapping_sub(1);
193            num = num.wrapping_add(prod1);
194            remainder = remainder.wrapping_add(divisor_hi);
195
196            if num < prod1 {
197                // Detected carry.
198                let tmp = remainder;
199                remainder = remainder.wrapping_add(1);
200                if tmp < divisor_hi {
201                    break;
202                }
203            }
204            if remainder < divisor_hi {
205                break; // detected carry
206            }
207        }
208
209        self.set_low64(num);
210        self.data[2] = remainder;
211        quo
212    }
213}
214
215enum DivError {
216    Overflow,
217}
218
219pub(crate) fn div_impl(dividend: &Decimal, divisor: &Decimal) -> CalculationResult {
220    if divisor.is_zero() {
221        return CalculationResult::DivByZero;
222    }
223    if dividend.is_zero() {
224        return CalculationResult::Ok(Decimal::ZERO);
225    }
226    let dividend = Dec64::new(dividend);
227    let divisor = Dec64::new(divisor);
228
229    // Pre calculate the scale and the sign
230    let mut scale = (dividend.scale as i32) - (divisor.scale as i32);
231    let sign_negative = dividend.negative ^ divisor.negative;
232
233    // Set up some variables for modification throughout
234    let mut require_unscale = false;
235    let mut quotient = Buf12::from_dec64(&dividend);
236    let divisor = Buf12::from_dec64(&divisor);
237
238    // Branch depending on the complexity of the divisor
239    if divisor.data[2] | divisor.data[1] == 0 {
240        // We have a simple(r) divisor (32 bit)
241        let divisor32 = divisor.data[0];
242
243        // Remainder can only be 32 bits since the divisor is 32 bits.
244        let mut remainder = quotient.div32(divisor32);
245        let mut power_scale = 0;
246
247        // Figure out how to apply the remainder (i.e. we may have performed something like 10/3 or 8/5)
248        loop {
249            // Remainder is 0 so we have a simple situation
250            if remainder == 0 {
251                // If the scale is positive then we're actually done
252                if scale >= 0 {
253                    break;
254                }
255                power_scale = 9usize.min((-scale) as usize);
256            } else {
257                // We may need to normalize later, so set the flag appropriately
258                require_unscale = true;
259
260                // We have a remainder so we effectively want to try to adjust the quotient and add
261                // the remainder into the quotient. We do this below, however first of all we want
262                // to try to avoid overflowing so we do that check first.
263                let will_overflow = if scale == MAX_SCALE_I32 {
264                    true
265                } else {
266                    // Figure out how much we can scale by
267                    if let Some(s) = quotient.find_scale(scale) {
268                        power_scale = s;
269                    } else {
270                        return CalculationResult::Overflow;
271                    }
272                    // If it comes back as 0 (i.e. 10^0 = 1) then we're going to overflow since
273                    // we're doing nothing.
274                    power_scale == 0
275                };
276                if will_overflow {
277                    // No more scaling can be done, but remainder is non-zero so we round if necessary.
278                    let tmp = remainder << 1;
279                    let round = if tmp < remainder {
280                        // We round if we wrapped around
281                        true
282                    } else if tmp >= divisor32 {
283                        // If we're greater than the divisor (i.e. underflow)
284                        // or if there is a lo bit set, we round
285                        tmp > divisor32 || (quotient.data[0] & 0x1) > 0
286                    } else {
287                        false
288                    };
289
290                    // If we need to round, try to do so.
291                    if round {
292                        if let Ok(new_scale) = round_up(&mut quotient, scale) {
293                            scale = new_scale;
294                        } else {
295                            // Overflowed
296                            return CalculationResult::Overflow;
297                        }
298                    }
299                    break;
300                }
301            }
302
303            // Do some scaling
304            let power = POWERS_10[power_scale];
305            scale += power_scale as i32;
306            // Increase the quotient by the power that was looked up
307            let overflow = increase_scale(&mut quotient, power as u64);
308            if overflow > 0 {
309                return CalculationResult::Overflow;
310            }
311
312            let remainder_scaled = (remainder as u64) * (power as u64);
313            let remainder_quotient = (remainder_scaled / (divisor32 as u64)) as u32;
314            remainder = (remainder_scaled - remainder_quotient as u64 * divisor32 as u64) as u32;
315            if let Err(DivError::Overflow) = quotient.add32(remainder_quotient) {
316                if let Ok(adj) = unscale_from_overflow(&mut quotient, scale, remainder != 0) {
317                    scale = adj;
318                } else {
319                    // Still overflowing
320                    return CalculationResult::Overflow;
321                }
322                break;
323            }
324        }
325    } else {
326        // We have a divisor greater than 32 bits. Both of these share some quick calculation wins
327        // so we'll do those before branching into separate logic.
328        // The win we can do is shifting the bits to the left as much as possible. We do this to both
329        // the dividend and the divisor to ensure the quotient is not changed.
330        // As a simple contrived example: if we have 4 / 2 then we could bit shift all the way to the
331        // left meaning that the lo portion would have nothing inside of it. Of course, shifting these
332        // left one has the same result (8/4) etc.
333        // The advantage is that we may be able to write off lower portions of the number making things
334        // easier.
335        let mut power_scale = if divisor.data[2] == 0 {
336            divisor.data[1].leading_zeros()
337        } else {
338            divisor.data[2].leading_zeros()
339        } as usize;
340        let mut remainder = Buf16::zero();
341        remainder.set_low64(quotient.low64() << power_scale);
342        let tmp_high = ((quotient.data[1] as u64) + ((quotient.data[2] as u64) << 32)) >> (32 - power_scale);
343        remainder.set_high64(tmp_high);
344
345        // Work out the divisor after it's shifted
346        let divisor64 = divisor.low64() << power_scale;
347        // Check if the divisor is 64 bit or the full 96 bits
348        if divisor.data[2] == 0 {
349            // It's 64 bits
350            quotient.data[2] = 0;
351
352            // Calc mid/lo by shifting accordingly
353            let rem_lo = remainder.data[0];
354            remainder.data[0] = remainder.data[1];
355            remainder.data[1] = remainder.data[2];
356            remainder.data[2] = remainder.data[3];
357            quotient.data[1] = remainder.partial_divide_64(divisor64);
358
359            remainder.data[2] = remainder.data[1];
360            remainder.data[1] = remainder.data[0];
361            remainder.data[0] = rem_lo;
362            quotient.data[0] = remainder.partial_divide_64(divisor64);
363
364            loop {
365                let rem_low64 = remainder.low64();
366                if rem_low64 == 0 {
367                    // If the scale is positive then we're actually done
368                    if scale >= 0 {
369                        break;
370                    }
371                    power_scale = 9usize.min((-scale) as usize);
372                } else {
373                    // We may need to normalize later, so set the flag appropriately
374                    require_unscale = true;
375
376                    // We have a remainder so we effectively want to try to adjust the quotient and add
377                    // the remainder into the quotient. We do this below, however first of all we want
378                    // to try to avoid overflowing so we do that check first.
379                    let will_overflow = if scale == MAX_SCALE_I32 {
380                        true
381                    } else {
382                        // Figure out how much we can scale by
383                        if let Some(s) = quotient.find_scale(scale) {
384                            power_scale = s;
385                        } else {
386                            return CalculationResult::Overflow;
387                        }
388                        // If it comes back as 0 (i.e. 10^0 = 1) then we're going to overflow since
389                        // we're doing nothing.
390                        power_scale == 0
391                    };
392                    if will_overflow {
393                        // No more scaling can be done, but remainder is non-zero so we round if necessary.
394                        let mut tmp = remainder.low64();
395                        let round = if (tmp as i64) < 0 {
396                            // We round if we wrapped around
397                            true
398                        } else {
399                            tmp <<= 1;
400                            if tmp > divisor64 {
401                                true
402                            } else {
403                                tmp == divisor64 && quotient.data[0] & 0x1 != 0
404                            }
405                        };
406
407                        // If we need to round, try to do so.
408                        if round {
409                            if let Ok(new_scale) = round_up(&mut quotient, scale) {
410                                scale = new_scale;
411                            } else {
412                                // Overflowed
413                                return CalculationResult::Overflow;
414                            }
415                        }
416                        break;
417                    }
418                }
419
420                // Do some scaling
421                let power = POWERS_10[power_scale];
422                scale += power_scale as i32;
423
424                // Increase the quotient by the power that was looked up
425                let overflow = increase_scale(&mut quotient, power as u64);
426                if overflow > 0 {
427                    return CalculationResult::Overflow;
428                }
429                increase_scale64(&mut remainder, power as u64);
430
431                let tmp = remainder.partial_divide_64(divisor64);
432                if let Err(DivError::Overflow) = quotient.add32(tmp) {
433                    if let Ok(adj) = unscale_from_overflow(&mut quotient, scale, remainder.low64() != 0) {
434                        scale = adj;
435                    } else {
436                        // Still overflowing
437                        return CalculationResult::Overflow;
438                    }
439                    break;
440                }
441            }
442        } else {
443            // It's 96 bits
444            // Start by finishing the shift left
445            let divisor_mid = divisor.data[1];
446            let divisor_hi = divisor.data[2];
447            let mut divisor = divisor;
448            divisor.set_low64(divisor64);
449            divisor.data[2] = ((divisor_mid as u64 + ((divisor_hi as u64) << 32)) >> (32 - power_scale)) as u32;
450
451            let quo = remainder.partial_divide_96(&divisor);
452            quotient.set_low64(quo as u64);
453            quotient.data[2] = 0;
454
455            loop {
456                let mut rem_low64 = remainder.low64();
457                if rem_low64 == 0 && remainder.data[2] == 0 {
458                    // If the scale is positive then we're actually done
459                    if scale >= 0 {
460                        break;
461                    }
462                    power_scale = 9usize.min((-scale) as usize);
463                } else {
464                    // We may need to normalize later, so set the flag appropriately
465                    require_unscale = true;
466
467                    // We have a remainder so we effectively want to try to adjust the quotient and add
468                    // the remainder into the quotient. We do this below, however first of all we want
469                    // to try to avoid overflowing so we do that check first.
470                    let will_overflow = if scale == MAX_SCALE_I32 {
471                        true
472                    } else {
473                        // Figure out how much we can scale by
474                        if let Some(s) = quotient.find_scale(scale) {
475                            power_scale = s;
476                        } else {
477                            return CalculationResult::Overflow;
478                        }
479                        // If it comes back as 0 (i.e. 10^0 = 1) then we're going to overflow since
480                        // we're doing nothing.
481                        power_scale == 0
482                    };
483                    if will_overflow {
484                        // No more scaling can be done, but remainder is non-zero so we round if necessary.
485                        let round = if (remainder.data[2] as i32) < 0 {
486                            // We round if we wrapped around
487                            true
488                        } else {
489                            let tmp = remainder.data[1] >> 31;
490                            rem_low64 <<= 1;
491                            remainder.set_low64(rem_low64);
492                            remainder.data[2] = (&remainder.data[2] << 1) + tmp;
493
494                            match remainder.data[2].cmp(&divisor.data[2]) {
495                                Ordering::Less => false,
496                                Ordering::Equal => {
497                                    let divisor_low64 = divisor.low64();
498                                    if rem_low64 > divisor_low64 {
499                                        true
500                                    } else {
501                                        rem_low64 == divisor_low64 && (quotient.data[0] & 1) != 0
502                                    }
503                                }
504                                Ordering::Greater => true,
505                            }
506                        };
507
508                        // If we need to round, try to do so.
509                        if round {
510                            if let Ok(new_scale) = round_up(&mut quotient, scale) {
511                                scale = new_scale;
512                            } else {
513                                // Overflowed
514                                return CalculationResult::Overflow;
515                            }
516                        }
517                        break;
518                    }
519                }
520
521                // Do some scaling
522                let power = POWERS_10[power_scale];
523                scale += power_scale as i32;
524
525                // Increase the quotient by the power that was looked up
526                let overflow = increase_scale(&mut quotient, power as u64);
527                if overflow > 0 {
528                    return CalculationResult::Overflow;
529                }
530                let mut tmp_remainder = Buf12 {
531                    data: [remainder.data[0], remainder.data[1], remainder.data[2]],
532                };
533                let overflow = increase_scale(&mut tmp_remainder, power as u64);
534                remainder.data[0] = tmp_remainder.data[0];
535                remainder.data[1] = tmp_remainder.data[1];
536                remainder.data[2] = tmp_remainder.data[2];
537                remainder.data[3] = overflow;
538
539                let tmp = remainder.partial_divide_96(&divisor);
540                if let Err(DivError::Overflow) = quotient.add32(tmp) {
541                    if let Ok(adj) =
542                        unscale_from_overflow(&mut quotient, scale, (remainder.low64() | remainder.high64()) != 0)
543                    {
544                        scale = adj;
545                    } else {
546                        // Still overflowing
547                        return CalculationResult::Overflow;
548                    }
549                    break;
550                }
551            }
552        }
553    }
554    if require_unscale {
555        scale = unscale(&mut quotient, scale);
556    }
557    CalculationResult::Ok(Decimal::from_parts(
558        quotient.data[0],
559        quotient.data[1],
560        quotient.data[2],
561        sign_negative,
562        scale as u32,
563    ))
564}
565
566// Multiply num by power (multiple of 10). Power must be 32 bits.
567// Returns the overflow, if any
568fn increase_scale(num: &mut Buf12, power: u64) -> u32 {
569    let mut tmp = (num.data[0] as u64) * power;
570    num.data[0] = tmp as u32;
571    tmp >>= 32;
572    tmp += (num.data[1] as u64) * power;
573    num.data[1] = tmp as u32;
574    tmp >>= 32;
575    tmp += (num.data[2] as u64) * power;
576    num.data[2] = tmp as u32;
577    (tmp >> 32) as u32
578}
579
580// Multiply num by power (multiple of 10). Power must be 32 bits.
581fn increase_scale64(num: &mut Buf16, power: u64) {
582    let mut tmp = (num.data[0] as u64) * power;
583    num.data[0] = tmp as u32;
584    tmp >>= 32;
585    tmp += (num.data[1] as u64) * power;
586    num.set_mid64(tmp)
587}
588
589// Adjust the number to deal with an overflow. This function follows being scaled up (i.e. multiplied
590// by 10, so this effectively tries to reverse that by dividing by 10 then feeding in the high bit
591// to undo the overflow and rounding instead.
592// Returns the updated scale.
593fn unscale_from_overflow(num: &mut Buf12, scale: i32, sticky: bool) -> Result<i32, DivError> {
594    let scale = scale - 1;
595    if scale < 0 {
596        return Err(DivError::Overflow);
597    }
598
599    // This function is called when the hi portion has "overflowed" upon adding one and has wrapped
600    // back around to 0. Consequently, we need to "feed" that back in, but also rescaling down
601    // to reverse out the overflow.
602    const HIGH_BIT: u64 = 0x1_0000_0000;
603    num.data[2] = (HIGH_BIT / 10) as u32;
604
605    // Calc the mid
606    let mut tmp = ((HIGH_BIT % 10) << 32) + (num.data[1] as u64);
607    let mut val = (tmp / 10) as u32;
608    num.data[1] = val;
609
610    // Calc the lo using a similar method
611    tmp = ((tmp - (val as u64) * 10) << 32) + (num.data[0] as u64);
612    val = (tmp / 10) as u32;
613    num.data[0] = val;
614
615    // Work out the remainder, and round if we have one (since it doesn't fit)
616    let remainder = (tmp - (val as u64) * 10) as u32;
617    if remainder > 5 || (remainder == 5 && (sticky || num.data[0] & 0x1 > 0)) {
618        let _ = num.add32(1);
619    }
620    Ok(scale)
621}
622
623#[inline]
624fn round_up(num: &mut Buf12, scale: i32) -> Result<i32, DivError> {
625    let low64 = num.low64().wrapping_add(1);
626    num.set_low64(low64);
627    if low64 != 0 {
628        return Ok(scale);
629    }
630    let hi = num.data[2].wrapping_add(1);
631    num.data[2] = hi;
632    if hi != 0 {
633        return Ok(scale);
634    }
635    unscale_from_overflow(num, scale, true)
636}
637
638fn unscale(num: &mut Buf12, scale: i32) -> i32 {
639    // Since 10 = 2 * 5, there must be a factor of 2 for every power of 10 we can extract.
640    // We use this as a quick test on whether to try a given power.
641    let mut scale = scale;
642    while num.data[0] == 0 && scale >= 8 && num.div32_const(100000000) {
643        scale -= 8;
644    }
645
646    if (num.data[0] & 0xF) == 0 && scale >= 4 && num.div32_const(10000) {
647        scale -= 4;
648    }
649
650    if (num.data[0] & 0x3) == 0 && scale >= 2 && num.div32_const(100) {
651        scale -= 2;
652    }
653
654    if (num.data[0] & 0x1) == 0 && scale >= 1 && num.div32_const(10) {
655        scale -= 1;
656    }
657    scale
658}