Skip to content

Commit

Permalink
Merge pull request #1670 from multiversx/mng-dec-log-root
Browse files Browse the repository at this point in the history
Logarithm & ManagedDecimal cleanup
  • Loading branch information
andrei-marinica authored Jul 5, 2024
2 parents ead1f3f + c1c68cd commit 260b498
Show file tree
Hide file tree
Showing 53 changed files with 2,309 additions and 865 deletions.
517 changes: 17 additions & 500 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ members = [

"tools/mxpy-snippet-generator",
"tools/payload-macro-generator",
"tools/plotter",
# "tools/plotter",

"vm",

Expand Down
2 changes: 1 addition & 1 deletion contracts/feature-tests/abi-tester/src/abi_test_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub struct OnlyShowsUpInEsdtAttr {
pub field: OnlyShowsUpAsNested10,
}

#[derive(TypeAbi)]
#[type_abi]
pub struct ManagedDecimalWrapper<M: ManagedTypeApi> {
#[allow(dead_code)]
pub field: ManagedDecimal<M, ConstDecimals<2>>,
Expand Down
4 changes: 2 additions & 2 deletions contracts/feature-tests/basic-features/src/big_num_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ pub trait BigIntMethods {

#[endpoint]
fn log2_big_uint(&self, a: BigUint) -> u32 {
a.log2()
a.log2_floor().unwrap_or_default()
}

#[endpoint]
fn log2_big_uint_ref(&self, a: &BigUint) -> u32 {
a.log2()
a.log2_floor().unwrap_or_default()
}

#[endpoint]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"steps": [
{
"step": "setState",
"accounts": {
"sc:basic-features": {
"nonce": "0",
"balance": "0",
"code": "mxsc:../output/big-float-features.mxsc.json"
},
"address:an_account": {
"nonce": "0",
"balance": "100000000000"
}
}
},
{
"step": "scCall",
"id": "ln_big_float_precision_9(23)",
"comment": "ln(23) = 3.135514648 (9 decimals)",
"tx": {
"from": "address:an_account",
"to": "sc:basic-features",
"function": "ln_big_float_precision_9",
"arguments": [
"23"
],
"gasLimit": "2,000,000",
"gasPrice": "0"
},
"expect": {
"out": [
"+3135514648"
]
}
},
{
"step": "scCall",
"id": "ln_big_float_any_precision(23, 9)",
"comment": "ln(23) = 3.135514648 (9 decimals)",
"tx": {
"from": "address:an_account",
"to": "sc:basic-features",
"function": "ln_big_float_any_precision",
"arguments": [
"23",
"9"
],
"gasLimit": "2,000,000",
"gasPrice": "0"
},
"expect": {
"out": [
"u32:5|+3135514648|u32:9"
]
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -820,26 +820,6 @@
"-1"
]
}
},
{
"step": "scCall",
"id": "LnBigFloatRef - 1",
"tx": {
"from": "address:an_account",
"to": "sc:basic-features",
"function": "ln_big_float_ref_wrapped",
"arguments": [
"23",
"9"
],
"gasLimit": "50,000,000",
"gasPrice": "0"
},
"expect": {
"out": [
"0x00000004bae4281800000009"
]
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ multiversx_sc::imports!();
pub mod big_float_methods;
pub mod big_float_methods_wrapped;
pub mod big_float_operators;
pub mod big_float_operators_ln;
pub mod big_float_operators_wrapped;

#[multiversx_sc::contract]
pub trait BigFloatFeatures:
big_float_methods::BigFloatMethods
+ big_float_operators::BigFloatOperators
+ big_float_methods_wrapped::BigFloatWrappedMethods
+ big_float_operators_ln::BigFloatWrappedLn
+ big_float_operators_wrapped::BigFloatWrappedOperators
{
#[init]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,4 @@ pub trait BigFloatOperators {
r /= b;
r
}
#[endpoint]
fn ln_big_float_ref(&self, a: &BigFloat) -> BigFloat {
a.ln()
.unwrap_or_else(|| sc_panic!("log argument must pe strictly positive"))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
multiversx_sc::imports!();

#[multiversx_sc::module]
pub trait BigFloatWrappedLn {
#[endpoint]
fn ln_big_float_ref(&self, a: &BigFloat) -> BigFloat {
a.ln()
.unwrap_or_else(|| sc_panic!("log argument must pe strictly positive"))
}

#[endpoint]
fn ln_big_float_precision_9(
&self,
a: BigInt,
) -> ManagedDecimalSigned<Self::Api, ConstDecimals<9>> {
let number = self.ln_big_float_ref(&BigFloat::from(a));
number.to_managed_decimal_signed(ConstDecimals)
}

#[endpoint]
fn ln_big_float_any_precision(
&self,
a: BigInt,
precision: usize,
) -> ManagedDecimalSigned<Self::Api, usize> {
let number = self.ln_big_float_ref(&BigFloat::from(a));
number.to_managed_decimal_signed(precision)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,4 @@ pub trait BigFloatWrappedOperators: big_float_operators::BigFloatOperators {
let number = self.div_assign_big_float_ref(&BigFloat::from(a), &BigFloat::from(b));
number.to_fixed_point(&BigFloat::from(fixed_point_denominator))
}

#[endpoint]
fn ln_big_float_ref_wrapped(
&self,
a: BigInt,
precision: usize,
) -> ManagedDecimal<Self::Api, usize> {
let number = self.ln_big_float_ref(&BigFloat::from(a));
number.to_managed_decimal(precision)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ fn world() -> ScenarioWorld {
ScenarioWorld::vm_go()
}

#[test]
fn big_float_ln_go() {
world().run("scenarios/big_float_ln.scen.json");
}

#[test]
fn big_float_new_from_big_int_go() {
world().run("scenarios/big_float_new_from_big_int.scen.json");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ fn world() -> ScenarioWorld {
blockchain
}

#[test]
fn big_float_ln_rs() {
world().run("scenarios/big_float_ln.scen.json");
}

#[test]
fn big_float_new_from_big_int_rs() {
world().run("scenarios/big_float_new_from_big_int.scen.json");
Expand Down
9 changes: 5 additions & 4 deletions contracts/feature-tests/big-float-features/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
////////////////////////////////////////////////////

// Init: 1
// Endpoints: 72
// Endpoints: 73
// Async Callback (empty): 1
// Total number of exported functions: 74
// Total number of exported functions: 75

#![no_std]

Expand Down Expand Up @@ -54,7 +54,6 @@ multiversx_sc_wasm_adapter::endpoints! {
mul_assign_big_float_ref => mul_assign_big_float_ref
div_assign_big_float => div_assign_big_float
div_assign_big_float_ref => div_assign_big_float_ref
ln_big_float_ref => ln_big_float_ref
new_from_parts_big_float_wrapped => new_from_parts_big_float_wrapped
new_from_frac_big_float_wrapped => new_from_frac_big_float_wrapped
new_from_sci_big_float_wrapped => new_from_sci_big_float_wrapped
Expand All @@ -73,6 +72,9 @@ multiversx_sc_wasm_adapter::endpoints! {
pow_big_float_ref_wrapped => pow_big_float_ref_wrapped
big_float_zero_wrapped => big_float_zero_wrapped
big_float_neg_wrapped => big_float_neg_wrapped
ln_big_float_ref => ln_big_float_ref
ln_big_float_precision_9 => ln_big_float_precision_9
ln_big_float_any_precision => ln_big_float_any_precision
add_big_float_wrapped => add_big_float_wrapped
add_big_float_ref_wrapped => add_big_float_ref_wrapped
sub_big_float_wrapped => sub_big_float_wrapped
Expand All @@ -89,7 +91,6 @@ multiversx_sc_wasm_adapter::endpoints! {
mul_assign_big_float_ref_wrapped => mul_assign_big_float_ref_wrapped
div_assign_big_float_wrapped => div_assign_big_float_wrapped
div_assign_big_float_ref_wrapped => div_assign_big_float_ref_wrapped
ln_big_float_ref_wrapped => ln_big_float_ref_wrapped
)
}

Expand Down
2 changes: 1 addition & 1 deletion framework/base/src/api/managed_types/big_int_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub trait BigIntApiImpl: HandleTypeInfo + ErrorApi {

fn bi_sqrt(&self, dest: Self::BigIntHandle, x: Self::BigIntHandle);
fn bi_pow(&self, dest: Self::BigIntHandle, x: Self::BigIntHandle, y: Self::BigIntHandle);
fn bi_log2(&self, x: Self::BigIntHandle) -> u32;
fn bi_log2(&self, x: Self::BigIntHandle) -> i32;

fn bi_and(&self, dest: Self::BigIntHandle, x: Self::BigIntHandle, y: Self::BigIntHandle);
fn bi_or(&self, dest: Self::BigIntHandle, x: Self::BigIntHandle, y: Self::BigIntHandle);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl BigIntApiImpl for super::UncallableApi {
unreachable!()
}

fn bi_log2(&self, _x: Self::BigIntHandle) -> u32 {
fn bi_log2(&self, _x: Self::BigIntHandle) -> i32 {
unreachable!()
}

Expand Down
1 change: 1 addition & 0 deletions framework/base/src/err_msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub const VALUE_EXCEEDS_SLICE: &str = "value exceeds target slice";
pub const CAST_TO_I64_ERROR: &str = "cast to i64 error";
pub const BIG_UINT_EXCEEDS_SLICE: &str = "big uint as_bytes exceed target slice";
pub const BIG_UINT_SUB_NEGATIVE: &str = "cannot subtract because result would be negative";
pub const UNSIGNED_NEGATIVE: &str = "cannot convert to unsigned, number is negative";

pub const DESERIALIZATION_INVALID_BYTE: &str = "call data deserialization error: not a valid byte";
pub const DESERIALIZATION_NOT_32_BYTES: &str =
Expand Down
1 change: 1 addition & 0 deletions framework/base/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod heap;
mod interaction;
mod io;
mod managed;
pub(crate) mod math_util;
mod static_buffer;

pub use crypto::*;
Expand Down
55 changes: 43 additions & 12 deletions framework/base/src/types/managed/basic/big_float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use crate::{
api::{
use_raw_handle, BigFloatApiImpl, ManagedTypeApi, ManagedTypeApiImpl, Sign, StaticVarApiImpl,
},
types::{BigInt, BigUint, Decimals, ManagedDecimal, ManagedType},
contract_base::ErrorHelper,
types::{BigInt, BigUint, Decimals, ManagedDecimalSigned, ManagedType},
};
use alloc::string::String;

Expand Down Expand Up @@ -175,8 +176,11 @@ impl<M: ManagedTypeApi> BigFloat<M> {
(self * denominator).trunc()
}

pub fn to_managed_decimal<T: Decimals>(&self, decimals: T) -> ManagedDecimal<M, T> {
ManagedDecimal::<M, T>::from_big_float(self, decimals)
pub fn to_managed_decimal_signed<T: Decimals>(
&self,
decimals: T,
) -> ManagedDecimalSigned<M, T> {
ManagedDecimalSigned::<M, T>::from_big_float(self, decimals)
}

/// Computes the natural logarithm of the current number.
Expand Down Expand Up @@ -223,13 +227,14 @@ impl<M: ManagedTypeApi> BigFloat<M> {
let trunc_val_unsigned = trunc_val
.into_big_uint()
.unwrap_or_sc_panic("log argument must be positive");
let bit_log2 = trunc_val_unsigned.log2(); // approximate, based on position of the most significant bit
if bit_log2 == u32::MAX {
// means the input was zero, TODO: change log2 return type

// start with aproximation, based on position of the most significant bit
let Some(log2_floor) = trunc_val_unsigned.log2_floor() else {
// means the input was zero, practically unreachable
return BigFloat::from(0i64);
// return None;
}
let divisor = BigFloat::from(1 << bit_log2);
};

let divisor = BigFloat::from(1 << log2_floor);
let x = self / &divisor; // normalize to [1.0, 2.0]

debug_assert!(x >= 1);
Expand All @@ -238,13 +243,11 @@ impl<M: ManagedTypeApi> BigFloat<M> {
let mut result = x.ln_between_one_and_two();

let ln_of_2 = BigFloat::from_frac(693147180, DENOMINATOR); // 0.69314718
result += BigFloat::from(bit_log2 as i32) * ln_of_2;
result += BigFloat::from(log2_floor as i32) * ln_of_2;

result
}
}

impl<M: ManagedTypeApi> BigFloat<M> {
#[inline]
pub fn zero() -> Self {
BigFloat::from_handle(M::managed_type_impl().bf_new_zero())
Expand Down Expand Up @@ -304,6 +307,34 @@ impl<M: ManagedTypeApi> BigFloat<M> {
}
}

impl<M: ManagedTypeApi> From<f64> for BigFloat<M> {
fn from(x: f64) -> Self {
const PREC: i64 = 1_000_000_000;
Self::from_frac((x * PREC as f64) as i64, PREC)
}
}

impl<M: ManagedTypeApi> From<f32> for BigFloat<M> {
fn from(x: f32) -> Self {
Self::from(x as f64)
}
}

impl<M: ManagedTypeApi> BigFloat<M> {
/// Warning: cannot be used in contracts. It is only meant to simplify certain tests.
///
/// It might also not be optimal with respect to precision.
pub fn to_f64(&self) -> f64 {
const PREC: i64 = 1_000_000_000;
let mut rescaled = Self::from(PREC);
rescaled *= self;
let ln_units = rescaled.trunc().to_i64().unwrap_or_else(|| {
ErrorHelper::<M>::signal_error_with_message("BigFloat out of precision range")
});
ln_units as f64 / PREC as f64
}
}

impl<M: ManagedTypeApi> Clone for BigFloat<M> {
fn clone(&self) -> Self {
let new_handle: M::BigFloatHandle = use_raw_handle(M::static_var_api_impl().next_handle());
Expand Down
Loading

0 comments on commit 260b498

Please sign in to comment.