1use std::fmt::Write;
2
3#[cfg(feature = "num-bigint")]
4mod num_bigint_interop;
5
6#[cfg(feature = "bigdecimal")]
7mod bigdecimal_interop;
8
9#[derive(Clone, Debug, PartialEq)]
13#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct BigInt {
15 pub(crate) negative: bool,
16 pub(crate) weight: i16,
17 pub(crate) digits: Vec<u16>,
18}
19
20#[derive(Clone, Debug, PartialEq)]
24#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
25pub struct Decimal {
26 pub(crate) negative: bool,
27 pub(crate) weight: i16,
28 pub(crate) decimal_digits: u16,
29 pub(crate) digits: Vec<u16>,
30}
31
32impl BigInt {
33 pub fn negative(&self) -> bool {
34 self.negative
35 }
36
37 pub fn weight(&self) -> i16 {
38 self.weight
39 }
40
41 pub fn digits(&self) -> &[u16] {
42 &self.digits
43 }
44
45 fn normalize(mut self) -> BigInt {
46 while let Some(0) = self.digits.last() {
47 self.digits.pop();
48 }
49 while let Some(0) = self.digits.first() {
50 self.digits.remove(0);
51 self.weight -= 1;
52 }
53 self
54 }
55
56 fn trailing_zero_groups(&self) -> i16 {
57 self.weight - self.digits.len() as i16 + 1
58 }
59}
60
61impl std::fmt::Display for BigInt {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 if self.negative {
64 write!(f, "-")?;
65 }
66 if let Some(digit) = self.digits.first() {
67 write!(f, "{digit}")?;
68 for digit in &mut self.digits.iter().skip(1) {
69 write!(f, "{digit:04}")?;
70 }
71 let trailing_zero_groups = self.trailing_zero_groups();
72 debug_assert!(trailing_zero_groups >= 0);
73 for _ in 0..trailing_zero_groups {
74 write!(f, "0000")?;
75 }
76 } else {
77 write!(f, "0")?;
78 }
79 Ok(())
80 }
81}
82
83impl From<u64> for BigInt {
84 fn from(v: u64) -> BigInt {
85 BigInt {
86 negative: false,
87 weight: 4,
88 digits: vec![
89 (v / 10_000_000_000_000_000 % 10000) as u16,
90 (v / 1_000_000_000_000 % 10000) as u16,
91 (v / 100_000_000 % 10000) as u16,
92 (v / 10000 % 10000) as u16,
93 (v % 10000) as u16,
94 ],
95 }
96 .normalize()
97 }
98}
99
100impl From<i64> for BigInt {
101 fn from(v: i64) -> BigInt {
102 let (abs, negative) = if v < 0 {
103 (u64::MAX - v as u64 + 1, true)
104 } else {
105 (v as u64, false)
106 };
107 BigInt {
108 negative,
109 weight: 4,
110 digits: vec![
111 (abs / 10_000_000_000_000_000 % 10000) as u16,
112 (abs / 1_000_000_000_000 % 10000) as u16,
113 (abs / 100_000_000 % 10000) as u16,
114 (abs / 10000 % 10000) as u16,
115 (abs % 10000) as u16,
116 ],
117 }
118 .normalize()
119 }
120}
121
122impl From<u32> for BigInt {
123 fn from(v: u32) -> BigInt {
124 BigInt {
125 negative: false,
126 weight: 2,
127 digits: vec![
128 (v / 100_000_000) as u16,
129 (v / 10000 % 10000) as u16,
130 (v % 10000) as u16,
131 ],
132 }
133 .normalize()
134 }
135}
136
137impl From<i32> for BigInt {
138 fn from(v: i32) -> BigInt {
139 let (abs, negative) = if v < 0 {
140 (u32::MAX - v as u32 + 1, true)
141 } else {
142 (v as u32, false)
143 };
144 BigInt {
145 negative,
146 weight: 2,
147 digits: vec![
148 (abs / 100_000_000) as u16,
149 (abs / 10000 % 10000) as u16,
150 (abs % 10000) as u16,
151 ],
152 }
153 .normalize()
154 }
155}
156
157impl Decimal {
158 pub fn negative(&self) -> bool {
159 self.negative
160 }
161
162 pub fn weight(&self) -> i16 {
163 self.weight
164 }
165
166 pub fn decimal_digits(&self) -> u16 {
167 self.decimal_digits
168 }
169
170 pub fn digits(&self) -> &[u16] {
171 &self.digits
172 }
173
174 #[allow(dead_code)] fn normalize(mut self) -> Decimal {
176 while let Some(0) = self.digits.last() {
177 self.digits.pop();
178 }
179 while let Some(0) = self.digits.first() {
180 self.digits.remove(0);
181 self.weight -= 1;
182 }
183 self
184 }
185}
186
187impl std::fmt::Display for Decimal {
188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189 if self.negative {
190 write!(f, "-")?;
191 }
192
193 let mut index = 0;
194
195 while self.weight - index >= 0 {
197 if let Some(digit) = self.digits.get(index as usize) {
198 if index == 0 {
199 write!(f, "{digit}")?;
200 } else {
201 write!(f, "{digit:04}")?;
202 }
203 index += 1;
204 } else {
205 break;
206 }
207 }
208
209 for _ in 0..(self.weight - index + 1) {
211 f.write_str("0000")?;
212 }
213
214 if index == 0 {
215 write!(f, "0")?;
216 }
217
218 write!(f, ".")?;
220
221 let mut decimals = u16::max(self.decimal_digits, 1);
223 if index == 0 && self.weight < 0 {
224 for _ in 0..(-1 - self.weight) {
225 f.write_str("0000")?;
226 decimals -= 4;
227 }
228 }
229
230 while decimals > 0 {
231 if let Some(digit) = self.digits.get(index as usize) {
232 let digit = format!("{digit:04}");
233 let consumed = u16::min(4, decimals);
234 f.write_str(&digit[0..consumed as usize])?;
235 decimals -= consumed;
236 index += 1;
237 } else {
238 break;
239 }
240 }
241 for _ in 0..decimals {
243 f.write_char('0')?;
244 }
245 Ok(())
246 }
247}
248
249#[cfg(test)]
250#[allow(dead_code)] mod test_helpers {
252 use rand::Rng;
253
254 pub fn gen_u64<T: Rng>(rng: &mut T) -> u64 {
255 let max = 10_u64.pow(rng.random_range(0..20));
257 rng.random_range(0..max)
258 }
259
260 pub fn gen_i64<T: Rng>(rng: &mut T) -> i64 {
261 let max = 10_i64.pow(rng.random_range(0..19));
263 rng.random_range(-max..max)
264 }
265
266 pub fn gen_f64<T: Rng>(rng: &mut T) -> f64 {
267 rng.random::<f64>()
268 }
269}
270
271#[cfg(test)]
272#[allow(unused_imports)] mod test {
274 use super::{BigInt, Decimal};
275 use std::convert::TryFrom;
276 use std::str::FromStr;
277
278 #[test]
279 fn big_int_conversion() {
280 assert_eq!(BigInt::from(125u32).weight, 0);
281 assert_eq!(&BigInt::from(125u32).digits, &[125]);
282 assert_eq!(BigInt::from(30000u32).weight, 1);
283 assert_eq!(&BigInt::from(30000u32).digits, &[3]);
284 assert_eq!(BigInt::from(30001u32).weight, 1);
285 assert_eq!(&BigInt::from(30001u32).digits, &[3, 1]);
286 assert_eq!(BigInt::from(u32::MAX).weight, 2);
287 assert_eq!(BigInt::from(u32::MAX).digits, &[42, 9496, 7295]);
288
289 assert_eq!(BigInt::from(125i32).weight, 0);
290 assert_eq!(&BigInt::from(125i32).digits, &[125]);
291 assert_eq!(BigInt::from(30000i32).weight, 1);
292 assert_eq!(&BigInt::from(30000i32).digits, &[3]);
293 assert_eq!(BigInt::from(30001i32).weight, 1);
294 assert_eq!(&BigInt::from(30001i32).digits, &[3, 1]);
295 assert_eq!(BigInt::from(i32::MAX).weight, 2);
296 assert_eq!(BigInt::from(i32::MAX).digits, &[21, 4748, 3647]);
297
298 assert_eq!(BigInt::from(-125i32).weight, 0);
299 assert_eq!(&BigInt::from(-125i32).digits, &[125]);
300 assert_eq!(BigInt::from(-30000i32).weight, 1);
301 assert_eq!(&BigInt::from(-30000i32).digits, &[3]);
302 assert_eq!(BigInt::from(-30001i32).weight, 1);
303 assert_eq!(&BigInt::from(-30001i32).digits, &[3, 1]);
304 assert_eq!(BigInt::from(i32::MIN).weight, 2);
305 assert_eq!(BigInt::from(i32::MIN).digits, &[21, 4748, 3648]);
306
307 assert_eq!(BigInt::from(125u64).weight, 0);
308 assert_eq!(&BigInt::from(125u64).digits, &[125]);
309 assert_eq!(BigInt::from(30000u64).weight, 1);
310 assert_eq!(&BigInt::from(30000u64).digits, &[3]);
311 assert_eq!(BigInt::from(30001u64).weight, 1);
312 assert_eq!(&BigInt::from(30001u64).digits, &[3, 1]);
313 assert_eq!(BigInt::from(u64::MAX).weight, 4);
314 assert_eq!(BigInt::from(u64::MAX).digits, &[1844, 6744, 737, 955, 1615]);
315
316 assert_eq!(BigInt::from(125i64).weight, 0);
317 assert_eq!(&BigInt::from(125i64).digits, &[125]);
318 assert_eq!(BigInt::from(30000i64).weight, 1);
319 assert_eq!(&BigInt::from(30000i64).digits, &[3]);
320 assert_eq!(BigInt::from(30001i64).weight, 1);
321 assert_eq!(&BigInt::from(30001i64).digits, &[3, 1]);
322 assert_eq!(BigInt::from(i64::MAX).weight, 4);
323 assert_eq!(BigInt::from(i64::MAX).digits, &[922, 3372, 368, 5477, 5807]);
324
325 assert_eq!(BigInt::from(-125i64).weight, 0);
326 assert_eq!(&BigInt::from(-125i64).digits, &[125]);
327 assert_eq!(BigInt::from(-30000i64).weight, 1);
328 assert_eq!(&BigInt::from(-30000i64).digits, &[3]);
329 assert_eq!(BigInt::from(-30001i64).weight, 1);
330 assert_eq!(&BigInt::from(-30001i64).digits, &[3, 1]);
331 assert_eq!(BigInt::from(i64::MIN).weight, 4);
332 assert_eq!(BigInt::from(i64::MIN).digits, &[922, 3372, 368, 5477, 5808]);
333 }
334
335 #[test]
336 fn bigint_display() {
337 let cases = [0, 1, -1, 1_0000, -1_0000, 1_2345_6789, i64::MAX, i64::MIN];
338 for i in cases.iter() {
339 assert_eq!(BigInt::from(*i).to_string(), i.to_string());
340 }
341 }
342
343 #[test]
344 fn bigint_display_rand() {
345 use rand::{rngs::StdRng, Rng, SeedableRng};
346 let mut rng = StdRng::seed_from_u64(4);
347 for _ in 0..1000 {
348 let i = super::test_helpers::gen_i64(&mut rng);
349 assert_eq!(BigInt::from(i).to_string(), i.to_string());
350 }
351 }
352
353 #[test]
354 fn decimal_display() {
355 assert_eq!(
356 Decimal {
357 negative: false,
358 weight: 0,
359 decimal_digits: 0,
360 digits: vec![42],
361 }
362 .to_string(),
363 "42.0"
364 );
365
366 assert_eq!(
367 Decimal {
368 negative: false,
369 weight: 0,
370 decimal_digits: 10,
371 digits: vec![42],
372 }
373 .to_string(),
374 "42.0000000000"
375 );
376
377 assert_eq!(
378 Decimal {
379 negative: true,
380 weight: 0,
381 decimal_digits: 1,
382 digits: vec![42],
383 }
384 .to_string(),
385 "-42.0"
386 );
387
388 assert_eq!(
389 Decimal {
390 negative: false,
391 weight: 1,
392 decimal_digits: 10,
393 digits: vec![42],
394 }
395 .to_string(),
396 "420000.0000000000"
397 );
398
399 assert_eq!(
400 Decimal {
401 negative: false,
402 weight: -2,
403 decimal_digits: 10,
404 digits: vec![42],
405 }
406 .to_string(),
407 "0.0000004200"
408 );
409
410 assert_eq!(
411 Decimal {
412 negative: false,
413 weight: -6,
414 decimal_digits: 21,
415 digits: vec![1000],
416 }
417 .to_string(),
418 "0.000000000000000000001"
419 );
420 }
421}