Skip to main content

ttv_fixed_point/
lib.rs

1use anchor_lang::{AnchorDeserialize, AnchorSerialize};
2use spl_math::{
3    precise_number::{self, *},
4    uint::U256,
5};
6use std::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};
7
8/// High precision number, stored as 4 u64 words in little endian
9#[derive(Default, Clone, Debug, Copy, PartialEq, Eq, AnchorSerialize, AnchorDeserialize)]
10pub struct Number([u64; 4]);
11
12impl core::fmt::Display for Number {
13    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
14        let n = U256(self.0);
15        write!(f, "{}", n)
16    }
17}
18
19impl From<u64> for Number {
20    fn from(value: u64) -> Self {
21        let pn = PreciseNumber::new(value.into()).unwrap();
22        Number(pn.value.0)
23    }
24}
25
26impl From<u128> for Number {
27    fn from(value: u128) -> Self {
28        let pn = PreciseNumber::new(value).unwrap();
29        Number(pn.value.0)
30    }
31}
32
33/// Wrapper around PreciseNumber (a U256) that has 1e12 precision
34impl Number {
35    // The byte size of Number
36    pub const SIZEOF: usize = 32;
37
38    pub const ZERO: Self = Self(U256::zero().0);
39
40    // It just so happens that 1 is 10e12, which is smaller than a u64
41    pub const ONE: Self = Self([precise_number::ONE as u64, 0, 0, 0]);
42
43    pub const DENOM: u128 = precise_number::ONE;
44
45    pub fn from_bytes_le(slice: &[u8]) -> Self {
46        Self(U256::from_little_endian(slice).0)
47    }
48
49    pub fn from_natural_u64(value: u64) -> Self {
50        value.into()
51    }
52
53    pub fn from_ratio(num: u128, den: u128) -> Self {
54        let num = PreciseNumber::new(num).unwrap();
55        let den = PreciseNumber::new(den).unwrap();
56
57        PreciseNumber::checked_div(&num, &den)
58            .unwrap_or(PreciseNumber::new(0).unwrap())
59            .into()
60    }
61
62    /// Convert BPS into Number
63    pub fn from_bps(bps: u16) -> Self {
64        Self::from_natural_u64(bps as u64) / Self::from_natural_u64(10_000)
65    }
66
67    pub fn checked_add(&self, x: &Self) -> Option<Self> {
68        self.to_pn()
69            .checked_add(&x.to_pn())
70            .map(|pn| Self(pn.value.0))
71    }
72
73    pub fn checked_sub(&self, x: &Self) -> Option<Self> {
74        self.to_pn()
75            .checked_sub(&x.to_pn())
76            .map(|pn| Self(pn.value.0))
77    }
78
79    pub fn checked_mul(&self, x: &Self) -> Option<Self> {
80        self.to_pn()
81            .checked_mul(&x.to_pn())
82            .map(|pn| Self(pn.value.0))
83    }
84
85    pub fn checked_div(&self, x: &Self) -> Option<Self> {
86        self.to_pn()
87            .checked_div(&x.to_pn())
88            .map(|pn| Self(pn.value.0))
89    }
90
91    pub fn to_pn(&self) -> PreciseNumber {
92        PreciseNumber {
93            value: U256(self.0),
94        }
95    }
96
97    pub fn min(numbers: &[Self]) -> Self {
98        *numbers.iter().min().unwrap()
99    }
100
101    pub fn floor_u64(&self) -> u64 {
102        self.to_pn()
103            .floor()
104            .unwrap()
105            .to_imprecise()
106            .unwrap()
107            .try_into()
108            .unwrap()
109    }
110
111    pub fn ceil(&self) -> u128 {
112        self.to_pn().ceiling().unwrap().to_imprecise().unwrap()
113    }
114
115    pub fn ceil_u64(&self) -> u64 {
116        self.ceil().try_into().unwrap()
117    }
118
119    pub fn floor_u128(&self) -> u128 {
120        self.to_pn().floor().unwrap().to_imprecise().unwrap()
121    }
122
123    pub fn to_f64(&self) -> Option<f64> {
124        // scale up by 1e12 to avoid precision loss
125        let n = self
126            .checked_mul(&Number::from(Self::DENOM))
127            .unwrap()
128            .to_pn()
129            .to_imprecise()
130            .unwrap();
131        // denominator is always 1e12
132        let d = precise_number::ONE;
133        u128_to_f64_checked(n, d)
134    }
135}
136
137/// Convert a u128 ratio to f64, checking for overflow
138fn u128_to_f64_checked(numerator: u128, denominator: u128) -> Option<f64> {
139    // Constants for maximum values f64 can represent exactly
140    const MAX_EXACT_U64: u128 = (1u128 << 53) - 1;
141
142    // 2^64
143    const U64_MAX_PLUS_ONE: f64 = 18446744073709551616.0;
144    if denominator == 0 {
145        return None; // Division by zero is invalid
146    }
147
148    // Split the u128 into high and low 64-bit parts for both numerator and denominator
149    let num_high = (numerator >> 64) as u64;
150    let num_low = numerator as u64;
151
152    let denom_high = (denominator >> 64) as u64;
153    let denom_low = denominator as u64;
154
155    // Check if the high part of numerator or denominator exceeds the safe f64 range
156    if numerator > MAX_EXACT_U64 || denominator > MAX_EXACT_U64 {
157        return None; // Overflow: numbers are too large to represent as f64
158    }
159
160    // Convert the high and low parts to f64
161    let num_f64 = (num_high as f64) * U64_MAX_PLUS_ONE + num_low as f64;
162    let denom_f64 = (denom_high as f64) * U64_MAX_PLUS_ONE + denom_low as f64;
163
164    // Perform the division
165    Some(num_f64 / denom_f64)
166}
167
168impl From<PreciseNumber> for Number {
169    fn from(pn: PreciseNumber) -> Self {
170        Self(pn.value.0)
171    }
172}
173
174impl Add<Number> for Number {
175    type Output = Self;
176
177    fn add(self, rhs: Number) -> Self::Output {
178        Self(self.to_pn().checked_add(&rhs.to_pn()).unwrap().value.0)
179    }
180}
181
182impl Mul<Number> for Number {
183    type Output = Self;
184
185    fn mul(self, x: Number) -> Self::Output {
186        Self(self.checked_mul(&x).unwrap().0)
187    }
188}
189
190impl Div<Number> for Number {
191    type Output = Self;
192
193    fn div(self, x: Number) -> Self {
194        Self(self.checked_div(&x).unwrap().0)
195    }
196}
197
198impl AddAssign<Number> for Number {
199    fn add_assign(&mut self, rhs: Number) {
200        self.0 = self.checked_add(&rhs).unwrap().0;
201    }
202}
203
204impl SubAssign<Number> for Number {
205    fn sub_assign(&mut self, rhs: Number) {
206        self.0 = self.checked_sub(&rhs).unwrap().0;
207    }
208}
209
210impl Sub<Number> for Number {
211    type Output = Self;
212
213    fn sub(self, x: Number) -> Self {
214        self.checked_sub(&x).unwrap()
215    }
216}
217
218impl PartialOrd for Number {
219    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
220        Some(self.cmp(other))
221    }
222}
223
224impl Ord for Number {
225    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
226        U256(self.0).cmp(&U256(other.0))
227    }
228}
229
230#[cfg(test)]
231mod test {
232    use super::*;
233
234    #[test]
235    fn test_to_f64() {
236        let n = Number::from_ratio(1, 2);
237        assert_eq!(n.to_f64(), Some(0.5));
238
239        let n = Number::from_ratio(123456789, 1_000_000_000);
240        assert_eq!(n.to_f64(), Some(0.123456789));
241
242        let n = Number::from_ratio(0, 1_000_000_000);
243        assert_eq!(n.to_f64(), Some(0.0));
244
245        let n = Number::from_ratio(1_000_000_000, 1_000_000_000);
246        assert_eq!(n.to_f64(), Some(1.0));
247
248        let n = Number::from_ratio(1_000_000_000_000, 1_000_000_000);
249        assert_eq!(n.to_f64(), Some(1000.0));
250
251        let n = Number::from_ratio(123456789123, 100_000_000_000);
252        assert_eq!(n.to_f64(), Some(1.23456789123));
253    }
254
255    #[test]
256    fn test_serialization() {
257        let n = Number([ONE as u64, 0, 0, 0]);
258        assert_eq!(n.floor_u64(), 1);
259
260        let n = Number::from_natural_u64(1_000_000_000);
261        let w0 = n.0[0] as u128;
262        let w1 = n.0[1] as u128;
263        let target: u128 = 1_000_000_000 * ONE;
264        assert_eq!(w0 + (w1 << 64), target);
265    }
266
267    #[test]
268    fn test_add() {
269        let num1 = Number::from(100u64);
270        let num2 = Number::from(200u64);
271        let ans = Number::from(300u64);
272        let num3 = num1 + num2;
273        assert_eq!(num3, ans);
274    }
275
276    #[test]
277    fn test_sub() {
278        let num1 = Number::from(100u64);
279        let num2 = Number::from(200u64);
280        let ans = Number::from(100u64);
281        let num3 = num2 - num1;
282        assert_eq!(num3, ans);
283    }
284
285    #[test]
286    fn test_mul() {
287        let num1 = Number::from(100u64);
288        let num2 = Number::from(200u64);
289        let ans = Number::from(20000u64);
290        let num3 = num1 * num2;
291        assert_eq!(num3, ans);
292    }
293
294    #[test]
295    fn test_div() {
296        let num1 = Number::from(100u64);
297        let num2 = Number::from(20u64);
298        let ans = Number::from(5u64);
299        let num3 = num1 / num2;
300        assert_eq!(num3, ans);
301    }
302
303    #[test]
304    fn test_add_assign() {
305        let mut num1 = Number::from(100u64);
306        let num2 = Number::from(200u64);
307        let ans = Number::from(300u64);
308        num1 += num2;
309        assert_eq!(num1, ans);
310    }
311
312    #[test]
313    fn test_sub_assign() {
314        let mut num1 = Number::from(300u64);
315        let num2 = Number::from(200u64);
316        let ans = Number::from(100u64);
317        num1 -= num2;
318        assert_eq!(num1, ans);
319    }
320
321    #[test]
322    fn test_min() {
323        let numbers = [
324            Number::from(300u64),
325            Number::from(100u64),
326            Number::from(200u64),
327            Number::from(400u64),
328        ];
329        let min_value = Number::min(&numbers);
330        assert_eq!(min_value, Number::from(100u64));
331    }
332
333    #[test]
334    fn test_from_ratio() {
335        let num1 = Number::from_ratio(1, 2);
336        assert!(num1 > Number::from(0u64));
337        assert!(num1 < Number::from(1u64));
338    }
339
340    #[test]
341    fn test_mul_div() {
342        // test multiplying and dividing
343        let e = Number::from_ratio(22346643, 234216);
344
345        let a = Number::from_natural_u64(100);
346
347        let e_a = e * a;
348
349        let e_i = Number::ONE / e;
350
351        assert_eq!(a / e_a, e_i);
352    }
353
354    #[test]
355    fn test_floor_u64() {
356        let e = Number::from_ratio(10, 11);
357        assert_eq!(e.floor_u64(), 0);
358
359        let e = Number::from_ratio(11, 10);
360        assert_eq!(e.floor_u64(), 1);
361    }
362
363    #[test]
364    fn test_floor_u128() {
365        assert_eq!(Number::from_ratio(19, 10).floor_u128(), 1);
366        assert_eq!(Number::from_ratio(21, 10).floor_u128(), 2);
367        assert_eq!(Number::from_ratio(29, 10).floor_u128(), 2);
368        assert_eq!(Number::from_ratio(20, 10).floor_u128(), 2);
369        assert_eq!(Number::from_ratio(300, 100).floor_u128(), 3);
370        assert_eq!(Number::from_ratio(299, 10).floor_u128(), 29);
371        assert_eq!(Number::from_ratio(9, 10).floor_u128(), 0);
372    }
373}