|
| 1 | +--- |
| 2 | +id: managed-decimal |
| 3 | +title: Managed Decimal |
| 4 | +--- |
| 5 | + |
| 6 | +[comment]: # (mx-context-auto) |
| 7 | + |
| 8 | +## Managed Decimal Overview |
| 9 | + |
| 10 | +`ManagedDecimal` is a generic type representing a fixed-point decimal number managed by the API. |
| 11 | +It is designed to handle decimal values with a specific number of decimals, providing operations such as addition, subtraction, multiplication, division, scaling, and conversion between different decimal precision and also more complex operations such as logarithm and nth root with a customizable degree of precision. |
| 12 | + |
| 13 | +Essentially, `ManagedDecimal` is simply a struct containing a wrapper over a `BigIntHandle` (`BigUint`) and the number of decimals associated with that value (precision). Having such a light design helps `ManagedDecimal` become the optimal solution for dealing with fixed-point decimal numbers in terms of efficiency and readability. |
| 14 | + |
| 15 | +```rust title=managed_decimal.rs |
| 16 | +#[derive(Debug, Clone)] |
| 17 | +pub struct ManagedDecimal<M: ManagedTypeApi, D: Decimals> { |
| 18 | + data: BigUint<M>, // value * scaling_factor |
| 19 | + decimals: D, // number_of_decimals (precision) |
| 20 | +} |
| 21 | +``` |
| 22 | + |
| 23 | +The `scaling factor` of the decimal is `10^num_of_decimals` and is a cached value across multiple `ManagedDecimal` instances for increased efficiency. |
| 24 | + |
| 25 | +```rust title=example.rs |
| 26 | +pub fn main() { |
| 27 | + let decimal = ManagedDecimal::<StaticApi, ConstDecimals<2>>::from(BigUint::from(1u64)); |
| 28 | + let cached_decimal = ManagedDecimal::<StaticApi, ConstDecimals<2>>::from(BigUint::from(5u64)); |
| 29 | +} |
| 30 | +``` |
| 31 | + |
| 32 | +[comment]: # (mx-context-auto) |
| 33 | + |
| 34 | +## Number of decimals |
| 35 | + |
| 36 | +`Decimals` is a trait representing the number of decimals associated with a decimal value and is only |
| 37 | +implemented for `NumDecimals` and `ConstDecimals`. |
| 38 | +`NumDecimals` is a type alias for `usize` and is used to specify the number of decimals dynamically, while `ConstDecimals` is a type that represents a constant number of decimals and is used to statically specify the number of decimals for ManagedDecimal instances. |
| 39 | + |
| 40 | +```rust title=example.rs |
| 41 | +pub fn main() { |
| 42 | + let decimal: ManagedDecimal<StaticApi, NumDecimals> = ManagedDecimal::from_raw_units(BigUint::from(100u64), 2usize); |
| 43 | + let const_decimal = ManagedDecimal::<StaticApi, ConstDecimals<3>>::const_decimals_from_raw(BigUint::from(500u64)) |
| 44 | +} |
| 45 | +``` |
| 46 | + |
| 47 | +[comment]: # (mx-context-auto) |
| 48 | + |
| 49 | +## Operations |
| 50 | + |
| 51 | +`ManagedDecimal` supports various types of simple and complex operations, as well as conversions and scaling. More code examples can be found at `mx-sdk-rs/framework/scenario/tests/managed_decimal_test.rs` |
| 52 | + |
| 53 | +### Available methods: |
| 54 | +- Simple Operations: |
| 55 | + - `add`, `mul`, `div`, `sub` are all implemented for `ConstDecimals` of the same scale. |
| 56 | + ```rust title=example.rs |
| 57 | + pub fn main() { |
| 58 | + let fixed = ManagedDecimal::<StaticApi, ConstDecimals<2>>::from(BigUint::from(1u64)); |
| 59 | + let fixed_2 = ManagedDecimal::<StaticApi, ConstDecimals<2>>::from(BigUint::from(5u64)); |
| 60 | + |
| 61 | + let addition = fixed + fixed_2; |
| 62 | + assert_eq!( |
| 63 | + addition, |
| 64 | + ManagedDecimal::<StaticApi, ConstDecimals<2>>::from(BigUint::from(6u64)) |
| 65 | + ); |
| 66 | + } |
| 67 | + ``` |
| 68 | + - `trunc(&self) -> BigUint<M>` returns the `data` field without the `scaling_factor` applied, by dividing the value to the scaling factor and truncating. |
| 69 | + ```rust title=example.rs |
| 70 | + pub fn main() { |
| 71 | + ... |
| 72 | + assert_eq!(addition.trunc(), BigUint::from(6u64)); |
| 73 | + } |
| 74 | + ``` |
| 75 | +- Complex Operations: |
| 76 | + - `log<T: Decimals>(self, target_base: BigUint<M>, precision: T) -> ManagedDecimal<M, T>` returns the value of log in any base with customizable precision level. |
| 77 | + ```rust title=example.rs |
| 78 | + pub fn logarithm() { |
| 79 | + let fixed = ManagedDecimal::<StaticApi, NumDecimals>::from_raw_units(BigUint::from(10u64), 1usize); |
| 80 | + let fixed_const = ManagedDecimal::<StaticApi, ConstDecimals<1>>::const_decimals_from_raw(BigUint::from(10u64)); |
| 81 | + |
| 82 | + let log2_fixed = fixed.log(BigUint::from(2u64), 10_000usize); |
| 83 | + assert_eq!( |
| 84 | + log2_fixed, |
| 85 | + ManagedDecimal::<StaticApi, NumDecimals>::from_raw_units(BigUint::from(33219u64), 10_000usize) |
| 86 | + ); |
| 87 | + } |
| 88 | + ``` |
| 89 | +- Scaling: |
| 90 | + - `scale(&self) -> usize` returns the number of decimals (the scale). |
| 91 | + - `scaling_factor<M: ManagedTypeApi>(&self) -> BigUint<M>` returns the scaling factor value (`10^num_decimals`). |
| 92 | + - `rescale<T: Decimals>(self, scale_to: T) -> ManagedDecimal<M, T>` returns the correspondent of the decimal in the newly specified scale. It can also convert between `NumDecimal` and `ConstDecimals` instances. |
| 93 | + |
| 94 | + ```rust title=example.rs |
| 95 | + pub fn main() { |
| 96 | + ... |
| 97 | + let fixed_8: ManagedDecimal<StaticApi, NumDecimals> = ManagedDecimal::from_raw_units(BigUint::from(5u64), 5usize); |
| 98 | + let fixed_9 = fixed_8.rescale(ConstDecimals::<3>); |
| 99 | + assert_eq!( |
| 100 | + fixed_9, |
| 101 | + ManagedDecimal::<StaticApi, ConstDecimals<3>>::const_decimals_from_raw(BigUint::from(500u64)) |
| 102 | + ); |
| 103 | + } |
| 104 | + ``` |
| 105 | +- Conversions: |
| 106 | + - `into_raw_units(&self) -> &BigUint<M>` returns the `data` field value. |
| 107 | + |
| 108 | + ```rust title=example.rs |
| 109 | + pub fn main() { |
| 110 | + ... |
| 111 | + assert_eq!(addition.into_raw_units(), &BigUint::from(600u64)); |
| 112 | + } |
| 113 | + ``` |
| 114 | + - `from_raw_units(data: BigUint<M>, decimals: D) -> Self` returns a `ManagedDecimal` from a data field value without applying scaling factor. |
| 115 | + |
| 116 | + ```rust title=example.rs |
| 117 | + pub fn main() { |
| 118 | + ... |
| 119 | + let fixed_4: ManagedDecimal<StaticApi, NumDecimals> = ManagedDecimal::from_raw_units(BigUint::from(100u64), 2usize); |
| 120 | + let fixed_5 = fixed_4.rescale(2usize); |
| 121 | + assert_eq!( |
| 122 | + fixed_5, |
| 123 | + ManagedDecimal::from_raw_units(BigUint::from(100000000u64), 8usize) |
| 124 | + ); |
| 125 | + } |
| 126 | + ``` |
| 127 | + - `const_decimals_from_raw(data: BigUint<M>) -> Self` returns a `ConstDecimals` type of `ManagedDecimal` from a data field value without applying scaling factor. |
| 128 | + ```rust title=example.rs |
| 129 | + pub fn main() { |
| 130 | + ... |
| 131 | + let fixed_const: ManagedDecimal<StaticApi, ConstDecimals<1>> = ManagedDecimal::const_decimals_from_raw(BigUint::from(1u64)); |
| 132 | + } |
| 133 | + ``` |
| 134 | + - `num_decimals(&self) -> NumDecimals` returns the number of decimals. |
| 135 | + - `to_big_float(&self) -> BigFloat<M>` returns the decimal as `BigFloat<M>`. |
| 136 | + - `to_big_int(self) -> BigInt<M>` returns the decimal as `BigInt`. |
| 137 | + - `from_big_int<T: Decimals>(big_int: BigInt<M>, num_decimals: T) -> ManagedDecimal<M, T>` constructs a `ManagedDecimal` from a `BigInt` with customizable `num_decimals`. |
| 138 | + - `from_big_float<T: Decimals>(big_float: BigFloat<M>, num_decimals: T) -> ManagedDecimal<M, T>` constructs a `ManagedDecimal` from a `BigFloat` with customizable `num_decimals`. |
| 139 | + ```rust title=example.rs |
| 140 | + pub fn main() { |
| 141 | + ... |
| 142 | + let float_1 = BigFloat::<StaticApi>::from_frac(3i64, 2i64); |
| 143 | + let fixed_float_1 = ManagedDecimal::<StaticApi, ConstDecimals<1>>::from_big_float(float_1.clone(),ConstDecimals::<1>); |
| 144 | + let fixed_float_2 = ManagedDecimal::<StaticApi, NumDecimals>::from_big_float(float_1, 1usize); |
| 145 | + |
| 146 | + assert_eq!( |
| 147 | + fixed_float_1, |
| 148 | + ManagedDecimal::<StaticApi, ConstDecimals<1>>::const_decimals_from_raw(BigUint::from(15u64)) |
| 149 | + ); |
| 150 | + assert_eq!( |
| 151 | + fixed_float_2, |
| 152 | + ManagedDecimal::<StaticApi, NumDecimals>::from_raw_units(BigUint::from(15u64), 1usize) |
| 153 | + ); |
| 154 | + } |
| 155 | + ``` |
0 commit comments