Skip to content

Commit

Permalink
BigUint - ln
Browse files Browse the repository at this point in the history
  • Loading branch information
andrei-marinica committed Jun 13, 2024
1 parent 0f0bff6 commit 8540cc7
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub trait BigIntMethods {
}

#[endpoint]
fn biguint_overwrite_u64(&self, bu: BigUint, small: u64) -> BigUint {
fn biguint_overwrite_u64(&self, mut bu: BigUint, small: u64) -> BigUint {
bu.overwrite_u64(small);
bu
}
Expand Down
51 changes: 48 additions & 3 deletions framework/base/src/types/managed/basic/big_uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ use crate::{
DecodeErrorHandler, EncodeErrorHandler, NestedDecode, NestedDecodeInput, NestedEncode,
NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput, TryStaticCast,
},
contract_base::ErrorHelper,
formatter::{hex_util::encode_bytes_as_hex, FormatBuffer, FormatByteReceiver, SCDisplay},
proxy_imports::ManagedRef,
types::{heap::BoxedBytes, ManagedBuffer, ManagedBufferCachedBuilder, ManagedType},
types::{
heap::BoxedBytes, ConstDecimals, Decimals, ManagedBuffer, ManagedBufferCachedBuilder,
ManagedDecimal, ManagedRef, ManagedType,
},
};

use super::cast_to_i64::cast_to_i64;
Expand Down Expand Up @@ -176,7 +179,7 @@ impl<M: ManagedTypeApi> BigUint<M> {
}

#[inline]
pub fn overwrite_u64(&self, value: u64) {
pub fn overwrite_u64(&mut self, value: u64) {
Self::set_value(self.handle.clone(), value);
}

Expand Down Expand Up @@ -236,6 +239,48 @@ impl<M: ManagedTypeApi> BigUint<M> {
let api = M::managed_type_impl();
api.bi_log2(self.handle.clone())
}

pub fn ln(&self) -> ManagedDecimal<M, ConstDecimals<9>> {
let bit_log2 = self.log2(); // aproximate, based on position of the most significant bit
let scaling_factor_9 = ConstDecimals::<9>.scaling_factor();
let divisor = BigUint::from(1u64 << bit_log2);
let normalized = self * &*scaling_factor_9 / divisor;

let x = normalized
.to_u64()
.unwrap_or_else(|| ErrorHelper::<M>::signal_error_with_message("ln internal error"))
as i64;

const DENOMINATOR: i64 = 1_000_000_000;

// x normalized to [1.0, 2.0]
debug_assert!(x >= DENOMINATOR);
debug_assert!(x <= 2 * DENOMINATOR);

let mut result: i64 = -56570851; // -0.056570851
result *= x;
result /= DENOMINATOR;
result += 447179550; // 0.44717955
result *= x;
result /= DENOMINATOR;
result += -1469956800; // -1.4699568
result *= x;
result /= DENOMINATOR;
result += 2821202600; // 2.8212026
result *= x;
result /= DENOMINATOR;
result += -1741793900; // -1.7417939

const LN_OF_2_SCALE_9: i64 = 693147180; // 0.69314718
result += bit_log2 as i64 * LN_OF_2_SCALE_9;

debug_assert!(result > 0);

let mut result_bi = normalized; // reuse handle
result_bi.overwrite_u64(result as u64);

ManagedDecimal::const_decimals_from_raw(result_bi)
}
}

impl<M: ManagedTypeApi> Clone for BigUint<M> {
Expand Down
10 changes: 10 additions & 0 deletions framework/scenario/tests/big_uint_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use multiversx_sc::types::BigUint;
use multiversx_sc_scenario::api::StaticApi;

#[test]
fn test_big_uint_ln() {
// ln(23) = 3.1354942159291497
let x = BigUint::<StaticApi>::from(23u32);
let ln_x = x.ln();
assert_eq!(ln_x.to_string(), "3.135514649"); // first 6 decimals are ok
}

0 comments on commit 8540cc7

Please sign in to comment.