1use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
2
3use bytemuck::{Pod, Zeroable};
4
5const PRECISION: i32 = 10;
6const ONE: i128 = 10_000_000_000;
7
8const POWERS_OF_TEN: &[i128] = &[
9 1,
10 10,
11 100,
12 1_000,
13 10_000,
14 100_000,
15 1_000_000,
16 10_000_000,
17 100_000_000,
18 1_000_000_000,
19 10_000_000_000,
20 100_000_000_000,
21 1_000_000_000_000,
22];
23
24#[derive(Pod, Zeroable, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
26#[repr(C)]
27pub struct Number128(i128);
28
29impl Number128 {
30 pub const ONE: Self = Self(ONE);
31 pub const ZERO: Self = Self(0i128);
32
33 pub fn as_u64(&self, exponent: impl Into<i32>) -> u64 {
38 let extra_precision = PRECISION + exponent.into();
39 let prec_value = POWERS_OF_TEN[extra_precision.abs() as usize];
40
41 let target_value = if extra_precision < 0 {
42 self.0 * prec_value
43 } else {
44 self.0 / prec_value
45 };
46
47 if target_value > std::u64::MAX as i128 {
48 panic!("cannot convert to u64 due to overflow");
49 }
50
51 if target_value < 0 {
52 panic!("cannot convert to u64 because value < 0");
53 }
54
55 target_value as u64
56 }
57
58 pub fn from_decimal(value: impl Into<i128>, exponent: impl Into<i32>) -> Self {
60 let extra_precision = PRECISION + exponent.into();
61 let prec_value = POWERS_OF_TEN[extra_precision.abs() as usize];
62
63 if extra_precision < 0 {
64 Self(value.into() / prec_value)
65 } else {
66 Self(value.into() * prec_value)
67 }
68 }
69
70 pub fn from_bps(basis_points: u16) -> Self {
72 Self::from_decimal(basis_points, crate::BPS_EXPONENT)
73 }
74
75 pub fn into_bits(self) -> [u8; 16] {
78 self.0.to_ne_bytes()
79 }
80
81 pub fn from_bits(bits: [u8; 16]) -> Self {
85 Self(i128::from_ne_bytes(bits))
86 }
87
88 pub fn to_i128(self) -> i128 {
90 self.0
91 }
92
93 pub fn from_i128(value: i128) -> Self {
95 Self(value)
96 }
97}
98
99impl std::fmt::Display for Number128 {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 let rem = self.0 % ONE;
103 let decimal_digits = PRECISION as usize;
104 let rem_str = rem.abs().to_string();
106 let decimals = "0".repeat(decimal_digits - rem_str.len()) + &*rem_str;
108 let stripped_decimals = decimals.trim_end_matches('0');
109 let pretty_decimals = if stripped_decimals.is_empty() {
110 "0"
111 } else {
112 stripped_decimals
113 };
114 if self.0 < -ONE {
115 let int = self.0 / ONE;
116 write!(f, "{}.{}", int, pretty_decimals)?;
117 } else if self.0 < 0 {
118 write!(f, "-0.{}", pretty_decimals)?;
119 } else if self.0 < ONE {
120 write!(f, "0.{}", pretty_decimals)?;
121 } else {
122 let int = self.0 / ONE;
123 write!(f, "{}.{}", int, pretty_decimals)?;
124 }
125 Ok(())
126 }
127}
128
129impl Add<Number128> for Number128 {
130 type Output = Self;
131
132 fn add(self, rhs: Number128) -> Self::Output {
133 Self(self.0.checked_add(rhs.0).unwrap())
134 }
135}
136
137impl AddAssign<Number128> for Number128 {
138 fn add_assign(&mut self, rhs: Number128) {
139 self.0 = self.0.checked_add(rhs.0).unwrap();
140 }
141}
142
143impl Sub<Number128> for Number128 {
144 type Output = Self;
145
146 fn sub(self, rhs: Number128) -> Self::Output {
147 Self(self.0.checked_sub(rhs.0).unwrap())
148 }
149}
150
151impl SubAssign<Number128> for Number128 {
152 fn sub_assign(&mut self, rhs: Number128) {
153 self.0 = self.0.checked_sub(rhs.0).unwrap();
154 }
155}
156
157impl Mul<Number128> for Number128 {
158 type Output = Number128;
159
160 fn mul(self, rhs: Number128) -> Self::Output {
161 Self(self.0.checked_mul(rhs.0).unwrap().div(ONE))
162 }
163}
164
165impl MulAssign<Number128> for Number128 {
166 fn mul_assign(&mut self, rhs: Number128) {
167 self.0 = self.0 * rhs.0 / ONE;
168 }
169}
170
171impl Div<Number128> for Number128 {
172 type Output = Number128;
173
174 fn div(self, rhs: Number128) -> Self::Output {
175 Self(self.0.mul(ONE).div(rhs.0))
176 }
177}
178
179impl DivAssign<Number128> for Number128 {
180 fn div_assign(&mut self, rhs: Number128) {
181 self.0 = self.0 * ONE / rhs.0;
182 }
183}
184
185impl<T: Into<i128>> Mul<T> for Number128 {
186 type Output = Number128;
187
188 fn mul(self, rhs: T) -> Self::Output {
189 Self(self.0.mul(rhs.into()))
190 }
191}
192
193impl<T: Into<i128>> Div<T> for Number128 {
194 type Output = Number128;
195
196 fn div(self, rhs: T) -> Self::Output {
197 Self(self.0.div(rhs.into()))
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn zero_equals_zero() {
207 assert_eq!(Number128::ZERO, Number128::from_decimal(0, 0));
208 }
209
210 #[test]
211 fn one_equals_one() {
212 assert_eq!(Number128::ONE, Number128::from_decimal(1, 0));
213 }
214
215 #[test]
216 fn one_plus_one_equals_two() {
217 assert_eq!(
218 Number128::from_decimal(2, 0),
219 Number128::ONE + Number128::ONE
220 );
221 }
222
223 #[test]
224 fn one_minus_one_equals_zero() {
225 assert_eq!(Number128::ONE - Number128::ONE, Number128::ZERO);
226 }
227
228 #[test]
229 fn one_times_one_equals_one() {
230 assert_eq!(Number128::ONE, Number128::ONE * Number128::ONE);
231 }
232
233 #[test]
234 fn one_divided_by_one_equals_one() {
235 assert_eq!(Number128::ONE, Number128::ONE / Number128::ONE);
236 }
237
238 #[test]
239 fn ten_div_100_equals_point_1() {
240 assert_eq!(
241 Number128::from_decimal(1, -1),
242 Number128::from_decimal(1, 1) / Number128::from_decimal(100, 0)
243 );
244 }
245
246 #[test]
247 fn comparison() {
248 let a = Number128::from_decimal(1000, -4);
249 let b = Number128::from_decimal(10, -2);
250 assert!(a >= b);
251
252 let c = Number128::from_decimal(1001, -4);
253 assert!(c > a);
254 assert!(c > b);
255
256 let d = Number128::from_decimal(9999999, -8);
257 assert!(d < a);
258 assert!(d < b);
259 assert!(d < c);
260 assert!(d <= d);
261
262 assert_eq!(a.cmp(&b), std::cmp::Ordering::Equal);
263 assert_eq!(a.cmp(&c), std::cmp::Ordering::Less);
264 assert_eq!(a.cmp(&d), std::cmp::Ordering::Greater);
265 }
266
267 #[test]
268 fn multiply_by_u64() {
269 assert_eq!(
270 Number128::from_decimal(3, 1),
271 Number128::from_decimal(1, 1) * 3u64
272 )
273 }
274
275 #[test]
276 fn test_add_assign_101_2() {
277 let mut a = Number128::from_decimal(101, 0);
278 a += Number128::from_decimal(2, 0);
279 assert_eq!(Number128::from_decimal(103, 0), a);
280 }
281
282 #[test]
283 fn test_sub_assign_101_2() {
284 let mut a = Number128::from_decimal(101, 0);
285 a -= Number128::from_decimal(2, 0);
286 assert_eq!(Number128::from_decimal(99, 0), a);
287 }
288
289 #[test]
290 fn test_mul_assign_101_2() {
291 let mut a = Number128::from_decimal(101, 0);
292 a *= Number128::from_decimal(2, 0);
293 assert_eq!(Number128::from_decimal(202, 0).0, a.0);
294 }
295
296 #[test]
297 fn test_div_assign_101_2() {
298 let mut a = Number128::from_decimal(101, 0);
299 a /= Number128::from_decimal(2, 0);
300 assert_eq!(Number128::from_decimal(505, -1), a);
301 }
302
303 #[test]
304 fn test_div_assign_102_3() {
305 let mut a = Number128::from_decimal(1, 1);
306 a /= Number128::from_decimal(100, 0);
307 assert_eq!(Number128::from_decimal(1, -1).0, a.0);
308 }
309
310 #[test]
311 fn div_into_i128() {
312 let a = Number128::from_decimal(1000, 0);
313 let b = a / 500;
314 assert_eq!(Number128::from_decimal(2, 0), b);
315
316 let c = Number128::from_decimal(1000, -3);
317 let d = c / 3;
318 assert_eq!(Number128::from_decimal(3333333333i64, -10).0, d.0);
319 }
320
321 #[test]
322 fn equality() {
323 let a = Number128::from_decimal(1000, -4);
324 let b = Number128::from_decimal(10, -2);
325 assert_eq!(a, b);
326
327 let c = Number128::from_decimal(-1000, -4);
328 assert_ne!(a, c);
329 assert_ne!(b, c);
330 }
331
332 #[test]
333 fn as_u64() {
334 let u64in = 31455;
335 let a = Number128::from_decimal(u64in, -3);
336 let b = a.as_u64(-3);
337 assert_eq!(b, u64in);
338 }
339
340 #[test]
341 #[should_panic = "cannot convert to u64 because value < 0"]
342 fn as_u64_panic_neg() {
343 let a = Number128::from_decimal(-10000, -3);
344 a.as_u64(-3);
345 }
346
347 #[test]
348 #[should_panic = "cannot convert to u64 due to overflow"]
349 fn as_u64_panic_big() {
350 let a = Number128::from_decimal(u64::MAX as i128 + 1, -3);
351 a.as_u64(-3);
352 }
353
354 #[test]
355 fn display() {
356 let a = Number128::from_bps(15000);
357 assert_eq!("1.5", a.to_string().as_str());
358
359 let a = Number128::from_bps(0) - Number128::from_bps(15000);
360 assert_eq!("-1.5", a.to_string().as_str());
361
362 let b = Number128::from_decimal(12345678901i128, -10);
363 assert_eq!("1.2345678901", b.to_string().as_str());
364
365 let b = Number128::from_decimal(-12345678901i128, -10);
366 assert_eq!("-1.2345678901", b.to_string().as_str());
367
368 let c = Number128::from_decimal(-12345678901i128, -9);
369 assert_eq!("-12.345678901", c.to_string().as_str());
370
371 let c = Number128::from_decimal(12345678901i128, -9);
372 assert_eq!("12.345678901", c.to_string().as_str());
373
374 let d = Number128::from_decimal(ONE - 1, 1);
375 assert_eq!("99999999990.0", d.to_string().as_str());
376
377 let e = Number128::from_decimal(12345678901i128, -13);
378 assert_eq!("0.0012345678", e.to_string().as_str());
379
380 let e = Number128::from_decimal(-12345678901i128, -13);
381 assert_eq!("-0.0012345678", e.to_string().as_str());
382 }
383
384 #[test]
385 fn into_bits() {
386 let bits = Number128::from_decimal(1242, -3).into_bits();
387 let number = Number128::from_bits(bits);
388
389 assert_eq!(Number128::from_decimal(1242, -3), number);
390 }
391}