1#![allow(clippy::arithmetic_side_effects)]
2use crate::uint::U256;
5
6type InnerUint = U256;
8
9pub const ONE: u128 = 1_000_000_000_000;
11
12#[derive(Clone, Debug, PartialEq)]
15pub struct PreciseNumber {
16 pub value: InnerUint,
18}
19
20fn one() -> InnerUint {
22 InnerUint::from(ONE)
23}
24
25fn zero() -> InnerUint {
27 InnerUint::from(0)
28}
29
30impl PreciseNumber {
31 fn rounding_correction() -> InnerUint {
35 InnerUint::from(ONE / 2)
36 }
37
38 fn precision() -> InnerUint {
43 InnerUint::from(100)
44 }
45
46 fn zero() -> Self {
47 Self { value: zero() }
48 }
49
50 fn one() -> Self {
51 Self { value: one() }
52 }
53
54 const MAX_APPROXIMATION_ITERATIONS: u128 = 100;
56
57 fn min_pow_base() -> InnerUint {
60 InnerUint::from(1)
61 }
62
63 fn max_pow_base() -> InnerUint {
69 InnerUint::from(2 * ONE)
70 }
71
72 pub fn new(value: u128) -> Option<Self> {
74 let value = InnerUint::from(value).checked_mul(one())?;
75 Some(Self { value })
76 }
77
78 pub fn to_imprecise(&self) -> Option<u128> {
80 self.value
81 .checked_add(Self::rounding_correction())?
82 .checked_div(one())
83 .map(|v| v.as_u128())
84 }
85
86 pub fn almost_eq(&self, rhs: &Self, precision: InnerUint) -> bool {
88 let (difference, _) = self.unsigned_sub(rhs);
89 difference.value < precision
90 }
91
92 pub fn less_than(&self, rhs: &Self) -> bool {
94 self.value < rhs.value
95 }
96
97 pub fn greater_than(&self, rhs: &Self) -> bool {
99 self.value > rhs.value
100 }
101
102 pub fn less_than_or_equal(&self, rhs: &Self) -> bool {
104 self.value <= rhs.value
105 }
106
107 pub fn greater_than_or_equal(&self, rhs: &Self) -> bool {
109 self.value >= rhs.value
110 }
111
112 pub fn floor(&self) -> Option<Self> {
114 let value = self.value.checked_div(one())?.checked_mul(one())?;
115 Some(Self { value })
116 }
117
118 pub fn ceiling(&self) -> Option<Self> {
120 let value = self
121 .value
122 .checked_add(one().checked_sub(InnerUint::from(1))?)?
123 .checked_div(one())?
124 .checked_mul(one())?;
125 Some(Self { value })
126 }
127
128 pub fn checked_div(&self, rhs: &Self) -> Option<Self> {
130 if *rhs == Self::zero() {
131 return None;
132 }
133 match self.value.checked_mul(one()) {
134 Some(v) => {
135 let value = v
136 .checked_add(Self::rounding_correction())?
137 .checked_div(rhs.value)?;
138 Some(Self { value })
139 }
140 None => {
141 let value = self
142 .value
143 .checked_add(Self::rounding_correction())?
144 .checked_div(rhs.value)?
145 .checked_mul(one())?;
146 Some(Self { value })
147 }
148 }
149 }
150
151 pub fn checked_mul(&self, rhs: &Self) -> Option<Self> {
153 match self.value.checked_mul(rhs.value) {
154 Some(v) => {
155 let value = v
156 .checked_add(Self::rounding_correction())?
157 .checked_div(one())?;
158 Some(Self { value })
159 }
160 None => {
161 let value = if self.value >= rhs.value {
162 self.value.checked_div(one())?.checked_mul(rhs.value)?
163 } else {
164 rhs.value.checked_div(one())?.checked_mul(self.value)?
165 };
166 Some(Self { value })
167 }
168 }
169 }
170
171 pub fn checked_add(&self, rhs: &Self) -> Option<Self> {
173 let value = self.value.checked_add(rhs.value)?;
174 Some(Self { value })
175 }
176
177 pub fn checked_sub(&self, rhs: &Self) -> Option<Self> {
179 let value = self.value.checked_sub(rhs.value)?;
180 Some(Self { value })
181 }
182
183 pub fn unsigned_sub(&self, rhs: &Self) -> (Self, bool) {
186 match self.value.checked_sub(rhs.value) {
187 None => {
188 let value = rhs.value.checked_sub(self.value).unwrap();
189 (Self { value }, true)
190 }
191 Some(value) => (Self { value }, false),
192 }
193 }
194
195 pub fn checked_pow(&self, exponent: u128) -> Option<Self> {
197 let value = if exponent.checked_rem(2)? == 0 {
200 one()
201 } else {
202 self.value
203 };
204 let mut result = Self { value };
205
206 let mut squared_base = self.clone();
210 let mut current_exponent = exponent.checked_div(2)?;
211 while current_exponent != 0 {
212 squared_base = squared_base.checked_mul(&squared_base)?;
213
214 if current_exponent.checked_rem(2)? != 0 {
216 result = result.checked_mul(&squared_base)?;
217 }
218
219 current_exponent = current_exponent.checked_div(2)?;
220 }
221 Some(result)
222 }
223
224 fn checked_pow_approximation(&self, exponent: &Self, max_iterations: u128) -> Option<Self> {
243 assert!(self.value >= Self::min_pow_base());
244 assert!(self.value <= Self::max_pow_base());
245 let one = Self::one();
246 if *exponent == Self::zero() {
247 return Some(one);
248 }
249 let mut precise_guess = one.clone();
250 let mut term = precise_guess.clone();
251 let (x_minus_a, x_minus_a_negative) = self.unsigned_sub(&precise_guess);
252 let exponent_plus_one = exponent.checked_add(&one)?;
253 let mut negative = false;
254 for k in 1..max_iterations {
255 let k = Self::new(k)?;
256 let (current_exponent, current_exponent_negative) = exponent_plus_one.unsigned_sub(&k);
257 term = term.checked_mul(¤t_exponent)?;
258 term = term.checked_mul(&x_minus_a)?;
259 term = term.checked_div(&k)?;
260 if term.value < Self::precision() {
261 break;
262 }
263 if x_minus_a_negative {
264 negative = !negative;
265 }
266 if current_exponent_negative {
267 negative = !negative;
268 }
269 if negative {
270 precise_guess = precise_guess.checked_sub(&term)?;
271 } else {
272 precise_guess = precise_guess.checked_add(&term)?;
273 }
274 }
275 Some(precise_guess)
276 }
277
278 #[allow(dead_code)]
283 fn checked_pow_fraction(&self, exponent: &Self) -> Option<Self> {
284 assert!(self.value >= Self::min_pow_base());
285 assert!(self.value <= Self::max_pow_base());
286 let whole_exponent = exponent.floor()?;
287 let precise_whole = self.checked_pow(whole_exponent.to_imprecise()?)?;
288 let (remainder_exponent, negative) = exponent.unsigned_sub(&whole_exponent);
289 assert!(!negative);
290 if remainder_exponent.value == InnerUint::from(0) {
291 return Some(precise_whole);
292 }
293 let precise_remainder = self
294 .checked_pow_approximation(&remainder_exponent, Self::MAX_APPROXIMATION_ITERATIONS)?;
295 precise_whole.checked_mul(&precise_remainder)
296 }
297
298 fn newtonian_root_approximation(
303 &self,
304 root: &Self,
305 mut guess: Self,
306 iterations: u128,
307 ) -> Option<Self> {
308 let zero = Self::zero();
309 if *self == zero {
310 return Some(zero);
311 }
312 if *root == zero {
313 return None;
314 }
315 let one = Self::new(1)?;
316 let root_minus_one = root.checked_sub(&one)?;
317 let root_minus_one_whole = root_minus_one.to_imprecise()?;
318 let mut last_guess = guess.clone();
319 let precision = Self::precision();
320 for _ in 0..iterations {
321 let first_term = root_minus_one.checked_mul(&guess)?;
323 let power = guess.checked_pow(root_minus_one_whole);
324 let second_term = match power {
325 Some(num) => self.checked_div(&num)?,
326 None => Self::new(0)?,
327 };
328 guess = first_term.checked_add(&second_term)?.checked_div(root)?;
329 if last_guess.almost_eq(&guess, precision) {
330 break;
331 } else {
332 last_guess = guess.clone();
333 }
334 }
335 Some(guess)
336 }
337
338 fn minimum_sqrt_base() -> Self {
341 Self {
342 value: InnerUint::from(0),
343 }
344 }
345
346 fn maximum_sqrt_base() -> Self {
349 Self::new(u128::MAX).unwrap()
350 }
351
352 pub fn sqrt(&self) -> Option<Self> {
356 if self.less_than(&Self::minimum_sqrt_base())
357 || self.greater_than(&Self::maximum_sqrt_base())
358 {
359 return None;
360 }
361 let two = PreciseNumber::new(2)?;
362 let one = PreciseNumber::new(1)?;
363 let guess = self.checked_add(&one)?.checked_div(&two)?;
366 self.newtonian_root_approximation(&two, guess, Self::MAX_APPROXIMATION_ITERATIONS)
367 }
368}
369
370#[cfg(test)]
371mod tests {
372 use {super::*, proptest::prelude::*};
373
374 fn check_pow_approximation(base: InnerUint, exponent: InnerUint, expected: InnerUint) {
375 let precision = InnerUint::from(5_000_000); let base = PreciseNumber { value: base };
377 let exponent = PreciseNumber { value: exponent };
378 let root = base
379 .checked_pow_approximation(&exponent, PreciseNumber::MAX_APPROXIMATION_ITERATIONS)
380 .unwrap();
381 let expected = PreciseNumber { value: expected };
382 assert!(root.almost_eq(&expected, precision));
383 }
384
385 #[test]
386 fn test_root_approximation() {
387 let one = one();
388 check_pow_approximation(one / 4, one / 2, one / 2); check_pow_approximation(one * 11 / 10, one / 2, InnerUint::from(1_048808848161u128)); check_pow_approximation(one * 4 / 5, one * 2 / 5, InnerUint::from(914610103850u128));
394 check_pow_approximation(one / 2, one * 4 / 50, InnerUint::from(946057646730u128));
398 }
400
401 fn check_pow_fraction(
402 base: InnerUint,
403 exponent: InnerUint,
404 expected: InnerUint,
405 precision: InnerUint,
406 ) {
407 let base = PreciseNumber { value: base };
408 let exponent = PreciseNumber { value: exponent };
409 let power = base.checked_pow_fraction(&exponent).unwrap();
410 let expected = PreciseNumber { value: expected };
411 assert!(power.almost_eq(&expected, precision));
412 }
413
414 #[test]
415 fn test_pow_fraction() {
416 let one = one();
417 let precision = InnerUint::from(50_000_000); let less_precision = precision * 1_000; check_pow_fraction(one, one, one, precision);
420 check_pow_fraction(
421 one * 20 / 13,
422 one * 50 / 3,
423 InnerUint::from(1312_534484739100u128),
424 precision,
425 ); check_pow_fraction(one * 2 / 7, one * 49 / 4, InnerUint::from(2163), precision);
427 check_pow_fraction(
428 one * 5000 / 5100,
429 one / 9,
430 InnerUint::from(997802126900u128),
431 precision,
432 ); check_pow_fraction(
436 one * 2,
437 one * 27 / 5,
438 InnerUint::from(42_224253144700u128),
439 less_precision,
440 ); check_pow_fraction(
442 one * 18 / 10,
443 one * 11 / 3,
444 InnerUint::from(8_629769290500u128),
445 less_precision,
446 ); }
448
449 #[test]
450 fn test_newtonian_approximation() {
451 let test = PreciseNumber::new(0).unwrap();
452 let nth_root = PreciseNumber::new(0).unwrap();
453 let guess = test.checked_div(&nth_root);
454 assert_eq!(guess, Option::None);
455
456 let test = PreciseNumber::new(9).unwrap();
458 let nth_root = PreciseNumber::new(2).unwrap();
459 let guess = test.checked_div(&nth_root).unwrap();
460 let root = test
461 .newtonian_root_approximation(
462 &nth_root,
463 guess,
464 PreciseNumber::MAX_APPROXIMATION_ITERATIONS,
465 )
466 .unwrap()
467 .to_imprecise()
468 .unwrap();
469 assert_eq!(root, 3); let test = PreciseNumber::new(101).unwrap();
472 let nth_root = PreciseNumber::new(2).unwrap();
473 let guess = test.checked_div(&nth_root).unwrap();
474 let root = test
475 .newtonian_root_approximation(
476 &nth_root,
477 guess,
478 PreciseNumber::MAX_APPROXIMATION_ITERATIONS,
479 )
480 .unwrap()
481 .to_imprecise()
482 .unwrap();
483 assert_eq!(root, 10); let test = PreciseNumber::new(1_000_000_000).unwrap();
486 let nth_root = PreciseNumber::new(2).unwrap();
487 let guess = test.checked_div(&nth_root).unwrap();
488 let root = test
489 .newtonian_root_approximation(
490 &nth_root,
491 guess,
492 PreciseNumber::MAX_APPROXIMATION_ITERATIONS,
493 )
494 .unwrap()
495 .to_imprecise()
496 .unwrap();
497 assert_eq!(root, 31_623); let test = PreciseNumber::new(500).unwrap();
501 let nth_root = PreciseNumber::new(5).unwrap();
502 let guess = test.checked_div(&nth_root).unwrap();
503 let root = test
504 .newtonian_root_approximation(
505 &nth_root,
506 guess,
507 PreciseNumber::MAX_APPROXIMATION_ITERATIONS,
508 )
509 .unwrap()
510 .to_imprecise()
511 .unwrap();
512 assert_eq!(root, 3); }
514
515 #[test]
516 fn test_checked_mul() {
517 let number_one = PreciseNumber::new(0).unwrap();
518 let number_two = PreciseNumber::new(0).unwrap();
519 let result = number_one.checked_mul(&number_two);
520 assert_eq!(
521 result,
522 Option::Some(PreciseNumber {
523 value: U256::from(0)
524 })
525 );
526
527 let number_one = PreciseNumber::new(2).unwrap();
528 let number_two = PreciseNumber::new(2).unwrap();
529 let result = number_one.checked_mul(&number_two).unwrap();
530 assert_eq!(result, PreciseNumber::new(2 * 2).unwrap());
531
532 let number_one = PreciseNumber { value: U256::MAX };
533 let number_two = PreciseNumber::new(1).unwrap();
534 let result = number_one.checked_mul(&number_two).unwrap();
535 assert_eq!(result.value, U256::MAX / one() * one());
536
537 let number_one = PreciseNumber { value: U256::MAX };
538 let mut number_two = PreciseNumber::new(1).unwrap();
539 number_two.value += U256::from(1);
540 let result = number_one.checked_mul(&number_two);
541 assert_eq!(result, Option::None);
542 }
543
544 fn check_square_root(check: &PreciseNumber) {
545 let epsilon = PreciseNumber {
546 value: InnerUint::from(10),
547 }; let one = PreciseNumber::one();
549 let one_plus_epsilon = one.checked_add(&epsilon).unwrap();
550 let one_minus_epsilon = one.checked_sub(&epsilon).unwrap();
551 let approximate_root = check.sqrt().unwrap();
552 let lower_bound = approximate_root
553 .checked_mul(&one_minus_epsilon)
554 .unwrap()
555 .checked_pow(2)
556 .unwrap();
557 let upper_bound = approximate_root
558 .checked_mul(&one_plus_epsilon)
559 .unwrap()
560 .checked_pow(2)
561 .unwrap();
562 assert!(check.less_than_or_equal(&upper_bound));
563 assert!(check.greater_than_or_equal(&lower_bound));
564 }
565
566 #[test]
567 fn test_square_root_min_max() {
568 let test_roots = [
569 PreciseNumber::minimum_sqrt_base(),
570 PreciseNumber::maximum_sqrt_base(),
571 ];
572 for i in test_roots.iter() {
573 check_square_root(i);
574 }
575 }
576
577 #[test]
578 fn test_floor() {
579 let whole_number = PreciseNumber::new(2).unwrap();
580 let mut decimal_number = PreciseNumber::new(2).unwrap();
581 decimal_number.value += InnerUint::from(1);
582 let floor = decimal_number.floor().unwrap();
583 let floor_again = floor.floor().unwrap();
584 assert_eq!(whole_number.value, floor.value);
585 assert_eq!(whole_number.value, floor_again.value);
586 }
587
588 #[test]
589 fn test_ceiling() {
590 let whole_number = PreciseNumber::new(2).unwrap();
591 let mut decimal_number = PreciseNumber::new(2).unwrap();
592 decimal_number.value -= InnerUint::from(1);
593 let ceiling = decimal_number.ceiling().unwrap();
594 let ceiling_again = ceiling.ceiling().unwrap();
595 assert_eq!(whole_number.value, ceiling.value);
596 assert_eq!(whole_number.value, ceiling_again.value);
597 }
598
599 proptest! {
600 #[test]
601 fn test_square_root(a in 0..u128::MAX) {
602 let a = PreciseNumber { value: InnerUint::from(a) };
603 check_square_root(&a);
604 }
605 }
606}