Coverage Report

Created: 2025-07-18 06:22

/rust/registry/src/index.crates.io-6f17d22bba15001f/fixed_decimal-0.5.6/src/decimal.rs
Line
Count
Source (jump to first uncovered line)
1
// This file is part of ICU4X. For terms of use, please see the file
2
// called LICENSE at the top level of the ICU4X source tree
3
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5
use smallvec::SmallVec;
6
7
use core::cmp;
8
use core::cmp::Ordering;
9
use core::convert::TryFrom;
10
use core::fmt;
11
use core::ops::RangeInclusive;
12
13
use core::str::FromStr;
14
15
use crate::uint_iterator::IntIterator;
16
17
use crate::Error;
18
19
// FixedDecimal assumes usize (digits.len()) is at least as big as a u16
20
#[cfg(not(any(
21
    target_pointer_width = "16",
22
    target_pointer_width = "32",
23
    target_pointer_width = "64"
24
)))]
25
compile_error!("The fixed_decimal crate only works if usizes are at least the size of a u16");
26
27
/// A struct containing decimal digits with efficient iteration and manipulation by magnitude
28
/// (power of 10). Supports a mantissa of non-zero digits and a number of leading and trailing
29
/// zeros, as well as an optional sign; used for formatting and plural selection.
30
///
31
/// # Data Types
32
///
33
/// The following types can be converted to a `FixedDecimal`:
34
///
35
/// - Integers, signed and unsigned
36
/// - Strings representing an arbitrary-precision decimal
37
///
38
/// To create a [`FixedDecimal`] with fraction digits, either create it from an integer and then
39
/// call [`FixedDecimal::multiplied_pow10`], or create it from a string.
40
///
41
/// Floating point numbers will be supported pending a resolution to
42
/// [#166](https://github.com/unicode-org/icu4x/issues/166). In the mean time, a third-party
43
/// float-to-string library may be used.
44
///
45
/// # Magnitude and Position
46
///
47
/// Each digit in a `FixedDecimal` is indexed by a *magnitude*, or the digit's power of 10.
48
/// Illustration for the number "12.34":
49
///
50
/// | Magnitude | Digit | Description      |
51
/// |-----------|-------|------------------|
52
/// | 1         | 1     | Tens place       |
53
/// | 0         | 2     | Ones place       |
54
/// | -1        | 3     | Tenths place     |
55
/// | -2        | 4     | Hundredths place |
56
///
57
/// Some functions deal with a *position* for the purpose of padding, truncating, or rounding a
58
/// number. In these cases, the position is the index on the right side of the digit of the
59
/// corresponding magnitude. Illustration:
60
///
61
/// ```text
62
/// Position:   2   0  -2
63
/// Number:     |1|2.3|4|
64
/// Position:     1  -1
65
/// ```
66
///
67
/// Expected output of various operations, all with input "12.34":
68
///
69
/// | Operation       | Position  | Expected Result |
70
/// |-----------------|-----------|-----------------|
71
/// | Truncate Left   | 1         | 10              |
72
/// | Truncate Right  | -1        | 12.3            |
73
/// | Pad Left        | 4         | 0012.34         |
74
/// | Pad Right       | -4        | 12.3400         |
75
///
76
/// # Examples
77
///
78
/// ```
79
/// use fixed_decimal::FixedDecimal;
80
///
81
/// let mut dec = FixedDecimal::from(250);
82
/// assert_eq!("250", dec.to_string());
83
///
84
/// dec.multiply_pow10(-2);
85
/// assert_eq!("2.50", dec.to_string());
86
/// ```
87
#[derive(Debug, Clone, PartialEq)]
88
pub struct FixedDecimal {
89
    /// List of digits; digits\[0\] is the most significant.
90
    ///
91
    /// Invariants:
92
    /// - Must not include leading or trailing zeros
93
    /// - Length must not exceed (magnitude - lower_magnitude + 1)
94
    // TODO: Consider using a nibble array
95
    digits: SmallVec<[u8; 8]>,
96
97
    /// Power of 10 of digits\[0\].
98
    ///
99
    /// Invariants:
100
    /// - <= upper_magnitude
101
    /// - >= lower_magnitude
102
    magnitude: i16,
103
104
    /// Power of 10 of the most significant digit, which may be zero.
105
    ///
106
    /// Invariants:
107
    /// - >= 0
108
    /// - >= magnitude
109
    upper_magnitude: i16,
110
111
    /// Power of 10 of the least significant digit, which may be zero.
112
    ///
113
    /// Invariants:
114
    /// - <= 0
115
    /// - <= magnitude
116
    lower_magnitude: i16,
117
118
    /// The sign; note that a positive value may be represented by either
119
    /// `Sign::Positive` (corresponding to a prefix +) or `Sign::None`
120
    /// (corresponding to the absence of a prefix sign).
121
    sign: Sign,
122
}
123
124
/// A specification of the sign used when formatting a number.
125
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
126
#[allow(clippy::exhaustive_enums)]
127
// There are only 3 sign values, and they correspond to the low-level data model of FixedDecimal and UTS 35.
128
pub enum Sign {
129
    /// No sign (implicitly positive, e.g., 1729).
130
    None,
131
    /// A negative sign, e.g., -1729.
132
    Negative,
133
    /// An explicit positive sign, e.g., +1729.
134
    Positive,
135
}
136
137
/// Configuration for when to render the minus sign or plus sign.
138
#[non_exhaustive]
139
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
140
pub enum SignDisplay {
141
    /// Render the sign according to locale preferences. In most cases, this means a minus sign
142
    /// will be shown on negative numbers, and no sign will be shown on positive numbers.
143
    Auto,
144
145
    /// Do not display the sign. Positive and negative numbers are indistinguishable.
146
    Never,
147
148
    /// Show a minus sign on negative numbers and a plus sign on positive numbers, including zero.
149
    Always,
150
151
    /// Show a minus sign on negative numbers and a plus sign on positive numbers, except do not
152
    /// show any sign on positive or negative zero.
153
    ExceptZero,
154
155
    /// Show a minus sign on strictly negative numbers. Do not show a sign on positive numbers or
156
    /// on positive or negative zero.
157
    ///
158
    /// This differs from [`Auto`](SignDisplay::Auto) in that it does not render a sign on negative zero.
159
    Negative,
160
}
161
162
impl Default for FixedDecimal {
163
    /// Returns a `FixedDecimal` representing zero.
164
0
    fn default() -> Self {
165
0
        Self {
166
0
            digits: SmallVec::new(),
167
0
            magnitude: 0,
168
0
            upper_magnitude: 0,
169
0
            lower_magnitude: 0,
170
0
            sign: Sign::None,
171
0
        }
172
0
    }
173
}
174
175
macro_rules! impl_from_signed_integer_type {
176
    ($itype:ident, $utype: ident) => {
177
        impl From<$itype> for FixedDecimal {
178
0
            fn from(value: $itype) -> Self {
179
0
                let int_iterator: IntIterator<$utype> = value.into();
180
0
                let sign = if int_iterator.is_negative {
181
0
                    Sign::Negative
182
                } else {
183
0
                    Sign::None
184
                };
185
0
                let mut result = Self::from_ascending(int_iterator)
186
0
                    .expect("All built-in integer types should fit");
187
0
                result.sign = sign;
188
0
                result
189
0
            }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as core::convert::From<isize>>::from
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as core::convert::From<i128>>::from
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as core::convert::From<i64>>::from
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as core::convert::From<i32>>::from
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as core::convert::From<i16>>::from
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as core::convert::From<i8>>::from
190
        }
191
    };
192
}
193
194
macro_rules! impl_from_unsigned_integer_type {
195
    ($utype: ident) => {
196
        impl From<$utype> for FixedDecimal {
197
0
            fn from(value: $utype) -> Self {
198
0
                let int_iterator: IntIterator<$utype> = value.into();
199
0
                Self::from_ascending(int_iterator).expect("All built-in integer types should fit")
200
0
            }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as core::convert::From<usize>>::from
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as core::convert::From<u128>>::from
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as core::convert::From<u64>>::from
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as core::convert::From<u32>>::from
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as core::convert::From<u16>>::from
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as core::convert::From<u8>>::from
201
        }
202
    };
203
}
204
205
impl_from_signed_integer_type!(isize, usize);
206
impl_from_signed_integer_type!(i128, u128);
207
impl_from_signed_integer_type!(i64, u64);
208
impl_from_signed_integer_type!(i32, u32);
209
impl_from_signed_integer_type!(i16, u16);
210
impl_from_signed_integer_type!(i8, u8);
211
212
impl_from_unsigned_integer_type!(usize);
213
impl_from_unsigned_integer_type!(u128);
214
impl_from_unsigned_integer_type!(u64);
215
impl_from_unsigned_integer_type!(u32);
216
impl_from_unsigned_integer_type!(u16);
217
impl_from_unsigned_integer_type!(u8);
218
219
/// Increment used in a rounding operation.
220
///
221
/// Forces a rounding operation to round to only multiples of the specified increment.
222
#[derive(Debug, Eq, PartialEq, Clone, Copy, Default)]
223
#[non_exhaustive]
224
pub enum RoundingIncrement {
225
    /// Round the last digit to any digit (0-9).
226
    ///
227
    /// This is the default rounding increment for all the methods that don't take a
228
    /// `RoundingIncrement` as an argument.
229
    #[default]
230
    MultiplesOf1,
231
    /// Round the last digit to only multiples of two (0, 2, 4, 6, 8).
232
    MultiplesOf2,
233
    /// Round the last digit to only multiples of five (0, 5).
234
    MultiplesOf5,
235
    /// Round the last two digits to only multiples of twenty-five (0, 25, 50, 75).
236
    MultiplesOf25,
237
}
238
239
// Adapters to convert runtime dispatched calls into const-inlined methods.
240
// This allows reducing the codesize for the common case of no increment.
241
242
#[derive(Copy, Clone, PartialEq)]
243
struct NoIncrement;
244
245
trait IncrementLike: Copy + Sized + PartialEq {
246
    const MULTIPLES_OF_1: Option<Self>;
247
    const MULTIPLES_OF_2: Option<Self>;
248
    const MULTIPLES_OF_5: Option<Self>;
249
    const MULTIPLES_OF_25: Option<Self>;
250
}
251
252
impl IncrementLike for RoundingIncrement {
253
    const MULTIPLES_OF_1: Option<Self> = Some(Self::MultiplesOf1);
254
255
    const MULTIPLES_OF_2: Option<Self> = Some(Self::MultiplesOf2);
256
257
    const MULTIPLES_OF_5: Option<Self> = Some(Self::MultiplesOf5);
258
259
    const MULTIPLES_OF_25: Option<Self> = Some(Self::MultiplesOf25);
260
}
261
262
impl IncrementLike for NoIncrement {
263
    const MULTIPLES_OF_1: Option<Self> = Some(Self);
264
265
    const MULTIPLES_OF_2: Option<Self> = None;
266
267
    const MULTIPLES_OF_5: Option<Self> = None;
268
269
    const MULTIPLES_OF_25: Option<Self> = None;
270
}
271
272
impl FixedDecimal {
273
    /// Initialize a `FixedDecimal` with an iterator of digits in ascending
274
    /// order of magnitude, starting with the digit at magnitude 0.
275
    ///
276
    /// This method is not public; use `TryFrom::<isize>` instead.
277
0
    fn from_ascending<T>(digits_iter: T) -> Result<Self, Error>
278
0
    where
279
0
        T: Iterator<Item = u8>,
280
0
    {
281
        // TODO: make X a usize generic to customize the size of this array
282
        // https://github.com/rust-lang/rust/issues/44580
283
        // NOTE: 39 is the size required for u128: ceil(log10(u128::MAX)) == 39.
284
        const X: usize = 39;
285
        // A temporary structure to allow the digits in the iterator to be reversed.
286
        // The digits are inserted started from the end, and then a slice is copied
287
        // into its final destination (result.digits).
288
0
        let mut mem: [u8; X] = [0u8; X];
289
0
        let mut trailing_zeros: usize = 0;
290
0
        let mut i: usize = 0;
291
0
        for (x, d) in digits_iter.enumerate() {
292
            // Take only up to i16::MAX values so that we have enough capacity
293
0
            if x > i16::MAX as usize {
294
0
                return Err(Error::Limit);
295
0
            }
296
0
            // TODO: Should we check here that `d` is between 0 and 9?
297
0
            // That should always be the case if IntIterator is used.
298
0
            if i != 0 || d != 0 {
299
0
                i += 1;
300
0
                match X.checked_sub(i) {
301
                    #[allow(clippy::indexing_slicing)] // X - i < X
302
0
                    Some(v) => mem[v] = d,
303
                    // This error should be obsolete after X is made generic
304
0
                    None => return Err(Error::Limit),
305
                }
306
0
            } else {
307
0
                trailing_zeros += 1;
308
0
            }
309
        }
310
0
        let mut result: Self = Default::default();
311
0
        if i != 0 {
312
0
            let magnitude = trailing_zeros + i - 1;
313
0
            debug_assert!(magnitude <= i16::MAX as usize);
314
0
            result.magnitude = magnitude as i16;
315
0
            result.upper_magnitude = result.magnitude;
316
0
            debug_assert!(i <= X);
317
            #[allow(clippy::indexing_slicing)] // X - i < X
318
0
            result.digits.extend_from_slice(&mem[(X - i)..]);
319
0
        }
320
        #[cfg(debug_assertions)]
321
        result.check_invariants();
322
0
        Ok(result)
323
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::from_ascending::<fixed_decimal::uint_iterator::IntIterator<u8>>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::from_ascending::<fixed_decimal::uint_iterator::IntIterator<usize>>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::from_ascending::<fixed_decimal::uint_iterator::IntIterator<u32>>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::from_ascending::<fixed_decimal::uint_iterator::IntIterator<u128>>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::from_ascending::<fixed_decimal::uint_iterator::IntIterator<u16>>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::from_ascending::<fixed_decimal::uint_iterator::IntIterator<u64>>
324
325
    /// Gets the digit at the specified order of magnitude. Returns 0 if the magnitude is out of
326
    /// range of the currently visible digits.
327
    ///
328
    /// # Examples
329
    ///
330
    /// ```
331
    /// use fixed_decimal::FixedDecimal;
332
    ///
333
    /// let dec = FixedDecimal::from(945);
334
    /// assert_eq!(0, dec.digit_at(-1));
335
    /// assert_eq!(5, dec.digit_at(0));
336
    /// assert_eq!(4, dec.digit_at(1));
337
    /// assert_eq!(9, dec.digit_at(2));
338
    /// assert_eq!(0, dec.digit_at(3));
339
    /// ```
340
0
    pub fn digit_at(&self, magnitude: i16) -> u8 {
341
0
        if magnitude > self.magnitude {
342
0
            0 // Leading zero
343
        } else {
344
            // The following line can't fail: magnitude <= self.magnitude, by
345
            // the if statement above, and u16::MAX == i16::MAX - i16::MIN, and
346
            // usize is asserted to be at least as big as u16.
347
0
            let j = crate::ops::i16_abs_sub(self.magnitude, magnitude) as usize;
348
0
            match self.digits.get(j) {
349
0
                Some(v) => *v,
350
0
                None => 0, // Trailing zero
351
            }
352
        }
353
0
    }
354
355
    /// Gets the digit at the specified order of next upper magnitude (magnitude + 1).
356
    /// Returns 0 if the next upper magnitude is out of range of currently visible digits or
357
    /// the magnitude is equal to `i16::MAX`.
358
0
    fn digit_at_previous_position(&self, magnitude: i16) -> u8 {
359
0
        if magnitude == i16::MAX {
360
0
            0
361
        } else {
362
0
            self.digit_at(magnitude + 1)
363
        }
364
0
    }
365
366
    /// Gets the digit at the specified order of next lower magnitude (magnitude - 1).
367
    /// Returns 0 if the next lower magnitude is out of range of currently visible digits or the
368
    /// magnitude is equal to `i16::MIN`.
369
0
    fn digit_at_next_position(&self, magnitude: i16) -> u8 {
370
0
        if magnitude == i16::MIN {
371
0
            0
372
        } else {
373
0
            self.digit_at(magnitude - 1)
374
        }
375
0
    }
376
377
    /// Returns the relative ordering of the digits after `magnitude` with respect to 5.
378
0
    fn half_at_next_magnitude(&self, magnitude: i16) -> Ordering {
379
0
        #[cfg(debug_assertions)] // Depends on having no trailing zeroes.
380
0
        self.check_invariants();
381
0
382
0
        match self.digit_at_next_position(magnitude).cmp(&5) {
383
            // If the next digit is equal to 5, we can know if we're at exactly 5
384
            // by comparing the next magnitude with the last nonzero magnitude of
385
            // the number.
386
0
            Ordering::Equal => match (magnitude - 1).cmp(&self.nonzero_magnitude_end()) {
387
                Ordering::Greater => {
388
                    // `magnitude - 1` has non-zero digits at its right,
389
                    // meaning the number overall must be greater than 5.
390
0
                    Ordering::Greater
391
                }
392
                Ordering::Equal => {
393
                    // `magnitude - 1` is the last digit of the number,
394
                    // meaning the number is exactly 5.
395
0
                    Ordering::Equal
396
                }
397
                Ordering::Less => {
398
0
                    debug_assert!(false, "digit `magnitude - 1` should not be zero");
399
0
                    Ordering::Less
400
                }
401
            },
402
            // If the next digit is either greater or less than 5,
403
            // we know that the digits cannot sum to exactly 5.
404
0
            ord => ord,
405
        }
406
0
    }
407
408
    /// Returns the relative ordering of the digits from `magnitude` onwards
409
    /// with respect to the half increment of `increment`.
410
0
    fn half_increment_at_magnitude<R: IncrementLike>(
411
0
        &self,
412
0
        magnitude: i16,
413
0
        increment: R,
414
0
    ) -> Ordering {
415
0
        #[cfg(debug_assertions)] // Depends on having no trailing zeroes.
416
0
        self.check_invariants();
417
0
418
0
        match Some(increment) {
419
0
            x if x == R::MULTIPLES_OF_1 => self.half_at_next_magnitude(magnitude),
420
0
            x if x == R::MULTIPLES_OF_2 => {
421
0
                let current_digit = self.digit_at(magnitude);
422
0
423
0
                // Equivalent to "if current_digit is odd".
424
0
                if current_digit & 0x01 == 1 {
425
0
                    match magnitude.cmp(&self.nonzero_magnitude_end()) {
426
                        Ordering::Greater => {
427
                            // `magnitude` has non-zero digits at its right,
428
                            // meaning the number overall must be greater than
429
                            // the half increment.
430
0
                            Ordering::Greater
431
                        }
432
                        Ordering::Equal => {
433
                            // `magnitude` is the last digit of the number,
434
                            // meaning the number is exactly at a half increment.
435
0
                            Ordering::Equal
436
                        }
437
                        Ordering::Less => {
438
0
                            debug_assert!(false, "digit `magnitude` should not be zero");
439
0
                            Ordering::Less
440
                        }
441
                    }
442
                } else {
443
                    // Even numbers are always below the half increment.
444
0
                    Ordering::Less
445
                }
446
            }
447
0
            x if x == R::MULTIPLES_OF_5 => {
448
0
                let current_digit = self.digit_at(magnitude);
449
0
                match (current_digit % 5).cmp(&2) {
450
                    Ordering::Equal => {
451
                        // Need to know if the number exceeds 2.5.
452
0
                        self.half_at_next_magnitude(magnitude)
453
                    }
454
                    // If the next digit is either greater or less than the half increment,
455
                    // we know that the digits cannot sum to exactly it.
456
0
                    ord => ord,
457
                }
458
            }
459
0
            x if x == R::MULTIPLES_OF_25 => {
460
0
                let current_digit = self.digit_at(magnitude);
461
0
                let prev_digit = self.digit_at_previous_position(magnitude);
462
0
                let number = prev_digit * 10 + current_digit;
463
0
464
0
                match (number % 25).cmp(&12) {
465
                    Ordering::Equal => {
466
                        // Need to know if the number exceeds 12.5.
467
0
                        self.half_at_next_magnitude(magnitude)
468
                    }
469
                    // If the next digit is either greater or less than the half increment,
470
                    // we know that the digits cannot sum to exactly it.
471
0
                    ord => ord,
472
                }
473
            }
474
            _ => {
475
0
                debug_assert!(false, "increment should be 1, 2, 5, or 25");
476
0
                Ordering::Equal
477
            }
478
        }
479
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::half_increment_at_magnitude::<fixed_decimal::decimal::NoIncrement>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::half_increment_at_magnitude::<fixed_decimal::decimal::RoundingIncrement>
480
481
    /// Checks if this number is already rounded to the specified magnitude and
482
    /// increment.
483
0
    fn is_rounded<R: IncrementLike>(&self, position: i16, increment: R) -> bool {
484
0
        // The number is rounded if it's already zero, since zero is a multiple of
485
0
        // all increments.
486
0
        if self.is_zero() {
487
0
            return true;
488
0
        }
489
0
490
0
        match Some(increment) {
491
0
            x if x == R::MULTIPLES_OF_1 => {
492
                // The number is rounded if `position` is the last digit
493
0
                position <= self.nonzero_magnitude_end()
494
            }
495
0
            x if x == R::MULTIPLES_OF_2 => {
496
                // The number is rounded if the digit at `position` is zero or
497
                // the position is the last digit and the digit is a multiple of the increment
498
                // already.
499
0
                match position.cmp(&self.nonzero_magnitude_end()) {
500
0
                    Ordering::Less => true,
501
0
                    Ordering::Equal => self.digit_at(position) & 0x01 == 0,
502
0
                    Ordering::Greater => false,
503
                }
504
            }
505
0
            x if x == R::MULTIPLES_OF_5 => {
506
                // The number is rounded if the digit at `position` is zero or
507
                // the position is the last digit and the digit is a multiple of the increment
508
                // already.
509
0
                match position.cmp(&self.nonzero_magnitude_end()) {
510
0
                    Ordering::Less => true,
511
0
                    Ordering::Equal => self.digit_at(position) == 5,
512
0
                    Ordering::Greater => false,
513
                }
514
            }
515
0
            x if x == R::MULTIPLES_OF_25 => {
516
                // The number is rounded if the digits at `position` and `position + 1` are
517
                // both zeroes or if the last two digits are a multiple of the increment already.
518
0
                match position.cmp(&self.nonzero_magnitude_end()) {
519
                    Ordering::Less => {
520
                        // `position` cannot be `i16::MAX` since it's less than
521
                        // `self.nonzero_magnitude_end()`
522
0
                        if position + 1 < self.nonzero_magnitude_end() {
523
0
                            true
524
                        } else {
525
                            // position + 1 is equal to the last digit.
526
                            // Need to exit if the number is 50.
527
0
                            self.digit_at(position + 1) == 5
528
                        }
529
                    }
530
                    Ordering::Equal => {
531
0
                        let current_digit = self.digit_at(position);
532
0
                        let prev_digit = self.digit_at_previous_position(position);
533
0
                        let number = prev_digit * 10 + current_digit;
534
535
0
                        matches!(number, 25 | 75)
536
                    }
537
0
                    Ordering::Greater => false,
538
                }
539
            }
540
            _ => {
541
0
                debug_assert!(false, "INCREMENT should be 1, 2, 5, or 25");
542
0
                false
543
            }
544
        }
545
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::is_rounded::<fixed_decimal::decimal::NoIncrement>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::is_rounded::<fixed_decimal::decimal::RoundingIncrement>
546
547
    /// Gets the visible range of digit magnitudes, in ascending order of magnitude. Call `.rev()`
548
    /// on the return value to get the range in descending order. Magnitude 0 is always included,
549
    /// even if the number has leading or trailing zeros.
550
    ///
551
    /// # Examples
552
    ///
553
    /// ```
554
    /// use fixed_decimal::FixedDecimal;
555
    ///
556
    /// let dec: FixedDecimal = "012.340".parse().expect("valid syntax");
557
    /// assert_eq!(-3..=2, dec.magnitude_range());
558
    /// ```
559
0
    pub const fn magnitude_range(&self) -> RangeInclusive<i16> {
560
0
        self.lower_magnitude..=self.upper_magnitude
561
0
    }
562
563
    /// Gets the magnitude of the largest nonzero digit. If the number is zero, 0 is returned.
564
    ///
565
    /// # Examples
566
    ///
567
    /// ```
568
    /// use fixed_decimal::FixedDecimal;
569
    ///
570
    /// let dec: FixedDecimal = "012.340".parse().expect("valid syntax");
571
    /// assert_eq!(1, dec.nonzero_magnitude_start());
572
    ///
573
    /// assert_eq!(0, FixedDecimal::from(0).nonzero_magnitude_start());
574
    /// ```
575
0
    pub fn nonzero_magnitude_start(&self) -> i16 {
576
0
        self.magnitude
577
0
    }
578
579
    /// Gets the magnitude of the smallest nonzero digit. If the number is zero, 0 is returned.
580
    ///
581
    /// # Examples
582
    ///
583
    /// ```
584
    /// use fixed_decimal::FixedDecimal;
585
    ///
586
    /// let dec: FixedDecimal = "012.340".parse().expect("valid syntax");
587
    /// assert_eq!(-2, dec.nonzero_magnitude_end());
588
    ///
589
    /// assert_eq!(0, FixedDecimal::from(0).nonzero_magnitude_end());
590
    /// ```
591
0
    pub fn nonzero_magnitude_end(&self) -> i16 {
592
0
        if self.is_zero() {
593
0
            0
594
        } else {
595
0
            crate::ops::i16_sub_unsigned(self.magnitude, self.digits.len() as u16 - 1)
596
        }
597
0
    }
598
599
    /// Returns whether the number has a numeric value of zero.
600
    ///
601
    /// # Examples
602
    ///
603
    /// ```
604
    /// use fixed_decimal::FixedDecimal;
605
    ///
606
    /// let dec: FixedDecimal = "000.000".parse().expect("valid syntax");
607
    /// assert!(dec.is_zero());
608
    /// ```
609
    #[inline]
610
0
    pub fn is_zero(&self) -> bool {
611
0
        self.digits.is_empty()
612
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::is_zero
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::is_zero
613
614
    /// Clears all the fields and sets the number to zero.
615
0
    fn clear(&mut self) {
616
0
        self.upper_magnitude = 0;
617
0
        self.lower_magnitude = 0;
618
0
        self.magnitude = 0;
619
0
        self.digits.clear();
620
0
        self.sign = Sign::None;
621
0
622
0
        #[cfg(debug_assertions)]
623
0
        self.check_invariants();
624
0
    }
625
626
    /// Shift the digits by a power of 10, modifying self.
627
    ///
628
    /// Leading or trailing zeros may be added to keep the digit at magnitude 0 (the last digit
629
    /// before the decimal separator) visible.
630
    ///
631
    /// NOTE: if the operation causes overflow, the number will be set to zero.
632
    ///
633
    /// # Examples
634
    ///
635
    /// ```
636
    /// use fixed_decimal::FixedDecimal;
637
    ///
638
    /// let mut dec = FixedDecimal::from(42);
639
    /// assert_eq!("42", dec.to_string());
640
    ///
641
    /// dec.multiply_pow10(3);
642
    /// assert_eq!("42000", dec.to_string());
643
    /// ```
644
0
    pub fn multiply_pow10(&mut self, delta: i16) {
645
0
        match delta.cmp(&0) {
646
            Ordering::Greater => {
647
0
                let upper_magnitude = self.upper_magnitude.checked_add(delta);
648
0
                match upper_magnitude {
649
0
                    Some(upper_magnitude) => {
650
0
                        self.upper_magnitude = upper_magnitude;
651
0
                        // If we get here, then the magnitude change is in-bounds.
652
0
                        let lower_magnitude = self.lower_magnitude + delta;
653
0
                        self.lower_magnitude = cmp::min(0, lower_magnitude);
654
0
                    }
655
0
                    None => {
656
0
                        // there is an overflow
657
0
                        self.clear();
658
0
                    }
659
                }
660
            }
661
            Ordering::Less => {
662
0
                let lower_magnitude = self.lower_magnitude.checked_add(delta);
663
0
                match lower_magnitude {
664
0
                    Some(lower_magnitude) => {
665
0
                        self.lower_magnitude = lower_magnitude;
666
0
                        // If we get here, then the magnitude change is in-bounds.
667
0
                        let upper_magnitude = self.upper_magnitude + delta;
668
0
                        self.upper_magnitude = cmp::max(0, upper_magnitude);
669
0
                    }
670
0
                    None => {
671
0
                        // there is an overflow
672
0
                        self.clear();
673
0
                    }
674
                }
675
            }
676
0
            Ordering::Equal => {}
677
        };
678
0
        if !self.is_zero() {
679
0
            self.magnitude += delta;
680
0
        }
681
        #[cfg(debug_assertions)]
682
        self.check_invariants();
683
0
    }
684
685
    /// Shift the digits by a power of 10, consuming self and returning a new object if successful.
686
    ///
687
    /// Leading or trailing zeros may be added to keep the digit at magnitude 0 (the last digit
688
    /// before the decimal separator) visible.
689
    ///
690
    /// NOTE: if the operation causes overflow, the returned number will be zero.
691
    ///
692
    /// # Examples
693
    ///
694
    /// ```
695
    /// use fixed_decimal::FixedDecimal;
696
    ///
697
    /// let dec = FixedDecimal::from(42).multiplied_pow10(3);
698
    /// assert_eq!("42000", dec.to_string());
699
    /// ```
700
0
    pub fn multiplied_pow10(mut self, delta: i16) -> Self {
701
0
        self.multiply_pow10(delta);
702
0
        self
703
0
    }
704
705
    /// Returns the sign.
706
    /// # Examples
707
    /// ```
708
    /// use fixed_decimal::FixedDecimal;
709
    /// use fixed_decimal::Sign;
710
    /// # use std::str::FromStr;
711
    ///
712
    /// assert_eq!(FixedDecimal::from_str("1729").unwrap().sign(), Sign::None);
713
    /// assert_eq!(
714
    ///     FixedDecimal::from_str("-1729").unwrap().sign(),
715
    ///     Sign::Negative
716
    /// );
717
    /// assert_eq!(
718
    ///     FixedDecimal::from_str("+1729").unwrap().sign(),
719
    ///     Sign::Positive
720
    /// );
721
    /// ```
722
0
    pub fn sign(&self) -> Sign {
723
0
        self.sign
724
0
    }
725
726
    /// Change the sign to the one given.
727
    ///
728
    /// # Examples
729
    ///
730
    /// ```
731
    /// use fixed_decimal::FixedDecimal;
732
    /// use fixed_decimal::Sign;
733
    ///
734
    /// let mut dec = FixedDecimal::from(1729);
735
    /// assert_eq!("1729", dec.to_string());
736
    ///
737
    /// dec.set_sign(Sign::Negative);
738
    /// assert_eq!("-1729", dec.to_string());
739
    ///
740
    /// dec.set_sign(Sign::Positive);
741
    /// assert_eq!("+1729", dec.to_string());
742
    ///
743
    /// dec.set_sign(Sign::None);
744
    /// assert_eq!("1729", dec.to_string());
745
    /// ```
746
0
    pub fn set_sign(&mut self, sign: Sign) {
747
0
        self.sign = sign;
748
0
    }
749
750
    /// Change the sign to the one given, consuming self and returning a new object.
751
    ///
752
    /// # Examples
753
    ///
754
    /// ```
755
    /// use fixed_decimal::FixedDecimal;
756
    /// use fixed_decimal::Sign;
757
    ///
758
    /// assert_eq!(
759
    ///     "+1729",
760
    ///     FixedDecimal::from(1729)
761
    ///         .with_sign(Sign::Positive)
762
    ///         .to_string()
763
    /// );
764
    /// assert_eq!(
765
    ///     "1729",
766
    ///     FixedDecimal::from(-1729).with_sign(Sign::None).to_string()
767
    /// );
768
    /// assert_eq!(
769
    ///     "-1729",
770
    ///     FixedDecimal::from(1729)
771
    ///         .with_sign(Sign::Negative)
772
    ///         .to_string()
773
    /// );
774
    /// ```
775
0
    pub fn with_sign(mut self, sign: Sign) -> Self {
776
0
        self.set_sign(sign);
777
0
        self
778
0
    }
779
780
    /// Sets the sign according to the given sign display strategy.
781
    ///
782
    /// # Examples
783
    /// ```
784
    /// use fixed_decimal::FixedDecimal;
785
    /// use fixed_decimal::SignDisplay::*;
786
    ///
787
    /// let mut dec = FixedDecimal::from(1729);
788
    /// assert_eq!("1729", dec.to_string());
789
    /// dec.apply_sign_display(Always);
790
    /// assert_eq!("+1729", dec.to_string());
791
    /// ```
792
0
    pub fn apply_sign_display(&mut self, sign_display: SignDisplay) {
793
        use Sign::*;
794
0
        match sign_display {
795
            SignDisplay::Auto => {
796
0
                if self.sign != Negative {
797
0
                    self.sign = None
798
0
                }
799
            }
800
            SignDisplay::Always => {
801
0
                if self.sign != Negative {
802
0
                    self.sign = Positive
803
0
                }
804
            }
805
0
            SignDisplay::Never => self.sign = None,
806
            SignDisplay::ExceptZero => {
807
0
                if self.is_zero() {
808
0
                    self.sign = None
809
0
                } else if self.sign != Negative {
810
0
                    self.sign = Positive
811
0
                }
812
            }
813
            SignDisplay::Negative => {
814
0
                if self.sign != Negative || self.is_zero() {
815
0
                    self.sign = None
816
0
                }
817
            }
818
        }
819
0
    }
820
821
    /// Sets the sign according to the given sign display strategy, consuming
822
    /// self and returning a new object.
823
    ///
824
    /// # Examples
825
    /// ```
826
    /// use fixed_decimal::FixedDecimal;
827
    /// use fixed_decimal::SignDisplay::*;
828
    ///
829
    /// assert_eq!(
830
    ///     "+1729",
831
    ///     FixedDecimal::from(1729)
832
    ///         .with_sign_display(ExceptZero)
833
    ///         .to_string()
834
    /// );
835
    /// ```
836
0
    pub fn with_sign_display(mut self, sign_display: SignDisplay) -> Self {
837
0
        self.apply_sign_display(sign_display);
838
0
        self
839
0
    }
840
841
    /// Remove leading zeroes, consuming self and returning a new object.
842
    ///
843
    /// # Examples
844
    ///
845
    /// ```
846
    /// use fixed_decimal::FixedDecimal;
847
    ///
848
    /// let dec = FixedDecimal::from(123400)
849
    ///     .multiplied_pow10(-4)
850
    ///     .padded_start(4);
851
    /// assert_eq!("0012.3400", dec.to_string());
852
    ///
853
    /// assert_eq!("12.3400", dec.trimmed_start().to_string());
854
    /// ```
855
0
    pub fn trimmed_start(mut self) -> Self {
856
0
        self.trim_start();
857
0
        self
858
0
    }
859
860
    /// Remove leading zeroes, modifying self.
861
    ///
862
    /// # Examples
863
    ///
864
    /// ```
865
    /// use fixed_decimal::FixedDecimal;
866
    ///
867
    /// let mut dec = FixedDecimal::from(123400)
868
    ///     .multiplied_pow10(-4)
869
    ///     .padded_start(4);
870
    /// assert_eq!("0012.3400", dec.to_string());
871
    ///
872
    /// dec.trim_start();
873
    /// assert_eq!("12.3400", dec.to_string());
874
    /// ```
875
    ///
876
    /// There is no effect if the most significant digit has magnitude less than zero:
877
    ///
878
    /// ```
879
    /// # use fixed_decimal::FixedDecimal;
880
    /// let mut dec = FixedDecimal::from(22).multiplied_pow10(-4);
881
    /// assert_eq!("0.0022", dec.to_string());
882
    ///
883
    /// dec.trim_start();
884
    /// assert_eq!("0.0022", dec.to_string());
885
    /// ```
886
0
    pub fn trim_start(&mut self) {
887
0
        self.upper_magnitude = cmp::max(self.magnitude, 0);
888
0
        #[cfg(debug_assertions)]
889
0
        self.check_invariants();
890
0
    }
891
892
    /// Remove trailing zeroes, consuming self and returning a new object.
893
    ///
894
    /// # Examples
895
    ///
896
    /// ```
897
    /// use fixed_decimal::FixedDecimal;
898
    ///
899
    /// let dec = FixedDecimal::from(123400)
900
    ///     .multiplied_pow10(-4)
901
    ///     .padded_start(4);
902
    /// assert_eq!("0012.3400", dec.to_string());
903
    ///
904
    /// assert_eq!("0012.34", dec.trimmed_end().to_string());
905
    /// ```
906
0
    pub fn trimmed_end(mut self) -> Self {
907
0
        self.trim_end();
908
0
        self
909
0
    }
910
911
    /// Remove trailing zeroes, modifying self.
912
    ///
913
    /// # Examples
914
    ///
915
    /// ```
916
    /// use fixed_decimal::FixedDecimal;
917
    ///
918
    /// let mut dec = FixedDecimal::from(123400)
919
    ///     .multiplied_pow10(-4)
920
    ///     .padded_start(4);
921
    /// assert_eq!("0012.3400", dec.to_string());
922
    ///
923
    /// dec.trim_end();
924
    /// assert_eq!("0012.34", dec.to_string());
925
    /// ```
926
    ///
927
    /// There is no effect if the least significant digit has magnitude more than zero:
928
    ///
929
    /// ```
930
    /// # use fixed_decimal::FixedDecimal;
931
    /// let mut dec = FixedDecimal::from(2200);
932
    /// assert_eq!("2200", dec.to_string());
933
    ///
934
    /// dec.trim_end();
935
    /// assert_eq!("2200", dec.to_string());
936
    /// ```
937
0
    pub fn trim_end(&mut self) {
938
0
        self.lower_magnitude = cmp::min(0, self.nonzero_magnitude_end());
939
0
        #[cfg(debug_assertions)]
940
0
        self.check_invariants();
941
0
    }
942
943
    /// Zero-pad the number on the left to a particular position,
944
    /// returning the result.
945
    ///
946
    /// Negative numbers have no effect.
947
    ///
948
    /// Also see [`FixedDecimal::with_max_position()`].
949
    ///
950
    /// # Examples
951
    ///
952
    /// ```
953
    /// use fixed_decimal::FixedDecimal;
954
    ///
955
    /// let mut dec = FixedDecimal::from(42);
956
    /// assert_eq!("42", dec.to_string());
957
    /// assert_eq!("0042", dec.clone().padded_start(4).to_string());
958
    ///
959
    /// assert_eq!("042", dec.clone().padded_start(3).to_string());
960
    ///
961
    /// assert_eq!("42", dec.clone().padded_start(2).to_string());
962
    ///
963
    /// assert_eq!("42", dec.clone().padded_start(1).to_string());
964
    /// ```
965
0
    pub fn padded_start(mut self, position: i16) -> Self {
966
0
        self.pad_start(position);
967
0
        self
968
0
    }
969
970
    /// Zero-pad the number on the left to a particular position.
971
    ///
972
    /// Negative numbers have no effect.
973
    ///
974
    /// Also see [`FixedDecimal::set_max_position()`].
975
    ///
976
    /// # Examples
977
    ///
978
    /// ```
979
    /// use fixed_decimal::FixedDecimal;
980
    ///
981
    /// let mut dec = FixedDecimal::from(42);
982
    /// assert_eq!("42", dec.to_string());
983
    ///
984
    /// dec.pad_start(4);
985
    /// assert_eq!("0042", dec.to_string());
986
    ///
987
    /// dec.pad_start(3);
988
    /// assert_eq!("042", dec.to_string());
989
    ///
990
    /// dec.pad_start(2);
991
    /// assert_eq!("42", dec.to_string());
992
    ///
993
    /// dec.pad_start(1);
994
    /// assert_eq!("42", dec.to_string());
995
    /// ```
996
0
    pub fn pad_start(&mut self, position: i16) {
997
0
        if position <= 0 {
998
0
            return;
999
0
        }
1000
0
        let mut magnitude = position - 1;
1001
0
        // Do not truncate nonzero digits
1002
0
        if magnitude <= self.magnitude {
1003
0
            magnitude = self.magnitude;
1004
0
        }
1005
0
        self.upper_magnitude = magnitude;
1006
        #[cfg(debug_assertions)]
1007
        self.check_invariants();
1008
0
    }
1009
1010
    /// Zero-pad the number on the right to a particular (negative) position. Will truncate
1011
    /// trailing zeros if necessary, but will not truncate other digits, returning the result.
1012
    ///
1013
    /// Positive numbers have no effect.
1014
    ///
1015
    /// Also see [`FixedDecimal::trunced()`].
1016
    ///
1017
    /// # Examples
1018
    ///
1019
    /// ```
1020
    /// use fixed_decimal::FixedDecimal;
1021
    /// # use std::str::FromStr;
1022
    ///
1023
    /// let mut dec = FixedDecimal::from_str("123.456").unwrap();
1024
    /// assert_eq!("123.456", dec.to_string());
1025
    ///
1026
    /// assert_eq!("123.456", dec.clone().padded_end(-1).to_string());
1027
    ///
1028
    /// assert_eq!("123.456", dec.clone().padded_end(-2).to_string());
1029
    ///
1030
    /// assert_eq!("123.456000", dec.clone().padded_end(-6).to_string());
1031
    ///
1032
    /// assert_eq!("123.4560", dec.clone().padded_end(-4).to_string());
1033
    /// ```
1034
0
    pub fn padded_end(mut self, position: i16) -> Self {
1035
0
        self.pad_end(position);
1036
0
        self
1037
0
    }
1038
1039
    /// Zero-pad the number on the right to a particular (negative) position. Will truncate
1040
    /// trailing zeros if necessary, but will not truncate other digits.
1041
    ///
1042
    /// Positive numbers have no effect.
1043
    ///
1044
    /// Also see [`FixedDecimal::trunc()`].
1045
    ///
1046
    /// # Examples
1047
    ///
1048
    /// ```
1049
    /// use fixed_decimal::FixedDecimal;
1050
    /// # use std::str::FromStr;
1051
    ///
1052
    /// let mut dec = FixedDecimal::from_str("123.456").unwrap();
1053
    /// assert_eq!("123.456", dec.to_string());
1054
    ///
1055
    /// dec.pad_end(-1);
1056
    /// assert_eq!("123.456", dec.to_string());
1057
    ///
1058
    /// dec.pad_end(-2);
1059
    /// assert_eq!("123.456", dec.to_string());
1060
    ///
1061
    /// dec.pad_end(-6);
1062
    /// assert_eq!("123.456000", dec.to_string());
1063
    ///
1064
    /// dec.pad_end(-4);
1065
    /// assert_eq!("123.4560", dec.to_string());
1066
    /// ```
1067
0
    pub fn pad_end(&mut self, position: i16) {
1068
0
        if position >= 0 {
1069
0
            return;
1070
0
        }
1071
0
        let bottom_magnitude = self.nonzero_magnitude_end();
1072
0
        let mut magnitude = position;
1073
0
        // Do not truncate nonzero digits
1074
0
        if magnitude >= bottom_magnitude {
1075
0
            magnitude = bottom_magnitude;
1076
0
        }
1077
0
        self.lower_magnitude = magnitude;
1078
        #[cfg(debug_assertions)]
1079
        self.check_invariants();
1080
0
    }
1081
1082
    /// Truncate the number on the left to a particular position, deleting
1083
    /// digits if necessary, returning the result.
1084
    ///
1085
    /// Also see [`FixedDecimal::padded_start()`].
1086
    ///
1087
    /// # Examples
1088
    ///
1089
    /// ```
1090
    /// use fixed_decimal::FixedDecimal;
1091
    ///
1092
    /// let mut dec = FixedDecimal::from(4235970).multiplied_pow10(-3);
1093
    /// assert_eq!("4235.970", dec.to_string());
1094
    ///
1095
    /// assert_eq!("04235.970", dec.clone().with_max_position(5).to_string());
1096
    ///
1097
    /// assert_eq!("35.970", dec.clone().with_max_position(2).to_string());
1098
    ///
1099
    /// assert_eq!("5.970", dec.clone().with_max_position(1).to_string());
1100
    ///
1101
    /// assert_eq!("0.970", dec.clone().with_max_position(0).to_string());
1102
    ///
1103
    /// assert_eq!("0.070", dec.clone().with_max_position(-1).to_string());
1104
    ///
1105
    /// assert_eq!("0.000", dec.clone().with_max_position(-2).to_string());
1106
    ///
1107
    /// assert_eq!("0.0000", dec.clone().with_max_position(-4).to_string());
1108
    /// ```
1109
0
    pub fn with_max_position(mut self, position: i16) -> Self {
1110
0
        self.set_max_position(position);
1111
0
        self
1112
0
    }
1113
1114
    /// Truncate the number on the left to a particular position, deleting
1115
    /// digits if necessary.
1116
    ///
1117
    /// Also see [`FixedDecimal::pad_start()`].
1118
    ///
1119
    /// # Examples
1120
    ///
1121
    /// ```
1122
    /// use fixed_decimal::FixedDecimal;
1123
    ///
1124
    /// let mut dec = FixedDecimal::from(4235970).multiplied_pow10(-3);
1125
    /// assert_eq!("4235.970", dec.to_string());
1126
    ///
1127
    /// dec.set_max_position(5);
1128
    /// assert_eq!("04235.970", dec.to_string());
1129
    ///
1130
    /// dec.set_max_position(2);
1131
    /// assert_eq!("35.970", dec.to_string());
1132
    ///
1133
    /// dec.set_max_position(1);
1134
    /// assert_eq!("5.970", dec.to_string());
1135
    ///
1136
    /// dec.set_max_position(0);
1137
    /// assert_eq!("0.970", dec.to_string());
1138
    ///
1139
    /// dec.set_max_position(-1);
1140
    /// assert_eq!("0.070", dec.to_string());
1141
    ///
1142
    /// dec.set_max_position(-2);
1143
    /// assert_eq!("0.000", dec.to_string());
1144
    ///
1145
    /// dec.set_max_position(-4);
1146
    /// assert_eq!("0.0000", dec.to_string());
1147
    /// ```
1148
0
    pub fn set_max_position(&mut self, position: i16) {
1149
0
        self.lower_magnitude = cmp::min(self.lower_magnitude, position);
1150
0
        self.upper_magnitude = if position <= 0 { 0 } else { position - 1 };
1151
0
        if position <= self.nonzero_magnitude_end() {
1152
0
            self.digits.clear();
1153
0
            self.magnitude = 0;
1154
0
            #[cfg(debug_assertions)]
1155
0
            self.check_invariants();
1156
0
            return;
1157
0
        }
1158
0
        let magnitude = position - 1;
1159
0
        if self.magnitude >= magnitude {
1160
0
            let cut = crate::ops::i16_abs_sub(self.magnitude, magnitude) as usize;
1161
0
            let _ = self.digits.drain(0..cut).count();
1162
0
            // Count number of leading zeroes
1163
0
            let extra_zeroes = self.digits.iter().position(|x| *x != 0).unwrap_or(0);
1164
0
            let _ = self.digits.drain(0..extra_zeroes).count();
1165
0
            debug_assert!(!self.digits.is_empty());
1166
0
            self.magnitude = crate::ops::i16_sub_unsigned(magnitude, extra_zeroes as u16);
1167
0
        }
1168
        #[cfg(debug_assertions)]
1169
        self.check_invariants();
1170
0
    }
1171
1172
    /// Truncates the number on the right to a particular position, deleting
1173
    /// digits if necessary.
1174
    ///
1175
    /// Also see [`FixedDecimal::pad_end()`].
1176
    ///
1177
    /// # Examples
1178
    ///
1179
    /// ```
1180
    /// use fixed_decimal::FixedDecimal;
1181
    /// # use std::str::FromStr;
1182
    ///
1183
    /// let mut dec = FixedDecimal::from_str("-1.5").unwrap();
1184
    /// dec.trunc(0);
1185
    /// assert_eq!("-1", dec.to_string());
1186
    /// let mut dec = FixedDecimal::from_str("0.4").unwrap();
1187
    /// dec.trunc(0);
1188
    /// assert_eq!("0", dec.to_string());
1189
    /// let mut dec = FixedDecimal::from_str("0.5").unwrap();
1190
    /// dec.trunc(0);
1191
    /// assert_eq!("0", dec.to_string());
1192
    /// let mut dec = FixedDecimal::from_str("0.6").unwrap();
1193
    /// dec.trunc(0);
1194
    /// assert_eq!("0", dec.to_string());
1195
    /// let mut dec = FixedDecimal::from_str("1.5").unwrap();
1196
    /// dec.trunc(0);
1197
    /// assert_eq!("1", dec.to_string());
1198
    /// ```
1199
    #[inline(never)]
1200
0
    pub fn trunc(&mut self, position: i16) {
1201
0
        self.trunc_to_increment_internal(position, NoIncrement)
1202
0
    }
1203
1204
    /// Truncates the number on the right to a particular position and rounding
1205
    /// increment, deleting digits if necessary.
1206
    ///
1207
    /// # Examples
1208
    ///
1209
    /// ```
1210
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
1211
    /// # use std::str::FromStr;
1212
    ///
1213
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
1214
    /// dec.trunc_to_increment(0, RoundingIncrement::MultiplesOf2);
1215
    /// assert_eq!("-2", dec.to_string());
1216
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
1217
    /// dec.trunc_to_increment(-1, RoundingIncrement::MultiplesOf5);
1218
    /// assert_eq!("7.5", dec.to_string());
1219
    /// let mut dec = FixedDecimal::from_str("5.45").unwrap();
1220
    /// dec.trunc_to_increment(-2, RoundingIncrement::MultiplesOf25);
1221
    /// assert_eq!("5.25", dec.to_string());
1222
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
1223
    /// dec.trunc_to_increment(-1, RoundingIncrement::MultiplesOf25);
1224
    /// assert_eq!("7.5", dec.to_string());
1225
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
1226
    /// dec.trunc_to_increment(-2, RoundingIncrement::MultiplesOf2);
1227
    /// assert_eq!("9.98", dec.to_string());
1228
    /// ```
1229
    #[inline(never)]
1230
0
    pub fn trunc_to_increment(&mut self, position: i16, increment: RoundingIncrement) {
1231
0
        self.trunc_to_increment_internal(position, increment)
1232
0
    }
1233
1234
0
    fn trunc_to_increment_internal<R: IncrementLike>(&mut self, position: i16, inner_increment: R) {
1235
0
        let increment = Some(inner_increment);
1236
0
1237
0
        // 1. Set upper and lower magnitude
1238
0
        self.lower_magnitude = cmp::min(position, 0);
1239
0
1240
0
        match position.cmp(&i16::MIN) {
1241
            // Don't return if the increment is not one, because we
1242
            // also need to round to the next increment if necessary.
1243
0
            Ordering::Equal if increment == R::MULTIPLES_OF_1 => {
1244
0
                // Nothing more to do
1245
0
                #[cfg(debug_assertions)]
1246
0
                self.check_invariants();
1247
0
                return;
1248
            }
1249
0
            Ordering::Greater => {
1250
0
                self.upper_magnitude = cmp::max(self.upper_magnitude, position - 1);
1251
0
            }
1252
0
            _ => {
1253
0
                // Ordering::Less is unreachable, and Ordering::Equal needs to apply roundings
1254
0
                // when the increment is not equal to 1.
1255
0
                // We don't override `self.upper_magnitude` because `self.upper_magnitude` is
1256
0
                // always equal or bigger than `i16::MIN`.
1257
0
            }
1258
        }
1259
1260
        // 2. If the number is already rounded, exit early.
1261
0
        if self.is_rounded(position, inner_increment) {
1262
            #[cfg(debug_assertions)]
1263
            self.check_invariants();
1264
0
            return;
1265
0
        }
1266
0
1267
0
        // 3. If the rounding position is *in the middle* of the nonzero digits
1268
0
        if position <= self.magnitude {
1269
            // 3a. Calculate the number of digits to retain and remove the rest
1270
0
            let digits_to_retain = crate::ops::i16_abs_sub(self.magnitude, position) + 1;
1271
0
            self.digits.truncate(digits_to_retain as usize);
1272
0
1273
0
            // 3b. Truncate to the previous multiple.
1274
0
            match increment {
1275
0
                x if x == R::MULTIPLES_OF_1 => {
1276
0
                    // No need to do more work, trailing zeroes are removed below.
1277
0
                }
1278
0
                x if x == R::MULTIPLES_OF_2 => {
1279
0
                    let Some(last_digit) = self.digits.last_mut() else {
1280
0
                        debug_assert!(false, "`self.digits` should have at least a digit");
1281
0
                        return;
1282
                    };
1283
1284
                    // Equivalent to (n / 2) * 2, which truncates to the previous
1285
                    // multiple of two
1286
0
                    *last_digit &= 0xFE;
1287
                }
1288
0
                x if x == R::MULTIPLES_OF_5 => {
1289
0
                    let Some(last_digit) = self.digits.last_mut() else {
1290
0
                        debug_assert!(false, "`self.digits` should have at least a digit");
1291
0
                        return;
1292
                    };
1293
1294
0
                    *last_digit = if *last_digit < 5 { 0 } else { 5 };
1295
                }
1296
0
                x if x == R::MULTIPLES_OF_25 => {
1297
                    // Extend with zeroes to have the correct trailing digits.
1298
0
                    self.digits.resize(digits_to_retain as usize, 0);
1299
1300
0
                    let Some((last_digit, digits)) = self.digits.split_last_mut() else {
1301
0
                        debug_assert!(false, "`self.digits` should have at least a digit");
1302
0
                        return;
1303
                    };
1304
1305
0
                    if let Some(second_last_digit) = digits.last_mut() {
1306
0
                        let number = *second_last_digit * 10 + *last_digit;
1307
1308
                        // Trailing zeroes will be removed below. We can defer
1309
                        // the deletion to there.
1310
0
                        (*second_last_digit, *last_digit) = if number < 25 {
1311
0
                            (0, 0)
1312
0
                        } else if number < 50 {
1313
0
                            (2, 5)
1314
0
                        } else if number < 75 {
1315
0
                            (5, 0)
1316
                        } else {
1317
0
                            (7, 5)
1318
                        };
1319
0
                    } else {
1320
0
                        // The number has no other digits aside from the last,
1321
0
                        // making it strictly less than 25.
1322
0
                        *last_digit = 0;
1323
0
                    };
1324
                }
1325
                _ => {
1326
0
                    debug_assert!(false, "INCREMENT should be 1, 2, 5, or 25");
1327
0
                    return;
1328
                }
1329
            }
1330
1331
            // 3c. Handle the case where `digits` has trailing zeroes after
1332
            // truncating to the previous multiple.
1333
0
            let position_last_nonzero_digit = self
1334
0
                .digits
1335
0
                .iter()
1336
0
                .rposition(|x| *x != 0)
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::trunc_to_increment_internal::<fixed_decimal::decimal::NoIncrement>::{closure#0}
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::trunc_to_increment_internal::<fixed_decimal::decimal::RoundingIncrement>::{closure#0}
1337
0
                .map(|x| x + 1)
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::trunc_to_increment_internal::<fixed_decimal::decimal::NoIncrement>::{closure#1}
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::trunc_to_increment_internal::<fixed_decimal::decimal::RoundingIncrement>::{closure#1}
1338
0
                .unwrap_or(0);
1339
0
            self.digits.truncate(position_last_nonzero_digit);
1340
0
1341
0
            // 3d. If `digits` had only trailing zeroes after truncating,
1342
0
            // reset to zero.
1343
0
            if self.digits.is_empty() {
1344
0
                self.magnitude = 0;
1345
0
            }
1346
0
        } else {
1347
0
            // 4. If the rounding position is *above* the leftmost nonzero
1348
0
            // digit, set to zero
1349
0
            self.digits.clear();
1350
0
            self.magnitude = 0;
1351
0
        }
1352
1353
        #[cfg(debug_assertions)]
1354
        self.check_invariants();
1355
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::trunc_to_increment_internal::<fixed_decimal::decimal::NoIncrement>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::trunc_to_increment_internal::<fixed_decimal::decimal::RoundingIncrement>
1356
1357
    /// Truncate the number on the right to a particular position, deleting
1358
    /// digits if necessary.
1359
    ///
1360
    /// Also see [`FixedDecimal::padded_end()`].
1361
    ///
1362
    /// # Examples
1363
    ///
1364
    /// ```
1365
    /// use fixed_decimal::FixedDecimal;
1366
    /// # use std::str::FromStr;
1367
    ///
1368
    /// let dec = FixedDecimal::from_str("-1.5").unwrap();
1369
    /// assert_eq!("-1", dec.trunced(0).to_string());
1370
    /// let dec = FixedDecimal::from_str("0.4").unwrap();
1371
    /// assert_eq!("0", dec.trunced(0).to_string());
1372
    /// let dec = FixedDecimal::from_str("0.5").unwrap();
1373
    /// assert_eq!("0", dec.trunced(0).to_string());
1374
    /// let dec = FixedDecimal::from_str("0.6").unwrap();
1375
    /// assert_eq!("0", dec.trunced(0).to_string());
1376
    /// let dec = FixedDecimal::from_str("1.5").unwrap();
1377
    /// assert_eq!("1", dec.trunced(0).to_string());
1378
    /// ```
1379
0
    pub fn trunced(mut self, position: i16) -> Self {
1380
0
        self.trunc(position);
1381
0
        self
1382
0
    }
1383
1384
    /// Truncates the number on the right to a particular position and rounding
1385
    /// increment, deleting digits if necessary.
1386
    ///
1387
    /// # Examples
1388
    ///
1389
    /// ```
1390
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
1391
    /// # use std::str::FromStr;
1392
    ///
1393
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
1394
    /// assert_eq!(
1395
    ///     "-2",
1396
    ///     dec.trunced_to_increment(0, RoundingIncrement::MultiplesOf2)
1397
    ///         .to_string()
1398
    /// );
1399
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
1400
    /// assert_eq!(
1401
    ///     "7.5",
1402
    ///     dec.trunced_to_increment(-1, RoundingIncrement::MultiplesOf5)
1403
    ///         .to_string()
1404
    /// );
1405
    /// let mut dec = FixedDecimal::from_str("5.45").unwrap();
1406
    /// assert_eq!(
1407
    ///     "5.25",
1408
    ///     dec.trunced_to_increment(-2, RoundingIncrement::MultiplesOf25)
1409
    ///         .to_string()
1410
    /// );
1411
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
1412
    /// assert_eq!(
1413
    ///     "7.5",
1414
    ///     dec.trunced_to_increment(-1, RoundingIncrement::MultiplesOf25)
1415
    ///         .to_string()
1416
    /// );
1417
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
1418
    /// assert_eq!(
1419
    ///     "9.98",
1420
    ///     dec.trunced_to_increment(-2, RoundingIncrement::MultiplesOf2)
1421
    ///         .to_string()
1422
    /// );
1423
    /// ```
1424
0
    pub fn trunced_to_increment(mut self, position: i16, increment: RoundingIncrement) -> Self {
1425
0
        self.trunc_to_increment(position, increment);
1426
0
        self
1427
0
    }
1428
1429
    /// Half Truncates the number on the right to a particular position, deleting
1430
    /// digits if necessary.
1431
    ///
1432
    /// # Examples
1433
    ///
1434
    /// ```
1435
    /// use fixed_decimal::FixedDecimal;
1436
    /// # use std::str::FromStr;
1437
    ///
1438
    /// let mut dec = FixedDecimal::from_str("-1.5").unwrap();
1439
    /// dec.half_trunc(0);
1440
    /// assert_eq!("-1", dec.to_string());
1441
    /// let mut dec = FixedDecimal::from_str("0.4").unwrap();
1442
    /// dec.half_trunc(0);
1443
    /// assert_eq!("0", dec.to_string());
1444
    /// let mut dec = FixedDecimal::from_str("0.5").unwrap();
1445
    /// dec.half_trunc(0);
1446
    /// assert_eq!("0", dec.to_string());
1447
    /// let mut dec = FixedDecimal::from_str("0.6").unwrap();
1448
    /// dec.half_trunc(0);
1449
    /// assert_eq!("1", dec.to_string());
1450
    /// let mut dec = FixedDecimal::from_str("1.5").unwrap();
1451
    /// dec.half_trunc(0);
1452
    /// assert_eq!("1", dec.to_string());
1453
    /// let mut dec = FixedDecimal::from_str("3.954").unwrap();
1454
    /// dec.half_trunc(0);
1455
    /// assert_eq!("4", dec.to_string());
1456
    /// ```
1457
    #[inline(never)]
1458
0
    pub fn half_trunc(&mut self, position: i16) {
1459
0
        self.half_trunc_to_increment_internal(position, NoIncrement);
1460
0
    }
1461
1462
    /// Half Truncates the number on the right to a particular position and rounding increment,
1463
    /// deleting digits if necessary.
1464
    ///
1465
    /// # Examples
1466
    ///
1467
    /// ```
1468
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
1469
    /// # use std::str::FromStr;
1470
    ///
1471
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
1472
    /// dec.half_trunc_to_increment(0, RoundingIncrement::MultiplesOf2);
1473
    /// assert_eq!("-4", dec.to_string());
1474
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
1475
    /// dec.half_trunc_to_increment(-1, RoundingIncrement::MultiplesOf5);
1476
    /// assert_eq!("7.5", dec.to_string());
1477
    /// let mut dec = FixedDecimal::from_str("5.45").unwrap();
1478
    /// dec.half_trunc_to_increment(-2, RoundingIncrement::MultiplesOf25);
1479
    /// assert_eq!("5.50", dec.to_string());
1480
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
1481
    /// dec.half_trunc_to_increment(-1, RoundingIncrement::MultiplesOf25);
1482
    /// assert_eq!("10.0", dec.to_string());
1483
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
1484
    /// dec.half_trunc_to_increment(-2, RoundingIncrement::MultiplesOf2);
1485
    /// assert_eq!("9.98", dec.to_string());
1486
    /// ```
1487
    #[inline(never)]
1488
0
    pub fn half_trunc_to_increment(&mut self, position: i16, increment: RoundingIncrement) {
1489
0
        self.half_trunc_to_increment_internal(position, increment)
1490
0
    }
1491
1492
0
    fn half_trunc_to_increment_internal<R: IncrementLike>(&mut self, position: i16, increment: R) {
1493
0
        // Only expand if the rounding position is strictly greater than the half increment.
1494
0
        // At the half increment, `half_trunc` always truncates.
1495
0
        let should_expand =
1496
0
            self.half_increment_at_magnitude(position, increment) == Ordering::Greater;
1497
0
1498
0
        if should_expand {
1499
0
            self.expand_to_increment_internal(position, increment);
1500
0
        } else {
1501
0
            self.trunc_to_increment_internal(position, increment);
1502
0
        }
1503
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::half_trunc_to_increment_internal::<fixed_decimal::decimal::NoIncrement>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::half_trunc_to_increment_internal::<fixed_decimal::decimal::RoundingIncrement>
1504
1505
    /// Half Truncates the number on the right to a particular position, deleting
1506
    /// digits if necessary.
1507
    ///
1508
    /// # Examples
1509
    ///
1510
    /// ```
1511
    /// use fixed_decimal::FixedDecimal;
1512
    /// # use std::str::FromStr;
1513
    ///
1514
    /// let dec = FixedDecimal::from_str("-1.5").unwrap();
1515
    /// assert_eq!("-1", dec.half_trunced(0).to_string());
1516
    /// let dec = FixedDecimal::from_str("0.4").unwrap();
1517
    /// assert_eq!("0", dec.half_trunced(0).to_string());
1518
    /// let dec = FixedDecimal::from_str("0.5").unwrap();
1519
    /// assert_eq!("0", dec.half_trunced(0).to_string());
1520
    /// let dec = FixedDecimal::from_str("0.6").unwrap();
1521
    /// assert_eq!("1", dec.half_trunced(0).to_string());
1522
    /// let dec = FixedDecimal::from_str("1.5").unwrap();
1523
    /// assert_eq!("1", dec.half_trunced(0).to_string());
1524
    /// let dec = FixedDecimal::from_str("3.954").unwrap();
1525
    /// assert_eq!("4", dec.half_trunced(0).to_string());
1526
    /// ```
1527
0
    pub fn half_trunced(mut self, position: i16) -> Self {
1528
0
        self.half_trunc(position);
1529
0
        self
1530
0
    }
1531
1532
    /// Half Truncates the number on the right to a particular position and rounding increment,
1533
    /// deleting digits if necessary.
1534
    ///
1535
    /// # Examples
1536
    ///
1537
    /// ```
1538
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
1539
    /// # use std::str::FromStr;
1540
    ///
1541
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
1542
    /// assert_eq!(
1543
    ///     "-4",
1544
    ///     dec.half_trunced_to_increment(0, RoundingIncrement::MultiplesOf2)
1545
    ///         .to_string()
1546
    /// );
1547
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
1548
    /// assert_eq!(
1549
    ///     "7.5",
1550
    ///     dec.half_trunced_to_increment(-1, RoundingIncrement::MultiplesOf5)
1551
    ///         .to_string()
1552
    /// );
1553
    /// let mut dec = FixedDecimal::from_str("5.45").unwrap();
1554
    /// assert_eq!(
1555
    ///     "5.50",
1556
    ///     dec.half_trunced_to_increment(-2, RoundingIncrement::MultiplesOf25)
1557
    ///         .to_string()
1558
    /// );
1559
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
1560
    /// assert_eq!(
1561
    ///     "10.0",
1562
    ///     dec.half_trunced_to_increment(-1, RoundingIncrement::MultiplesOf25)
1563
    ///         .to_string()
1564
    /// );
1565
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
1566
    /// assert_eq!(
1567
    ///     "9.98",
1568
    ///     dec.half_trunced_to_increment(-2, RoundingIncrement::MultiplesOf2)
1569
    ///         .to_string()
1570
    /// );
1571
    /// ```
1572
0
    pub fn half_trunced_to_increment(
1573
0
        mut self,
1574
0
        position: i16,
1575
0
        increment: RoundingIncrement,
1576
0
    ) -> Self {
1577
0
        self.half_trunc_to_increment(position, increment);
1578
0
        self
1579
0
    }
1580
1581
    /// Take the expand of the number at a particular position.
1582
    ///
1583
    /// # Examples
1584
    ///
1585
    /// ```
1586
    /// use fixed_decimal::FixedDecimal;
1587
    /// # use std::str::FromStr;
1588
    ///
1589
    /// let mut dec = FixedDecimal::from_str("-1.5").unwrap();
1590
    /// dec.expand(0);
1591
    /// assert_eq!("-2", dec.to_string());
1592
    /// let mut dec = FixedDecimal::from_str("0.4").unwrap();
1593
    /// dec.expand(0);
1594
    /// assert_eq!("1", dec.to_string());
1595
    /// let mut dec = FixedDecimal::from_str("0.5").unwrap();
1596
    /// dec.expand(0);
1597
    /// assert_eq!("1", dec.to_string());
1598
    /// let mut dec = FixedDecimal::from_str("0.6").unwrap();
1599
    /// dec.expand(0);
1600
    /// assert_eq!("1", dec.to_string());
1601
    /// let mut dec = FixedDecimal::from_str("1.5").unwrap();
1602
    /// dec.expand(0);
1603
    /// assert_eq!("2", dec.to_string());
1604
    /// ```
1605
    #[inline(never)]
1606
0
    pub fn expand(&mut self, position: i16) {
1607
0
        self.expand_to_increment_internal(position, NoIncrement)
1608
0
    }
1609
1610
    /// Take the expand of the number at a particular position and rounding increment.
1611
    ///
1612
    /// # Examples
1613
    ///
1614
    /// ```
1615
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
1616
    /// # use std::str::FromStr;
1617
    ///
1618
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
1619
    /// dec.expand_to_increment(0, RoundingIncrement::MultiplesOf2);
1620
    /// assert_eq!("-4", dec.to_string());
1621
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
1622
    /// dec.expand_to_increment(-1, RoundingIncrement::MultiplesOf5);
1623
    /// assert_eq!("8.0", dec.to_string());
1624
    /// let mut dec = FixedDecimal::from_str("5.45").unwrap();
1625
    /// dec.expand_to_increment(-2, RoundingIncrement::MultiplesOf25);
1626
    /// assert_eq!("5.50", dec.to_string());
1627
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
1628
    /// dec.expand_to_increment(-1, RoundingIncrement::MultiplesOf25);
1629
    /// assert_eq!("10.0", dec.to_string());
1630
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
1631
    /// dec.expand_to_increment(-2, RoundingIncrement::MultiplesOf2);
1632
    /// assert_eq!("10.00", dec.to_string());
1633
    /// ```
1634
    #[inline(never)]
1635
0
    pub fn expand_to_increment(&mut self, position: i16, increment: RoundingIncrement) {
1636
0
        self.expand_to_increment_internal(position, increment)
1637
0
    }
1638
1639
0
    fn expand_to_increment_internal<R: IncrementLike>(
1640
0
        &mut self,
1641
0
        position: i16,
1642
0
        inner_increment: R,
1643
0
    ) {
1644
        /// Modifies `number` to signal that an overflow happened.
1645
0
        fn overflow(number: &mut FixedDecimal) {
1646
0
            // TODO(#2297): Decide on behavior here
1647
0
            number.digits.clear();
1648
0
            number.magnitude = 0;
1649
0
            #[cfg(debug_assertions)]
1650
0
            number.check_invariants();
1651
0
        }
1652
1653
0
        let increment = Some(inner_increment);
1654
0
1655
0
        // 1. Set upper and lower magnitude
1656
0
        self.lower_magnitude = cmp::min(position, 0);
1657
0
1658
0
        match position.cmp(&i16::MIN) {
1659
            // Don't return if the increment is not one, because we
1660
            // also need to round to the next increment if necessary.
1661
0
            Ordering::Equal if increment == R::MULTIPLES_OF_1 => {
1662
0
                // Nothing more to do
1663
0
                #[cfg(debug_assertions)]
1664
0
                self.check_invariants();
1665
0
                return;
1666
            }
1667
0
            Ordering::Greater => {
1668
0
                self.upper_magnitude = cmp::max(self.upper_magnitude, position - 1);
1669
0
            }
1670
0
            _ => {
1671
0
                // Ordering::Less is unreachable, and Ordering::Equal needs to apply roundings
1672
0
                // when the increment is not equal to 1.
1673
0
                // We don't override `self.upper_magnitude` because `self.upper_magnitude` is
1674
0
                // always equal or bigger than `i16::MIN`.
1675
0
            }
1676
        }
1677
1678
        // 2. If the number is already rounded, exit early.
1679
0
        if self.is_rounded(position, inner_increment) {
1680
            #[cfg(debug_assertions)]
1681
            self.check_invariants();
1682
0
            return;
1683
0
        }
1684
0
1685
0
        // 3. If the rounding position is *in the middle* of the nonzero digits
1686
0
        if position <= self.magnitude {
1687
            // 3a. Calculate the number of digits to retain and remove the rest
1688
0
            let digits_to_retain = crate::ops::i16_abs_sub(self.magnitude, position) + 1;
1689
0
            self.digits.truncate(digits_to_retain as usize);
1690
1691
            // 3b. Handle the last digit considering the increment.
1692
0
            let iter = match increment {
1693
0
                x if x == R::MULTIPLES_OF_1 => {
1694
                    // Can just execute the algorithm normally.
1695
1696
0
                    self.digits.iter_mut().rev().enumerate()
1697
                }
1698
0
                x if x == R::MULTIPLES_OF_2 => {
1699
0
                    let mut iter = self.digits.iter_mut().rev().enumerate();
1700
1701
                    // Must round the last digit to the next increment.
1702
0
                    let Some((_, digit)) = iter.next() else {
1703
0
                        debug_assert!(false, "`self.digits` should have at least a digit");
1704
0
                        return;
1705
                    };
1706
1707
                    // Equivalent to (n + 2 / 2) * 2, which expands to the next
1708
                    // multiple of two
1709
0
                    *digit = (*digit + 2) & 0xFE;
1710
0
1711
0
                    if *digit < 10 {
1712
                        // Early returns if the expansion didn't generate a remainder.
1713
                        #[cfg(debug_assertions)]
1714
                        self.check_invariants();
1715
0
                        return;
1716
0
                    }
1717
0
1718
0
                    iter
1719
                }
1720
0
                x if x == R::MULTIPLES_OF_5 => {
1721
0
                    let mut iter = self.digits.iter_mut().rev().enumerate();
1722
1723
                    // Must round the last digit to the next increment.
1724
0
                    let Some((_, digit)) = iter.next() else {
1725
0
                        debug_assert!(false, "`self.digits` should have at least a digit");
1726
0
                        return;
1727
                    };
1728
1729
0
                    if *digit < 5 {
1730
0
                        *digit = 5;
1731
0
1732
0
                        // Early return since the expansion didn't generate a remainder.
1733
0
                        #[cfg(debug_assertions)]
1734
0
                        self.check_invariants();
1735
0
                        return;
1736
0
                    }
1737
0
1738
0
                    *digit = 10;
1739
0
1740
0
                    iter
1741
                }
1742
0
                x if x == R::MULTIPLES_OF_25 => {
1743
                    // Extend the digits to have the correct
1744
                    // number of trailing zeroes.
1745
0
                    self.digits.resize(digits_to_retain as usize, 0);
1746
1747
0
                    let Some((last_digit, digits)) = self.digits.split_last_mut() else {
1748
0
                        debug_assert!(false, "`self.digits` should have at least a digit");
1749
0
                        return;
1750
                    };
1751
1752
0
                    let Some((second_last_digit, _)) = digits.split_last_mut() else {
1753
                        // The number has no other digits aside from the last.
1754
                        // We need to manually increment the number to 25
1755
1756
0
                        if self.magnitude == i16::MAX {
1757
0
                            overflow(self);
1758
0
                            return;
1759
0
                        }
1760
0
1761
0
                        self.digits.clear();
1762
0
                        self.digits.extend_from_slice(&[2, 5]);
1763
0
                        self.magnitude += 1;
1764
0
                        self.upper_magnitude = cmp::max(self.upper_magnitude, self.magnitude);
1765
0
1766
0
                        #[cfg(debug_assertions)]
1767
0
                        self.check_invariants();
1768
0
                        return;
1769
                    };
1770
1771
0
                    let number = *second_last_digit * 10 + *last_digit;
1772
0
1773
0
                    if number < 75 {
1774
                        // We can return directly if the number won't expand
1775
                        // to 100.
1776
0
                        if number < 25 {
1777
0
                            *second_last_digit = 2;
1778
0
                            *last_digit = 5;
1779
0
                        } else if number < 50 {
1780
0
                            *second_last_digit = 5;
1781
0
                            self.digits.pop();
1782
0
                        } else {
1783
0
                            *second_last_digit = 7;
1784
0
                            *last_digit = 5;
1785
0
                        }
1786
1787
                        #[cfg(debug_assertions)]
1788
                        self.check_invariants();
1789
0
                        return;
1790
0
                    }
1791
0
1792
0
                    // The number reached 100. Continue the algorithm but with the
1793
0
                    // last two digits removed from the iterator.
1794
0
1795
0
                    *second_last_digit = 10;
1796
0
                    *last_digit = 10;
1797
0
1798
0
                    let mut iter = self.digits.iter_mut().rev().enumerate();
1799
0
1800
0
                    // Remove the last two items that were already handled.
1801
0
                    iter.next();
1802
0
                    iter.next();
1803
0
1804
0
                    iter
1805
                }
1806
                _ => {
1807
0
                    debug_assert!(false, "INCREMENT should be 1, 2, 5, or 25");
1808
0
                    return;
1809
                }
1810
            };
1811
1812
            // 3b. Increment the rightmost remaining digit since we are rounding up; this might
1813
            // require bubbling the addition to higher magnitudes, like 199 + 1 = 200
1814
0
            for (zero_count, digit) in iter {
1815
0
                *digit += 1;
1816
0
                if *digit < 10 {
1817
0
                    self.digits.truncate(self.digits.len() - zero_count);
1818
0
                    #[cfg(debug_assertions)]
1819
0
                    self.check_invariants();
1820
0
                    return;
1821
0
                }
1822
            }
1823
1824
            // 3c. If we get here, the mantissa is fully saturated.
1825
            // Clear the saturated mantissa and replace everything with a single 1.
1826
1827
0
            if self.magnitude == i16::MAX {
1828
0
                overflow(self);
1829
0
                return;
1830
0
            }
1831
0
1832
0
            self.digits.clear();
1833
0
            self.digits.push(1);
1834
0
1835
0
            self.magnitude += 1;
1836
0
            self.upper_magnitude = cmp::max(self.upper_magnitude, self.magnitude);
1837
0
1838
0
            #[cfg(debug_assertions)]
1839
0
            self.check_invariants();
1840
0
            return;
1841
0
        }
1842
0
1843
0
        // 4. If the rounding position is *above* the leftmost nonzero digit,
1844
0
        // set the value to the next increment at the appropriate position.
1845
0
1846
0
        // Check if we have enough available spaces to push a `25` at the start.
1847
0
        if increment == R::MULTIPLES_OF_25 && position == i16::MAX {
1848
            // Need an extra digit to push a 25, which we don't have.
1849
0
            overflow(self);
1850
0
            return;
1851
0
        }
1852
0
1853
0
        self.digits.clear();
1854
1855
        // We need to push the next multiple of the increment,
1856
        // and we also need to adjust the magnitude to the
1857
        // new upper magnitude.
1858
0
        let increment_digits = match increment {
1859
0
            x if x == R::MULTIPLES_OF_1 => [1].as_slice(),
1860
0
            x if x == R::MULTIPLES_OF_2 => [2].as_slice(),
1861
0
            x if x == R::MULTIPLES_OF_5 => [5].as_slice(),
1862
0
            x if x == R::MULTIPLES_OF_25 => [2, 5].as_slice(),
1863
            _ => {
1864
0
                debug_assert!(false, "INCREMENT should be 1, 2, 5, or 25");
1865
0
                return;
1866
            }
1867
        };
1868
0
        self.digits.extend_from_slice(increment_digits);
1869
0
1870
0
        // Could also be derived from `increment_digits.len() - 1`, but it makes
1871
0
        // the logic a bit harder to follow.
1872
0
        self.magnitude = if increment == R::MULTIPLES_OF_25 {
1873
0
            position + 1
1874
        } else {
1875
0
            position
1876
        };
1877
1878
0
        self.upper_magnitude = cmp::max(self.upper_magnitude, self.magnitude);
1879
1880
        #[cfg(debug_assertions)]
1881
        self.check_invariants();
1882
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::expand_to_increment_internal::<fixed_decimal::decimal::NoIncrement>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::expand_to_increment_internal::<fixed_decimal::decimal::RoundingIncrement>
1883
1884
    /// Take the expand of the number at a particular position.
1885
    ///
1886
    /// # Examples
1887
    ///
1888
    /// ```
1889
    /// use fixed_decimal::FixedDecimal;
1890
    /// # use std::str::FromStr;
1891
    ///
1892
    /// let dec = FixedDecimal::from_str("-1.5").unwrap();
1893
    /// assert_eq!("-2", dec.expanded(0).to_string());
1894
    /// let dec = FixedDecimal::from_str("0.4").unwrap();
1895
    /// assert_eq!("1", dec.expanded(0).to_string());
1896
    /// let dec = FixedDecimal::from_str("0.5").unwrap();
1897
    /// assert_eq!("1", dec.expanded(0).to_string());
1898
    /// let dec = FixedDecimal::from_str("0.6").unwrap();
1899
    /// assert_eq!("1", dec.expanded(0).to_string());
1900
    /// let dec = FixedDecimal::from_str("1.5").unwrap();
1901
    /// assert_eq!("2", dec.expanded(0).to_string());
1902
    /// ```
1903
0
    pub fn expanded(mut self, position: i16) -> Self {
1904
0
        self.expand(position);
1905
0
        self
1906
0
    }
1907
1908
    /// Take the expand of the number at a particular position and rounding increment.
1909
    ///
1910
    /// # Examples
1911
    ///
1912
    /// ```
1913
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
1914
    /// # use std::str::FromStr;
1915
    ///
1916
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
1917
    /// assert_eq!(
1918
    ///     "-4",
1919
    ///     dec.expanded_to_increment(0, RoundingIncrement::MultiplesOf2)
1920
    ///         .to_string()
1921
    /// );
1922
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
1923
    /// assert_eq!(
1924
    ///     "8.0",
1925
    ///     dec.expanded_to_increment(-1, RoundingIncrement::MultiplesOf5)
1926
    ///         .to_string()
1927
    /// );
1928
    /// let mut dec = FixedDecimal::from_str("5.45").unwrap();
1929
    /// assert_eq!(
1930
    ///     "5.50",
1931
    ///     dec.expanded_to_increment(-2, RoundingIncrement::MultiplesOf25)
1932
    ///         .to_string()
1933
    /// );
1934
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
1935
    /// assert_eq!(
1936
    ///     "10.0",
1937
    ///     dec.expanded_to_increment(-1, RoundingIncrement::MultiplesOf25)
1938
    ///         .to_string()
1939
    /// );
1940
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
1941
    /// assert_eq!(
1942
    ///     "10.00",
1943
    ///     dec.expanded_to_increment(-2, RoundingIncrement::MultiplesOf2)
1944
    ///         .to_string()
1945
    /// );
1946
    /// ```
1947
0
    pub fn expanded_to_increment(mut self, position: i16, increment: RoundingIncrement) -> Self {
1948
0
        self.expand_to_increment(position, increment);
1949
0
        self
1950
0
    }
1951
1952
    /// Take the half expand of the number at a particular position.
1953
    ///
1954
    /// # Examples
1955
    ///
1956
    /// ```
1957
    /// use fixed_decimal::FixedDecimal;
1958
    /// # use std::str::FromStr;
1959
    ///
1960
    /// let mut dec = FixedDecimal::from_str("-1.5").unwrap();
1961
    /// dec.half_expand(0);
1962
    /// assert_eq!("-2", dec.to_string());
1963
    /// let mut dec = FixedDecimal::from_str("0.4").unwrap();
1964
    /// dec.half_expand(0);
1965
    /// assert_eq!("0", dec.to_string());
1966
    /// let mut dec = FixedDecimal::from_str("0.5").unwrap();
1967
    /// dec.half_expand(0);
1968
    /// assert_eq!("1", dec.to_string());
1969
    /// let mut dec = FixedDecimal::from_str("0.6").unwrap();
1970
    /// dec.half_expand(0);
1971
    /// assert_eq!("1", dec.to_string());
1972
    /// let mut dec = FixedDecimal::from_str("1.5").unwrap();
1973
    /// dec.half_expand(0);
1974
    /// assert_eq!("2", dec.to_string());
1975
    /// ```
1976
    #[inline(never)]
1977
0
    pub fn half_expand(&mut self, position: i16) {
1978
0
        self.half_expand_to_increment_internal(position, NoIncrement)
1979
0
    }
1980
1981
    /// Take the half expand of the number at a particular position and rounding increment.
1982
    ///
1983
    /// # Examples
1984
    ///
1985
    /// ```
1986
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
1987
    /// # use std::str::FromStr;
1988
    ///
1989
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
1990
    /// dec.half_expand_to_increment(0, RoundingIncrement::MultiplesOf2);
1991
    /// assert_eq!("-4", dec.to_string());
1992
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
1993
    /// dec.half_expand_to_increment(-1, RoundingIncrement::MultiplesOf5);
1994
    /// assert_eq!("7.5", dec.to_string());
1995
    /// let mut dec = FixedDecimal::from_str("5.45").unwrap();
1996
    /// dec.half_expand_to_increment(-2, RoundingIncrement::MultiplesOf25);
1997
    /// assert_eq!("5.50", dec.to_string());
1998
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
1999
    /// dec.half_expand_to_increment(-1, RoundingIncrement::MultiplesOf25);
2000
    /// assert_eq!("10.0", dec.to_string());
2001
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2002
    /// dec.half_expand_to_increment(-2, RoundingIncrement::MultiplesOf2);
2003
    /// assert_eq!("10.00", dec.to_string());
2004
    /// ```
2005
    #[inline(never)]
2006
0
    pub fn half_expand_to_increment(&mut self, position: i16, increment: RoundingIncrement) {
2007
0
        self.half_expand_to_increment_internal(position, increment)
2008
0
    }
2009
2010
0
    fn half_expand_to_increment_internal<R: IncrementLike>(&mut self, position: i16, increment: R) {
2011
0
        // Only truncate if the rounding position is strictly less than the half increment.
2012
0
        // At the half increment, `half_expand` always expands.
2013
0
        let should_trunc = self.half_increment_at_magnitude(position, increment) == Ordering::Less;
2014
0
2015
0
        if should_trunc {
2016
0
            self.trunc_to_increment_internal(position, increment);
2017
0
        } else {
2018
0
            self.expand_to_increment_internal(position, increment);
2019
0
        }
2020
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::half_expand_to_increment_internal::<fixed_decimal::decimal::NoIncrement>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::half_expand_to_increment_internal::<fixed_decimal::decimal::RoundingIncrement>
2021
2022
    /// Take the half expand of the number at a particular position.
2023
    ///
2024
    /// # Examples
2025
    ///
2026
    /// ```
2027
    /// use fixed_decimal::FixedDecimal;
2028
    /// # use std::str::FromStr;
2029
    ///
2030
    /// let dec = FixedDecimal::from_str("-1.5").unwrap();
2031
    /// assert_eq!("-2", dec.half_expanded(0).to_string());
2032
    /// let dec = FixedDecimal::from_str("0.4").unwrap();
2033
    /// assert_eq!("0", dec.half_expanded(0).to_string());
2034
    /// let dec = FixedDecimal::from_str("0.5").unwrap();
2035
    /// assert_eq!("1", dec.half_expanded(0).to_string());
2036
    /// let dec = FixedDecimal::from_str("0.6").unwrap();
2037
    /// assert_eq!("1", dec.half_expanded(0).to_string());
2038
    /// let dec = FixedDecimal::from_str("1.5").unwrap();
2039
    /// assert_eq!("2", dec.half_expanded(0).to_string());
2040
    /// ```
2041
0
    pub fn half_expanded(mut self, position: i16) -> Self {
2042
0
        self.half_expand(position);
2043
0
        self
2044
0
    }
2045
2046
    /// Take the half expand of the number at a particular position and rounding increment.
2047
    ///
2048
    /// # Examples
2049
    ///
2050
    /// ```
2051
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
2052
    /// # use std::str::FromStr;
2053
    ///
2054
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
2055
    /// assert_eq!(
2056
    ///     "-4",
2057
    ///     dec.half_expanded_to_increment(0, RoundingIncrement::MultiplesOf2)
2058
    ///         .to_string()
2059
    /// );
2060
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
2061
    /// assert_eq!(
2062
    ///     "7.5",
2063
    ///     dec.half_expanded_to_increment(-1, RoundingIncrement::MultiplesOf5)
2064
    ///         .to_string()
2065
    /// );
2066
    /// let mut dec = FixedDecimal::from_str("5.45").unwrap();
2067
    /// assert_eq!(
2068
    ///     "5.50",
2069
    ///     dec.half_expanded_to_increment(-2, RoundingIncrement::MultiplesOf25)
2070
    ///         .to_string()
2071
    /// );
2072
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2073
    /// assert_eq!(
2074
    ///     "10.0",
2075
    ///     dec.half_expanded_to_increment(-1, RoundingIncrement::MultiplesOf25)
2076
    ///         .to_string()
2077
    /// );
2078
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2079
    /// assert_eq!(
2080
    ///     "10.00",
2081
    ///     dec.half_expanded_to_increment(-2, RoundingIncrement::MultiplesOf2)
2082
    ///         .to_string()
2083
    /// );
2084
    /// ```
2085
0
    pub fn half_expanded_to_increment(
2086
0
        mut self,
2087
0
        position: i16,
2088
0
        increment: RoundingIncrement,
2089
0
    ) -> Self {
2090
0
        self.half_expand_to_increment(position, increment);
2091
0
        self
2092
0
    }
2093
2094
    /// Take the ceiling of the number at a particular position.
2095
    ///
2096
    /// # Examples
2097
    ///
2098
    /// ```
2099
    /// use fixed_decimal::FixedDecimal;
2100
    /// # use std::str::FromStr;
2101
    ///
2102
    /// let mut dec = FixedDecimal::from_str("-1.5").unwrap();
2103
    /// dec.ceil(0);
2104
    /// assert_eq!("-1", dec.to_string());
2105
    /// let mut dec = FixedDecimal::from_str("0.4").unwrap();
2106
    /// dec.ceil(0);
2107
    /// assert_eq!("1", dec.to_string());
2108
    /// let mut dec = FixedDecimal::from_str("0.5").unwrap();
2109
    /// dec.ceil(0);
2110
    /// assert_eq!("1", dec.to_string());
2111
    /// let mut dec = FixedDecimal::from_str("0.6").unwrap();
2112
    /// dec.ceil(0);
2113
    /// assert_eq!("1", dec.to_string());
2114
    /// let mut dec = FixedDecimal::from_str("1.5").unwrap();
2115
    /// dec.ceil(0);
2116
    /// assert_eq!("2", dec.to_string());
2117
    /// ```
2118
    #[inline(never)]
2119
0
    pub fn ceil(&mut self, position: i16) {
2120
0
        self.ceil_to_increment_internal(position, NoIncrement);
2121
0
    }
2122
2123
    /// Take the ceiling of the number at a particular position and rounding increment.
2124
    ///
2125
    /// # Examples
2126
    ///
2127
    /// ```
2128
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
2129
    /// # use std::str::FromStr;
2130
    ///
2131
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
2132
    /// dec.ceil_to_increment(0, RoundingIncrement::MultiplesOf2);
2133
    /// assert_eq!("-2", dec.to_string());
2134
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
2135
    /// dec.ceil_to_increment(-1, RoundingIncrement::MultiplesOf5);
2136
    /// assert_eq!("8.0", dec.to_string());
2137
    /// let mut dec = FixedDecimal::from_str("-5.45").unwrap();
2138
    /// dec.ceil_to_increment(-2, RoundingIncrement::MultiplesOf25);
2139
    /// assert_eq!("-5.25", dec.to_string());
2140
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2141
    /// dec.ceil_to_increment(-1, RoundingIncrement::MultiplesOf25);
2142
    /// assert_eq!("10.0", dec.to_string());
2143
    /// let mut dec = FixedDecimal::from_str("-9.99").unwrap();
2144
    /// dec.ceil_to_increment(-2, RoundingIncrement::MultiplesOf2);
2145
    /// assert_eq!("-9.98", dec.to_string());
2146
    /// ```
2147
    #[inline(never)]
2148
0
    pub fn ceil_to_increment(&mut self, position: i16, increment: RoundingIncrement) {
2149
0
        self.ceil_to_increment_internal(position, increment)
2150
0
    }
2151
2152
0
    fn ceil_to_increment_internal<R: IncrementLike>(&mut self, position: i16, increment: R) {
2153
0
        if self.sign == Sign::Negative {
2154
0
            self.trunc_to_increment_internal(position, increment);
2155
0
            return;
2156
0
        }
2157
0
2158
0
        self.expand_to_increment_internal(position, increment);
2159
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::ceil_to_increment_internal::<fixed_decimal::decimal::NoIncrement>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::ceil_to_increment_internal::<fixed_decimal::decimal::RoundingIncrement>
2160
2161
    /// Take the ceiling of the number at a particular position.
2162
    ///
2163
    /// # Examples
2164
    ///
2165
    /// ```
2166
    /// use fixed_decimal::FixedDecimal;
2167
    /// # use std::str::FromStr;
2168
    ///
2169
    /// let dec = FixedDecimal::from_str("-1.5").unwrap();
2170
    /// assert_eq!("-1", dec.ceiled(0).to_string());
2171
    /// let dec = FixedDecimal::from_str("0.4").unwrap();
2172
    /// assert_eq!("1", dec.ceiled(0).to_string());
2173
    /// let dec = FixedDecimal::from_str("0.5").unwrap();
2174
    /// assert_eq!("1", dec.ceiled(0).to_string());
2175
    /// let dec = FixedDecimal::from_str("0.6").unwrap();
2176
    /// assert_eq!("1", dec.ceiled(0).to_string());
2177
    /// let dec = FixedDecimal::from_str("1.5").unwrap();
2178
    /// assert_eq!("2", dec.ceiled(0).to_string());
2179
    /// ```
2180
0
    pub fn ceiled(mut self, position: i16) -> Self {
2181
0
        self.ceil(position);
2182
0
        self
2183
0
    }
2184
2185
    /// Take the ceiling of the number at a particular position and rounding increment.
2186
    ///
2187
    /// # Examples
2188
    ///
2189
    /// ```
2190
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
2191
    /// # use std::str::FromStr;
2192
    ///
2193
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
2194
    /// assert_eq!(
2195
    ///     "-2",
2196
    ///     dec.ceiled_to_increment(0, RoundingIncrement::MultiplesOf2)
2197
    ///         .to_string()
2198
    /// );
2199
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
2200
    /// assert_eq!(
2201
    ///     "8.0",
2202
    ///     dec.ceiled_to_increment(-1, RoundingIncrement::MultiplesOf5)
2203
    ///         .to_string()
2204
    /// );
2205
    /// let mut dec = FixedDecimal::from_str("-5.45").unwrap();
2206
    /// assert_eq!(
2207
    ///     "-5.25",
2208
    ///     dec.ceiled_to_increment(-2, RoundingIncrement::MultiplesOf25)
2209
    ///         .to_string()
2210
    /// );
2211
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2212
    /// assert_eq!(
2213
    ///     "10.0",
2214
    ///     dec.ceiled_to_increment(-1, RoundingIncrement::MultiplesOf25)
2215
    ///         .to_string()
2216
    /// );
2217
    /// let mut dec = FixedDecimal::from_str("-9.99").unwrap();
2218
    /// assert_eq!(
2219
    ///     "-9.98",
2220
    ///     dec.ceiled_to_increment(-2, RoundingIncrement::MultiplesOf2)
2221
    ///         .to_string()
2222
    /// );
2223
    /// ```
2224
0
    pub fn ceiled_to_increment(mut self, position: i16, increment: RoundingIncrement) -> Self {
2225
0
        self.ceil_to_increment(position, increment);
2226
0
        self
2227
0
    }
2228
2229
    /// Take the half ceiling of the number at a particular position.
2230
    ///
2231
    /// # Examples
2232
    ///
2233
    /// ```
2234
    /// use fixed_decimal::FixedDecimal;
2235
    /// # use std::str::FromStr;
2236
    ///
2237
    /// let mut dec = FixedDecimal::from_str("-1.5").unwrap();
2238
    /// dec.half_ceil(0);
2239
    /// assert_eq!("-1", dec.to_string());
2240
    /// let mut dec = FixedDecimal::from_str("0.4").unwrap();
2241
    /// dec.half_ceil(0);
2242
    /// assert_eq!("0", dec.to_string());
2243
    /// let mut dec = FixedDecimal::from_str("0.5").unwrap();
2244
    /// dec.half_ceil(0);
2245
    /// assert_eq!("1", dec.to_string());
2246
    /// let mut dec = FixedDecimal::from_str("0.6").unwrap();
2247
    /// dec.half_ceil(0);
2248
    /// assert_eq!("1", dec.to_string());
2249
    /// let mut dec = FixedDecimal::from_str("1.5").unwrap();
2250
    /// dec.half_ceil(0);
2251
    /// assert_eq!("2", dec.to_string());
2252
    /// ```
2253
    #[inline(never)]
2254
0
    pub fn half_ceil(&mut self, position: i16) {
2255
0
        self.half_ceil_to_increment_internal(position, NoIncrement);
2256
0
    }
2257
2258
    /// Take the half ceiling of the number at a particular position and rounding increment.
2259
    ///
2260
    /// # Examples
2261
    ///
2262
    /// ```
2263
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
2264
    /// # use std::str::FromStr;
2265
    ///
2266
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
2267
    /// dec.half_ceil_to_increment(0, RoundingIncrement::MultiplesOf2);
2268
    /// assert_eq!("-4", dec.to_string());
2269
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
2270
    /// dec.half_ceil_to_increment(-1, RoundingIncrement::MultiplesOf5);
2271
    /// assert_eq!("7.5", dec.to_string());
2272
    /// let mut dec = FixedDecimal::from_str("-5.45").unwrap();
2273
    /// dec.half_ceil_to_increment(-2, RoundingIncrement::MultiplesOf25);
2274
    /// assert_eq!("-5.50", dec.to_string());
2275
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2276
    /// dec.half_ceil_to_increment(-1, RoundingIncrement::MultiplesOf25);
2277
    /// assert_eq!("10.0", dec.to_string());
2278
    /// let mut dec = FixedDecimal::from_str("-9.99").unwrap();
2279
    /// dec.half_ceil_to_increment(-2, RoundingIncrement::MultiplesOf2);
2280
    /// assert_eq!("-9.98", dec.to_string());
2281
    /// ```
2282
    #[inline(never)]
2283
0
    pub fn half_ceil_to_increment(&mut self, position: i16, increment: RoundingIncrement) {
2284
0
        self.half_ceil_to_increment_internal(position, increment)
2285
0
    }
2286
2287
0
    fn half_ceil_to_increment_internal<R: IncrementLike>(&mut self, position: i16, increment: R) {
2288
0
        if self.sign == Sign::Negative {
2289
0
            self.half_trunc_to_increment_internal(position, increment);
2290
0
            return;
2291
0
        }
2292
0
2293
0
        self.half_expand_to_increment_internal(position, increment);
2294
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::half_ceil_to_increment_internal::<fixed_decimal::decimal::NoIncrement>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::half_ceil_to_increment_internal::<fixed_decimal::decimal::RoundingIncrement>
2295
2296
    /// Take the half ceiling of the number at a particular position.
2297
    ///
2298
    /// # Examples
2299
    ///
2300
    /// ```
2301
    /// use fixed_decimal::FixedDecimal;
2302
    /// # use std::str::FromStr;
2303
    ///
2304
    /// let dec = FixedDecimal::from_str("-1.5").unwrap();
2305
    /// assert_eq!("-1", dec.half_ceiled(0).to_string());
2306
    /// let dec = FixedDecimal::from_str("0.4").unwrap();
2307
    /// assert_eq!("0", dec.half_ceiled(0).to_string());
2308
    /// let dec = FixedDecimal::from_str("0.5").unwrap();
2309
    /// assert_eq!("1", dec.half_ceiled(0).to_string());
2310
    /// let dec = FixedDecimal::from_str("0.6").unwrap();
2311
    /// assert_eq!("1", dec.half_ceiled(0).to_string());
2312
    /// let dec = FixedDecimal::from_str("1.5").unwrap();
2313
    /// assert_eq!("2", dec.half_ceiled(0).to_string());
2314
    /// ```
2315
0
    pub fn half_ceiled(mut self, position: i16) -> Self {
2316
0
        self.half_ceil(position);
2317
0
        self
2318
0
    }
2319
2320
    /// Take the half ceiling of the number at a particular position and rounding increment.
2321
    ///
2322
    /// # Examples
2323
    ///
2324
    /// ```
2325
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
2326
    /// # use std::str::FromStr;
2327
    ///
2328
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
2329
    /// assert_eq!(
2330
    ///     "-4",
2331
    ///     dec.half_ceiled_to_increment(0, RoundingIncrement::MultiplesOf2)
2332
    ///         .to_string()
2333
    /// );
2334
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
2335
    /// assert_eq!(
2336
    ///     "7.5",
2337
    ///     dec.half_ceiled_to_increment(-1, RoundingIncrement::MultiplesOf5)
2338
    ///         .to_string()
2339
    /// );
2340
    /// let mut dec = FixedDecimal::from_str("-5.45").unwrap();
2341
    /// assert_eq!(
2342
    ///     "-5.50",
2343
    ///     dec.half_ceiled_to_increment(-2, RoundingIncrement::MultiplesOf25)
2344
    ///         .to_string()
2345
    /// );
2346
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2347
    /// assert_eq!(
2348
    ///     "10.0",
2349
    ///     dec.half_ceiled_to_increment(-1, RoundingIncrement::MultiplesOf25)
2350
    ///         .to_string()
2351
    /// );
2352
    /// let mut dec = FixedDecimal::from_str("-9.99").unwrap();
2353
    /// assert_eq!(
2354
    ///     "-9.98",
2355
    ///     dec.half_ceiled_to_increment(-2, RoundingIncrement::MultiplesOf2)
2356
    ///         .to_string()
2357
    /// );
2358
    /// ```
2359
0
    pub fn half_ceiled_to_increment(mut self, position: i16, increment: RoundingIncrement) -> Self {
2360
0
        self.half_ceil_to_increment(position, increment);
2361
0
        self
2362
0
    }
2363
2364
    /// Take the floor of the number at a particular position.
2365
    ///
2366
    /// # Examples
2367
    ///
2368
    /// ```
2369
    /// use fixed_decimal::FixedDecimal;
2370
    /// # use std::str::FromStr;
2371
    ///
2372
    /// let mut dec = FixedDecimal::from_str("-1.5").unwrap();
2373
    /// dec.floor(0);
2374
    /// assert_eq!("-2", dec.to_string());
2375
    /// let mut dec = FixedDecimal::from_str("0.4").unwrap();
2376
    /// dec.floor(0);
2377
    /// assert_eq!("0", dec.to_string());
2378
    /// let mut dec = FixedDecimal::from_str("0.5").unwrap();
2379
    /// dec.floor(0);
2380
    /// assert_eq!("0", dec.to_string());
2381
    /// let mut dec = FixedDecimal::from_str("0.6").unwrap();
2382
    /// dec.floor(0);
2383
    /// assert_eq!("0", dec.to_string());
2384
    /// let mut dec = FixedDecimal::from_str("1.5").unwrap();
2385
    /// dec.floor(0);
2386
    /// assert_eq!("1", dec.to_string());
2387
    /// ```
2388
    #[inline(never)]
2389
0
    pub fn floor(&mut self, position: i16) {
2390
0
        self.floor_to_increment_internal(position, NoIncrement);
2391
0
    }
2392
2393
    /// Take the floor of the number at a particular position and rounding increment.
2394
    ///
2395
    /// # Examples
2396
    ///
2397
    /// ```
2398
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
2399
    /// # use std::str::FromStr;
2400
    ///
2401
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
2402
    /// dec.floor_to_increment(0, RoundingIncrement::MultiplesOf2);
2403
    /// assert_eq!("-4", dec.to_string());
2404
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
2405
    /// dec.floor_to_increment(-1, RoundingIncrement::MultiplesOf5);
2406
    /// assert_eq!("7.5", dec.to_string());
2407
    /// let mut dec = FixedDecimal::from_str("-5.45").unwrap();
2408
    /// dec.floor_to_increment(-2, RoundingIncrement::MultiplesOf25);
2409
    /// assert_eq!("-5.50", dec.to_string());
2410
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2411
    /// dec.floor_to_increment(-1, RoundingIncrement::MultiplesOf25);
2412
    /// assert_eq!("7.5", dec.to_string());
2413
    /// let mut dec = FixedDecimal::from_str("-9.99").unwrap();
2414
    /// dec.floor_to_increment(-2, RoundingIncrement::MultiplesOf2);
2415
    /// assert_eq!("-10.00", dec.to_string());
2416
    /// ```
2417
    #[inline(never)]
2418
0
    pub fn floor_to_increment(&mut self, position: i16, increment: RoundingIncrement) {
2419
0
        self.floor_to_increment_internal(position, increment)
2420
0
    }
2421
2422
0
    fn floor_to_increment_internal<R: IncrementLike>(&mut self, position: i16, increment: R) {
2423
0
        if self.sign == Sign::Negative {
2424
0
            self.expand_to_increment_internal(position, increment);
2425
0
            return;
2426
0
        }
2427
0
2428
0
        self.trunc_to_increment_internal(position, increment);
2429
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::floor_to_increment_internal::<fixed_decimal::decimal::NoIncrement>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::floor_to_increment_internal::<fixed_decimal::decimal::RoundingIncrement>
2430
2431
    /// Take the floor of the number at a particular position.
2432
    ///
2433
    /// # Examples
2434
    ///
2435
    /// ```
2436
    /// use fixed_decimal::FixedDecimal;
2437
    /// # use std::str::FromStr;
2438
    ///
2439
    /// let dec = FixedDecimal::from_str("-1.5").unwrap();
2440
    /// assert_eq!("-2", dec.floored(0).to_string());
2441
    /// let dec = FixedDecimal::from_str("0.4").unwrap();
2442
    /// assert_eq!("0", dec.floored(0).to_string());
2443
    /// let dec = FixedDecimal::from_str("0.5").unwrap();
2444
    /// assert_eq!("0", dec.floored(0).to_string());
2445
    /// let dec = FixedDecimal::from_str("0.6").unwrap();
2446
    /// assert_eq!("0", dec.floored(0).to_string());
2447
    /// let dec = FixedDecimal::from_str("1.5").unwrap();
2448
    /// assert_eq!("1", dec.floored(0).to_string());
2449
    /// ```
2450
0
    pub fn floored(mut self, position: i16) -> Self {
2451
0
        self.floor(position);
2452
0
        self
2453
0
    }
2454
2455
    /// Take the floor of the number at a particular position and rounding increment.
2456
    ///
2457
    /// # Examples
2458
    ///
2459
    /// ```
2460
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
2461
    /// # use std::str::FromStr;
2462
    ///
2463
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
2464
    /// assert_eq!(
2465
    ///     "-4",
2466
    ///     dec.floored_to_increment(0, RoundingIncrement::MultiplesOf2)
2467
    ///         .to_string()
2468
    /// );
2469
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
2470
    /// assert_eq!(
2471
    ///     "7.5",
2472
    ///     dec.floored_to_increment(-1, RoundingIncrement::MultiplesOf5)
2473
    ///         .to_string()
2474
    /// );
2475
    /// let mut dec = FixedDecimal::from_str("-5.45").unwrap();
2476
    /// assert_eq!(
2477
    ///     "-5.50",
2478
    ///     dec.floored_to_increment(-2, RoundingIncrement::MultiplesOf25)
2479
    ///         .to_string()
2480
    /// );
2481
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2482
    /// assert_eq!(
2483
    ///     "7.5",
2484
    ///     dec.floored_to_increment(-1, RoundingIncrement::MultiplesOf25)
2485
    ///         .to_string()
2486
    /// );
2487
    /// let mut dec = FixedDecimal::from_str("-9.99").unwrap();
2488
    /// assert_eq!(
2489
    ///     "-10.00",
2490
    ///     dec.floored_to_increment(-2, RoundingIncrement::MultiplesOf2)
2491
    ///         .to_string()
2492
    /// );
2493
    /// ```
2494
0
    pub fn floored_to_increment(mut self, position: i16, increment: RoundingIncrement) -> Self {
2495
0
        self.floor_to_increment(position, increment);
2496
0
        self
2497
0
    }
2498
2499
    /// Take the half floor of the number at a particular position.
2500
    ///
2501
    /// # Examples
2502
    ///
2503
    /// ```
2504
    /// use fixed_decimal::FixedDecimal;
2505
    /// # use std::str::FromStr;
2506
    ///
2507
    /// let mut dec = FixedDecimal::from_str("-1.5").unwrap();
2508
    /// dec.half_floor(0);
2509
    /// assert_eq!("-2", dec.to_string());
2510
    /// let mut dec = FixedDecimal::from_str("0.4").unwrap();
2511
    /// dec.half_floor(0);
2512
    /// assert_eq!("0", dec.to_string());
2513
    /// let mut dec = FixedDecimal::from_str("0.5").unwrap();
2514
    /// dec.half_floor(0);
2515
    /// assert_eq!("0", dec.to_string());
2516
    /// let mut dec = FixedDecimal::from_str("0.6").unwrap();
2517
    /// dec.half_floor(0);
2518
    /// assert_eq!("1", dec.to_string());
2519
    /// let mut dec = FixedDecimal::from_str("1.5").unwrap();
2520
    /// dec.half_floor(0);
2521
    /// assert_eq!("1", dec.to_string());
2522
    /// ```
2523
    #[inline(never)]
2524
0
    pub fn half_floor(&mut self, position: i16) {
2525
0
        self.half_floor_to_increment_internal(position, NoIncrement);
2526
0
    }
2527
2528
    /// Take the half floor of the number at a particular position and rounding increment.
2529
    ///
2530
    /// # Examples
2531
    ///
2532
    /// ```
2533
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
2534
    /// # use std::str::FromStr;
2535
    ///
2536
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
2537
    /// dec.half_floor_to_increment(0, RoundingIncrement::MultiplesOf2);
2538
    /// assert_eq!("-4", dec.to_string());
2539
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
2540
    /// dec.half_floor_to_increment(-1, RoundingIncrement::MultiplesOf5);
2541
    /// assert_eq!("7.5", dec.to_string());
2542
    /// let mut dec = FixedDecimal::from_str("-5.45").unwrap();
2543
    /// dec.half_floor_to_increment(-2, RoundingIncrement::MultiplesOf25);
2544
    /// assert_eq!("-5.50", dec.to_string());
2545
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2546
    /// dec.half_floor_to_increment(-1, RoundingIncrement::MultiplesOf25);
2547
    /// assert_eq!("10.0", dec.to_string());
2548
    /// let mut dec = FixedDecimal::from_str("-9.99").unwrap();
2549
    /// dec.half_floor_to_increment(-2, RoundingIncrement::MultiplesOf2);
2550
    /// assert_eq!("-10.00", dec.to_string());
2551
    /// ```
2552
    #[inline(never)]
2553
0
    pub fn half_floor_to_increment(&mut self, position: i16, increment: RoundingIncrement) {
2554
0
        self.half_floor_to_increment_internal(position, increment)
2555
0
    }
2556
2557
0
    fn half_floor_to_increment_internal<R: IncrementLike>(&mut self, position: i16, increment: R) {
2558
0
        if self.sign == Sign::Negative {
2559
0
            self.half_expand_to_increment_internal(position, increment);
2560
0
            return;
2561
0
        }
2562
0
2563
0
        self.half_trunc_to_increment_internal(position, increment);
2564
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::half_floor_to_increment_internal::<fixed_decimal::decimal::NoIncrement>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::half_floor_to_increment_internal::<fixed_decimal::decimal::RoundingIncrement>
2565
2566
    /// Take the half floor of the number at a particular position.
2567
    ///
2568
    /// # Examples
2569
    ///
2570
    /// ```
2571
    /// use fixed_decimal::FixedDecimal;
2572
    /// # use std::str::FromStr;
2573
    ///
2574
    /// let dec = FixedDecimal::from_str("-1.5").unwrap();
2575
    /// assert_eq!("-2", dec.half_floored(0).to_string());
2576
    /// let dec = FixedDecimal::from_str("0.4").unwrap();
2577
    /// assert_eq!("0", dec.half_floored(0).to_string());
2578
    /// let dec = FixedDecimal::from_str("0.5").unwrap();
2579
    /// assert_eq!("0", dec.half_floored(0).to_string());
2580
    /// let dec = FixedDecimal::from_str("0.6").unwrap();
2581
    /// assert_eq!("1", dec.half_floored(0).to_string());
2582
    /// let dec = FixedDecimal::from_str("1.5").unwrap();
2583
    /// assert_eq!("1", dec.half_floored(0).to_string());
2584
    /// ```
2585
0
    pub fn half_floored(mut self, position: i16) -> Self {
2586
0
        self.half_floor(position);
2587
0
        self
2588
0
    }
2589
2590
    /// Take the half floor of the number at a particular position and rounding increment.
2591
    ///
2592
    /// # Examples
2593
    ///
2594
    /// ```
2595
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
2596
    /// # use std::str::FromStr;
2597
    ///
2598
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
2599
    /// assert_eq!(
2600
    ///     "-4",
2601
    ///     dec.half_floored_to_increment(0, RoundingIncrement::MultiplesOf2)
2602
    ///         .to_string()
2603
    /// );
2604
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
2605
    /// assert_eq!(
2606
    ///     "7.5",
2607
    ///     dec.half_floored_to_increment(-1, RoundingIncrement::MultiplesOf5)
2608
    ///         .to_string()
2609
    /// );
2610
    /// let mut dec = FixedDecimal::from_str("-5.45").unwrap();
2611
    /// assert_eq!(
2612
    ///     "-5.50",
2613
    ///     dec.half_floored_to_increment(-2, RoundingIncrement::MultiplesOf25)
2614
    ///         .to_string()
2615
    /// );
2616
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2617
    /// assert_eq!(
2618
    ///     "10.0",
2619
    ///     dec.half_floored_to_increment(-1, RoundingIncrement::MultiplesOf25)
2620
    ///         .to_string()
2621
    /// );
2622
    /// let mut dec = FixedDecimal::from_str("-9.99").unwrap();
2623
    /// assert_eq!(
2624
    ///     "-10.00",
2625
    ///     dec.half_floored_to_increment(-2, RoundingIncrement::MultiplesOf2)
2626
    ///         .to_string()
2627
    /// );
2628
    /// ```
2629
0
    pub fn half_floored_to_increment(
2630
0
        mut self,
2631
0
        position: i16,
2632
0
        increment: RoundingIncrement,
2633
0
    ) -> Self {
2634
0
        self.half_floor_to_increment(position, increment);
2635
0
        self
2636
0
    }
2637
2638
    /// Take the half even of the number at a particular position.
2639
    ///
2640
    /// # Examples
2641
    ///
2642
    /// ```
2643
    /// use fixed_decimal::FixedDecimal;
2644
    /// # use std::str::FromStr;
2645
    ///
2646
    /// let mut dec = FixedDecimal::from_str("-1.5").unwrap();
2647
    /// dec.half_even(0);
2648
    /// assert_eq!("-2", dec.to_string());
2649
    /// let mut dec = FixedDecimal::from_str("0.4").unwrap();
2650
    /// dec.half_even(0);
2651
    /// assert_eq!("0", dec.to_string());
2652
    /// let mut dec = FixedDecimal::from_str("0.5").unwrap();
2653
    /// dec.half_even(0);
2654
    /// assert_eq!("0", dec.to_string());
2655
    /// let mut dec = FixedDecimal::from_str("0.6").unwrap();
2656
    /// dec.half_even(0);
2657
    /// assert_eq!("1", dec.to_string());
2658
    /// let mut dec = FixedDecimal::from_str("1.5").unwrap();
2659
    /// dec.half_even(0);
2660
    /// assert_eq!("2", dec.to_string());
2661
    /// ```
2662
    #[inline(never)]
2663
0
    pub fn half_even(&mut self, position: i16) {
2664
0
        self.half_even_to_increment_internal(position, NoIncrement);
2665
0
    }
2666
2667
    /// Take the half even of the number at a particular position and rounding increment.
2668
    ///
2669
    /// # Examples
2670
    ///
2671
    /// ```
2672
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
2673
    /// # use std::str::FromStr;
2674
    ///
2675
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
2676
    /// dec.half_even_to_increment(0, RoundingIncrement::MultiplesOf2);
2677
    /// assert_eq!("-4", dec.to_string());
2678
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
2679
    /// dec.half_even_to_increment(-1, RoundingIncrement::MultiplesOf5);
2680
    /// assert_eq!("7.5", dec.to_string());
2681
    /// let mut dec = FixedDecimal::from_str("5.45").unwrap();
2682
    /// dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf25);
2683
    /// assert_eq!("5.50", dec.to_string());
2684
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2685
    /// dec.half_even_to_increment(-1, RoundingIncrement::MultiplesOf25);
2686
    /// assert_eq!("10.0", dec.to_string());
2687
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2688
    /// dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf2);
2689
    /// assert_eq!("10.00", dec.to_string());
2690
    /// ```
2691
    #[inline(never)]
2692
0
    pub fn half_even_to_increment(&mut self, position: i16, increment: RoundingIncrement) {
2693
0
        self.half_even_to_increment_internal(position, increment)
2694
0
    }
2695
2696
0
    fn half_even_to_increment_internal<R: IncrementLike>(&mut self, position: i16, increment: R) {
2697
0
        let should_expand = match self.half_increment_at_magnitude(position, increment) {
2698
0
            Ordering::Greater => true,
2699
0
            Ordering::Less => false,
2700
0
            Ordering::Equal => match Some(increment) {
2701
0
                x if x == R::MULTIPLES_OF_1 => {
2702
                    // Expand if odd, truncate if even.
2703
0
                    self.digit_at(position) & 0x01 == 1
2704
                }
2705
0
                x if x == R::MULTIPLES_OF_2 => {
2706
0
                    let current_digit = self.digit_at(position);
2707
0
                    let previous_digit = self.digit_at_previous_position(position);
2708
0
                    let full = previous_digit * 10 + current_digit;
2709
0
2710
0
                    // This essentially expands to the "even" increments,
2711
0
                    // or the increments that are in the even places on the
2712
0
                    // rounding range: [0, 4, 8, 12, 16, 20, ...].
2713
0
                    // Equivalent to `(full / 2) is odd`.
2714
0
                    //
2715
0
                    // Examples:
2716
0
                    // - 37 should truncate, since 37 % 20 = 17, which truncates to 16.
2717
0
                    //   37 / 2 = 18, which is even.
2718
0
                    // - 83 should expand, since 83 % 20 = 3, which expands to 4.
2719
0
                    //   83 / 2 = 41, which is odd.
2720
0
                    (full >> 1) & 0x01 == 1
2721
                }
2722
0
                x if x == R::MULTIPLES_OF_5 => {
2723
                    // Expand 7.5 to 10 and truncate 2.5 to 0.
2724
0
                    self.digit_at(position) == 7
2725
                }
2726
0
                x if x == R::MULTIPLES_OF_25 => {
2727
0
                    let current_digit = self.digit_at(position);
2728
0
                    let prev_digit = self.digit_at_previous_position(position);
2729
0
                    let full_number = prev_digit * 10 + current_digit;
2730
0
2731
0
                    // Expand `37.5` to 50 and `87.5` to 100.
2732
0
                    // Truncate `12.5` to 0 and `62.5` to 50.
2733
0
                    full_number == 37 || full_number == 87
2734
                }
2735
                _ => {
2736
0
                    debug_assert!(false, "INCREMENT should be 1, 2, 5, or 25");
2737
0
                    return;
2738
                }
2739
            },
2740
        };
2741
2742
0
        if should_expand {
2743
0
            self.expand_to_increment_internal(position, increment);
2744
0
        } else {
2745
0
            self.trunc_to_increment_internal(position, increment);
2746
0
        }
2747
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::half_even_to_increment_internal::<fixed_decimal::decimal::NoIncrement>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal>::half_even_to_increment_internal::<fixed_decimal::decimal::RoundingIncrement>
2748
2749
    /// Take the half even of the number at a particular position.
2750
    ///
2751
    /// # Examples
2752
    ///
2753
    /// ```
2754
    /// use fixed_decimal::FixedDecimal;
2755
    /// # use std::str::FromStr;
2756
    ///
2757
    /// let dec = FixedDecimal::from_str("-1.5").unwrap();
2758
    /// assert_eq!("-2", dec.half_evened(0).to_string());
2759
    /// let dec = FixedDecimal::from_str("0.4").unwrap();
2760
    /// assert_eq!("0", dec.half_evened(0).to_string());
2761
    /// let dec = FixedDecimal::from_str("0.5").unwrap();
2762
    /// assert_eq!("0", dec.half_evened(0).to_string());
2763
    /// let dec = FixedDecimal::from_str("0.6").unwrap();
2764
    /// assert_eq!("1", dec.half_evened(0).to_string());
2765
    /// let dec = FixedDecimal::from_str("1.5").unwrap();
2766
    /// assert_eq!("2", dec.half_evened(0).to_string());
2767
    /// ```
2768
0
    pub fn half_evened(mut self, position: i16) -> Self {
2769
0
        self.half_even(position);
2770
0
        self
2771
0
    }
2772
2773
    /// Take the half even of the number at a particular position and rounding increment.
2774
    ///
2775
    /// # Examples
2776
    ///
2777
    /// ```
2778
    /// use fixed_decimal::{FixedDecimal, RoundingIncrement};
2779
    /// # use std::str::FromStr;
2780
    ///
2781
    /// let mut dec = FixedDecimal::from_str("-3.5").unwrap();
2782
    /// assert_eq!(
2783
    ///     "-4",
2784
    ///     dec.half_evened_to_increment(0, RoundingIncrement::MultiplesOf2)
2785
    ///         .to_string()
2786
    /// );
2787
    /// let mut dec = FixedDecimal::from_str("7.57").unwrap();
2788
    /// assert_eq!(
2789
    ///     "7.5",
2790
    ///     dec.half_evened_to_increment(-1, RoundingIncrement::MultiplesOf5)
2791
    ///         .to_string()
2792
    /// );
2793
    /// let mut dec = FixedDecimal::from_str("5.45").unwrap();
2794
    /// assert_eq!(
2795
    ///     "5.50",
2796
    ///     dec.half_evened_to_increment(-2, RoundingIncrement::MultiplesOf25)
2797
    ///         .to_string()
2798
    /// );
2799
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2800
    /// assert_eq!(
2801
    ///     "10.0",
2802
    ///     dec.half_evened_to_increment(-1, RoundingIncrement::MultiplesOf25)
2803
    ///         .to_string()
2804
    /// );
2805
    /// let mut dec = FixedDecimal::from_str("9.99").unwrap();
2806
    /// assert_eq!(
2807
    ///     "10.00",
2808
    ///     dec.half_evened_to_increment(-2, RoundingIncrement::MultiplesOf2)
2809
    ///         .to_string()
2810
    /// );
2811
    /// ```
2812
0
    pub fn half_evened_to_increment(mut self, position: i16, increment: RoundingIncrement) -> Self {
2813
0
        self.half_even_to_increment(position, increment);
2814
0
        self
2815
0
    }
2816
2817
    /// Concatenate another `FixedDecimal` into the end of this `FixedDecimal`.
2818
    ///
2819
    /// All nonzero digits in `other` must have lower magnitude than nonzero digits in `self`.
2820
    /// If the two decimals represent overlapping ranges of magnitudes, an `Err` is returned,
2821
    /// passing ownership of `other` back to the caller.
2822
    ///
2823
    /// The magnitude range of `self` will be increased if `other` covers a larger range.
2824
    ///
2825
    /// # Examples
2826
    ///
2827
    /// ```
2828
    /// use fixed_decimal::FixedDecimal;
2829
    ///
2830
    /// let integer = FixedDecimal::from(123);
2831
    /// let fraction = FixedDecimal::from(456).multiplied_pow10(-3);
2832
    ///
2833
    /// let result = integer.concatenated_end(fraction).expect("nonoverlapping");
2834
    ///
2835
    /// assert_eq!("123.456", result.to_string());
2836
    /// ```
2837
0
    pub fn concatenated_end(mut self, other: FixedDecimal) -> Result<Self, FixedDecimal> {
2838
0
        match self.concatenate_end(other) {
2839
0
            Ok(()) => Ok(self),
2840
0
            Err(err) => Err(err),
2841
        }
2842
0
    }
2843
2844
    /// Concatenate another `FixedDecimal` into the end of this `FixedDecimal`.
2845
    ///
2846
    /// All nonzero digits in `other` must have lower magnitude than nonzero digits in `self`.
2847
    /// If the two decimals represent overlapping ranges of magnitudes, an `Err` is returned,
2848
    /// passing ownership of `other` back to the caller.
2849
    ///
2850
    /// The magnitude range of `self` will be increased if `other` covers a larger range.
2851
    ///
2852
    /// # Examples
2853
    ///
2854
    /// ```
2855
    /// use fixed_decimal::FixedDecimal;
2856
    ///
2857
    /// let mut integer = FixedDecimal::from(123);
2858
    /// let fraction = FixedDecimal::from(456).multiplied_pow10(-3);
2859
    ///
2860
    /// integer.concatenate_end(fraction);
2861
    ///
2862
    /// assert_eq!("123.456", integer.to_string());
2863
    /// ```
2864
0
    pub fn concatenate_end(&mut self, other: FixedDecimal) -> Result<(), FixedDecimal> {
2865
0
        let self_right = self.nonzero_magnitude_end();
2866
0
        let other_left = other.nonzero_magnitude_start();
2867
0
        if self.is_zero() {
2868
0
            // Operation will succeed. We can move the digits into self.
2869
0
            self.digits = other.digits;
2870
0
            self.magnitude = other.magnitude;
2871
0
        } else if other.is_zero() {
2872
0
            // No changes to the digits are necessary.
2873
0
        } else if self_right <= other_left {
2874
            // Illegal: `other` is not to the right of `self`
2875
0
            return Err(other);
2876
0
        } else {
2877
0
            // Append the digits from other to the end of self
2878
0
            let inner_zeroes = crate::ops::i16_abs_sub(self_right, other_left) as usize - 1;
2879
0
            self.append_digits(inner_zeroes, &other.digits);
2880
0
        }
2881
0
        self.upper_magnitude = cmp::max(self.upper_magnitude, other.upper_magnitude);
2882
0
        self.lower_magnitude = cmp::min(self.lower_magnitude, other.lower_magnitude);
2883
0
        #[cfg(debug_assertions)]
2884
0
        self.check_invariants();
2885
0
        Ok(())
2886
0
    }
2887
2888
    /// Appends a slice of digits to the end of `self.digits` with optional inner zeroes.
2889
    ///
2890
    /// This function does not check invariants.
2891
0
    fn append_digits(&mut self, inner_zeroes: usize, new_digits: &[u8]) {
2892
0
        let new_len = self.digits.len() + inner_zeroes;
2893
0
        self.digits.resize_with(new_len, || 0);
2894
0
        self.digits.extend_from_slice(new_digits);
2895
0
    }
2896
2897
    /// Assert that the invariants among struct fields are enforced. Returns true if all are okay.
2898
    /// Call this in any method that mutates the struct fields.
2899
    ///
2900
    /// Example: `debug_assert!(self.check_invariants())`
2901
    #[cfg(debug_assertions)]
2902
    #[allow(clippy::indexing_slicing)]
2903
    fn check_invariants(&self) {
2904
        // magnitude invariants:
2905
        debug_assert!(
2906
            self.upper_magnitude >= self.magnitude,
2907
            "Upper magnitude too small {self:?}"
2908
        );
2909
        debug_assert!(
2910
            self.lower_magnitude <= self.magnitude,
2911
            "Lower magnitude too large {self:?}"
2912
        );
2913
        debug_assert!(
2914
            self.upper_magnitude >= 0,
2915
            "Upper magnitude below zero {self:?}"
2916
        );
2917
        debug_assert!(
2918
            self.lower_magnitude <= 0,
2919
            "Lower magnitude above zero {self:?}",
2920
        );
2921
2922
        // digits invariants:
2923
        debug_assert!(
2924
            self.digits.len() <= (self.magnitude as i32 - self.lower_magnitude as i32 + 1) as usize,
2925
            "{self:?}"
2926
        );
2927
        if !self.digits.is_empty() {
2928
            debug_assert_ne!(self.digits[0], 0, "Starts with a zero {self:?}");
2929
            debug_assert_ne!(
2930
                self.digits[self.digits.len() - 1],
2931
                0,
2932
                "Ends with a zero {self:?}",
2933
            );
2934
        } else {
2935
            debug_assert_eq!(self.magnitude, 0);
2936
        }
2937
    }
2938
}
2939
2940
/// Render the `FixedDecimal` as a string of ASCII digits with a possible decimal point.
2941
///
2942
/// # Examples
2943
///
2944
/// ```
2945
/// # use fixed_decimal::FixedDecimal;
2946
/// # use writeable::assert_writeable_eq;
2947
/// #
2948
/// assert_writeable_eq!(FixedDecimal::from(42), "42");
2949
/// ```
2950
impl writeable::Writeable for FixedDecimal {
2951
0
    fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result {
2952
0
        match self.sign {
2953
0
            Sign::Negative => sink.write_char('-')?,
2954
0
            Sign::Positive => sink.write_char('+')?,
2955
0
            Sign::None => (),
2956
        }
2957
0
        for m in self.magnitude_range().rev() {
2958
0
            if m == -1 {
2959
0
                sink.write_char('.')?;
2960
0
            }
2961
0
            let d = self.digit_at(m);
2962
0
            sink.write_char((b'0' + d) as char)?;
2963
        }
2964
0
        Ok(())
2965
0
    }
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as writeable::Writeable>::write_to::<writeable::parts_write_adapter::CoreWriteAsPartsWrite<&mut diplomat_runtime::writeable::DiplomatWriteable>>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as writeable::Writeable>::write_to::<diplomat_runtime::writeable::DiplomatWriteable>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as writeable::Writeable>::write_to::<writeable::parts_write_adapter::CoreWriteAsPartsWrite<&mut core::fmt::Formatter>>
Unexecuted instantiation: <fixed_decimal::decimal::FixedDecimal as writeable::Writeable>::write_to::<_>
2966
2967
0
    fn writeable_length_hint(&self) -> writeable::LengthHint {
2968
0
        writeable::LengthHint::exact(1)
2969
0
            + ((self.upper_magnitude as i32 - self.lower_magnitude as i32) as usize)
2970
0
            + (self.sign != Sign::None) as usize
2971
0
            + (self.lower_magnitude < 0) as usize
2972
0
    }
2973
}
2974
2975
writeable::impl_display_with_writeable!(FixedDecimal);
2976
2977
impl FromStr for FixedDecimal {
2978
    type Err = Error;
2979
0
    fn from_str(input_str: &str) -> Result<Self, Self::Err> {
2980
0
        Self::try_from(input_str.as_bytes())
2981
0
    }
2982
}
2983
2984
impl TryFrom<&[u8]> for FixedDecimal {
2985
    type Error = Error;
2986
0
    fn try_from(input_str: &[u8]) -> Result<Self, Self::Error> {
2987
0
        // input_str: the input string
2988
0
        // no_sign_str: the input string when the sign is removed from it
2989
0
        if input_str.is_empty() {
2990
0
            return Err(Error::Syntax);
2991
0
        }
2992
        #[allow(clippy::indexing_slicing)] // The string is not empty.
2993
0
        let sign = match input_str[0] {
2994
0
            b'-' => Sign::Negative,
2995
0
            b'+' => Sign::Positive,
2996
0
            _ => Sign::None,
2997
        };
2998
        #[allow(clippy::indexing_slicing)] // The string is not empty.
2999
0
        let no_sign_str = if sign == Sign::None {
3000
0
            input_str
3001
        } else {
3002
0
            &input_str[1..]
3003
        };
3004
0
        if no_sign_str.is_empty() {
3005
0
            return Err(Error::Syntax);
3006
0
        }
3007
0
        // Compute length of each string once and store it, so if you use that multiple times,
3008
0
        // you don't compute it multiple times
3009
0
        // has_dot: shows if your input has dot in it
3010
0
        // has_exponent: shows if your input has an exponent in it
3011
0
        // dot_index: gives the index of dot (after removing the sign) -- equal to length of
3012
0
        // the no_sign_str if there is no dot
3013
0
        // exponent_index: gives the index of exponent (after removing the sign) -- equal to length of
3014
0
        // the no_sign_str if there is no dot
3015
0
        let mut has_dot = false;
3016
0
        let mut has_exponent = false;
3017
0
        let mut dot_index = no_sign_str.len();
3018
0
        let mut exponent_index = no_sign_str.len();
3019
        // The following loop computes has_dot, dot_index, and also checks to see if all
3020
        // characters are digits and if you have at most one dot
3021
        // Note: Input of format 111_123 is detected as syntax error here
3022
        // Note: Input starting or ending with a dot is detected as syntax error here (Ex: .123, 123.)
3023
0
        for (i, c) in no_sign_str.iter().enumerate() {
3024
0
            if *c == b'.' {
3025
0
                if has_dot || has_exponent {
3026
                    // multiple dots or dots after the exponent
3027
0
                    return Err(Error::Syntax);
3028
0
                }
3029
0
                dot_index = i;
3030
0
                has_dot = true;
3031
0
                // We do support omitting the leading zero,
3032
0
                // but not trailing decimal points
3033
0
                if i == no_sign_str.len() - 1 {
3034
0
                    return Err(Error::Syntax);
3035
0
                }
3036
0
            } else if *c == b'e' || *c == b'E' {
3037
0
                if has_exponent {
3038
                    // multiple exponents
3039
0
                    return Err(Error::Syntax);
3040
0
                }
3041
0
                exponent_index = i;
3042
0
                has_exponent = true;
3043
0
                if i == 0 || i == no_sign_str.len() - 1 {
3044
0
                    return Err(Error::Syntax);
3045
0
                }
3046
0
            } else if *c == b'-' {
3047
                // Allow a single minus sign after the exponent
3048
0
                if has_exponent && exponent_index == i - 1 {
3049
0
                    continue;
3050
                } else {
3051
0
                    return Err(Error::Syntax);
3052
                }
3053
0
            } else if *c < b'0' || *c > b'9' {
3054
0
                return Err(Error::Syntax);
3055
0
            }
3056
        }
3057
3058
        // The string without the exponent (or sign)
3059
        // We do the bulk of the calculation on this string,
3060
        // and extract the exponent at the end
3061
        #[allow(clippy::indexing_slicing)] // exponent_index comes from enumerate
3062
0
        let no_exponent_str = &no_sign_str[..exponent_index];
3063
0
3064
0
        // If there was no dot, truncate the dot index
3065
0
        if dot_index > exponent_index {
3066
0
            dot_index = exponent_index;
3067
0
        }
3068
3069
        // defining the output dec here and set its sign
3070
0
        let mut dec = Self {
3071
0
            sign,
3072
0
            ..Default::default()
3073
0
        };
3074
0
3075
0
        // no_dot_str_len: shows length of the string after removing the dot
3076
0
        let mut no_dot_str_len = no_exponent_str.len();
3077
0
        if has_dot {
3078
0
            no_dot_str_len -= 1;
3079
0
        }
3080
3081
        // Computing DecimalFixed.upper_magnitude
3082
        // We support strings like `0.x` and `.x`. The upper magnitude
3083
        // is always one less than the position of the dot, except in the case where
3084
        // the 0 is omitted; when dot_index = 0. We use saturating_sub to set
3085
        // magnitude to 0 in that case.
3086
0
        let temp_upper_magnitude = dot_index.saturating_sub(1);
3087
0
        if temp_upper_magnitude > i16::MAX as usize {
3088
0
            return Err(Error::Limit);
3089
0
        }
3090
0
        dec.upper_magnitude = temp_upper_magnitude as i16;
3091
0
3092
0
        // Computing DecimalFixed.lower_magnitude
3093
0
        let temp_lower_magnitude = no_dot_str_len - dot_index;
3094
0
        if temp_lower_magnitude > (i16::MIN as u16) as usize {
3095
0
            return Err(Error::Limit);
3096
0
        }
3097
0
        dec.lower_magnitude = (temp_lower_magnitude as i16).wrapping_neg();
3098
0
3099
0
        // leftmost_digit: index of the first non-zero digit
3100
0
        // rightmost_digit: index of the first element after the last non-zero digit
3101
0
        // Example:
3102
0
        //     input string    leftmost_digit     rightmost_digit
3103
0
        //     00123000              2                  5
3104
0
        //     0.0123000             3                  6
3105
0
        //     001.23000             2                  6
3106
0
        //     001230.00             2                  5
3107
0
        // Compute leftmost_digit
3108
0
        let leftmost_digit = no_exponent_str
3109
0
            .iter()
3110
0
            .position(|c| *c != b'.' && *c != b'0');
3111
3112
        // If the input only has zeros (like 000, 00.0, -00.000) we handle the situation here
3113
        // by returning the dec and don't running the rest of the code
3114
0
        let leftmost_digit = if let Some(leftmost_digit) = leftmost_digit {
3115
0
            leftmost_digit
3116
        } else {
3117
0
            return Ok(dec);
3118
        };
3119
3120
        // Else if the input is not all zeros, we compute its magnitude:
3121
        // Note that we can cast with "as" here because lower and upper magnitude have been checked already
3122
0
        let mut temp_magnitude = ((dot_index as i32) - (leftmost_digit as i32) - 1i32) as i16;
3123
0
        if dot_index < leftmost_digit {
3124
0
            temp_magnitude += 1;
3125
0
        }
3126
0
        dec.magnitude = temp_magnitude;
3127
0
3128
0
        // Compute the index where the rightmost_digit ends
3129
0
        let rightmost_digit_end = no_exponent_str
3130
0
            .iter()
3131
0
            .rposition(|c| *c != b'.' && *c != b'0')
3132
0
            .map(|p| p + 1)
3133
0
            .unwrap_or(no_exponent_str.len());
3134
0
3135
0
        // digits_str_len: shows the length of digits (Ex. 0012.8900 --> 4)
3136
0
        let mut digits_str_len = rightmost_digit_end - leftmost_digit;
3137
0
        if leftmost_digit < dot_index && dot_index < rightmost_digit_end {
3138
0
            digits_str_len -= 1;
3139
0
        }
3140
3141
        // Constructing DecimalFixed.digits
3142
        #[allow(clippy::indexing_slicing)]
3143
        // leftmost_digit  and rightmost_digit_end come from Iterator::position and Iterator::rposition.
3144
0
        let v: SmallVec<[u8; 8]> = no_exponent_str[leftmost_digit..rightmost_digit_end]
3145
0
            .iter()
3146
0
            .filter(|c| **c != b'.')
3147
0
            .map(|c| c - b'0')
3148
0
            .collect();
3149
0
3150
0
        let v_len = v.len();
3151
0
        debug_assert_eq!(v_len, digits_str_len);
3152
0
        dec.digits = v;
3153
0
3154
0
        // Extract the exponent part
3155
0
        if has_exponent {
3156
0
            let mut pow = 0;
3157
0
            let mut pos_neg = 1;
3158
            #[allow(clippy::indexing_slicing)]
3159
            // exponent_index is exist, then exponent_index + 1 will equal at most no_sign_str.len().
3160
0
            for digit in &no_sign_str[exponent_index + 1..] {
3161
0
                if *digit == b'-' {
3162
0
                    pos_neg = -1;
3163
0
                    continue;
3164
0
                }
3165
0
                pow *= 10;
3166
0
                pow += (digit - b'0') as i16;
3167
            }
3168
3169
0
            dec.multiply_pow10(pos_neg * pow);
3170
0
3171
0
            // Clean up magnitude after multiplication
3172
0
            if dec.magnitude > 0 {
3173
0
                dec.upper_magnitude = dec.magnitude;
3174
0
            }
3175
0
            let neg_mag = dec.magnitude - dec.digits.len() as i16 + 1;
3176
0
            if neg_mag < 0 {
3177
0
                dec.lower_magnitude = neg_mag;
3178
0
            }
3179
0
        }
3180
3181
0
        Ok(dec)
3182
0
    }
3183
}
3184
3185
/// Specifies the precision of a floating point value when constructing a FixedDecimal.
3186
///
3187
/// IEEE 754 is a representation of a point on the number line. On the other hand, FixedDecimal
3188
/// specifies not only the point on the number line but also the precision of the number to a
3189
/// specific power of 10. This enum augments a floating-point value with the additional
3190
/// information required by FixedDecimal.
3191
#[non_exhaustive]
3192
#[cfg(feature = "ryu")]
3193
#[derive(Debug, Clone, Copy)]
3194
pub enum FloatPrecision {
3195
    /// Specify that the floating point number is integer-valued.
3196
    ///
3197
    /// If the floating point is not actually integer-valued, an error will be returned.
3198
    Integer,
3199
3200
    /// Specify that the floating point number is precise to a specific power of 10.
3201
    /// The number may be rounded or trailing zeros may be added as necessary.
3202
    Magnitude(i16),
3203
3204
    /// Specify that the floating point number is precise to a specific number of significant digits.
3205
    /// The number may be rounded or trailing zeros may be added as necessary.
3206
    ///
3207
    /// The number requested may not be zero
3208
    SignificantDigits(u8),
3209
3210
    /// Specify that the floating point number is precise to the maximum representable by IEEE.
3211
    ///
3212
    /// This results in a FixedDecimal having enough digits to recover the original floating point
3213
    /// value, with no trailing zeros.
3214
    Floating,
3215
}
3216
3217
#[cfg(feature = "ryu")]
3218
impl FixedDecimal {
3219
    /// Construct a [`FixedDecimal`] from an f64.
3220
    ///
3221
    /// Since f64 values do not carry a notion of their precision, the second argument to this
3222
    /// function specifies the type of precision associated with the f64. For more information,
3223
    /// see [`FloatPrecision`].
3224
    ///
3225
    /// This function uses `ryu`, which is an efficient double-to-string algorithm, but other
3226
    /// implementations may yield higher performance; for more details, see
3227
    /// [icu4x#166](https://github.com/unicode-org/icu4x/issues/166).
3228
    ///
3229
    /// This function can be made available with the `"ryu"` Cargo feature.
3230
    ///
3231
    /// ```rust
3232
    /// use fixed_decimal::{FixedDecimal, FloatPrecision};
3233
    /// use writeable::assert_writeable_eq;
3234
    ///
3235
    /// let decimal =
3236
    ///     FixedDecimal::try_from_f64(-5.1, FloatPrecision::Magnitude(-2))
3237
    ///         .expect("Finite quantity with limited precision");
3238
    /// assert_writeable_eq!(decimal, "-5.10");
3239
    ///
3240
    /// let decimal =
3241
    ///     FixedDecimal::try_from_f64(0.012345678, FloatPrecision::Floating)
3242
    ///         .expect("Finite quantity");
3243
    /// assert_writeable_eq!(decimal, "0.012345678");
3244
    ///
3245
    /// let decimal =
3246
    ///     FixedDecimal::try_from_f64(12345678000., FloatPrecision::Integer)
3247
    ///         .expect("Finite, integer-valued quantity");
3248
    /// assert_writeable_eq!(decimal, "12345678000");
3249
    /// ```
3250
    ///
3251
    /// Negative zero is supported.
3252
    ///
3253
    /// ```rust
3254
    /// use fixed_decimal::{FixedDecimal, FloatPrecision};
3255
    /// use writeable::assert_writeable_eq;
3256
    ///
3257
    /// // IEEE 754 for floating point defines the sign bit separate
3258
    /// // from the mantissa and exponent, allowing for -0.
3259
    /// let negative_zero =
3260
    ///     FixedDecimal::try_from_f64(-0.0, FloatPrecision::Integer)
3261
    ///         .expect("Negative zero");
3262
    /// assert_writeable_eq!(negative_zero, "-0");
3263
    /// ```
3264
0
    pub fn try_from_f64(float: f64, precision: FloatPrecision) -> Result<Self, Error> {
3265
0
        let mut decimal = Self::new_from_f64_raw(float)?;
3266
0
        let n_digits = decimal.digits.len();
3267
0
        // magnitude of the lowest digit in self.digits
3268
0
        let lowest_magnitude = decimal.magnitude - n_digits as i16 + 1;
3269
0
        // ryū will usually tack on a `.0` to integers which gets included when parsing.
3270
0
        // Explicitly remove it before doing anything else
3271
0
        if lowest_magnitude >= 0 && decimal.lower_magnitude < 0 {
3272
0
            decimal.lower_magnitude = 0;
3273
0
        }
3274
0
        match precision {
3275
0
            FloatPrecision::Floating => (),
3276
            FloatPrecision::Integer => {
3277
0
                if lowest_magnitude < 0 {
3278
0
                    return Err(Error::Limit);
3279
0
                }
3280
            }
3281
0
            FloatPrecision::Magnitude(mag) => {
3282
0
                decimal.half_even(mag);
3283
0
            }
3284
0
            FloatPrecision::SignificantDigits(sig) => {
3285
0
                if sig == 0 {
3286
0
                    return Err(Error::Limit);
3287
0
                }
3288
0
3289
0
                let position = decimal.magnitude - (sig as i16) + 1;
3290
0
                let old_magnitude = decimal.magnitude;
3291
0
                decimal.half_even(position);
3292
0
3293
0
                // This means the significant digits has been increased by 1.
3294
0
                if decimal.magnitude > old_magnitude {
3295
0
                    decimal.lower_magnitude = cmp::min(0, position + 1);
3296
0
                }
3297
            }
3298
        }
3299
        #[cfg(debug_assertions)]
3300
        decimal.check_invariants();
3301
0
        Ok(decimal)
3302
0
    }
3303
3304
    /// Internal function for parsing directly from floats using ryū
3305
0
    fn new_from_f64_raw(float: f64) -> Result<Self, Error> {
3306
0
        if !float.is_finite() {
3307
0
            return Err(Error::Limit);
3308
0
        }
3309
0
        // note: this does not heap allocate
3310
0
        let mut buf = ryu::Buffer::new();
3311
0
        let formatted = buf.format_finite(float);
3312
0
        Self::from_str(formatted)
3313
0
    }
3314
}
3315
3316
#[cfg(feature = "ryu")]
3317
#[test]
3318
fn test_float() {
3319
    #[derive(Debug)]
3320
    struct TestCase {
3321
        pub input: f64,
3322
        pub precision: FloatPrecision,
3323
        pub expected: &'static str,
3324
    }
3325
    let cases = [
3326
        TestCase {
3327
            input: 1.234567,
3328
            precision: FloatPrecision::Floating,
3329
            expected: "1.234567",
3330
        },
3331
        TestCase {
3332
            input: 888999.,
3333
            precision: FloatPrecision::Floating,
3334
            expected: "888999",
3335
        },
3336
        // HalfExpand tests
3337
        TestCase {
3338
            input: 1.234567,
3339
            precision: FloatPrecision::Magnitude(-2),
3340
            expected: "1.23",
3341
        },
3342
        TestCase {
3343
            input: 1.235567,
3344
            precision: FloatPrecision::Magnitude(-2),
3345
            expected: "1.24",
3346
        },
3347
        TestCase {
3348
            input: 1.2002,
3349
            precision: FloatPrecision::Magnitude(-3),
3350
            expected: "1.200",
3351
        },
3352
        TestCase {
3353
            input: 888999.,
3354
            precision: FloatPrecision::Magnitude(2),
3355
            expected: "889000",
3356
        },
3357
        TestCase {
3358
            input: 888999.,
3359
            precision: FloatPrecision::Magnitude(4),
3360
            expected: "890000",
3361
        },
3362
        TestCase {
3363
            input: 0.9,
3364
            precision: FloatPrecision::Magnitude(0),
3365
            expected: "1",
3366
        },
3367
        TestCase {
3368
            input: 0.9,
3369
            precision: FloatPrecision::Magnitude(2),
3370
            expected: "00",
3371
        },
3372
        TestCase {
3373
            input: 0.009,
3374
            precision: FloatPrecision::Magnitude(-2),
3375
            expected: "0.01",
3376
        },
3377
        TestCase {
3378
            input: 0.009,
3379
            precision: FloatPrecision::Magnitude(-1),
3380
            expected: "0.0",
3381
        },
3382
        TestCase {
3383
            input: 0.009,
3384
            precision: FloatPrecision::Magnitude(0),
3385
            expected: "0",
3386
        },
3387
        TestCase {
3388
            input: 0.0000009,
3389
            precision: FloatPrecision::Magnitude(0),
3390
            expected: "0",
3391
        },
3392
        TestCase {
3393
            input: 0.0000009,
3394
            precision: FloatPrecision::Magnitude(-7),
3395
            expected: "0.0000009",
3396
        },
3397
        TestCase {
3398
            input: 0.0000009,
3399
            precision: FloatPrecision::Magnitude(-6),
3400
            expected: "0.000001",
3401
        },
3402
        TestCase {
3403
            input: 1.234567,
3404
            precision: FloatPrecision::SignificantDigits(1),
3405
            expected: "1",
3406
        },
3407
        TestCase {
3408
            input: 1.234567,
3409
            precision: FloatPrecision::SignificantDigits(2),
3410
            expected: "1.2",
3411
        },
3412
        TestCase {
3413
            input: 1.234567,
3414
            precision: FloatPrecision::SignificantDigits(4),
3415
            expected: "1.235",
3416
        },
3417
        TestCase {
3418
            input: 1.234567,
3419
            precision: FloatPrecision::SignificantDigits(10),
3420
            expected: "1.234567000",
3421
        },
3422
        TestCase {
3423
            input: 888999.,
3424
            precision: FloatPrecision::SignificantDigits(1),
3425
            expected: "900000",
3426
        },
3427
        TestCase {
3428
            input: 888999.,
3429
            precision: FloatPrecision::SignificantDigits(2),
3430
            expected: "890000",
3431
        },
3432
        TestCase {
3433
            input: 888999.,
3434
            precision: FloatPrecision::SignificantDigits(4),
3435
            expected: "889000",
3436
        },
3437
        TestCase {
3438
            input: 988999.,
3439
            precision: FloatPrecision::SignificantDigits(1),
3440
            expected: "1000000",
3441
        },
3442
        TestCase {
3443
            input: 99888.,
3444
            precision: FloatPrecision::SignificantDigits(1),
3445
            expected: "100000",
3446
        },
3447
        TestCase {
3448
            input: 99888.,
3449
            precision: FloatPrecision::SignificantDigits(2),
3450
            expected: "100000",
3451
        },
3452
        TestCase {
3453
            input: 99888.,
3454
            precision: FloatPrecision::SignificantDigits(3),
3455
            expected: "99900",
3456
        },
3457
        TestCase {
3458
            input: 0.0099,
3459
            precision: FloatPrecision::SignificantDigits(1),
3460
            expected: "0.01",
3461
        },
3462
        TestCase {
3463
            input: 9.9888,
3464
            precision: FloatPrecision::SignificantDigits(1),
3465
            expected: "10",
3466
        },
3467
        TestCase {
3468
            input: 9.9888,
3469
            precision: FloatPrecision::SignificantDigits(2),
3470
            expected: "10",
3471
        },
3472
        TestCase {
3473
            input: 99888.0,
3474
            precision: FloatPrecision::SignificantDigits(1),
3475
            expected: "100000",
3476
        },
3477
        TestCase {
3478
            input: 99888.0,
3479
            precision: FloatPrecision::SignificantDigits(2),
3480
            expected: "100000",
3481
        },
3482
        TestCase {
3483
            input: 9.9888,
3484
            precision: FloatPrecision::SignificantDigits(3),
3485
            expected: "9.99",
3486
        },
3487
    ];
3488
3489
    for case in &cases {
3490
        let dec = FixedDecimal::try_from_f64(case.input, case.precision).unwrap();
3491
        writeable::assert_writeable_eq!(dec, case.expected, "{:?}", case);
3492
    }
3493
}
3494
3495
#[test]
3496
fn test_basic() {
3497
    #[derive(Debug)]
3498
    struct TestCase {
3499
        pub input: isize,
3500
        pub delta: i16,
3501
        pub expected: &'static str,
3502
    }
3503
    let cases = [
3504
        TestCase {
3505
            input: 51423,
3506
            delta: 0,
3507
            expected: "51423",
3508
        },
3509
        TestCase {
3510
            input: 51423,
3511
            delta: -2,
3512
            expected: "514.23",
3513
        },
3514
        TestCase {
3515
            input: 51423,
3516
            delta: -5,
3517
            expected: "0.51423",
3518
        },
3519
        TestCase {
3520
            input: 51423,
3521
            delta: -8,
3522
            expected: "0.00051423",
3523
        },
3524
        TestCase {
3525
            input: 51423,
3526
            delta: 3,
3527
            expected: "51423000",
3528
        },
3529
        TestCase {
3530
            input: 0,
3531
            delta: 0,
3532
            expected: "0",
3533
        },
3534
        TestCase {
3535
            input: 0,
3536
            delta: -2,
3537
            expected: "0.00",
3538
        },
3539
        TestCase {
3540
            input: 0,
3541
            delta: 3,
3542
            expected: "0000",
3543
        },
3544
        TestCase {
3545
            input: 500,
3546
            delta: 0,
3547
            expected: "500",
3548
        },
3549
        TestCase {
3550
            input: 500,
3551
            delta: -1,
3552
            expected: "50.0",
3553
        },
3554
        TestCase {
3555
            input: 500,
3556
            delta: -2,
3557
            expected: "5.00",
3558
        },
3559
        TestCase {
3560
            input: 500,
3561
            delta: -3,
3562
            expected: "0.500",
3563
        },
3564
        TestCase {
3565
            input: 500,
3566
            delta: -4,
3567
            expected: "0.0500",
3568
        },
3569
        TestCase {
3570
            input: 500,
3571
            delta: 3,
3572
            expected: "500000",
3573
        },
3574
        TestCase {
3575
            input: -123,
3576
            delta: 0,
3577
            expected: "-123",
3578
        },
3579
        TestCase {
3580
            input: -123,
3581
            delta: -2,
3582
            expected: "-1.23",
3583
        },
3584
        TestCase {
3585
            input: -123,
3586
            delta: -5,
3587
            expected: "-0.00123",
3588
        },
3589
        TestCase {
3590
            input: -123,
3591
            delta: 3,
3592
            expected: "-123000",
3593
        },
3594
    ];
3595
    for cas in &cases {
3596
        let mut dec: FixedDecimal = cas.input.into();
3597
        // println!("{}", cas.input + 0.01);
3598
        dec.multiply_pow10(cas.delta);
3599
        writeable::assert_writeable_eq!(dec, cas.expected, "{:?}", cas);
3600
    }
3601
}
3602
3603
#[test]
3604
fn test_from_str() {
3605
    #[derive(Debug)]
3606
    struct TestCase {
3607
        pub input_str: &'static str,
3608
        /// The output str, `None` for roundtrip
3609
        pub output_str: Option<&'static str>,
3610
        /// [upper magnitude, upper nonzero magnitude, lower nonzero magnitude, lower magnitude]
3611
        pub magnitudes: [i16; 4],
3612
    }
3613
    let cases = [
3614
        TestCase {
3615
            input_str: "-00123400",
3616
            output_str: None,
3617
            magnitudes: [7, 5, 2, 0],
3618
        },
3619
        TestCase {
3620
            input_str: "+00123400",
3621
            output_str: None,
3622
            magnitudes: [7, 5, 2, 0],
3623
        },
3624
        TestCase {
3625
            input_str: "0.0123400",
3626
            output_str: None,
3627
            magnitudes: [0, -2, -5, -7],
3628
        },
3629
        TestCase {
3630
            input_str: "-00.123400",
3631
            output_str: None,
3632
            magnitudes: [1, -1, -4, -6],
3633
        },
3634
        TestCase {
3635
            input_str: "0012.3400",
3636
            output_str: None,
3637
            magnitudes: [3, 1, -2, -4],
3638
        },
3639
        TestCase {
3640
            input_str: "-0012340.0",
3641
            output_str: None,
3642
            magnitudes: [6, 4, 1, -1],
3643
        },
3644
        TestCase {
3645
            input_str: "1234",
3646
            output_str: None,
3647
            magnitudes: [3, 3, 0, 0],
3648
        },
3649
        TestCase {
3650
            input_str: "0.000000001",
3651
            output_str: None,
3652
            magnitudes: [0, -9, -9, -9],
3653
        },
3654
        TestCase {
3655
            input_str: "0.0000000010",
3656
            output_str: None,
3657
            magnitudes: [0, -9, -9, -10],
3658
        },
3659
        TestCase {
3660
            input_str: "1000000",
3661
            output_str: None,
3662
            magnitudes: [6, 6, 6, 0],
3663
        },
3664
        TestCase {
3665
            input_str: "10000001",
3666
            output_str: None,
3667
            magnitudes: [7, 7, 0, 0],
3668
        },
3669
        TestCase {
3670
            input_str: "123",
3671
            output_str: None,
3672
            magnitudes: [2, 2, 0, 0],
3673
        },
3674
        TestCase {
3675
            input_str: "922337203685477580898230948203840239384.9823094820384023938423424",
3676
            output_str: None,
3677
            magnitudes: [38, 38, -25, -25],
3678
        },
3679
        TestCase {
3680
            input_str: "009223372000.003685477580898230948203840239384000",
3681
            output_str: None,
3682
            magnitudes: [11, 9, -33, -36],
3683
        },
3684
        TestCase {
3685
            input_str: "-009223372000.003685477580898230948203840239384000",
3686
            output_str: None,
3687
            magnitudes: [11, 9, -33, -36],
3688
        },
3689
        TestCase {
3690
            input_str: "0",
3691
            output_str: None,
3692
            magnitudes: [0, 0, 0, 0],
3693
        },
3694
        TestCase {
3695
            input_str: "-0",
3696
            output_str: None,
3697
            magnitudes: [0, 0, 0, 0],
3698
        },
3699
        TestCase {
3700
            input_str: "+0",
3701
            output_str: None,
3702
            magnitudes: [0, 0, 0, 0],
3703
        },
3704
        TestCase {
3705
            input_str: "000",
3706
            output_str: None,
3707
            magnitudes: [2, 0, 0, 0],
3708
        },
3709
        TestCase {
3710
            input_str: "-00.0",
3711
            output_str: None,
3712
            magnitudes: [1, 0, 0, -1],
3713
        },
3714
        // no leading 0 parsing
3715
        TestCase {
3716
            input_str: ".0123400",
3717
            output_str: Some("0.0123400"),
3718
            magnitudes: [0, -2, -5, -7],
3719
        },
3720
        TestCase {
3721
            input_str: ".000000001",
3722
            output_str: Some("0.000000001"),
3723
            magnitudes: [0, -9, -9, -9],
3724
        },
3725
        TestCase {
3726
            input_str: "-.123400",
3727
            output_str: Some("-0.123400"),
3728
            magnitudes: [0, -1, -4, -6],
3729
        },
3730
    ];
3731
    for cas in &cases {
3732
        let fd = FixedDecimal::from_str(cas.input_str).unwrap();
3733
        assert_eq!(
3734
            fd.magnitude_range(),
3735
            cas.magnitudes[3]..=cas.magnitudes[0],
3736
            "{cas:?}"
3737
        );
3738
        assert_eq!(fd.nonzero_magnitude_start(), cas.magnitudes[1], "{cas:?}");
3739
        assert_eq!(fd.nonzero_magnitude_end(), cas.magnitudes[2], "{cas:?}");
3740
        let input_str_roundtrip = fd.to_string();
3741
        let output_str = cas.output_str.unwrap_or(cas.input_str);
3742
        assert_eq!(output_str, input_str_roundtrip, "{cas:?}");
3743
    }
3744
}
3745
3746
#[test]
3747
fn test_from_str_scientific() {
3748
    #[derive(Debug)]
3749
    struct TestCase {
3750
        pub input_str: &'static str,
3751
        pub output: &'static str,
3752
    }
3753
    let cases = [
3754
        TestCase {
3755
            input_str: "-5.4e10",
3756
            output: "-54000000000",
3757
        },
3758
        TestCase {
3759
            input_str: "5.4e-2",
3760
            output: "0.054",
3761
        },
3762
        TestCase {
3763
            input_str: "54.1e-2",
3764
            output: "0.541",
3765
        },
3766
        TestCase {
3767
            input_str: "-541e-2",
3768
            output: "-5.41",
3769
        },
3770
        TestCase {
3771
            input_str: "0.009E10",
3772
            output: "90000000",
3773
        },
3774
        TestCase {
3775
            input_str: "-9000E-10",
3776
            output: "-0.0000009",
3777
        },
3778
    ];
3779
    for cas in &cases {
3780
        let input_str_roundtrip = FixedDecimal::from_str(cas.input_str).unwrap().to_string();
3781
        assert_eq!(cas.output, input_str_roundtrip);
3782
    }
3783
}
3784
3785
#[test]
3786
fn test_isize_limits() {
3787
    for num in &[isize::MAX, isize::MIN] {
3788
        let dec: FixedDecimal = (*num).into();
3789
        let dec_str = dec.to_string();
3790
        assert_eq!(num.to_string(), dec_str);
3791
        assert_eq!(dec, FixedDecimal::from_str(&dec_str).unwrap());
3792
        writeable::assert_writeable_eq!(dec, dec_str);
3793
    }
3794
}
3795
3796
#[test]
3797
fn test_ui128_limits() {
3798
    for num in &[i128::MAX, i128::MIN] {
3799
        let dec: FixedDecimal = (*num).into();
3800
        let dec_str = dec.to_string();
3801
        assert_eq!(num.to_string(), dec_str);
3802
        assert_eq!(dec, FixedDecimal::from_str(&dec_str).unwrap());
3803
        writeable::assert_writeable_eq!(dec, dec_str);
3804
    }
3805
    for num in &[u128::MAX, u128::MIN] {
3806
        let dec: FixedDecimal = (*num).into();
3807
        let dec_str = dec.to_string();
3808
        assert_eq!(num.to_string(), dec_str);
3809
        assert_eq!(dec, FixedDecimal::from_str(&dec_str).unwrap());
3810
        writeable::assert_writeable_eq!(dec, dec_str);
3811
    }
3812
}
3813
3814
#[test]
3815
fn test_upper_magnitude_bounds() {
3816
    let mut dec: FixedDecimal = 98765.into();
3817
    assert_eq!(dec.upper_magnitude, 4);
3818
    dec.multiply_pow10(i16::MAX - 4);
3819
    assert_eq!(dec.upper_magnitude, i16::MAX);
3820
    assert_eq!(dec.nonzero_magnitude_start(), i16::MAX);
3821
    let dec_backup = dec.clone();
3822
    dec.multiply_pow10(1);
3823
    assert!(dec.is_zero());
3824
    assert_ne!(dec, dec_backup, "Value should be unchanged on failure");
3825
3826
    // Checking from_str for dec (which is valid)
3827
    let dec_roundtrip = FixedDecimal::from_str(&dec.to_string()).unwrap();
3828
    assert_eq!(dec, dec_roundtrip);
3829
}
3830
3831
#[test]
3832
fn test_lower_magnitude_bounds() {
3833
    let mut dec: FixedDecimal = 98765.into();
3834
    assert_eq!(dec.lower_magnitude, 0);
3835
    dec.multiply_pow10(i16::MIN);
3836
    assert_eq!(dec.lower_magnitude, i16::MIN);
3837
    assert_eq!(dec.nonzero_magnitude_end(), i16::MIN);
3838
    let dec_backup = dec.clone();
3839
    dec.multiply_pow10(-1);
3840
    assert!(dec.is_zero());
3841
    assert_ne!(dec, dec_backup);
3842
3843
    // Checking from_str for dec (which is valid)
3844
    let dec_roundtrip = FixedDecimal::from_str(&dec.to_string()).unwrap();
3845
    assert_eq!(dec, dec_roundtrip);
3846
}
3847
3848
#[test]
3849
fn test_zero_str_bounds() {
3850
    #[derive(Debug)]
3851
    struct TestCase {
3852
        pub zeros_before_dot: usize,
3853
        pub zeros_after_dot: usize,
3854
        pub expected_err: Option<Error>,
3855
    }
3856
    let cases = [
3857
        TestCase {
3858
            zeros_before_dot: i16::MAX as usize + 1,
3859
            zeros_after_dot: 0,
3860
            expected_err: None,
3861
        },
3862
        TestCase {
3863
            zeros_before_dot: i16::MAX as usize,
3864
            zeros_after_dot: 0,
3865
            expected_err: None,
3866
        },
3867
        TestCase {
3868
            zeros_before_dot: i16::MAX as usize + 2,
3869
            zeros_after_dot: 0,
3870
            expected_err: Some(Error::Limit),
3871
        },
3872
        TestCase {
3873
            zeros_before_dot: 0,
3874
            zeros_after_dot: i16::MAX as usize + 2,
3875
            expected_err: Some(Error::Limit),
3876
        },
3877
        TestCase {
3878
            zeros_before_dot: i16::MAX as usize + 1,
3879
            zeros_after_dot: i16::MAX as usize + 1,
3880
            expected_err: None,
3881
        },
3882
        TestCase {
3883
            zeros_before_dot: i16::MAX as usize + 2,
3884
            zeros_after_dot: i16::MAX as usize + 1,
3885
            expected_err: Some(Error::Limit),
3886
        },
3887
        TestCase {
3888
            zeros_before_dot: i16::MAX as usize + 1,
3889
            zeros_after_dot: i16::MAX as usize + 2,
3890
            expected_err: Some(Error::Limit),
3891
        },
3892
        TestCase {
3893
            zeros_before_dot: i16::MAX as usize,
3894
            zeros_after_dot: i16::MAX as usize + 2,
3895
            expected_err: Some(Error::Limit),
3896
        },
3897
        TestCase {
3898
            zeros_before_dot: i16::MAX as usize,
3899
            zeros_after_dot: i16::MAX as usize,
3900
            expected_err: None,
3901
        },
3902
        TestCase {
3903
            zeros_before_dot: i16::MAX as usize + 1,
3904
            zeros_after_dot: i16::MAX as usize,
3905
            expected_err: None,
3906
        },
3907
    ];
3908
    for cas in &cases {
3909
        let mut input_str = format!("{:0fill$}", 0, fill = cas.zeros_before_dot);
3910
        if cas.zeros_after_dot > 0 {
3911
            input_str.push('.');
3912
            input_str.push_str(&format!("{:0fill$}", 0, fill = cas.zeros_after_dot));
3913
        }
3914
        match FixedDecimal::from_str(&input_str) {
3915
            Ok(dec) => {
3916
                assert_eq!(cas.expected_err, None, "{cas:?}");
3917
                assert_eq!(input_str, dec.to_string(), "{cas:?}");
3918
            }
3919
            Err(err) => {
3920
                assert_eq!(cas.expected_err, Some(err), "{cas:?}");
3921
            }
3922
        }
3923
    }
3924
}
3925
3926
#[test]
3927
fn test_syntax_error() {
3928
    #[derive(Debug)]
3929
    struct TestCase {
3930
        pub input_str: &'static str,
3931
        pub expected_err: Option<Error>,
3932
    }
3933
    let cases = [
3934
        TestCase {
3935
            input_str: "-12a34",
3936
            expected_err: Some(Error::Syntax),
3937
        },
3938
        TestCase {
3939
            input_str: "0.0123√400",
3940
            expected_err: Some(Error::Syntax),
3941
        },
3942
        TestCase {
3943
            input_str: "0.012.3400",
3944
            expected_err: Some(Error::Syntax),
3945
        },
3946
        TestCase {
3947
            input_str: "-0-0123400",
3948
            expected_err: Some(Error::Syntax),
3949
        },
3950
        TestCase {
3951
            input_str: "0-0123400",
3952
            expected_err: Some(Error::Syntax),
3953
        },
3954
        TestCase {
3955
            input_str: "-0.00123400",
3956
            expected_err: None,
3957
        },
3958
        TestCase {
3959
            input_str: "00123400.",
3960
            expected_err: Some(Error::Syntax),
3961
        },
3962
        TestCase {
3963
            input_str: "00123400.0",
3964
            expected_err: None,
3965
        },
3966
        TestCase {
3967
            input_str: "123_456",
3968
            expected_err: Some(Error::Syntax),
3969
        },
3970
        TestCase {
3971
            input_str: "",
3972
            expected_err: Some(Error::Syntax),
3973
        },
3974
        TestCase {
3975
            input_str: "-",
3976
            expected_err: Some(Error::Syntax),
3977
        },
3978
        TestCase {
3979
            input_str: "+",
3980
            expected_err: Some(Error::Syntax),
3981
        },
3982
        TestCase {
3983
            input_str: "-1",
3984
            expected_err: None,
3985
        },
3986
    ];
3987
    for cas in &cases {
3988
        match FixedDecimal::from_str(cas.input_str) {
3989
            Ok(dec) => {
3990
                assert_eq!(cas.expected_err, None, "{cas:?}");
3991
                assert_eq!(cas.input_str, dec.to_string(), "{cas:?}");
3992
            }
3993
            Err(err) => {
3994
                assert_eq!(cas.expected_err, Some(err), "{cas:?}");
3995
            }
3996
        }
3997
    }
3998
}
3999
4000
#[test]
4001
fn test_pad() {
4002
    let mut dec = FixedDecimal::from_str("-0.42").unwrap();
4003
    assert_eq!("-0.42", dec.to_string());
4004
4005
    dec.pad_start(1);
4006
    assert_eq!("-0.42", dec.to_string());
4007
4008
    dec.pad_start(4);
4009
    assert_eq!("-0000.42", dec.to_string());
4010
4011
    dec.pad_start(2);
4012
    assert_eq!("-00.42", dec.to_string());
4013
}
4014
4015
#[test]
4016
fn test_sign_display() {
4017
    use SignDisplay::*;
4018
    let positive_nonzero = FixedDecimal::from(163);
4019
    let negative_nonzero = FixedDecimal::from(-163);
4020
    let positive_zero = FixedDecimal::from(0);
4021
    let negative_zero = FixedDecimal::from(0).with_sign(Sign::Negative);
4022
    assert_eq!(
4023
        "163",
4024
        positive_nonzero.clone().with_sign_display(Auto).to_string()
4025
    );
4026
    assert_eq!(
4027
        "-163",
4028
        negative_nonzero.clone().with_sign_display(Auto).to_string()
4029
    );
4030
    assert_eq!(
4031
        "0",
4032
        positive_zero.clone().with_sign_display(Auto).to_string()
4033
    );
4034
    assert_eq!(
4035
        "-0",
4036
        negative_zero.clone().with_sign_display(Auto).to_string()
4037
    );
4038
    assert_eq!(
4039
        "+163",
4040
        positive_nonzero
4041
            .clone()
4042
            .with_sign_display(Always)
4043
            .to_string()
4044
    );
4045
    assert_eq!(
4046
        "-163",
4047
        negative_nonzero
4048
            .clone()
4049
            .with_sign_display(Always)
4050
            .to_string()
4051
    );
4052
    assert_eq!(
4053
        "+0",
4054
        positive_zero.clone().with_sign_display(Always).to_string()
4055
    );
4056
    assert_eq!(
4057
        "-0",
4058
        negative_zero.clone().with_sign_display(Always).to_string()
4059
    );
4060
    assert_eq!(
4061
        "163",
4062
        positive_nonzero
4063
            .clone()
4064
            .with_sign_display(Never)
4065
            .to_string()
4066
    );
4067
    assert_eq!(
4068
        "163",
4069
        negative_nonzero
4070
            .clone()
4071
            .with_sign_display(Never)
4072
            .to_string()
4073
    );
4074
    assert_eq!(
4075
        "0",
4076
        positive_zero.clone().with_sign_display(Never).to_string()
4077
    );
4078
    assert_eq!(
4079
        "0",
4080
        negative_zero.clone().with_sign_display(Never).to_string()
4081
    );
4082
    assert_eq!(
4083
        "+163",
4084
        positive_nonzero
4085
            .clone()
4086
            .with_sign_display(ExceptZero)
4087
            .to_string()
4088
    );
4089
    assert_eq!(
4090
        "-163",
4091
        negative_nonzero
4092
            .clone()
4093
            .with_sign_display(ExceptZero)
4094
            .to_string()
4095
    );
4096
    assert_eq!(
4097
        "0",
4098
        positive_zero
4099
            .clone()
4100
            .with_sign_display(ExceptZero)
4101
            .to_string()
4102
    );
4103
    assert_eq!(
4104
        "0",
4105
        negative_zero
4106
            .clone()
4107
            .with_sign_display(ExceptZero)
4108
            .to_string()
4109
    );
4110
    assert_eq!(
4111
        "163",
4112
        positive_nonzero.with_sign_display(Negative).to_string()
4113
    );
4114
    assert_eq!(
4115
        "-163",
4116
        negative_nonzero.with_sign_display(Negative).to_string()
4117
    );
4118
    assert_eq!("0", positive_zero.with_sign_display(Negative).to_string());
4119
    assert_eq!("0", negative_zero.with_sign_display(Negative).to_string());
4120
}
4121
4122
#[test]
4123
fn test_set_max_position() {
4124
    let mut dec = FixedDecimal::from(1000);
4125
    assert_eq!("1000", dec.to_string());
4126
4127
    dec.set_max_position(2);
4128
    assert_eq!("00", dec.to_string());
4129
4130
    dec.set_max_position(0);
4131
    assert_eq!("0", dec.to_string());
4132
4133
    dec.set_max_position(3);
4134
    assert_eq!("000", dec.to_string());
4135
4136
    let mut dec = FixedDecimal::from_str("0.456").unwrap();
4137
    assert_eq!("0.456", dec.to_string());
4138
4139
    dec.set_max_position(0);
4140
    assert_eq!("0.456", dec.to_string());
4141
4142
    dec.set_max_position(-1);
4143
    assert_eq!("0.056", dec.to_string());
4144
4145
    dec.set_max_position(-2);
4146
    assert_eq!("0.006", dec.to_string());
4147
4148
    dec.set_max_position(-3);
4149
    assert_eq!("0.000", dec.to_string());
4150
4151
    dec.set_max_position(-4);
4152
    assert_eq!("0.0000", dec.to_string());
4153
4154
    let mut dec = FixedDecimal::from_str("100.01").unwrap();
4155
    dec.set_max_position(1);
4156
    assert_eq!("0.01", dec.to_string());
4157
}
4158
4159
#[test]
4160
fn test_pad_start_bounds() {
4161
    let mut dec = FixedDecimal::from_str("299792.458").unwrap();
4162
    let max_integer_digits = i16::MAX as usize + 1;
4163
4164
    dec.pad_start(i16::MAX - 1);
4165
    assert_eq!(
4166
        max_integer_digits - 2,
4167
        dec.to_string().split_once('.').unwrap().0.len()
4168
    );
4169
4170
    dec.pad_start(i16::MAX);
4171
    assert_eq!(
4172
        max_integer_digits - 1,
4173
        dec.to_string().split_once('.').unwrap().0.len()
4174
    );
4175
}
4176
4177
#[test]
4178
fn test_pad_end_bounds() {
4179
    let mut dec = FixedDecimal::from_str("299792.458").unwrap();
4180
    let max_fractional_digits = -(i16::MIN as isize) as usize;
4181
4182
    dec.pad_end(i16::MIN + 1);
4183
    assert_eq!(
4184
        max_fractional_digits - 1,
4185
        dec.to_string().split_once('.').unwrap().1.len()
4186
    );
4187
4188
    dec.pad_end(i16::MIN);
4189
    assert_eq!(
4190
        max_fractional_digits,
4191
        dec.to_string().split_once('.').unwrap().1.len()
4192
    );
4193
}
4194
4195
#[test]
4196
fn test_rounding() {
4197
    pub(crate) use std::str::FromStr;
4198
4199
    // Test Ceil
4200
    let mut dec = FixedDecimal::from_str("3.234").unwrap();
4201
    dec.ceil(0);
4202
    assert_eq!("4", dec.to_string());
4203
4204
    let mut dec = FixedDecimal::from_str("2.222").unwrap();
4205
    dec.ceil(-1);
4206
    assert_eq!("2.3", dec.to_string());
4207
4208
    let mut dec = FixedDecimal::from_str("22.222").unwrap();
4209
    dec.ceil(-2);
4210
    assert_eq!("22.23", dec.to_string());
4211
4212
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4213
    dec.ceil(-2);
4214
    assert_eq!("100.00", dec.to_string());
4215
4216
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4217
    dec.ceil(-5);
4218
    assert_eq!("99.99900", dec.to_string());
4219
4220
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4221
    dec.ceil(-5);
4222
    assert_eq!("-99.99900", dec.to_string());
4223
4224
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4225
    dec.ceil(-2);
4226
    assert_eq!("-99.99", dec.to_string());
4227
4228
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4229
    dec.ceil(4);
4230
    assert_eq!("10000", dec.to_string());
4231
4232
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4233
    dec.ceil(4);
4234
    assert_eq!("-0000", dec.to_string());
4235
4236
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
4237
    dec.ceil(-1);
4238
    assert_eq!("0.1", dec.to_string());
4239
4240
    let mut dec = FixedDecimal::from_str("-0.009").unwrap();
4241
    dec.ceil(-1);
4242
    assert_eq!("-0.0", dec.to_string());
4243
4244
    // Test Half Ceil
4245
    let mut dec = FixedDecimal::from_str("3.234").unwrap();
4246
    dec.half_ceil(0);
4247
    assert_eq!("3", dec.to_string());
4248
4249
    let mut dec = FixedDecimal::from_str("3.534").unwrap();
4250
    dec.half_ceil(0);
4251
    assert_eq!("4", dec.to_string());
4252
4253
    let mut dec = FixedDecimal::from_str("3.934").unwrap();
4254
    dec.half_ceil(0);
4255
    assert_eq!("4", dec.to_string());
4256
4257
    let mut dec = FixedDecimal::from_str("2.222").unwrap();
4258
    dec.half_ceil(-1);
4259
    assert_eq!("2.2", dec.to_string());
4260
4261
    let mut dec = FixedDecimal::from_str("2.44").unwrap();
4262
    dec.half_ceil(-1);
4263
    assert_eq!("2.4", dec.to_string());
4264
4265
    let mut dec = FixedDecimal::from_str("2.45").unwrap();
4266
    dec.half_ceil(-1);
4267
    assert_eq!("2.5", dec.to_string());
4268
4269
    let mut dec = FixedDecimal::from_str("-2.44").unwrap();
4270
    dec.half_ceil(-1);
4271
    assert_eq!("-2.4", dec.to_string());
4272
4273
    let mut dec = FixedDecimal::from_str("-2.45").unwrap();
4274
    dec.half_ceil(-1);
4275
    assert_eq!("-2.4", dec.to_string());
4276
4277
    let mut dec = FixedDecimal::from_str("22.222").unwrap();
4278
    dec.half_ceil(-2);
4279
    assert_eq!("22.22", dec.to_string());
4280
4281
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4282
    dec.half_ceil(-2);
4283
    assert_eq!("100.00", dec.to_string());
4284
4285
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4286
    dec.half_ceil(-5);
4287
    assert_eq!("99.99900", dec.to_string());
4288
4289
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4290
    dec.half_ceil(-5);
4291
    assert_eq!("-99.99900", dec.to_string());
4292
4293
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4294
    dec.half_ceil(-2);
4295
    assert_eq!("-100.00", dec.to_string());
4296
4297
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4298
    dec.half_ceil(4);
4299
    assert_eq!("0000", dec.to_string());
4300
4301
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4302
    dec.half_ceil(4);
4303
    assert_eq!("-0000", dec.to_string());
4304
4305
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
4306
    dec.half_ceil(-1);
4307
    assert_eq!("0.0", dec.to_string());
4308
4309
    let mut dec = FixedDecimal::from_str("-0.009").unwrap();
4310
    dec.half_ceil(-1);
4311
    assert_eq!("-0.0", dec.to_string());
4312
4313
    // Test Floor
4314
    let mut dec = FixedDecimal::from_str("3.234").unwrap();
4315
    dec.floor(0);
4316
    assert_eq!("3", dec.to_string());
4317
4318
    let mut dec = FixedDecimal::from_str("2.222").unwrap();
4319
    dec.floor(-1);
4320
    assert_eq!("2.2", dec.to_string());
4321
4322
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4323
    dec.floor(-2);
4324
    assert_eq!("99.99", dec.to_string());
4325
4326
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4327
    dec.floor(-10);
4328
    assert_eq!("99.9990000000", dec.to_string());
4329
4330
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4331
    dec.floor(-10);
4332
    assert_eq!("-99.9990000000", dec.to_string());
4333
4334
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4335
    dec.floor(10);
4336
    assert_eq!("0000000000", dec.to_string());
4337
4338
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4339
    dec.floor(10);
4340
    assert_eq!("-10000000000", dec.to_string());
4341
4342
    // Test Half Floor
4343
    let mut dec = FixedDecimal::from_str("3.234").unwrap();
4344
    dec.half_floor(0);
4345
    assert_eq!("3", dec.to_string());
4346
4347
    let mut dec = FixedDecimal::from_str("3.534").unwrap();
4348
    dec.half_floor(0);
4349
    assert_eq!("4", dec.to_string());
4350
4351
    let mut dec = FixedDecimal::from_str("3.934").unwrap();
4352
    dec.half_floor(0);
4353
    assert_eq!("4", dec.to_string());
4354
4355
    let mut dec = FixedDecimal::from_str("2.222").unwrap();
4356
    dec.half_floor(-1);
4357
    assert_eq!("2.2", dec.to_string());
4358
4359
    let mut dec = FixedDecimal::from_str("2.44").unwrap();
4360
    dec.half_floor(-1);
4361
    assert_eq!("2.4", dec.to_string());
4362
4363
    let mut dec = FixedDecimal::from_str("2.45").unwrap();
4364
    dec.half_floor(-1);
4365
    assert_eq!("2.4", dec.to_string());
4366
4367
    let mut dec = FixedDecimal::from_str("-2.44").unwrap();
4368
    dec.half_floor(-1);
4369
    assert_eq!("-2.4", dec.to_string());
4370
4371
    let mut dec = FixedDecimal::from_str("-2.45").unwrap();
4372
    dec.half_floor(-1);
4373
    assert_eq!("-2.5", dec.to_string());
4374
4375
    let mut dec = FixedDecimal::from_str("22.222").unwrap();
4376
    dec.half_floor(-2);
4377
    assert_eq!("22.22", dec.to_string());
4378
4379
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4380
    dec.half_floor(-2);
4381
    assert_eq!("100.00", dec.to_string());
4382
4383
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4384
    dec.half_floor(-5);
4385
    assert_eq!("99.99900", dec.to_string());
4386
4387
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4388
    dec.half_floor(-5);
4389
    assert_eq!("-99.99900", dec.to_string());
4390
4391
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4392
    dec.half_floor(-2);
4393
    assert_eq!("-100.00", dec.to_string());
4394
4395
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4396
    dec.half_floor(4);
4397
    assert_eq!("0000", dec.to_string());
4398
4399
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4400
    dec.half_floor(4);
4401
    assert_eq!("-0000", dec.to_string());
4402
4403
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
4404
    dec.half_floor(-1);
4405
    assert_eq!("0.0", dec.to_string());
4406
4407
    let mut dec = FixedDecimal::from_str("-0.009").unwrap();
4408
    dec.half_floor(-1);
4409
    assert_eq!("-0.0", dec.to_string());
4410
4411
    // Test Truncate Right
4412
    let mut dec = FixedDecimal::from(4235970).multiplied_pow10(-3);
4413
    assert_eq!("4235.970", dec.to_string());
4414
4415
    dec.trunc(-5);
4416
    assert_eq!("4235.97000", dec.to_string());
4417
4418
    dec.trunc(-1);
4419
    assert_eq!("4235.9", dec.to_string());
4420
4421
    dec.trunc(0);
4422
    assert_eq!("4235", dec.to_string());
4423
4424
    dec.trunc(1);
4425
    assert_eq!("4230", dec.to_string());
4426
4427
    dec.trunc(5);
4428
    assert_eq!("00000", dec.to_string());
4429
4430
    dec.trunc(2);
4431
    assert_eq!("00000", dec.to_string());
4432
4433
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4434
    dec.trunc(-2);
4435
    assert_eq!("-99.99", dec.to_string());
4436
4437
    let mut dec = FixedDecimal::from_str("1234.56").unwrap();
4438
    dec.trunc(-1);
4439
    assert_eq!("1234.5", dec.to_string());
4440
4441
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
4442
    dec.trunc(-1);
4443
    assert_eq!("0.0", dec.to_string());
4444
4445
    // Test trunced
4446
    let dec = FixedDecimal::from(4235970).multiplied_pow10(-3);
4447
    assert_eq!("4235.970", dec.to_string());
4448
4449
    assert_eq!("4235.97000", dec.clone().trunced(-5).to_string());
4450
4451
    assert_eq!("4230", dec.clone().trunced(1).to_string());
4452
4453
    assert_eq!("4200", dec.clone().trunced(2).to_string());
4454
4455
    assert_eq!("00000", dec.trunced(5).to_string());
4456
4457
    //Test expand
4458
    let mut dec = FixedDecimal::from_str("3.234").unwrap();
4459
    dec.expand(0);
4460
    assert_eq!("4", dec.to_string());
4461
4462
    let mut dec = FixedDecimal::from_str("2.222").unwrap();
4463
    dec.expand(-1);
4464
    assert_eq!("2.3", dec.to_string());
4465
4466
    let mut dec = FixedDecimal::from_str("22.222").unwrap();
4467
    dec.expand(-2);
4468
    assert_eq!("22.23", dec.to_string());
4469
4470
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4471
    dec.expand(-2);
4472
    assert_eq!("100.00", dec.to_string());
4473
4474
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4475
    dec.expand(-5);
4476
    assert_eq!("99.99900", dec.to_string());
4477
4478
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4479
    dec.expand(-5);
4480
    assert_eq!("-99.99900", dec.to_string());
4481
4482
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4483
    dec.expand(-2);
4484
    assert_eq!("-100.00", dec.to_string());
4485
4486
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4487
    dec.expand(4);
4488
    assert_eq!("10000", dec.to_string());
4489
4490
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4491
    dec.expand(4);
4492
    assert_eq!("-10000", dec.to_string());
4493
4494
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
4495
    dec.expand(-1);
4496
    assert_eq!("0.1", dec.to_string());
4497
4498
    let mut dec = FixedDecimal::from_str("-0.009").unwrap();
4499
    dec.expand(-1);
4500
    assert_eq!("-0.1", dec.to_string());
4501
4502
    let mut dec = FixedDecimal::from_str("3.954").unwrap();
4503
    dec.expand(0);
4504
    assert_eq!("4", dec.to_string());
4505
4506
    // Test half_expand
4507
    let mut dec = FixedDecimal::from_str("3.234").unwrap();
4508
    dec.half_expand(0);
4509
    assert_eq!("3", dec.to_string());
4510
4511
    let mut dec = FixedDecimal::from_str("3.534").unwrap();
4512
    dec.half_expand(0);
4513
    assert_eq!("4", dec.to_string());
4514
4515
    let mut dec = FixedDecimal::from_str("3.934").unwrap();
4516
    dec.half_expand(0);
4517
    assert_eq!("4", dec.to_string());
4518
4519
    let mut dec = FixedDecimal::from_str("2.222").unwrap();
4520
    dec.half_expand(-1);
4521
    assert_eq!("2.2", dec.to_string());
4522
4523
    let mut dec = FixedDecimal::from_str("2.44").unwrap();
4524
    dec.half_expand(-1);
4525
    assert_eq!("2.4", dec.to_string());
4526
4527
    let mut dec = FixedDecimal::from_str("2.45").unwrap();
4528
    dec.half_expand(-1);
4529
    assert_eq!("2.5", dec.to_string());
4530
4531
    let mut dec = FixedDecimal::from_str("-2.44").unwrap();
4532
    dec.half_expand(-1);
4533
    assert_eq!("-2.4", dec.to_string());
4534
4535
    let mut dec = FixedDecimal::from_str("-2.45").unwrap();
4536
    dec.half_expand(-1);
4537
    assert_eq!("-2.5", dec.to_string());
4538
4539
    let mut dec = FixedDecimal::from_str("22.222").unwrap();
4540
    dec.half_expand(-2);
4541
    assert_eq!("22.22", dec.to_string());
4542
4543
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4544
    dec.half_expand(-2);
4545
    assert_eq!("100.00", dec.to_string());
4546
4547
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4548
    dec.half_expand(-5);
4549
    assert_eq!("99.99900", dec.to_string());
4550
4551
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4552
    dec.half_expand(-5);
4553
    assert_eq!("-99.99900", dec.to_string());
4554
4555
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4556
    dec.half_expand(-2);
4557
    assert_eq!("-100.00", dec.to_string());
4558
4559
    let mut dec = FixedDecimal::from_str("99.999").unwrap();
4560
    dec.half_expand(4);
4561
    assert_eq!("0000", dec.to_string());
4562
4563
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4564
    dec.half_expand(4);
4565
    assert_eq!("-0000", dec.to_string());
4566
4567
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
4568
    dec.half_expand(-1);
4569
    assert_eq!("0.0", dec.to_string());
4570
4571
    let mut dec = FixedDecimal::from_str("-0.009").unwrap();
4572
    dec.half_expand(-1);
4573
    assert_eq!("-0.0", dec.to_string());
4574
4575
    // Test specific cases
4576
    let mut dec = FixedDecimal::from_str("1.108").unwrap();
4577
    dec.half_even(-2);
4578
    assert_eq!("1.11", dec.to_string());
4579
4580
    let mut dec = FixedDecimal::from_str("1.108").unwrap();
4581
    dec.expand(-2);
4582
    assert_eq!("1.11", dec.to_string());
4583
4584
    let mut dec = FixedDecimal::from_str("1.108").unwrap();
4585
    dec.trunc(-2);
4586
    assert_eq!("1.10", dec.to_string());
4587
4588
    let mut dec = FixedDecimal::from_str("2.78536913177").unwrap();
4589
    dec.half_even(-2);
4590
    assert_eq!("2.79", dec.to_string());
4591
}
4592
4593
#[test]
4594
fn test_concatenate() {
4595
    #[derive(Debug)]
4596
    struct TestCase {
4597
        pub input_1: &'static str,
4598
        pub input_2: &'static str,
4599
        pub expected: Option<&'static str>,
4600
    }
4601
    let cases = [
4602
        TestCase {
4603
            input_1: "123",
4604
            input_2: "0.456",
4605
            expected: Some("123.456"),
4606
        },
4607
        TestCase {
4608
            input_1: "0.456",
4609
            input_2: "123",
4610
            expected: None,
4611
        },
4612
        TestCase {
4613
            input_1: "123",
4614
            input_2: "0.0456",
4615
            expected: Some("123.0456"),
4616
        },
4617
        TestCase {
4618
            input_1: "0.0456",
4619
            input_2: "123",
4620
            expected: None,
4621
        },
4622
        TestCase {
4623
            input_1: "100",
4624
            input_2: "0.456",
4625
            expected: Some("100.456"),
4626
        },
4627
        TestCase {
4628
            input_1: "0.456",
4629
            input_2: "100",
4630
            expected: None,
4631
        },
4632
        TestCase {
4633
            input_1: "100",
4634
            input_2: "0.001",
4635
            expected: Some("100.001"),
4636
        },
4637
        TestCase {
4638
            input_1: "0.001",
4639
            input_2: "100",
4640
            expected: None,
4641
        },
4642
        TestCase {
4643
            input_1: "123000",
4644
            input_2: "456",
4645
            expected: Some("123456"),
4646
        },
4647
        TestCase {
4648
            input_1: "456",
4649
            input_2: "123000",
4650
            expected: None,
4651
        },
4652
        TestCase {
4653
            input_1: "5",
4654
            input_2: "5",
4655
            expected: None,
4656
        },
4657
        TestCase {
4658
            input_1: "120",
4659
            input_2: "25",
4660
            expected: None,
4661
        },
4662
        TestCase {
4663
            input_1: "1.1",
4664
            input_2: "0.2",
4665
            expected: None,
4666
        },
4667
        TestCase {
4668
            input_1: "0",
4669
            input_2: "222",
4670
            expected: Some("222"),
4671
        },
4672
        TestCase {
4673
            input_1: "222",
4674
            input_2: "0",
4675
            expected: Some("222"),
4676
        },
4677
        TestCase {
4678
            input_1: "0",
4679
            input_2: "0",
4680
            expected: Some("0"),
4681
        },
4682
        TestCase {
4683
            input_1: "000",
4684
            input_2: "0",
4685
            expected: Some("000"),
4686
        },
4687
        TestCase {
4688
            input_1: "0.00",
4689
            input_2: "0",
4690
            expected: Some("0.00"),
4691
        },
4692
    ];
4693
    for cas in &cases {
4694
        let fd1 = FixedDecimal::from_str(cas.input_1).unwrap();
4695
        let fd2 = FixedDecimal::from_str(cas.input_2).unwrap();
4696
        match fd1.concatenated_end(fd2) {
4697
            Ok(fd) => {
4698
                assert_eq!(cas.expected, Some(fd.to_string().as_str()), "{cas:?}");
4699
            }
4700
            Err(_) => {
4701
                assert!(cas.expected.is_none(), "{cas:?}");
4702
            }
4703
        }
4704
    }
4705
}
4706
4707
#[test]
4708
fn test_rounding_increment() {
4709
    // Test Truncate Right
4710
    let mut dec = FixedDecimal::from(4235970).multiplied_pow10(-3);
4711
    assert_eq!("4235.970", dec.to_string());
4712
4713
    dec.trunc_to_increment(-2, RoundingIncrement::MultiplesOf2);
4714
    assert_eq!("4235.96", dec.to_string());
4715
4716
    dec.trunc_to_increment(-1, RoundingIncrement::MultiplesOf5);
4717
    assert_eq!("4235.5", dec.to_string());
4718
4719
    dec.trunc_to_increment(0, RoundingIncrement::MultiplesOf25);
4720
    assert_eq!("4225", dec.to_string());
4721
4722
    dec.trunc_to_increment(5, RoundingIncrement::MultiplesOf5);
4723
    assert_eq!("00000", dec.to_string());
4724
4725
    dec.trunc_to_increment(2, RoundingIncrement::MultiplesOf2);
4726
    assert_eq!("00000", dec.to_string());
4727
4728
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4729
    dec.trunc_to_increment(-2, RoundingIncrement::MultiplesOf25);
4730
    assert_eq!("-99.75", dec.to_string());
4731
4732
    let mut dec = FixedDecimal::from_str("1234.56").unwrap();
4733
    dec.trunc_to_increment(-1, RoundingIncrement::MultiplesOf2);
4734
    assert_eq!("1234.4", dec.to_string());
4735
4736
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
4737
    dec.trunc_to_increment(-1, RoundingIncrement::MultiplesOf5);
4738
    assert_eq!("0.0", dec.to_string());
4739
4740
    let mut dec = FixedDecimal::from_str("0.60").unwrap();
4741
    dec.trunc_to_increment(-2, RoundingIncrement::MultiplesOf25);
4742
    assert_eq!("0.50", dec.to_string());
4743
4744
    let mut dec = FixedDecimal::from_str("0.40").unwrap();
4745
    dec.trunc_to_increment(-2, RoundingIncrement::MultiplesOf25);
4746
    assert_eq!("0.25", dec.to_string());
4747
4748
    let mut dec = FixedDecimal::from_str("0.7000000099").unwrap();
4749
    dec.trunc_to_increment(-3, RoundingIncrement::MultiplesOf2);
4750
    assert_eq!("0.700", dec.to_string());
4751
4752
    let mut dec = FixedDecimal::from_str("5").unwrap();
4753
    dec.trunc_to_increment(0, RoundingIncrement::MultiplesOf25);
4754
    assert_eq!("0", dec.to_string());
4755
4756
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MIN);
4757
    dec.trunc_to_increment(i16::MIN, RoundingIncrement::MultiplesOf2);
4758
    assert_eq!(FixedDecimal::from(6).multiplied_pow10(i16::MIN), dec);
4759
4760
    let mut dec = FixedDecimal::from(9).multiplied_pow10(i16::MIN);
4761
    dec.trunc_to_increment(i16::MIN, RoundingIncrement::MultiplesOf5);
4762
    assert_eq!(FixedDecimal::from(5).multiplied_pow10(i16::MIN), dec);
4763
4764
    let mut dec = FixedDecimal::from(70).multiplied_pow10(i16::MIN);
4765
    dec.trunc_to_increment(i16::MIN, RoundingIncrement::MultiplesOf25);
4766
    assert_eq!(FixedDecimal::from(50).multiplied_pow10(i16::MIN), dec);
4767
4768
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
4769
    dec.trunc_to_increment(i16::MAX, RoundingIncrement::MultiplesOf2);
4770
    assert_eq!(FixedDecimal::from(6).multiplied_pow10(i16::MAX), dec);
4771
4772
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
4773
    dec.trunc_to_increment(i16::MAX, RoundingIncrement::MultiplesOf5);
4774
    assert_eq!(FixedDecimal::from(5).multiplied_pow10(i16::MAX), dec);
4775
4776
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
4777
    dec.trunc_to_increment(i16::MAX, RoundingIncrement::MultiplesOf25);
4778
    assert_eq!(FixedDecimal::from(0).multiplied_pow10(i16::MAX), dec);
4779
4780
    // Test Expand
4781
    let mut dec = FixedDecimal::from(4235970).multiplied_pow10(-3);
4782
    assert_eq!("4235.970", dec.to_string());
4783
4784
    dec.expand_to_increment(-2, RoundingIncrement::MultiplesOf2);
4785
    assert_eq!("4235.98", dec.to_string());
4786
4787
    dec.expand_to_increment(-1, RoundingIncrement::MultiplesOf5);
4788
    assert_eq!("4236.0", dec.to_string());
4789
4790
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf25);
4791
    assert_eq!("4250", dec.to_string());
4792
4793
    dec.expand_to_increment(5, RoundingIncrement::MultiplesOf5);
4794
    assert_eq!("500000", dec.to_string());
4795
4796
    dec.expand_to_increment(2, RoundingIncrement::MultiplesOf2);
4797
    assert_eq!("500000", dec.to_string());
4798
4799
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4800
    dec.expand_to_increment(-2, RoundingIncrement::MultiplesOf25);
4801
    assert_eq!("-100.00", dec.to_string());
4802
4803
    let mut dec = FixedDecimal::from_str("1234.56").unwrap();
4804
    dec.expand_to_increment(-1, RoundingIncrement::MultiplesOf2);
4805
    assert_eq!("1234.6", dec.to_string());
4806
4807
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
4808
    dec.expand_to_increment(-1, RoundingIncrement::MultiplesOf5);
4809
    assert_eq!("0.5", dec.to_string());
4810
4811
    let mut dec = FixedDecimal::from_str("0.60").unwrap();
4812
    dec.expand_to_increment(-2, RoundingIncrement::MultiplesOf25);
4813
    assert_eq!("0.75", dec.to_string());
4814
4815
    let mut dec = FixedDecimal::from_str("0.40").unwrap();
4816
    dec.expand_to_increment(-2, RoundingIncrement::MultiplesOf25);
4817
    assert_eq!("0.50", dec.to_string());
4818
4819
    let mut dec = FixedDecimal::from_str("0.7000000099").unwrap();
4820
    dec.expand_to_increment(-3, RoundingIncrement::MultiplesOf2);
4821
    assert_eq!("0.702", dec.to_string());
4822
4823
    let mut dec = FixedDecimal::from_str("5").unwrap();
4824
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf25);
4825
    assert_eq!("25", dec.to_string());
4826
4827
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MIN);
4828
    dec.expand_to_increment(i16::MIN, RoundingIncrement::MultiplesOf2);
4829
    assert_eq!(FixedDecimal::from(8).multiplied_pow10(i16::MIN), dec);
4830
4831
    let mut dec = FixedDecimal::from(9).multiplied_pow10(i16::MIN);
4832
    dec.expand_to_increment(i16::MIN, RoundingIncrement::MultiplesOf5);
4833
    assert_eq!(FixedDecimal::from(10).multiplied_pow10(i16::MIN), dec);
4834
4835
    let mut dec = FixedDecimal::from(70).multiplied_pow10(i16::MIN);
4836
    dec.expand_to_increment(i16::MIN, RoundingIncrement::MultiplesOf25);
4837
    assert_eq!(FixedDecimal::from(75).multiplied_pow10(i16::MIN), dec);
4838
4839
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
4840
    dec.expand_to_increment(i16::MAX, RoundingIncrement::MultiplesOf2);
4841
    assert_eq!(FixedDecimal::from(8).multiplied_pow10(i16::MAX), dec);
4842
4843
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
4844
    dec.expand_to_increment(i16::MAX, RoundingIncrement::MultiplesOf5);
4845
    assert_eq!(FixedDecimal::from(0).multiplied_pow10(i16::MAX), dec);
4846
4847
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
4848
    dec.expand_to_increment(i16::MAX, RoundingIncrement::MultiplesOf25);
4849
    assert_eq!(FixedDecimal::from(0).multiplied_pow10(i16::MAX), dec);
4850
4851
    // Test Half Truncate Right
4852
    let mut dec = FixedDecimal::from(4235970).multiplied_pow10(-3);
4853
    assert_eq!("4235.970", dec.to_string());
4854
4855
    dec.half_trunc_to_increment(-2, RoundingIncrement::MultiplesOf2);
4856
    assert_eq!("4235.96", dec.to_string());
4857
4858
    dec.half_trunc_to_increment(-1, RoundingIncrement::MultiplesOf5);
4859
    assert_eq!("4236.0", dec.to_string());
4860
4861
    dec.half_trunc_to_increment(0, RoundingIncrement::MultiplesOf25);
4862
    assert_eq!("4225", dec.to_string());
4863
4864
    dec.half_trunc_to_increment(5, RoundingIncrement::MultiplesOf5);
4865
    assert_eq!("00000", dec.to_string());
4866
4867
    dec.half_trunc_to_increment(2, RoundingIncrement::MultiplesOf2);
4868
    assert_eq!("00000", dec.to_string());
4869
4870
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4871
    dec.half_trunc_to_increment(-2, RoundingIncrement::MultiplesOf25);
4872
    assert_eq!("-100.00", dec.to_string());
4873
4874
    let mut dec = FixedDecimal::from_str("1234.56").unwrap();
4875
    dec.half_trunc_to_increment(-1, RoundingIncrement::MultiplesOf2);
4876
    assert_eq!("1234.6", dec.to_string());
4877
4878
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
4879
    dec.half_trunc_to_increment(-1, RoundingIncrement::MultiplesOf5);
4880
    assert_eq!("0.0", dec.to_string());
4881
4882
    let mut dec = FixedDecimal::from_str("0.60").unwrap();
4883
    dec.half_trunc_to_increment(-2, RoundingIncrement::MultiplesOf25);
4884
    assert_eq!("0.50", dec.to_string());
4885
4886
    let mut dec = FixedDecimal::from_str("0.40").unwrap();
4887
    dec.half_trunc_to_increment(-2, RoundingIncrement::MultiplesOf25);
4888
    assert_eq!("0.50", dec.to_string());
4889
4890
    let mut dec = FixedDecimal::from_str("0.7000000099").unwrap();
4891
    dec.half_trunc_to_increment(-3, RoundingIncrement::MultiplesOf2);
4892
    assert_eq!("0.700", dec.to_string());
4893
4894
    let mut dec = FixedDecimal::from_str("5").unwrap();
4895
    dec.half_trunc_to_increment(0, RoundingIncrement::MultiplesOf25);
4896
    assert_eq!("0", dec.to_string());
4897
4898
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MIN);
4899
    dec.half_trunc_to_increment(i16::MIN, RoundingIncrement::MultiplesOf2);
4900
    assert_eq!(FixedDecimal::from(6).multiplied_pow10(i16::MIN), dec);
4901
4902
    let mut dec = FixedDecimal::from(9).multiplied_pow10(i16::MIN);
4903
    dec.half_trunc_to_increment(i16::MIN, RoundingIncrement::MultiplesOf5);
4904
    assert_eq!(FixedDecimal::from(10).multiplied_pow10(i16::MIN), dec);
4905
4906
    let mut dec = FixedDecimal::from(70).multiplied_pow10(i16::MIN);
4907
    dec.half_trunc_to_increment(i16::MIN, RoundingIncrement::MultiplesOf25);
4908
    assert_eq!(FixedDecimal::from(75).multiplied_pow10(i16::MIN), dec);
4909
4910
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
4911
    dec.half_trunc_to_increment(i16::MAX, RoundingIncrement::MultiplesOf2);
4912
    assert_eq!(FixedDecimal::from(6).multiplied_pow10(i16::MAX), dec);
4913
4914
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
4915
    dec.half_trunc_to_increment(i16::MAX, RoundingIncrement::MultiplesOf5);
4916
    assert_eq!(FixedDecimal::from(5).multiplied_pow10(i16::MAX), dec);
4917
4918
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
4919
    dec.half_trunc_to_increment(i16::MAX, RoundingIncrement::MultiplesOf25);
4920
    assert_eq!(FixedDecimal::from(0).multiplied_pow10(i16::MAX), dec);
4921
4922
    // Test Half Expand
4923
    let mut dec = FixedDecimal::from(4235970).multiplied_pow10(-3);
4924
    assert_eq!("4235.970", dec.to_string());
4925
4926
    dec.half_expand_to_increment(-2, RoundingIncrement::MultiplesOf2);
4927
    assert_eq!("4235.98", dec.to_string());
4928
4929
    dec.half_expand_to_increment(-1, RoundingIncrement::MultiplesOf5);
4930
    assert_eq!("4236.0", dec.to_string());
4931
4932
    dec.half_expand_to_increment(0, RoundingIncrement::MultiplesOf25);
4933
    assert_eq!("4225", dec.to_string());
4934
4935
    dec.half_expand_to_increment(5, RoundingIncrement::MultiplesOf5);
4936
    assert_eq!("00000", dec.to_string());
4937
4938
    dec.half_expand_to_increment(2, RoundingIncrement::MultiplesOf2);
4939
    assert_eq!("00000", dec.to_string());
4940
4941
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
4942
    dec.half_expand_to_increment(-2, RoundingIncrement::MultiplesOf25);
4943
    assert_eq!("-100.00", dec.to_string());
4944
4945
    let mut dec = FixedDecimal::from_str("1234.56").unwrap();
4946
    dec.half_expand_to_increment(-1, RoundingIncrement::MultiplesOf2);
4947
    assert_eq!("1234.6", dec.to_string());
4948
4949
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
4950
    dec.half_expand_to_increment(-1, RoundingIncrement::MultiplesOf5);
4951
    assert_eq!("0.0", dec.to_string());
4952
4953
    let mut dec = FixedDecimal::from_str("0.60").unwrap();
4954
    dec.half_expand_to_increment(-2, RoundingIncrement::MultiplesOf25);
4955
    assert_eq!("0.50", dec.to_string());
4956
4957
    let mut dec = FixedDecimal::from_str("0.40").unwrap();
4958
    dec.half_expand_to_increment(-2, RoundingIncrement::MultiplesOf25);
4959
    assert_eq!("0.50", dec.to_string());
4960
4961
    let mut dec = FixedDecimal::from_str("0.7000000099").unwrap();
4962
    dec.half_expand_to_increment(-3, RoundingIncrement::MultiplesOf2);
4963
    assert_eq!("0.700", dec.to_string());
4964
4965
    let mut dec = FixedDecimal::from_str("5").unwrap();
4966
    dec.half_expand_to_increment(0, RoundingIncrement::MultiplesOf25);
4967
    assert_eq!("0", dec.to_string());
4968
4969
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MIN);
4970
    dec.half_expand_to_increment(i16::MIN, RoundingIncrement::MultiplesOf2);
4971
    assert_eq!(FixedDecimal::from(8).multiplied_pow10(i16::MIN), dec);
4972
4973
    let mut dec = FixedDecimal::from(9).multiplied_pow10(i16::MIN);
4974
    dec.half_expand_to_increment(i16::MIN, RoundingIncrement::MultiplesOf5);
4975
    assert_eq!(FixedDecimal::from(10).multiplied_pow10(i16::MIN), dec);
4976
4977
    let mut dec = FixedDecimal::from(70).multiplied_pow10(i16::MIN);
4978
    dec.half_expand_to_increment(i16::MIN, RoundingIncrement::MultiplesOf25);
4979
    assert_eq!(FixedDecimal::from(75).multiplied_pow10(i16::MIN), dec);
4980
4981
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
4982
    dec.half_expand_to_increment(i16::MAX, RoundingIncrement::MultiplesOf2);
4983
    assert_eq!(FixedDecimal::from(8).multiplied_pow10(i16::MAX), dec);
4984
4985
    // Test Ceil
4986
    let mut dec = FixedDecimal::from(4235970).multiplied_pow10(-3);
4987
    assert_eq!("4235.970", dec.to_string());
4988
4989
    dec.ceil_to_increment(-2, RoundingIncrement::MultiplesOf2);
4990
    assert_eq!("4235.98", dec.to_string());
4991
4992
    dec.ceil_to_increment(-1, RoundingIncrement::MultiplesOf5);
4993
    assert_eq!("4236.0", dec.to_string());
4994
4995
    dec.ceil_to_increment(0, RoundingIncrement::MultiplesOf25);
4996
    assert_eq!("4250", dec.to_string());
4997
4998
    dec.ceil_to_increment(5, RoundingIncrement::MultiplesOf5);
4999
    assert_eq!("500000", dec.to_string());
5000
5001
    dec.ceil_to_increment(2, RoundingIncrement::MultiplesOf2);
5002
    assert_eq!("500000", dec.to_string());
5003
5004
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
5005
    dec.ceil_to_increment(-2, RoundingIncrement::MultiplesOf25);
5006
    assert_eq!("-99.75", dec.to_string());
5007
5008
    let mut dec = FixedDecimal::from_str("1234.56").unwrap();
5009
    dec.ceil_to_increment(-1, RoundingIncrement::MultiplesOf2);
5010
    assert_eq!("1234.6", dec.to_string());
5011
5012
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
5013
    dec.ceil_to_increment(-1, RoundingIncrement::MultiplesOf5);
5014
    assert_eq!("0.5", dec.to_string());
5015
5016
    let mut dec = FixedDecimal::from_str("0.60").unwrap();
5017
    dec.ceil_to_increment(-2, RoundingIncrement::MultiplesOf25);
5018
    assert_eq!("0.75", dec.to_string());
5019
5020
    let mut dec = FixedDecimal::from_str("0.40").unwrap();
5021
    dec.ceil_to_increment(-2, RoundingIncrement::MultiplesOf25);
5022
    assert_eq!("0.50", dec.to_string());
5023
5024
    let mut dec = FixedDecimal::from_str("0.7000000099").unwrap();
5025
    dec.ceil_to_increment(-3, RoundingIncrement::MultiplesOf2);
5026
    assert_eq!("0.702", dec.to_string());
5027
5028
    let mut dec = FixedDecimal::from_str("5").unwrap();
5029
    dec.ceil_to_increment(0, RoundingIncrement::MultiplesOf25);
5030
    assert_eq!("25", dec.to_string());
5031
5032
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MIN);
5033
    dec.ceil_to_increment(i16::MIN, RoundingIncrement::MultiplesOf2);
5034
    assert_eq!(FixedDecimal::from(8).multiplied_pow10(i16::MIN), dec);
5035
5036
    let mut dec = FixedDecimal::from(9).multiplied_pow10(i16::MIN);
5037
    dec.ceil_to_increment(i16::MIN, RoundingIncrement::MultiplesOf5);
5038
    assert_eq!(FixedDecimal::from(10).multiplied_pow10(i16::MIN), dec);
5039
5040
    let mut dec = FixedDecimal::from(70).multiplied_pow10(i16::MIN);
5041
    dec.ceil_to_increment(i16::MIN, RoundingIncrement::MultiplesOf25);
5042
    assert_eq!(FixedDecimal::from(75).multiplied_pow10(i16::MIN), dec);
5043
5044
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
5045
    dec.ceil_to_increment(i16::MAX, RoundingIncrement::MultiplesOf2);
5046
    assert_eq!(FixedDecimal::from(8).multiplied_pow10(i16::MAX), dec);
5047
5048
    // Test Half Ceil
5049
    let mut dec = FixedDecimal::from(4235970).multiplied_pow10(-3);
5050
    assert_eq!("4235.970", dec.to_string());
5051
5052
    dec.half_ceil_to_increment(-2, RoundingIncrement::MultiplesOf2);
5053
    assert_eq!("4235.98", dec.to_string());
5054
5055
    dec.half_ceil_to_increment(-1, RoundingIncrement::MultiplesOf5);
5056
    assert_eq!("4236.0", dec.to_string());
5057
5058
    dec.half_ceil_to_increment(0, RoundingIncrement::MultiplesOf25);
5059
    assert_eq!("4225", dec.to_string());
5060
5061
    dec.half_ceil_to_increment(5, RoundingIncrement::MultiplesOf5);
5062
    assert_eq!("00000", dec.to_string());
5063
5064
    dec.half_ceil_to_increment(2, RoundingIncrement::MultiplesOf2);
5065
    assert_eq!("00000", dec.to_string());
5066
5067
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
5068
    dec.half_ceil_to_increment(-2, RoundingIncrement::MultiplesOf25);
5069
    assert_eq!("-100.00", dec.to_string());
5070
5071
    let mut dec = FixedDecimal::from_str("1234.56").unwrap();
5072
    dec.half_ceil_to_increment(-1, RoundingIncrement::MultiplesOf2);
5073
    assert_eq!("1234.6", dec.to_string());
5074
5075
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
5076
    dec.half_ceil_to_increment(-1, RoundingIncrement::MultiplesOf5);
5077
    assert_eq!("0.0", dec.to_string());
5078
5079
    let mut dec = FixedDecimal::from_str("0.60").unwrap();
5080
    dec.half_ceil_to_increment(-2, RoundingIncrement::MultiplesOf25);
5081
    assert_eq!("0.50", dec.to_string());
5082
5083
    let mut dec = FixedDecimal::from_str("0.40").unwrap();
5084
    dec.half_ceil_to_increment(-2, RoundingIncrement::MultiplesOf25);
5085
    assert_eq!("0.50", dec.to_string());
5086
5087
    let mut dec = FixedDecimal::from_str("0.7000000099").unwrap();
5088
    dec.half_ceil_to_increment(-3, RoundingIncrement::MultiplesOf2);
5089
    assert_eq!("0.700", dec.to_string());
5090
5091
    let mut dec = FixedDecimal::from_str("5").unwrap();
5092
    dec.half_ceil_to_increment(0, RoundingIncrement::MultiplesOf25);
5093
    assert_eq!("0", dec.to_string());
5094
5095
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MIN);
5096
    dec.half_ceil_to_increment(i16::MIN, RoundingIncrement::MultiplesOf2);
5097
    assert_eq!(FixedDecimal::from(8).multiplied_pow10(i16::MIN), dec);
5098
5099
    let mut dec = FixedDecimal::from(9).multiplied_pow10(i16::MIN);
5100
    dec.half_ceil_to_increment(i16::MIN, RoundingIncrement::MultiplesOf5);
5101
    assert_eq!(FixedDecimal::from(10).multiplied_pow10(i16::MIN), dec);
5102
5103
    let mut dec = FixedDecimal::from(70).multiplied_pow10(i16::MIN);
5104
    dec.half_ceil_to_increment(i16::MIN, RoundingIncrement::MultiplesOf25);
5105
    assert_eq!(FixedDecimal::from(75).multiplied_pow10(i16::MIN), dec);
5106
5107
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
5108
    dec.half_ceil_to_increment(i16::MAX, RoundingIncrement::MultiplesOf2);
5109
    assert_eq!(FixedDecimal::from(8).multiplied_pow10(i16::MAX), dec);
5110
5111
    // Test Floor
5112
    let mut dec = FixedDecimal::from(4235970).multiplied_pow10(-3);
5113
    assert_eq!("4235.970", dec.to_string());
5114
5115
    dec.floor_to_increment(-2, RoundingIncrement::MultiplesOf2);
5116
    assert_eq!("4235.96", dec.to_string());
5117
5118
    dec.floor_to_increment(-1, RoundingIncrement::MultiplesOf5);
5119
    assert_eq!("4235.5", dec.to_string());
5120
5121
    dec.floor_to_increment(0, RoundingIncrement::MultiplesOf25);
5122
    assert_eq!("4225", dec.to_string());
5123
5124
    dec.floor_to_increment(5, RoundingIncrement::MultiplesOf5);
5125
    assert_eq!("00000", dec.to_string());
5126
5127
    dec.floor_to_increment(2, RoundingIncrement::MultiplesOf2);
5128
    assert_eq!("00000", dec.to_string());
5129
5130
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
5131
    dec.floor_to_increment(-2, RoundingIncrement::MultiplesOf25);
5132
    assert_eq!("-100.00", dec.to_string());
5133
5134
    let mut dec = FixedDecimal::from_str("1234.56").unwrap();
5135
    dec.floor_to_increment(-1, RoundingIncrement::MultiplesOf2);
5136
    assert_eq!("1234.4", dec.to_string());
5137
5138
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
5139
    dec.floor_to_increment(-1, RoundingIncrement::MultiplesOf5);
5140
    assert_eq!("0.0", dec.to_string());
5141
5142
    let mut dec = FixedDecimal::from_str("0.60").unwrap();
5143
    dec.floor_to_increment(-2, RoundingIncrement::MultiplesOf25);
5144
    assert_eq!("0.50", dec.to_string());
5145
5146
    let mut dec = FixedDecimal::from_str("0.40").unwrap();
5147
    dec.floor_to_increment(-2, RoundingIncrement::MultiplesOf25);
5148
    assert_eq!("0.25", dec.to_string());
5149
5150
    let mut dec = FixedDecimal::from_str("0.7000000099").unwrap();
5151
    dec.floor_to_increment(-3, RoundingIncrement::MultiplesOf2);
5152
    assert_eq!("0.700", dec.to_string());
5153
5154
    let mut dec = FixedDecimal::from_str("5").unwrap();
5155
    dec.floor_to_increment(0, RoundingIncrement::MultiplesOf25);
5156
    assert_eq!("0", dec.to_string());
5157
5158
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MIN);
5159
    dec.floor_to_increment(i16::MIN, RoundingIncrement::MultiplesOf2);
5160
    assert_eq!(FixedDecimal::from(6).multiplied_pow10(i16::MIN), dec);
5161
5162
    let mut dec = FixedDecimal::from(9).multiplied_pow10(i16::MIN);
5163
    dec.floor_to_increment(i16::MIN, RoundingIncrement::MultiplesOf5);
5164
    assert_eq!(FixedDecimal::from(5).multiplied_pow10(i16::MIN), dec);
5165
5166
    let mut dec = FixedDecimal::from(70).multiplied_pow10(i16::MIN);
5167
    dec.floor_to_increment(i16::MIN, RoundingIncrement::MultiplesOf25);
5168
    assert_eq!(FixedDecimal::from(50).multiplied_pow10(i16::MIN), dec);
5169
5170
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
5171
    dec.floor_to_increment(i16::MAX, RoundingIncrement::MultiplesOf2);
5172
    assert_eq!(FixedDecimal::from(6).multiplied_pow10(i16::MAX), dec);
5173
5174
    // Test Half Floor
5175
    let mut dec = FixedDecimal::from(4235970).multiplied_pow10(-3);
5176
    assert_eq!("4235.970", dec.to_string());
5177
5178
    dec.half_floor_to_increment(-2, RoundingIncrement::MultiplesOf2);
5179
    assert_eq!("4235.96", dec.to_string());
5180
5181
    dec.half_floor_to_increment(-1, RoundingIncrement::MultiplesOf5);
5182
    assert_eq!("4236.0", dec.to_string());
5183
5184
    dec.half_floor_to_increment(0, RoundingIncrement::MultiplesOf25);
5185
    assert_eq!("4225", dec.to_string());
5186
5187
    dec.half_floor_to_increment(5, RoundingIncrement::MultiplesOf5);
5188
    assert_eq!("00000", dec.to_string());
5189
5190
    dec.half_floor_to_increment(2, RoundingIncrement::MultiplesOf2);
5191
    assert_eq!("00000", dec.to_string());
5192
5193
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
5194
    dec.half_floor_to_increment(-2, RoundingIncrement::MultiplesOf25);
5195
    assert_eq!("-100.00", dec.to_string());
5196
5197
    let mut dec = FixedDecimal::from_str("1234.56").unwrap();
5198
    dec.half_floor_to_increment(-1, RoundingIncrement::MultiplesOf2);
5199
    assert_eq!("1234.6", dec.to_string());
5200
5201
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
5202
    dec.half_floor_to_increment(-1, RoundingIncrement::MultiplesOf5);
5203
    assert_eq!("0.0", dec.to_string());
5204
5205
    let mut dec = FixedDecimal::from_str("0.60").unwrap();
5206
    dec.half_floor_to_increment(-2, RoundingIncrement::MultiplesOf25);
5207
    assert_eq!("0.50", dec.to_string());
5208
5209
    let mut dec = FixedDecimal::from_str("0.40").unwrap();
5210
    dec.half_floor_to_increment(-2, RoundingIncrement::MultiplesOf25);
5211
    assert_eq!("0.50", dec.to_string());
5212
5213
    let mut dec = FixedDecimal::from_str("0.7000000099").unwrap();
5214
    dec.half_floor_to_increment(-3, RoundingIncrement::MultiplesOf2);
5215
    assert_eq!("0.700", dec.to_string());
5216
5217
    let mut dec = FixedDecimal::from_str("5").unwrap();
5218
    dec.half_floor_to_increment(0, RoundingIncrement::MultiplesOf25);
5219
    assert_eq!("0", dec.to_string());
5220
5221
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MIN);
5222
    dec.half_floor_to_increment(i16::MIN, RoundingIncrement::MultiplesOf2);
5223
    assert_eq!(FixedDecimal::from(6).multiplied_pow10(i16::MIN), dec);
5224
5225
    let mut dec = FixedDecimal::from(9).multiplied_pow10(i16::MIN);
5226
    dec.half_floor_to_increment(i16::MIN, RoundingIncrement::MultiplesOf5);
5227
    assert_eq!(FixedDecimal::from(10).multiplied_pow10(i16::MIN), dec);
5228
5229
    let mut dec = FixedDecimal::from(70).multiplied_pow10(i16::MIN);
5230
    dec.half_floor_to_increment(i16::MIN, RoundingIncrement::MultiplesOf25);
5231
    assert_eq!(FixedDecimal::from(75).multiplied_pow10(i16::MIN), dec);
5232
5233
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
5234
    dec.half_floor_to_increment(i16::MAX, RoundingIncrement::MultiplesOf2);
5235
    assert_eq!(FixedDecimal::from(6).multiplied_pow10(i16::MAX), dec);
5236
5237
    // Test Half Even
5238
    let mut dec = FixedDecimal::from(4235970).multiplied_pow10(-3);
5239
    assert_eq!("4235.970", dec.to_string());
5240
5241
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf2);
5242
    assert_eq!("4235.96", dec.to_string());
5243
5244
    dec.half_even_to_increment(-1, RoundingIncrement::MultiplesOf5);
5245
    assert_eq!("4236.0", dec.to_string());
5246
5247
    dec.half_even_to_increment(0, RoundingIncrement::MultiplesOf25);
5248
    assert_eq!("4225", dec.to_string());
5249
5250
    dec.half_even_to_increment(5, RoundingIncrement::MultiplesOf5);
5251
    assert_eq!("00000", dec.to_string());
5252
5253
    dec.half_even_to_increment(2, RoundingIncrement::MultiplesOf2);
5254
    assert_eq!("00000", dec.to_string());
5255
5256
    let mut dec = FixedDecimal::from_str("-99.999").unwrap();
5257
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf25);
5258
    assert_eq!("-100.00", dec.to_string());
5259
5260
    let mut dec = FixedDecimal::from_str("1234.56").unwrap();
5261
    dec.half_even_to_increment(-1, RoundingIncrement::MultiplesOf2);
5262
    assert_eq!("1234.6", dec.to_string());
5263
5264
    let mut dec = FixedDecimal::from_str("0.009").unwrap();
5265
    dec.half_even_to_increment(-1, RoundingIncrement::MultiplesOf5);
5266
    assert_eq!("0.0", dec.to_string());
5267
5268
    let mut dec = FixedDecimal::from_str("0.60").unwrap();
5269
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf25);
5270
    assert_eq!("0.50", dec.to_string());
5271
5272
    let mut dec = FixedDecimal::from_str("0.40").unwrap();
5273
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf25);
5274
    assert_eq!("0.50", dec.to_string());
5275
5276
    let mut dec = FixedDecimal::from_str("0.7000000099").unwrap();
5277
    dec.half_even_to_increment(-3, RoundingIncrement::MultiplesOf2);
5278
    assert_eq!("0.700", dec.to_string());
5279
5280
    let mut dec = FixedDecimal::from_str("5").unwrap();
5281
    dec.half_even_to_increment(0, RoundingIncrement::MultiplesOf25);
5282
    assert_eq!("0", dec.to_string());
5283
5284
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MIN);
5285
    dec.half_even_to_increment(i16::MIN, RoundingIncrement::MultiplesOf2);
5286
    assert_eq!(FixedDecimal::from(8).multiplied_pow10(i16::MIN), dec);
5287
5288
    let mut dec = FixedDecimal::from(9).multiplied_pow10(i16::MIN);
5289
    dec.half_even_to_increment(i16::MIN, RoundingIncrement::MultiplesOf5);
5290
    assert_eq!(FixedDecimal::from(10).multiplied_pow10(i16::MIN), dec);
5291
5292
    let mut dec = FixedDecimal::from(70).multiplied_pow10(i16::MIN);
5293
    dec.half_even_to_increment(i16::MIN, RoundingIncrement::MultiplesOf25);
5294
    assert_eq!(FixedDecimal::from(75).multiplied_pow10(i16::MIN), dec);
5295
5296
    let mut dec = FixedDecimal::from(7).multiplied_pow10(i16::MAX);
5297
    dec.half_even_to_increment(i16::MAX, RoundingIncrement::MultiplesOf2);
5298
    assert_eq!(FixedDecimal::from(8).multiplied_pow10(i16::MAX), dec);
5299
5300
    // Test specific cases
5301
    let mut dec = FixedDecimal::from_str("1.108").unwrap();
5302
    dec.expand_to_increment(-2, RoundingIncrement::MultiplesOf2);
5303
    assert_eq!("1.12", dec.to_string());
5304
5305
    let mut dec = FixedDecimal::from_str("1.108").unwrap();
5306
    dec.expand_to_increment(-2, RoundingIncrement::MultiplesOf5);
5307
    assert_eq!("1.15", dec.to_string());
5308
5309
    let mut dec = FixedDecimal::from_str("1.108").unwrap();
5310
    dec.expand_to_increment(-2, RoundingIncrement::MultiplesOf25);
5311
    assert_eq!("1.25", dec.to_string());
5312
5313
    let mut dec = FixedDecimal::from(9).multiplied_pow10(i16::MAX - 1);
5314
    dec.expand_to_increment(i16::MAX - 1, RoundingIncrement::MultiplesOf25);
5315
    assert_eq!(FixedDecimal::from(25).multiplied_pow10(i16::MAX - 1), dec);
5316
5317
    let mut dec = FixedDecimal::from(9).multiplied_pow10(i16::MAX);
5318
    dec.expand_to_increment(i16::MAX, RoundingIncrement::MultiplesOf25);
5319
    assert_eq!(FixedDecimal::from(0).multiplied_pow10(i16::MAX), dec);
5320
5321
    let mut dec = FixedDecimal::from_str("0").unwrap();
5322
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf2);
5323
    assert_eq!("0", dec.to_string());
5324
5325
    let mut dec = FixedDecimal::from_str("0").unwrap();
5326
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf5);
5327
    assert_eq!("0", dec.to_string());
5328
5329
    let mut dec = FixedDecimal::from_str("0").unwrap();
5330
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf25);
5331
    assert_eq!("0", dec.to_string());
5332
5333
    let mut dec = FixedDecimal::from_str("0.1").unwrap();
5334
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf2);
5335
    assert_eq!("2", dec.to_string());
5336
5337
    let mut dec = FixedDecimal::from_str("0.1").unwrap();
5338
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf5);
5339
    assert_eq!("5", dec.to_string());
5340
5341
    let mut dec = FixedDecimal::from_str("0.1").unwrap();
5342
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf25);
5343
    assert_eq!("25", dec.to_string());
5344
5345
    let mut dec = FixedDecimal::from_str("1").unwrap();
5346
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf2);
5347
    assert_eq!("2", dec.to_string());
5348
5349
    let mut dec = FixedDecimal::from_str("1").unwrap();
5350
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf5);
5351
    assert_eq!("5", dec.to_string());
5352
5353
    let mut dec = FixedDecimal::from_str("1").unwrap();
5354
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf25);
5355
    assert_eq!("25", dec.to_string());
5356
5357
    let mut dec = FixedDecimal::from_str("2").unwrap();
5358
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf2);
5359
    assert_eq!("2", dec.to_string());
5360
5361
    let mut dec = FixedDecimal::from_str("2").unwrap();
5362
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf5);
5363
    assert_eq!("5", dec.to_string());
5364
5365
    let mut dec = FixedDecimal::from_str("2.1").unwrap();
5366
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf2);
5367
    assert_eq!("4", dec.to_string());
5368
5369
    let mut dec = FixedDecimal::from_str("2.1").unwrap();
5370
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf5);
5371
    assert_eq!("5", dec.to_string());
5372
5373
    let mut dec = FixedDecimal::from_str("4").unwrap();
5374
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf2);
5375
    assert_eq!("4", dec.to_string());
5376
5377
    let mut dec = FixedDecimal::from_str("4").unwrap();
5378
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf5);
5379
    assert_eq!("5", dec.to_string());
5380
5381
    let mut dec = FixedDecimal::from_str("4.1").unwrap();
5382
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf2);
5383
    assert_eq!("6", dec.to_string());
5384
5385
    let mut dec = FixedDecimal::from_str("4.1").unwrap();
5386
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf5);
5387
    assert_eq!("5", dec.to_string());
5388
5389
    let mut dec = FixedDecimal::from_str("5").unwrap();
5390
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf2);
5391
    assert_eq!("6", dec.to_string());
5392
5393
    let mut dec = FixedDecimal::from_str("5").unwrap();
5394
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf5);
5395
    assert_eq!("5", dec.to_string());
5396
5397
    let mut dec = FixedDecimal::from_str("5.1").unwrap();
5398
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf2);
5399
    assert_eq!("6", dec.to_string());
5400
5401
    let mut dec = FixedDecimal::from_str("5.1").unwrap();
5402
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf5);
5403
    assert_eq!("10", dec.to_string());
5404
5405
    let mut dec = FixedDecimal::from_str("6").unwrap();
5406
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf2);
5407
    assert_eq!("6", dec.to_string());
5408
5409
    let mut dec = FixedDecimal::from_str("6").unwrap();
5410
    dec.expand_to_increment(0, RoundingIncrement::MultiplesOf5);
5411
    assert_eq!("10", dec.to_string());
5412
5413
    let mut dec = FixedDecimal::from_str("0.50").unwrap();
5414
    dec.expand_to_increment(-2, RoundingIncrement::MultiplesOf25);
5415
    assert_eq!("0.50", dec.to_string());
5416
5417
    let mut dec = FixedDecimal::from_str("1.1025").unwrap();
5418
    dec.half_trunc_to_increment(-3, RoundingIncrement::MultiplesOf5);
5419
    assert_eq!("1.100", dec.to_string());
5420
5421
    let mut dec = FixedDecimal::from_str("1.10125").unwrap();
5422
    dec.half_expand_to_increment(-4, RoundingIncrement::MultiplesOf25);
5423
    assert_eq!("1.1025", dec.to_string());
5424
5425
    let mut dec = FixedDecimal::from_str("-1.25").unwrap();
5426
    dec.half_ceil_to_increment(-1, RoundingIncrement::MultiplesOf5);
5427
    assert_eq!("-1.0", dec.to_string());
5428
5429
    let mut dec = FixedDecimal::from_str("-1.251").unwrap();
5430
    dec.half_ceil_to_increment(-1, RoundingIncrement::MultiplesOf5);
5431
    assert_eq!("-1.5", dec.to_string());
5432
5433
    let mut dec = FixedDecimal::from_str("-1.125").unwrap();
5434
    dec.half_floor_to_increment(-2, RoundingIncrement::MultiplesOf25);
5435
    assert_eq!("-1.25", dec.to_string());
5436
5437
    let mut dec = FixedDecimal::from_str("2.71").unwrap();
5438
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf2);
5439
    assert_eq!("2.72", dec.to_string());
5440
5441
    let mut dec = FixedDecimal::from_str("2.73").unwrap();
5442
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf2);
5443
    assert_eq!("2.72", dec.to_string());
5444
5445
    let mut dec = FixedDecimal::from_str("2.75").unwrap();
5446
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf2);
5447
    assert_eq!("2.76", dec.to_string());
5448
5449
    let mut dec = FixedDecimal::from_str("2.77").unwrap();
5450
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf2);
5451
    assert_eq!("2.76", dec.to_string());
5452
5453
    let mut dec = FixedDecimal::from_str("2.79").unwrap();
5454
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf2);
5455
    assert_eq!("2.80", dec.to_string());
5456
5457
    let mut dec = FixedDecimal::from_str("2.41").unwrap();
5458
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf2);
5459
    assert_eq!("2.40", dec.to_string());
5460
5461
    let mut dec = FixedDecimal::from_str("2.43").unwrap();
5462
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf2);
5463
    assert_eq!("2.44", dec.to_string());
5464
5465
    let mut dec = FixedDecimal::from_str("2.45").unwrap();
5466
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf2);
5467
    assert_eq!("2.44", dec.to_string());
5468
5469
    let mut dec = FixedDecimal::from_str("2.47").unwrap();
5470
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf2);
5471
    assert_eq!("2.48", dec.to_string());
5472
5473
    let mut dec = FixedDecimal::from_str("2.49").unwrap();
5474
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf2);
5475
    assert_eq!("2.48", dec.to_string());
5476
5477
    let mut dec = FixedDecimal::from_str("2.725").unwrap();
5478
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf5);
5479
    assert_eq!("2.70", dec.to_string());
5480
5481
    let mut dec = FixedDecimal::from_str("2.775").unwrap();
5482
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf5);
5483
    assert_eq!("2.80", dec.to_string());
5484
5485
    let mut dec = FixedDecimal::from_str("2.875").unwrap();
5486
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf25);
5487
    assert_eq!("3.00", dec.to_string());
5488
5489
    let mut dec = FixedDecimal::from_str("2.375").unwrap();
5490
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf25);
5491
    assert_eq!("2.50", dec.to_string());
5492
5493
    let mut dec = FixedDecimal::from_str("2.125").unwrap();
5494
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf25);
5495
    assert_eq!("2.00", dec.to_string());
5496
5497
    let mut dec = FixedDecimal::from_str("2.625").unwrap();
5498
    dec.half_even_to_increment(-2, RoundingIncrement::MultiplesOf25);
5499
    assert_eq!("2.50", dec.to_string());
5500
}