soroban_math/
log.rs

1use soroban_sdk::{Bytes, Env, I256};
2
3use crate::{error::ArithmeticError, SoroNum};
4pub trait Logarithm {
5    fn log2<const CALC_SCALE: u32, const SCALE_OUT: u32>(
6        &self,
7        env: &Env,
8    ) -> Result<Self, ArithmeticError>
9    where
10        Self: Sized;
11
12    fn log10<const CALC_SCALE: u32, const SCALE_OUT: u32>(
13        &self,
14        env: &Env,
15    ) -> Result<Self, ArithmeticError>
16    where
17        Self: Sized;
18}
19
20pub trait I256Extensions {
21    fn leading_zeros(&self) -> u32;
22}
23
24impl I256Extensions for I256 {
25    fn leading_zeros(&self) -> u32 {
26        let bytes: Bytes = self.to_be_bytes();
27        let mut leading_zeros = 0;
28
29        for byte_index in 0..bytes.len() {
30            let byte_value = bytes.get(byte_index).unwrap_or(0);
31            if byte_value == 0 {
32                leading_zeros += 8; // Each byte has 8 bits.
33            } else {
34                leading_zeros += byte_value.leading_zeros();
35                break;
36            }
37        }
38
39        leading_zeros
40    }
41}
42
43impl Logarithm for SoroNum<i128> {
44    fn log2<const CALC_SCALE: u32, const SCALE_OUT: u32>(
45        &self,
46        env: &Env,
47    ) -> Result<Self, ArithmeticError> {
48        if self.value <= 0 {
49            return Err(ArithmeticError::InvalidInput);
50        }
51
52        let mut value = I256::from_i128(env, self.value);
53        let mut log2_result = I256::from_i128(env, 0);
54
55        // Iterate to calculate log2
56        while value > I256::from_i128(env, 1) {
57            value = value.div(&I256::from_i128(env, 2));
58            log2_result = log2_result.add(&I256::from_i128(env, 1));
59        }
60
61        // Scale result
62        let scaled_result = log2_result.mul(&I256::from_i128(env, 10).pow(SCALE_OUT));
63
64        if scaled_result > I256::from_i128(env, i128::MAX)
65            || scaled_result < I256::from_i128(env, i128::MIN)
66        {
67            Err(ArithmeticError::Overflow)
68        } else {
69            Ok(SoroNum {
70                value: scaled_result.to_i128().unwrap(),
71                scale: SCALE_OUT,
72            })
73        }
74    }
75
76    fn log10<const CALC_SCALE: u32, const SCALE_OUT: u32>(
77        &self,
78        env: &Env,
79    ) -> Result<Self, ArithmeticError> {
80        if self.value <= 0 {
81            return Err(ArithmeticError::InvalidInput);
82        }
83
84        let mut value = I256::from_i128(env, self.value);
85        let mut log10_result = I256::from_i128(env, 0);
86        let ten = I256::from_i128(env, 10);
87
88        // Iterate to calculate log10
89        while value >= ten {
90            value = value.div(&ten);
91            log10_result = log10_result.add(&I256::from_i128(env, 1));
92        }
93
94        // Scale result
95        let scaled_result = log10_result.mul(&I256::from_i128(env, 10).pow(SCALE_OUT));
96
97        if scaled_result > I256::from_i128(env, i128::MAX)
98            || scaled_result < I256::from_i128(env, i128::MIN)
99        {
100            Err(ArithmeticError::Overflow)
101        } else {
102            Ok(SoroNum {
103                value: scaled_result.to_i128().unwrap(),
104                scale: SCALE_OUT,
105            })
106        }
107    }
108}