injective_math/fp_decimal/
mod.rs

1use std::str::FromStr;
2use std::{convert::TryFrom, ops::Neg};
3
4use cosmwasm_std::{Decimal256, StdError, Uint128, Uint256};
5use primitive_types::U256;
6use schemars::JsonSchema;
7
8#[allow(clippy::upper_case_acronyms)]
9#[derive(Copy, Clone, Default, Debug, Eq, JsonSchema)]
10pub struct FPDecimal {
11    #[schemars(with = "String")]
12    pub num: U256,
13    pub sign: i8,
14}
15
16impl From<u128> for FPDecimal {
17    fn from(x: u128) -> FPDecimal {
18        FPDecimal {
19            num: U256::from_little_endian(&x.to_le_bytes()) * FPDecimal::ONE.num,
20            sign: 1,
21        }
22    }
23}
24
25impl From<i128> for FPDecimal {
26    fn from(x: i128) -> FPDecimal {
27        let mut sign = 1;
28        if x < 0 {
29            sign = 0;
30        }
31
32        let abs_x: u128 = x.unsigned_abs();
33        FPDecimal {
34            num: U256::from_little_endian(&abs_x.to_le_bytes()) * FPDecimal::ONE.num,
35            sign,
36        }
37    }
38}
39
40impl From<FPDecimal> for u128 {
41    fn from(x: FPDecimal) -> u128 {
42        let num: U256 = x.int().num / FPDecimal::ONE.num;
43        if num.bits() > 128 {
44            panic!("overflow");
45        }
46
47        let mut array: [u8; 32] = [0; 32];
48        num.to_little_endian(&mut array);
49
50        let mut arr2: [u8; 16] = Default::default();
51        arr2.copy_from_slice(&array[0..16]);
52        u128::from_le_bytes(arr2)
53    }
54}
55
56impl From<U256> for FPDecimal {
57    fn from(x: U256) -> FPDecimal {
58        FPDecimal { num: x, sign: 1 }
59    }
60}
61
62impl From<FPDecimal> for Uint128 {
63    fn from(x: FPDecimal) -> Uint128 {
64        let number: u128 = x.into();
65        number.into()
66    }
67}
68
69impl From<Uint128> for FPDecimal {
70    fn from(x: Uint128) -> FPDecimal {
71        FPDecimal::from_str(&x.to_string()).unwrap()
72    }
73}
74
75impl From<Uint256> for FPDecimal {
76    fn from(x: Uint256) -> FPDecimal {
77        FPDecimal::from_str(&x.to_string()).unwrap()
78    }
79}
80
81// impl that converts cosmwasm Decimal256 to FPDecimal.
82impl From<Decimal256> for FPDecimal {
83    fn from(value: Decimal256) -> FPDecimal {
84        let atomics = value.atomics().to_be_bytes();
85        FPDecimal {
86            num: atomics.into(),
87            sign: 1,
88        }
89    }
90}
91
92// impl that tries to convert FPDecimal into Decimal256.
93impl TryFrom<FPDecimal> for Decimal256 {
94    type Error = StdError;
95
96    fn try_from(fp_decimal: FPDecimal) -> Result<Self, Self::Error> {
97        if fp_decimal.is_negative() {
98            return Err(StdError::generic_err(format!("Value {} must be >= {}", fp_decimal.num, 0)));
99        }
100
101        let fp_decimal_num_uint256 = fp_decimal.to_u256();
102
103        Ok(Decimal256::new(fp_decimal_num_uint256))
104    }
105}
106
107impl Neg for FPDecimal {
108    type Output = FPDecimal;
109    fn neg(mut self) -> Self::Output {
110        if self.is_zero() {
111            return self;
112        }
113        match self.sign {
114            0 => {
115                self.sign = 1;
116            }
117            _ => {
118                self.sign = 0;
119            }
120        }
121        self
122    }
123}
124
125// constants
126impl FPDecimal {
127    pub const MAX: FPDecimal = FPDecimal { num: U256::MAX, sign: 1 };
128    pub const MIN: FPDecimal = FPDecimal { num: U256::MAX, sign: 0 };
129    pub const DIGITS: usize = 18;
130    pub const NEGATIVE_ONE: FPDecimal = FPDecimal {
131        num: U256([1_000_000_000_000_000_000, 0, 0, 0]),
132        sign: 0,
133    };
134    pub const ZERO: FPDecimal = FPDecimal {
135        num: U256([0, 0, 0, 0]),
136        sign: 1,
137    };
138
139    pub const LN2: FPDecimal = FPDecimal {
140        num: U256([693_147_180_559_945_309, 0, 0, 0]),
141        sign: 1,
142    };
143
144    pub const ONE: FPDecimal = FPDecimal {
145        num: U256([1_000_000_000_000_000_000, 0, 0, 0]),
146        sign: 1,
147    };
148
149    pub const TWO: FPDecimal = FPDecimal {
150        num: U256([2_000_000_000_000_000_000, 0, 0, 0]),
151        sign: 1,
152    };
153
154    pub const THREE: FPDecimal = FPDecimal {
155        num: U256([3_000_000_000_000_000_000, 0, 0, 0]),
156        sign: 1,
157    };
158
159    pub const FOUR: FPDecimal = FPDecimal {
160        num: U256([4_000_000_000_000_000_000, 0, 0, 0]),
161        sign: 1,
162    };
163
164    pub const FIVE: FPDecimal = FPDecimal {
165        num: U256([5_000_000_000_000_000_000, 0, 0, 0]),
166        sign: 1,
167    };
168    pub const SIX: FPDecimal = FPDecimal {
169        num: U256([6_000_000_000_000_000_000, 0, 0, 0]),
170        sign: 1,
171    };
172    pub const SEVEN: FPDecimal = FPDecimal {
173        num: U256([7_000_000_000_000_000_000, 0, 0, 0]),
174        sign: 1,
175    };
176    pub const EIGHT: FPDecimal = FPDecimal {
177        num: U256([8_000_000_000_000_000_000, 0, 0, 0]),
178        sign: 1,
179    };
180    pub const NINE: FPDecimal = FPDecimal {
181        num: U256([9_000_000_000_000_000_000, 0, 0, 0]),
182        sign: 1,
183    };
184    pub const TEN: FPDecimal = FPDecimal {
185        num: U256([10_000_000_000_000_000_000, 0, 0, 0]),
186        sign: 1,
187    };
188
189    pub const ELEVEN: FPDecimal = FPDecimal {
190        num: U256([11_000_000_000_000_000_000, 0, 0, 0]),
191        sign: 1,
192    };
193
194    pub const SMALLEST_PRECISION: FPDecimal = FPDecimal {
195        num: U256([1, 0, 0, 0]),
196        sign: 1,
197    };
198
199    pub const MUL_PRECISION: FPDecimal = FPDecimal {
200        num: U256([1_000_000_000, 0, 0, 0]),
201        sign: 1,
202    };
203
204    pub const E: FPDecimal = FPDecimal {
205        // 1_000_000_000_000_000_000
206        num: U256([2_718_281_828_459_045_235, 0, 0, 0]),
207        sign: 1,
208    };
209
210    pub const E_10: FPDecimal = FPDecimal {
211        num: U256([1_053_370_797_511_854_089u64, 1194u64, 0, 0]),
212        sign: 1,
213    }; // e^10
214
215    pub const LN_1_5: FPDecimal = FPDecimal {
216        // 405_465_108_704_634_977
217        // 0.40546510810816438199
218        num: U256([405_465_108_108_164_382, 0, 0, 0]),
219        sign: 1,
220    }; // ln(1.5)
221
222    pub const LN_2: FPDecimal = FPDecimal {
223        // 405_465_108_704_634_977
224        num: U256([693_147_180_559_945_309, 0, 0, 0]),
225        sign: 1,
226    }; // ln(1.5)
227
228    pub const LN_10: FPDecimal = FPDecimal {
229        num: U256([2_302_585_092_994_045_684, 0, 0, 0]),
230        sign: 1,
231    }; // ln(10)
232
233    pub const LOG2_10: FPDecimal = FPDecimal {
234        // 3.321_928_094_887_362_347
235        num: U256([3_321_928_094_887_362_347, 0, 0, 0]),
236        sign: 1,
237    }; // log2(10)
238
239    pub const LOG2_E: FPDecimal = FPDecimal {
240        // 1.4426950408889633306
241        num: U256([1_442_695_040_888_963_330, 0, 0, 0]),
242        sign: 1,
243    }; // log2(10)
244
245    pub const LOG10_2: FPDecimal = FPDecimal {
246        // 0.30102999566398119523
247        num: U256([301_029_995_663_981_195, 0, 0, 0]),
248        sign: 1,
249    };
250
251    pub const LOG10_E: FPDecimal = FPDecimal {
252        // 0.30102999566398119523
253        num: U256([301_029_995_663_981_195, 0, 0, 0]),
254        sign: 1,
255    };
256
257    pub const PI: FPDecimal = FPDecimal {
258        num: U256([3_141_592_653_589_793_115, 0, 0, 0]),
259        sign: 1,
260    };
261
262    pub const FRAC_1_PI: FPDecimal = FPDecimal {
263        // 318_309_886_183_790_683
264        num: U256([318_309_886_183_790_683, 0, 0, 0]),
265        sign: 1,
266    };
267
268    pub const FRAC_1_SQRT_2: FPDecimal = FPDecimal {
269        // 0.707106781186547524
270        num: U256([707_106_781_186_547_524, 0, 0, 0]),
271        sign: 1,
272    };
273
274    pub const FRAC_2_PI: FPDecimal = FPDecimal {
275        // 636_619_772_367_581_3679
276        num: U256([636_619_772_367_581_368, 0, 0, 0]),
277        sign: 1,
278    };
279
280    pub const FRAC_2_SQRT_PI: FPDecimal = FPDecimal {
281        // 1_128_379_167_095_512_595
282        num: U256([1_128_379_167_095_512_595, 0, 0, 0]),
283        sign: 1,
284    };
285
286    pub const FRAC_PI_2: FPDecimal = FPDecimal {
287        // 1_570_796_326_794_896_558
288        num: U256([1_570_796_326_794_896_558, 0, 0, 0]),
289        sign: 1,
290    };
291
292    pub const FRAC_PI_3: FPDecimal = FPDecimal {
293        // 1_047_197_551_196_597_705
294        num: U256([1_047_197_551_196_597_705, 0, 0, 0]),
295        sign: 1,
296    };
297
298    pub const FRAC_PI_4: FPDecimal = FPDecimal {
299        // 0_785_398_163_397_448_279
300        num: U256([785_398_163_397_448_279, 0, 0, 0]),
301        sign: 1,
302    };
303
304    pub const FRAC_PI_6: FPDecimal = FPDecimal {
305        // 523_598_775_598_298_852
306        num: U256([523_598_775_598_298_852, 0, 0, 0]),
307        sign: 1,
308    };
309
310    pub const FRAC_PI_8: FPDecimal = FPDecimal {
311        // 392_699_081_698_724_139
312        num: U256([392_699_081_698_724_139, 0, 0, 0]),
313        sign: 1,
314    };
315
316    pub const SQRT_2: FPDecimal = FPDecimal {
317        // 1.414_213_562_373_095_048
318        num: U256([1_414_213_562_373_095_048, 0, 0, 0]),
319        sign: 1,
320    };
321
322    pub const TAU: FPDecimal = FPDecimal {
323        // 2*PI
324        // 6.283185307179586232
325        num: U256([6_283_185_307_179_586_232, 0, 0, 0]),
326        sign: 1,
327    };
328
329    pub fn is_zero(&self) -> bool {
330        self.num.is_zero()
331    }
332
333    pub fn is_negative(&self) -> bool {
334        // Zero is positive regardless of sign
335        if self.num == FPDecimal::ZERO.num {
336            return false;
337        }
338
339        self.sign == 0
340    }
341
342    pub fn _int(x: FPDecimal) -> Self {
343        let x1 = x.num;
344        let x1_1 = x1 / FPDecimal::ONE.num;
345        let x_final = x1_1 * FPDecimal::ONE.num;
346        FPDecimal { num: x_final, sign: x.sign }
347    }
348
349    pub fn int(&self) -> Self {
350        FPDecimal::_int(*self)
351    }
352    pub fn is_int(&self) -> bool {
353        *self == self.int()
354    }
355
356    pub fn _fraction(x: FPDecimal) -> Self {
357        let x1 = x.num;
358        FPDecimal {
359            num: x1 - FPDecimal::_int(x).num,
360            sign: x.sign,
361        }
362    }
363
364    pub fn fraction(&self) -> Self {
365        FPDecimal::_fraction(*self)
366    }
367
368    pub fn into_uint256_ceil(self) -> Uint256 {
369        let uint256 = self.to_u256();
370        uint256.checked_add(1u64.into()).unwrap() // Add 1 to round up
371    }
372
373    pub fn into_uint256_floor(self) -> Uint256 {
374        self.to_u256()
375    }
376
377    pub fn to_u256(&self) -> Uint256 {
378        let mut bytes = [0u8; 32];
379        self.num.to_big_endian(&mut bytes);
380        Uint256::from_be_bytes(bytes)
381    }
382}
383
384mod arithmetic;
385mod comparison;
386pub mod display;
387pub mod error;
388mod exp;
389mod factorial;
390mod from_str;
391mod hyper;
392mod log;
393pub mod scale;
394mod serde;
395mod trigonometry;
396
397#[cfg(test)]
398mod tests {
399    use std::{convert::TryFrom, str::FromStr};
400
401    use crate::fp_decimal::U256;
402    use crate::FPDecimal;
403    use cosmwasm_std::{Decimal256, Uint256};
404
405    #[test]
406    fn test_const_pi() {
407        let pi = FPDecimal::PI;
408        let three_point_two = FPDecimal::must_from_str("3.2");
409        let three_point_one = FPDecimal::must_from_str("3.1");
410        let pi_precise = FPDecimal::must_from_str("3.141592653589793115");
411        assert!(three_point_one < pi);
412        assert!(pi < three_point_two);
413        assert_eq!(pi, pi_precise);
414    }
415
416    #[test]
417    fn test_const_ln2() {
418        let ln2 = FPDecimal::LN2;
419        let ln2_precise = FPDecimal::must_from_str("0.693147180559945309");
420        assert_eq!(ln2, ln2_precise);
421    }
422
423    #[test]
424    fn test_neg_sign() {
425        let lhs = FPDecimal::ZERO - FPDecimal::ONE;
426        let rhs = -FPDecimal::ONE;
427        assert_eq!(lhs, rhs);
428    }
429
430    #[test]
431    fn test_neg_zero() {
432        let lhs = FPDecimal::ZERO;
433        let rhs = -FPDecimal::ZERO;
434        assert_eq!(lhs, rhs);
435    }
436
437    #[test]
438    fn test_is_int() {
439        assert!(FPDecimal::TWO.is_int());
440    }
441
442    #[test]
443    fn test_is_not_int() {
444        assert!(!FPDecimal::must_from_str("2.1").is_int());
445        assert_eq!(FPDecimal::must_from_str("2.1") % FPDecimal::ONE, FPDecimal::must_from_str("0.1"));
446    }
447
448    #[test]
449    fn test_to_u256() {
450        let fp_decimal = FPDecimal {
451            num: U256::from(12345u64),
452            sign: 1, // Assuming it's always positive
453        };
454
455        let uint256 = fp_decimal.to_u256();
456        assert_eq!(uint256, Uint256::from(12345u64));
457    }
458
459    #[test]
460    fn into_uint256_floor() {
461        let fp_decimal = FPDecimal {
462            num: U256::from_dec_str("12345").unwrap(),
463            sign: 1,
464        };
465
466        let uint256 = fp_decimal.into_uint256_floor();
467        assert_eq!(uint256, Uint256::from(12345u64));
468    }
469
470    #[test]
471    fn into_uint256_ceil() {
472        let fp_decimal = FPDecimal {
473            num: U256::from_dec_str("12345").unwrap(),
474            sign: 1,
475        };
476
477        let uint256 = fp_decimal.into_uint256_ceil();
478        assert_eq!(uint256, Uint256::from(12346u64));
479    }
480
481    #[test]
482    fn dec256_to_fpdecimal_conversion() {
483        // Decimal value for testing
484        let decimal_value = Decimal256::from_str("1.234").unwrap(); // returns 1.234
485
486        //  Perform the conversion
487        let fp_decimal: FPDecimal = decimal_value.into();
488
489        // Check if the conversion produced the expected FPDecimal
490
491        let expected_fp_decimal = FPDecimal::must_from_str("1.234");
492
493        // Use assertions to check if the actual value matches the expected value
494        assert_eq!(fp_decimal.num, expected_fp_decimal.num);
495        assert_eq!(fp_decimal.sign, expected_fp_decimal.sign);
496    }
497
498    #[test]
499    fn fpdecimal_to_dec256() {
500        // Test a valid positive value
501        let fp_decimal_valid = FPDecimal::must_from_str("1.2345");
502        let decimal_valid = Decimal256::try_from(fp_decimal_valid).unwrap();
503        assert_eq!(decimal_valid.to_string(), fp_decimal_valid.to_string());
504
505        // Test a valid zero value
506        let fp_decimal_zero = FPDecimal::ZERO;
507        let decimal_zero = Decimal256::try_from(fp_decimal_zero).unwrap();
508        assert_eq!(decimal_zero.to_string(), "0");
509
510        // Test a negative value (should fail)
511        let fp_decimal_negative = FPDecimal::must_from_str("-1.2345");
512        assert!(Decimal256::try_from(fp_decimal_negative).is_err());
513    }
514}