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; } 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 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 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 while value >= ten {
90 value = value.div(&ten);
91 log10_result = log10_result.add(&I256::from_i128(env, 1));
92 }
93
94 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}