1use crate::*;
4use crate::arithmetic::{add_carry, store_carry, extend_adding_with_carry};
5use stdlib;
6use stdlib::num::NonZeroU64;
7
8include!(concat!(env!("OUT_DIR"), "/default_rounding_mode.rs"));
10
11)]
18pub enum RoundingMode {
19 Up,
31
32 Down,
43
44 Ceiling,
55
56 Floor,
67
68 HalfUp,
79
80 HalfDown,
91
92 HalfEven,
105}
106
107
108impl RoundingMode {
109 pub fn round_pair(&self, sign: Sign, pair: (u8, u8), trailing_zeros: bool) -> u8 {
135 use self::RoundingMode::*;
136 use stdlib::cmp::Ordering::*;
137
138 let (lhs, rhs) = pair;
139 if rhs == 0 && trailing_zeros {
141 return lhs;
142 }
143 let up = lhs + 1;
144 let down = lhs;
145 match (*self, rhs.cmp(&5)) {
146 (Up, _) => up,
147 (Down, _) => down,
148 (Floor, _) => if sign == Sign::Minus { up } else { down },
149 (Ceiling, _) => if sign == Sign::Minus { down } else { up },
150 (_, Less) => down,
151 (_, Greater) => up,
152 (_, Equal) if !trailing_zeros => up,
153 (HalfUp, Equal) => up,
154 (HalfDown, Equal) => down,
155 (HalfEven, Equal) => if lhs % 2 == 0 { down } else { up },
156 }
157 }
158
159 pub(crate) fn round_pair_with_carry(
161 &self,
162 sign: Sign,
163 pair: (u8, u8),
164 trailing_zeros: bool,
165 carry: &mut u8,
166 ) -> u8 {
167 let r = self.round_pair(sign, pair, trailing_zeros);
168 store_carry(r, carry)
169 }
170
171 pub fn round_u32(
195 &self,
196 at_digit: stdlib::num::NonZeroU8,
197 sign: Sign,
198 value: u32,
199 trailing_zeros: bool,
200 ) -> u32 {
201 let shift = 10u32.pow(at_digit.get() as u32 - 1);
202 let splitter = shift * 10;
203
204 let (top, bottom) = num_integer::div_rem(value, splitter);
206 let lhs = (top % 10) as u8;
207 let (rhs, remainder) = num_integer::div_rem(bottom, shift);
208 let pair = (lhs, rhs as u8);
209 let rounded = self.round_pair(sign, pair, trailing_zeros && remainder == 0);
210
211 let full = top - lhs as u32 + rounded as u32;
213
214 full * splitter
216 }
217
218 pub(crate) fn round_bigint_to_prec(
220 self, n: num_bigint::BigInt, prec: NonZeroU64
221 ) -> WithScale<num_bigint::BigInt> {
222 let (sign, mut biguint) = n.into_parts();
223
224 let ndrd = NonDigitRoundingData { mode: self, sign };
225 let ndigits = round_biguint_inplace(&mut biguint, prec, ndrd);
226
227 let result = BigInt::from_biguint(sign, biguint);
228 WithScale::from((result, -ndigits))
229 }
230
231 fn needs_trailing_zeros(&self, insig_digit: u8) -> bool {
233 use RoundingMode::*;
234
235 if #[allow(non_exhaustive_omitted_patterns)] match self {
HalfUp | HalfDown | HalfEven => true,
_ => false,
}matches!(self, HalfUp | HalfDown | HalfEven) {
237 insig_digit == 5
238 } else {
239 insig_digit == 0
240 }
241 }
242
243}
244
245impl Default for RoundingMode {
250 fn default() -> Self {
251 DEFAULT_ROUNDING_MODE
252 }
253}
254
255
256)]
261pub(crate) struct NonDigitRoundingData {
262 pub mode: RoundingMode,
264 pub sign: Sign,
266}
267
268impl NonDigitRoundingData {
269 pub fn round_pair(&self, pair: (u8, u8), trailing_zeros: bool) -> u8 {
271 self.mode.round_pair(self.sign, pair, trailing_zeros)
272 }
273
274 pub fn round_pair_with_carry(&self, pair: (u8, u8), trailing_zeros: bool, carry: &mut u8) -> u8 {
276 self.mode.round_pair_with_carry(self.sign, pair, trailing_zeros, carry)
277 }
278
279 pub fn default_with_sign(sign: Sign) -> Self {
281 NonDigitRoundingData { sign, mode: RoundingMode::default() }
282 }
283
284 pub(crate) fn round_biguint_to_prec(
290 self, mut n: num_bigint::BigUint, prec: NonZeroU64
291 ) -> WithScale<num_bigint::BigUint> {
292 let ndigits = round_biguint_inplace(&mut n, prec, self);
293 WithScale::from((n, -ndigits))
294 }
295
296}
297
298
299)]
312pub(crate) struct InsigData {
313 pub digit: u8,
315
316 pub trailing_zeros: bool,
321
322 pub rounding_data: NonDigitRoundingData
324}
325
326#[allow(dead_code)]
327impl InsigData {
328 pub fn from_digit_and_lazy_trailing_zeros(
330 rounder: NonDigitRoundingData,
331 insig_digit: u8,
332 calc_trailing_zeros: impl FnOnce() -> bool
333 ) -> Self {
334 Self {
335 digit: insig_digit,
336 trailing_zeros: rounder.mode.needs_trailing_zeros(insig_digit) && calc_trailing_zeros(),
337 rounding_data: rounder,
338 }
339 }
340
341 pub fn from_digit_slice(rounder: NonDigitRoundingData, digits: &[u8]) -> Self {
343 match digits.split_last() {
344 Some((&d0, trailing)) => {
345 Self::from_digit_and_lazy_trailing_zeros(
346 rounder, d0, || trailing.iter().all(Zero::is_zero)
347 )
348 }
349 None => {
350 Self {
351 digit: 0,
352 trailing_zeros: true,
353 rounding_data: rounder,
354 }
355 }
356 }
357 }
358
359 pub fn from_overlapping_digits_backward_sum(
361 rounder: NonDigitRoundingData,
362 mut a_digits: stdlib::iter::Rev<stdlib::slice::Iter<u8>>,
363 mut b_digits: stdlib::iter::Rev<stdlib::slice::Iter<u8>>,
364 carry: &mut u8,
365 ) -> Self {
366 if true {
if !(a_digits.len() >= b_digits.len()) {
::core::panicking::panic("assertion failed: a_digits.len() >= b_digits.len()")
};
};debug_assert!(a_digits.len() >= b_digits.len());
367 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);
368
369 let insig_digit;
371 match (a_digits.next(), b_digits.next()) {
372 (Some(a), Some(b)) => {
373 insig_digit = a + b;
375 }
376 (Some(d), None) | (None, Some(d)) => {
377 insig_digit = *d;
378 }
379 (None, None) => {
380 return Self {
382 digit: 0,
383 trailing_zeros: true,
384 rounding_data: rounder,
385 };
386 }
387 };
388
389 let mut sum = 9;
391 while sum == 9 {
392 let next_a = a_digits.next().unwrap_or(&0);
393 let next_b = b_digits.next().unwrap_or(&0);
394 sum = next_a + next_b;
395 }
396
397 let sum = store_carry(sum, carry);
400
401 let insig_digit = add_carry(insig_digit, carry);
403
404 let trailing_zeros = sum == 0
407 && rounder.mode.needs_trailing_zeros(insig_digit)
408 && a_digits.all(Zero::is_zero)
409 && b_digits.all(Zero::is_zero);
410
411 Self {
412 digit: insig_digit,
413 trailing_zeros: trailing_zeros,
414 rounding_data: rounder,
415 }
416 }
417
418 pub fn round_digit(&self, digit: u8) -> u8 {
419 self.rounding_data.round_pair((digit, self.digit), self.trailing_zeros)
420 }
421
422 pub fn round_digit_with_carry(&self, digit: u8, carry: &mut u8) -> u8 {
423 self.rounding_data.round_pair_with_carry((digit, self.digit), self.trailing_zeros, carry)
424 }
425
426 pub fn round_slice_into(&self, dest: &mut Vec<u8>, digits: &[u8]) {
427 let (&d0, rest) = digits.split_first().unwrap_or((&0, &[]));
428 let digits = rest.iter().copied();
429 let mut carry = 0;
430 let r0 = self.round_digit_with_carry(d0, &mut carry);
431 dest.push(r0);
432 extend_adding_with_carry(dest, digits, &mut carry);
433 if !carry.is_zero() {
434 dest.push(carry);
435 }
436 }
437
438 #[allow(dead_code)]
439 pub fn round_slice_into_with_carry(&self, dest: &mut Vec<u8>, digits: &[u8], carry: &mut u8) {
440 let (&d0, rest) = digits.split_first().unwrap_or((&0, &[]));
441 let digits = rest.iter().copied();
442 let r0 = self.round_digit_with_carry(d0, carry);
443 dest.push(r0);
444
445 extend_adding_with_carry(dest, digits, carry);
446 }
447}
448
449fn round_biguint_inplace(
451 n: &mut num_bigint::BigUint,
452 prec: NonZeroU64,
453 rounder: NonDigitRoundingData,
454) -> i64 {
455 use arithmetic::modulo::{mod_ten_2p64_le, mod_100_uint};
456 use arithmetic::decimal::count_digits_biguint;
457
458 let digit_count = count_digits_biguint(n);
459 let digits_to_remove = digit_count.saturating_sub(prec.get());
460 if digits_to_remove == 0 {
461 return 0;
462 }
463
464 if digits_to_remove == 1 {
465 let insig_digit = mod_ten_2p64_le(n.iter_u64_digits());
466 *n /= 10u8;
467 let sig_digit = mod_ten_2p64_le(n.iter_u64_digits());
468 let rounded_digit = rounder.round_pair((sig_digit, insig_digit), true);
469 *n += rounded_digit - sig_digit;
470 if rounded_digit != 10 {
471 return 1;
472 }
473 let digit_count = count_digits_biguint(n);
474 if digit_count == prec.get() {
475 return 1;
476 }
477 if true {
match (&digit_count, &(prec.get() + 1)) {
(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!(digit_count, prec.get() + 1);
478 *n /= 10u8;
479 return 2;
480 }
481
482 let shifter = ten_to_the_uint(digits_to_remove - 1);
483 let low_digits = &(*n) % &shifter;
484 let trailing_zeros = low_digits.is_zero();
485
486 *n /= &shifter;
487 let u = mod_100_uint(n);
488 let (sig_digit, insig_digit) = u.div_rem(&10);
489 let rounded_digit = rounder.round_pair((sig_digit, insig_digit), trailing_zeros);
490 *n /= 10u8;
491 *n += rounded_digit - sig_digit;
492
493 if rounded_digit != 10 {
494 return digits_to_remove as i64;
495 }
496
497 let digit_count = count_digits_biguint(n);
498 if digit_count == prec.get() {
499 return digits_to_remove as i64;
500 }
501
502 if true {
match (&digit_count, &(prec.get() + 1)) {
(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!(digit_count, prec.get() + 1);
503
504 *n /= 10u8;
507 return digits_to_remove as i64 + 1;
508}
509
510
511#[cfg(test)]
512include!("rounding.tests.rs");