1#![cfg_attr(not(test), warn(missing_docs))]
3
4use std::{cmp::Ordering, io::Write, num::IntErrorKind};
35
36use smallvec::{Array, SmallVec};
37
38#[cfg(feature = "dbsp")]
39mod dbsp_impl;
40
41#[cfg(feature = "serde")]
42mod serde_impl;
43mod u256;
44
45#[cfg(feature = "rkyv")]
46mod rkyv_impl;
47
48mod dynamic;
49pub use dynamic::DynamicDecimal;
50pub use dynamic::UniformDecimal;
51
52mod fixed;
53pub use fixed::Fixed;
54
55pub type FixedInteger = Fixed<38, 0>;
57
58fn debug_decimal(value: i128, s: usize, f: &mut std::fmt::Formatter) -> std::fmt::Result {
59 let mut buf = SmallVec::<[u8; 64]>::new();
60 write!(&mut buf, "{:01$}", value.unsigned_abs(), s + 1).unwrap();
61 let d = buf.len() - s;
62 while buf.len() > d && buf.ends_with(b"0") {
63 buf.pop();
64 }
65 let s = unsafe { str::from_utf8_unchecked(&buf) };
67 let (integer, fraction) = s.split_at(d);
68 let sign = if value < 0 { "-" } else { "" };
69 write!(f, "{sign}{integer}")?;
70 if !fraction.is_empty() {
71 write!(f, ".{fraction}")?;
72 }
73 Ok(())
74}
75
76fn display_decimal(value: i128, s: usize, f: &mut std::fmt::Formatter) -> std::fmt::Result {
77 let mut buf = SmallVec::<[u8; 64]>::new();
78 write!(&mut buf, "{:01$}", value.abs(), s + 1).unwrap();
79 debug_assert!(buf.len() > s);
80 let decimals = if let Some(precision) = f.precision() {
81 match precision.cmp(&s) {
82 Ordering::Less => {
83 let new_len = buf.len() - (s - precision);
84 let mut discard = buf[new_len..].iter();
85 enum Rounding {
86 Up,
87 Down,
88 Even,
89 }
90 impl Rounding {
91 fn round<A>(&self, s: &mut SmallVec<A>)
92 where
93 A: Array<Item = u8>,
94 {
95 let round_up = match self {
96 Rounding::Down => false,
97 Rounding::Up => true,
98 Rounding::Even => s.last().unwrap() % 2 == 1,
99 };
100 if round_up {
101 let mut nines = 0;
102 let c = loop {
103 match s.pop() {
104 Some(b'9') => nines += 1,
105 Some(c) => break c,
106 None => break b'0',
107 }
108 };
109 s.push(c + 1);
110 for _ in 0..nines {
111 s.push(b'0');
112 }
113 }
114 }
115 }
116 let rounding = match discard.next().unwrap() {
117 b'0'..=b'4' => Rounding::Down,
118 b'5' => loop {
119 match discard.next() {
120 Some(b'0') => (),
121 Some(_) => break Rounding::Up,
122 None => break Rounding::Even,
123 }
124 },
125 b'6'..=b'9' => Rounding::Up,
126 _ => unreachable!(),
127 };
128 buf.truncate(new_len);
129 rounding.round(&mut buf);
130 }
131 Ordering::Equal => (),
132 Ordering::Greater => {
133 for _ in s..precision {
134 buf.push(b'0');
135 }
136 }
137 }
138 precision
139 } else {
140 let mut decimals = s;
141 while decimals > 0 && buf.ends_with(b"0") {
142 buf.pop();
143 decimals -= 1;
144 }
145 decimals
146 };
147 if decimals > 0 {
148 buf.insert(buf.len() - decimals, b'.');
149 }
150
151 f.pad_integral(value >= 0, "", unsafe { str::from_utf8_unchecked(&buf) })
153}
154
155fn parse_decimal(s: &str, scale: i32) -> Result<(i128, i32), ParseDecimalError> {
159 let mut value = 0;
162 let mut exponent = scale;
163
164 let mut saw_dot = false;
165 let mut saw_digit = false;
166
167 let mut sign = None;
168 enum Sign {
169 Positive,
170 Negative,
171 }
172
173 let mut iter = s.chars();
174 while let Some(c) = iter.next() {
175 match c {
176 '-' | '+' if sign.is_some() => return Err(ParseDecimalError::SyntaxError),
177 '-' => {
178 sign = Some(Sign::Negative);
179 }
180 '+' => {
181 sign = Some(Sign::Positive);
182 }
183 '0'..='9' => {
184 saw_digit = true;
185 if value < i128::MAX / 10 {
186 value = value * 10 + (c as u8 - b'0') as i128;
187 if saw_dot {
188 exponent -= 1;
189 }
190 } else if !saw_dot {
191 exponent = exponent
192 .checked_add(1)
193 .ok_or(ParseDecimalError::OutOfRange)?;
194 }
195 }
196 '.' => {
197 if saw_dot {
198 return Err(ParseDecimalError::SyntaxError);
199 }
200 saw_dot = true;
201 }
202 'e' | 'E' => {
203 if !saw_digit {
204 return Err(ParseDecimalError::SyntaxError);
205 }
206 let e: i32 = match iter.as_str().parse() {
207 Ok(e) => e,
208 Err(error) => {
209 return match error.kind() {
210 IntErrorKind::Zero => unreachable!(),
211 IntErrorKind::PosOverflow => {
212 if value != 0 {
213 Err(ParseDecimalError::OutOfRange)
214 } else {
215 Ok((0, 0))
216 }
217 }
218 IntErrorKind::NegOverflow => Ok((0, 0)),
219 _ => Err(ParseDecimalError::SyntaxError),
220 };
221 }
222 };
223 exponent = match exponent.checked_add(e) {
224 Some(exponent) => exponent,
225 None => {
226 if e > 0 {
227 debug_assert_ne!(value, 0);
232 return Err(ParseDecimalError::OutOfRange);
233 } else {
234 return Ok((0, 0));
235 }
236 }
237 };
238 break;
239 }
240 _ => return Err(ParseDecimalError::SyntaxError),
241 }
242 }
243 if !saw_digit {
244 return Err(ParseDecimalError::SyntaxError);
245 }
246 let value = match sign {
247 Some(Sign::Negative) => -value,
248 _ => value,
249 };
250 Ok((value, exponent))
251}
252
253#[derive(Copy, Clone, Debug, PartialEq, Eq)]
255pub enum ParseDecimalError {
256 SyntaxError,
258
259 OutOfRange,
264}
265
266impl std::fmt::Display for ParseDecimalError {
267 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
268 let message = match self {
269 ParseDecimalError::OutOfRange => "Value out of range",
270 ParseDecimalError::SyntaxError => "Syntax error in numeric value",
271 };
272 f.write_str(message)
273 }
274}
275
276#[derive(Copy, Clone, Debug, PartialEq, Eq)]
278pub struct OutOfRange;
279
280impl std::fmt::Display for OutOfRange {
281 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
282 std::fmt::Display::fmt(&"Value out of range", f)
283 }
284}
285
286const fn checked_pow10(exponent: u32) -> Option<i128> {
289 10i128.checked_pow(exponent)
290}
291
292pub const fn pow10(exponent: usize) -> i128 {
299 10i128.checked_pow(exponent as u32).unwrap()
300}
301
302#[derive(Copy, Clone, PartialEq, Eq)]
304enum Halfway {
305 AwayFromZero,
307
308 Even,
310}
311
312fn round_inner(value: i128, scale: i32, n: i32, halfway: Halfway) -> Option<i128> {
313 let position = scale.saturating_sub(n);
314 if position <= 0 {
315 Some(value)
316 } else if value.abs() < 5 * pow10(position as usize - 1) {
317 Some(0)
318 } else {
319 let divisor = pow10(position as usize);
320 let quotient = value / divisor;
321 let remainder = value % divisor;
322 let round_away_from_zero = match remainder.abs().cmp(&(divisor / 2)) {
323 Ordering::Less => false,
324 Ordering::Equal => match halfway {
325 Halfway::AwayFromZero => true,
326 Halfway::Even => (quotient % 2) != 0,
327 },
328 Ordering::Greater => true,
329 };
330 let rounded_quotient = if round_away_from_zero {
331 quotient + value.signum()
332 } else {
333 quotient
334 };
335 divisor.checked_mul(rounded_quotient)
337 }
338}
339
340const fn div_floor(x: i128, y: i128) -> i128 {
343 let d = x / y;
344 let r = x % y;
345
346 let correction = (x ^ y) >> (i128::BITS - 1);
353 if r != 0 { d + correction } else { d }
354}
355
356const fn div_ceil(x: i128, y: i128) -> i128 {
359 let d = x / y;
360 let r = x % y;
361
362 let correction = 1 + ((x ^ y) >> (i128::BITS - 1));
365 if r != 0 { d + correction } else { d }
366}
367
368fn i128_mul_pow10_round_even(value: i128, exponent: i32) -> Option<i128> {
371 Some(match exponent.cmp(&0) {
372 Ordering::Less => {
373 if let Some(divisor) = checked_pow10(exponent.unsigned_abs()) {
375 debug_assert!(divisor >= 2);
380 let quotient = value / divisor;
381 let remainder = value % divisor;
382 let round_away_from_zero = match remainder.abs().cmp(&(divisor / 2)) {
383 Ordering::Less => false,
384 Ordering::Equal => (quotient % 2) != 0,
385 Ordering::Greater => true,
386 };
387 if round_away_from_zero {
388 quotient + quotient.signum()
389 } else {
390 quotient
391 }
392 } else {
393 0
396 }
397 }
398 Ordering::Equal => value,
399 Ordering::Greater => {
400 value.checked_mul(checked_pow10(exponent.cast_unsigned())?)?
402 }
403 })
404}
405
406fn _invalid_constant_test() {}
416
417#[cfg(test)]
418mod test {
419 use crate::{DynamicDecimal, Fixed, ParseDecimalError};
420 use std::fmt::Write;
421
422 #[test]
423 fn from_str() {
424 for (s, expect) in [
425 ("0", Ok(0.0)),
426 ("0.", Ok(0.0)),
427 (".0", Ok(0.0)),
428 ("-0", Ok(-0.0)),
429 ("+0", Ok(-0.0)),
430 ("--0", Err(ParseDecimalError::SyntaxError)),
431 ("-+0", Err(ParseDecimalError::SyntaxError)),
432 ("0x", Err(ParseDecimalError::SyntaxError)),
433 ("0e5x", Err(ParseDecimalError::SyntaxError)),
434 ("1.23", Ok(1.23)),
435 ("-1.23", Ok(-1.23)),
436 ("+1.23", Ok(1.23)),
437 ("99999999", Ok(9999_9999.0)),
438 ("999999999", Err(ParseDecimalError::OutOfRange)),
439 ("999999999E-1", Ok(9999_9999.9)),
440 ("9999999999e-1", Err(ParseDecimalError::OutOfRange)),
441 ("9999999999E-2", Ok(9999_9999.99)),
442 ("99999999999e-2", Err(ParseDecimalError::OutOfRange)),
443 ("99999999999e-3", Err(ParseDecimalError::OutOfRange)),
446 ("99999999991e-3", Ok(9999_9999.99)),
448 (
452 "111111111111111111111111111111111111111111e-34",
453 Ok(1111_1111.11),
454 ),
455 (
459 "1.23456788901234567890123456789012345678890123456",
460 Ok(1.23),
461 ),
462 ("1e999999999999999", Err(ParseDecimalError::OutOfRange)),
464 ("0e999999999999999", Ok(0.0)),
466 ("1e-999999999999999", Ok(0.0)),
468 (
472 "111111111111111111111111111111111111111111e2147483644",
473 Err(ParseDecimalError::OutOfRange),
474 ),
475 (
478 ".1111111111111111111111111111111111111111e-2147483648",
479 Ok(0.0),
480 ),
481 ("123e5", Ok(12_300_000.0)),
482 ("123E4", Ok(1_230_000.0)),
483 ("123e3", Ok(123_000.0)),
484 ("123e2", Ok(12_300.0)),
485 ("123e1", Ok(1_230.0)),
486 ("123e0", Ok(123.0)),
487 ("123e-1", Ok(12.3)),
488 ("123e-2", Ok(1.23)),
489 (".123", Ok(0.12)),
490 (".124", Ok(0.12)),
491 (".125", Ok(0.12)),
492 (".126", Ok(0.13)),
493 (".133", Ok(0.13)),
494 (".134", Ok(0.13)),
495 (".135", Ok(0.14)),
496 (".136", Ok(0.14)),
497 ] {
498 println!("{s}: {:?}", s.parse::<F>());
499 assert_eq!(s.parse::<F>(), expect.map(f));
500 }
501 }
502
503 #[test]
504 fn debug() {
505 fn test<const P: usize, const S: usize>(fixed: Fixed<P, S>, expect: &str) {
506 assert_eq!(format!("{fixed:?}"), expect);
507 let dynamic = DynamicDecimal::from(fixed);
508 assert_eq!(format!("{dynamic:?}"), expect);
509 }
510 test(Fixed::<20, 7>::try_from(0).unwrap(), "0");
511 test(Fixed::<20, 7>::try_from(5).unwrap(), "5");
512 test(Fixed::<20, 7>::try_from(-5).unwrap(), "-5");
513 test(Fixed::<20, 7>::try_from(10).unwrap(), "10");
514 test(Fixed::<20, 7>::try_from(0.0001).unwrap(), "0.0001");
515 test(Fixed::<20, 7>::try_from(-0.0001).unwrap(), "-0.0001");
516 test(Fixed::<20, 7>::try_from(1.0001).unwrap(), "1.0001");
517 test(Fixed::<20, 7>::try_from(-1.0001).unwrap(), "-1.0001");
518 test(Fixed::<20, 7>::try_from(1.682501).unwrap(), "1.682501");
519 test(Fixed::<20, 4>::try_from(1.6825).unwrap(), "1.6825");
520 test(Fixed::<20, 6>::try_from(1.995670).unwrap(), "1.99567");
521 test(Fixed::<20, 6>::try_from(0.995670).unwrap(), "0.99567");
522 test(Fixed::<6, 6>::try_from(0.995670).unwrap(), "0.99567");
523
524 test(Fixed::<20, 7>::try_from(-1.682501).unwrap(), "-1.682501");
525 test(Fixed::<20, 4>::try_from(-1.6825).unwrap(), "-1.6825");
526 test(Fixed::<20, 6>::try_from(-1.995670).unwrap(), "-1.99567");
527 test(Fixed::<20, 6>::try_from(-0.995670).unwrap(), "-0.99567");
528 }
529
530 #[test]
531 fn display() {
532 fn test<const P: usize, const S: usize>(fixed: Fixed<P, S>, expect: &str) {
533 let mut s = String::new();
534 write!(&mut s, "{fixed}").unwrap();
535 for precision in 0..=S + 1 {
536 write!(&mut s, " {fixed:.0$}", precision).unwrap();
537 }
538 assert_eq!(s, expect);
539
540 let dynamic = DynamicDecimal::from(fixed);
541 let mut s = String::new();
542 write!(&mut s, "{dynamic}").unwrap();
543 for precision in 0..=S + 1 {
544 write!(&mut s, " {dynamic:.0$}", precision).unwrap();
545 }
546 assert_eq!(s, expect);
547 }
548
549 test(
550 Fixed::<20, 7>::try_from(0.0001).unwrap(),
551 "0.0001 0 0.0 0.00 0.000 0.0001 0.00010 0.000100 0.0001000 0.00010000",
552 );
553 test(
554 Fixed::<20, 7>::try_from(-0.0001).unwrap(),
555 "-0.0001 -0 -0.0 -0.00 -0.000 -0.0001 -0.00010 -0.000100 -0.0001000 -0.00010000",
556 );
557 test(
558 Fixed::<20, 7>::try_from(1.0001).unwrap(),
559 "1.0001 1 1.0 1.00 1.000 1.0001 1.00010 1.000100 1.0001000 1.00010000",
560 );
561 test(
562 Fixed::<20, 7>::try_from(-1.0001).unwrap(),
563 "-1.0001 -1 -1.0 -1.00 -1.000 -1.0001 -1.00010 -1.000100 -1.0001000 -1.00010000",
564 );
565 test(
566 Fixed::<20, 7>::try_from(1.682501).unwrap(),
567 "1.682501 2 1.7 1.68 1.683 1.6825 1.68250 1.682501 1.6825010 1.68250100",
568 );
569 test(
570 Fixed::<20, 4>::try_from(1.6825).unwrap(),
571 "1.6825 2 1.7 1.68 1.682 1.6825 1.68250",
572 );
573 test(
574 Fixed::<20, 6>::try_from(1.995670).unwrap(),
575 "1.99567 2 2.0 2.00 1.996 1.9957 1.99567 1.995670 1.9956700",
576 );
577 test(
578 Fixed::<20, 6>::try_from(0.995670).unwrap(),
579 "0.99567 1 1.0 1.00 0.996 0.9957 0.99567 0.995670 0.9956700",
580 );
581 test(
582 Fixed::<6, 6>::try_from(0.995670).unwrap(),
583 "0.99567 1 1.0 1.00 0.996 0.9957 0.99567 0.995670 0.9956700",
584 );
585
586 test(
587 Fixed::<20, 7>::try_from(-1.682501).unwrap(),
588 "-1.682501 -2 -1.7 -1.68 -1.683 -1.6825 -1.68250 -1.682501 -1.6825010 -1.68250100",
589 );
590 test(
591 Fixed::<20, 4>::try_from(-1.6825).unwrap(),
592 "-1.6825 -2 -1.7 -1.68 -1.682 -1.6825 -1.68250",
593 );
594 test(
595 Fixed::<20, 6>::try_from(-1.995670).unwrap(),
596 "-1.99567 -2 -2.0 -2.00 -1.996 -1.9957 -1.99567 -1.995670 -1.9956700",
597 );
598 test(
599 Fixed::<20, 6>::try_from(-0.995670).unwrap(),
600 "-0.99567 -1 -1.0 -1.00 -0.996 -0.9957 -0.99567 -0.995670 -0.9956700",
601 );
602 }
603
604 type F = Fixed<10, 2>;
605 fn f(n: f64) -> F {
606 Fixed::try_from(n).unwrap()
607 }
608}