1use std::{
4 iter::Sum,
5 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign},
6};
7
8use bytemuck::{Pod, Zeroable};
9use std::fmt::{Display, Formatter};
10use thiserror::Error;
11use uint::construct_uint;
12
13construct_uint! {
14 #[derive(Pod, Zeroable)]
15 pub struct U192(3);
16}
17
18pub const BPS_EXPONENT: i32 = -4;
19const PRECISION: i32 = 15;
20const ONE: U192 = U192([1_000_000_000_000_000, 0, 0]);
21const U64_MAX: U192 = U192([0xffffffffffffffff, 0x0, 0x0]);
22
23#[derive(Pod, Zeroable, Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
25#[repr(transparent)]
26pub struct Number(U192);
27
28static_assertions::const_assert_eq!(24, std::mem::size_of::<Number>());
29static_assertions::const_assert_eq!(0, std::mem::size_of::<Number>() % 8);
30impl Number {
31 pub const ONE: Number = Number(ONE);
32 pub const ZERO: Number = Number(U192::zero());
33
34 pub fn as_u64(&self, exponent: impl Into<i32>) -> u64 {
39 let extra_precision = PRECISION + exponent.into();
40 let prec_value = Self::ten_pow(extra_precision.abs() as u32);
41
42 let target_value = if extra_precision < 0 {
43 self.0 * prec_value
44 } else {
45 self.0 / prec_value
46 };
47
48 if target_value > U64_MAX {
49 panic!("cannot convert to u64 due to overflow");
50 }
51
52 target_value.as_u64()
53 }
54
55 pub fn as_u64_ceil(&self, exponent: impl Into<i32>) -> u64 {
63 let extra_precision = PRECISION + exponent.into();
64 let prec_value = Self::ten_pow(extra_precision.abs() as u32);
65
66 let target_rounded = prec_value - U192::from(1) + self.0;
67 let target_value = if extra_precision < 0 {
68 target_rounded * prec_value
69 } else {
70 target_rounded / prec_value
71 };
72
73 if target_value > U64_MAX {
74 panic!("cannot convert to u64 due to overflow");
75 }
76
77 target_value.as_u64()
78 }
79
80 pub fn as_u64_rounded(&self, exponent: impl Into<i32>) -> u64 {
88 let extra_precision = PRECISION + exponent.into();
89 let prec_value = Self::ten_pow(extra_precision.abs() as u32);
90
91 let rounding = match extra_precision > 0 {
92 true => U192::from(1) * prec_value / 2,
93 false => U192::zero(),
94 };
95
96 let target_rounded = rounding + self.0;
97 let target_value = if extra_precision < 0 {
98 target_rounded * prec_value
99 } else {
100 target_rounded / prec_value
101 };
102
103 if target_value > U64_MAX {
104 panic!("cannot convert to u64 due to overflow");
105 }
106
107 target_value.as_u64()
108 }
109
110 pub fn from_decimal(value: impl Into<U192>, exponent: impl Into<i32>) -> Self {
112 let extra_precision = PRECISION + exponent.into();
113 let prec_value = Self::ten_pow(extra_precision.abs() as u32);
114
115 if extra_precision < 0 {
116 Self(value.into() / prec_value)
117 } else {
118 Self(value.into() * prec_value)
119 }
120 }
121
122 pub fn from_bps(basis_points: u16) -> Number {
124 Number::from_decimal(basis_points, BPS_EXPONENT)
125 }
126
127 pub fn pow(&self, exp: impl Into<Number>) -> Number {
128 let value = self.0.pow(exp.into().0);
129
130 Self(value)
131 }
132
133 pub fn saturating_add(&self, n: Number) -> Number {
134 Number(self.0.saturating_add(n.0))
135 }
136
137 pub fn saturating_sub(&self, n: Number) -> Number {
138 Number(self.0.saturating_sub(n.0))
139 }
140
141 pub fn saturating_mul(&self, n: Number) -> Number {
142 Number(self.0.saturating_mul(n.0))
143 }
144
145 pub fn ten_pow(exponent: u32) -> U192 {
146 let value: u64 = match exponent {
147 16 => 10_000_000_000_000_000,
148 15 => 1_000_000_000_000_000,
149 14 => 100_000_000_000_000,
150 13 => 10_000_000_000_000,
151 12 => 1_000_000_000_000,
152 11 => 100_000_000_000,
153 10 => 10_000_000_000,
154 9 => 1_000_000_000,
155 8 => 100_000_000,
156 7 => 10_000_000,
157 6 => 1_000_000,
158 5 => 100_000,
159 4 => 10_000,
160 3 => 1_000,
161 2 => 100,
162 1 => 10,
163 0 => 1,
164 _ => panic!("no support for exponent: {}", exponent),
165 };
166
167 value.into()
168 }
169
170 pub fn into_bits(self) -> [u8; 24] {
172 unsafe { std::mem::transmute(self.0 .0) }
173 }
174
175 pub fn from_bits(bits: [u8; 24]) -> Self {
178 Self(U192(unsafe { std::mem::transmute(bits) }))
179 }
180}
181
182impl<T: Into<U192>> From<T> for Number {
183 fn from(n: T) -> Number {
184 Number(n.into() * ONE)
185 }
186}
187
188impl From<Number> for [u8; 24] {
189 fn from(n: Number) -> Self {
190 n.0.into()
191 }
192}
193
194impl Display for Number {
195 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
196 let rem = self.0 % ONE;
198 let decimal_digits = PRECISION as usize;
199 let rem_str = rem.to_string();
200 let decimals = "0".repeat(decimal_digits - rem_str.len()) + &*rem_str;
202 let stripped_decimals = decimals.trim_end_matches('0');
203 let pretty_decimals = if stripped_decimals.is_empty() {
204 "0"
205 } else {
206 stripped_decimals
207 };
208 if self.0 < ONE {
209 write!(f, "0.{}", pretty_decimals)?;
210 } else {
211 let int = self.0 / ONE;
212 write!(f, "{}.{}", int, pretty_decimals)?;
213 }
214 Ok(())
215 }
216}
217
218#[derive(Error, Debug, Clone, Eq, PartialEq)]
219pub enum Error {
220 #[error("An integer value overflowed")]
221 Overflow(Number),
222
223 #[error("Attempting to divide by zero")]
224 DivideByZero,
225}
226
227impl Add<Number> for Number {
228 type Output = Number;
229
230 fn add(self, rhs: Number) -> Self::Output {
231 Self(self.0.add(rhs.0))
232 }
233}
234
235impl AddAssign<Number> for Number {
236 fn add_assign(&mut self, rhs: Number) {
237 self.0.add_assign(rhs.0)
238 }
239}
240
241impl SubAssign<Number> for Number {
242 fn sub_assign(&mut self, rhs: Number) {
243 self.0.sub_assign(rhs.0)
244 }
245}
246
247impl Sub<Number> for Number {
248 type Output = Number;
249
250 fn sub(self, rhs: Number) -> Self::Output {
251 Self(self.0.sub(rhs.0))
252 }
253}
254
255impl Mul<Number> for Number {
256 type Output = Number;
257
258 fn mul(self, rhs: Number) -> Self::Output {
259 Self(self.0.mul(rhs.0).div(ONE))
260 }
261}
262
263impl MulAssign<Number> for Number {
264 fn mul_assign(&mut self, rhs: Number) {
265 self.0.mul_assign(rhs.0);
266 self.0.div_assign(ONE);
267 }
268}
269
270impl Div<Number> for Number {
271 type Output = Number;
272
273 fn div(self, rhs: Number) -> Self::Output {
274 Self(self.0.mul(ONE).div(rhs.0))
275 }
276}
277
278impl<T: Into<U192>> Mul<T> for Number {
279 type Output = Number;
280
281 fn mul(self, rhs: T) -> Self::Output {
282 Self(self.0.mul(rhs.into()))
283 }
284}
285
286impl<T: Into<U192>> Div<T> for Number {
287 type Output = Number;
288
289 fn div(self, rhs: T) -> Self::Output {
290 Self(self.0.div(rhs.into()))
291 }
292}
293
294impl Sum for Number {
295 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
296 iter.reduce(|a, b| a + b).unwrap_or(Self::ZERO)
297 }
298}
299
300pub fn expm1_approx(x: Number, terms: usize) -> Number {
305 if terms == 0 {
306 return 0.into();
307 }
308 if terms == 1 {
309 return x;
310 }
311
312 let mut z = x;
313 let mut acc = x;
314 let mut fac = 1u64;
315
316 for k in 2..terms + 1 {
317 z *= x;
318 fac *= k as u64;
319 acc += z / fac;
320 }
321
322 acc
323}
324
325#[cfg(test)]
326mod tests {
327 use super::*;
328
329 #[test]
340 fn test_taylor_approx_point2ish() {
341 let expected: u64 = 221_402_758_160_170;
347 let expected_number: Number = Number::from_decimal(expected, -15);
348 let answer = expm1_approx(Number::from_decimal(2, -1), 5);
350 let tolerance = Number::from_decimal(10_000_000_000 as u64, -15);
351
352 let diff = if expected_number.gt(&answer) {
353 expected_number.sub(answer)
354 } else {
355 answer.sub(expected_number)
356 };
357 assert!(diff.lt(&tolerance));
358 }
359
360 #[test]
361 fn test_taylor_approx_point3ish() {
362 let expected: u64 = 349_858_807_576_000;
368 let expected_number: Number = Number::from_decimal(expected, -15);
369 let answer = expm1_approx(Number::from_decimal(3, -1), 5);
371 let tolerance = Number::from_decimal(10_000_000_000 as u64, -15);
372
373 let diff = if expected_number.gt(&answer) {
374 expected_number.sub(answer)
375 } else {
376 answer.sub(expected_number)
377 };
378
379 assert!(diff.lt(&tolerance));
380 }
381
382 #[test]
383 fn test_taylor_approx_maxish() {
384 let max_x = Number::from_decimal(76712328767123 as u64, -15);
388
389 let expected: u64 = 079_731_424_041_940;
395 let expected_number: Number = Number::from_decimal(expected, -15);
396 let answer = expm1_approx(max_x, 5);
398 let tolerance = Number::from_decimal(10_000_000_000 as u64, -15);
399
400 let diff = if expected_number.gt(&answer) {
401 expected_number.sub(answer)
402 } else {
403 answer.sub(expected_number)
404 };
405
406 assert!(diff.lt(&tolerance));
407 }
408
409 #[test]
410 fn test_taylor_approx_minish() {
411 let min_x = Number::from_decimal(50 as u64, -15);
412
413 let expected: u64 = 000_000_000_000_050;
419 let expected_number: Number = Number::from_decimal(expected, -15);
420 let answer = expm1_approx(min_x, 5);
422 let tolerance = Number::from_decimal(100 as u64, -15);
423
424 let diff = if expected_number.gt(&answer) {
425 expected_number.sub(answer)
426 } else {
427 answer.sub(expected_number)
428 };
429
430 assert!(diff.lt(&tolerance));
431 }
432
433 #[test]
434 fn zero_equals_zero() {
435 assert_eq!(Number::ZERO, Number::from_decimal(0, 0));
436 assert_eq!(Number::ZERO, Number::from(0u64));
437 }
438
439 #[test]
440 fn one_equals_one() {
441 assert_eq!(Number::ONE, Number::from_decimal(1, 0));
442 assert_eq!(Number::ONE, Number::from(1u64));
443 }
444
445 #[test]
446 fn one_plus_one_equals_two() {
447 assert_eq!(Number::from_decimal(2, 0), Number::ONE + Number::ONE);
448 }
449
450 #[test]
451 fn one_minus_one_equals_zero() {
452 assert_eq!(Number::ONE - Number::ONE, Number::ZERO);
453 }
454
455 #[test]
456 fn one_times_one_equals_one() {
457 assert_eq!(Number::ONE, Number::ONE * Number::ONE);
458 }
459
460 #[test]
461 fn one_divided_by_one_equals_one() {
462 assert_eq!(Number::ONE, Number::ONE / Number::ONE);
463 }
464
465 #[test]
466 fn ten_div_100_equals_point_1() {
467 assert_eq!(
468 Number::from_decimal(1, -1),
469 Number::from_decimal(1, 1) / Number::from_decimal(100, 0)
470 );
471 }
472
473 #[test]
474 fn multiply_by_u64() {
475 assert_eq!(
476 Number::from_decimal(3, 1),
477 Number::from_decimal(1, 1) * 3u64
478 )
479 }
480
481 #[test]
482 fn ceil_gt_one() {
483 assert_eq!(Number::from_decimal(11, -1).as_u64_ceil(0), 2u64);
484 assert_eq!(Number::from_decimal(19, -1).as_u64_ceil(0), 2u64);
485 }
486
487 #[test]
488 fn ceil_lt_one() {
489 assert_eq!(Number::from_decimal(1, -1).as_u64_ceil(0), 1u64);
490 assert_eq!(Number::from_decimal(1, -10).as_u64_ceil(0), 1u64);
491 }
492
493 #[test]
494 fn ceil_of_int() {
495 assert_eq!(Number::from_decimal(1, 0).as_u64_ceil(0), 1u64);
496 assert_eq!(
497 Number::from_decimal(1_000_000u64, 0).as_u64_ceil(0),
498 1_000_000u64
499 );
500 }
501
502 #[test]
503 fn to_string() {
504 assert_eq!("1000.0", Number::from(1000).to_string());
505 assert_eq!("1.0", Number::from(1).to_string());
506 assert_eq!("0.001", Number::from_decimal(1, -3).to_string());
507 }
508
509 #[test]
510 fn into_bits() {
511 let bits = Number::from_decimal(1242, -3).into_bits();
512 let number = Number::from_bits(bits);
513
514 assert_eq!(Number::from_decimal(1242, -3), number);
515 }
516}