Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 5611ad8

Browse files
Float exponentiation and logarithm instructions - MLH (#2968)
* Float exponentiation and logarithm instructions * Corrections to instructions and tests * Revamping Math Instructions * Changed E Constant and modified compute max * Formatting and Clippy Linting * increased log computation allowance Co-authored-by: Ronald Hood <[email protected]>
1 parent 1d1c2b1 commit 5611ad8

File tree

3 files changed

+160
-7
lines changed

3 files changed

+160
-7
lines changed

libraries/math/src/instruction.rs

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,25 @@ pub enum MathInstruction {
7070
/// The divisor
7171
divisor: f32,
7272
},
73+
74+
/// Exponentiate a float base by a power
75+
///
76+
/// No accounts required for this instruction
77+
F32Exponentiate {
78+
/// The base
79+
base: f32,
80+
/// The exponent
81+
exponent: f32,
82+
},
83+
84+
/// Natural Log of a float
85+
///
86+
/// No accounts required for this instruction
87+
F32NaturalLog {
88+
/// The argument
89+
argument: f32,
90+
},
91+
7392
/// Don't do anything for comparison
7493
///
7594
/// No accounts required for this instruction
@@ -87,7 +106,7 @@ pub fn precise_sqrt(radicand: u64) -> Instruction {
87106
}
88107
}
89108

90-
/// Create SquareRoot instruction
109+
/// Create U64 SquareRoot instruction
91110
pub fn sqrt_u64(radicand: u64) -> Instruction {
92111
Instruction {
93112
program_id: id(),
@@ -98,7 +117,7 @@ pub fn sqrt_u64(radicand: u64) -> Instruction {
98117
}
99118
}
100119

101-
/// Create SquareRoot instruction
120+
/// Create U128 SquareRoot instruction
102121
pub fn sqrt_u128(radicand: u128) -> Instruction {
103122
Instruction {
104123
program_id: id(),
@@ -109,7 +128,7 @@ pub fn sqrt_u128(radicand: u128) -> Instruction {
109128
}
110129
}
111130

112-
/// Create PreciseSquareRoot instruction
131+
/// Create U64 Multiplication instruction
113132
pub fn u64_multiply(multiplicand: u64, multiplier: u64) -> Instruction {
114133
Instruction {
115134
program_id: id(),
@@ -123,7 +142,7 @@ pub fn u64_multiply(multiplicand: u64, multiplier: u64) -> Instruction {
123142
}
124143
}
125144

126-
/// Create PreciseSquareRoot instruction
145+
/// Create U64 Division instruction
127146
pub fn u64_divide(dividend: u64, divisor: u64) -> Instruction {
128147
Instruction {
129148
program_id: id(),
@@ -134,7 +153,7 @@ pub fn u64_divide(dividend: u64, divisor: u64) -> Instruction {
134153
}
135154
}
136155

137-
/// Create PreciseSquareRoot instruction
156+
/// Create F32 Multiplication instruction
138157
pub fn f32_multiply(multiplicand: f32, multiplier: f32) -> Instruction {
139158
Instruction {
140159
program_id: id(),
@@ -148,7 +167,7 @@ pub fn f32_multiply(multiplicand: f32, multiplier: f32) -> Instruction {
148167
}
149168
}
150169

151-
/// Create PreciseSquareRoot instruction
170+
/// Create F32 Division instruction
152171
pub fn f32_divide(dividend: f32, divisor: f32) -> Instruction {
153172
Instruction {
154173
program_id: id(),
@@ -159,7 +178,29 @@ pub fn f32_divide(dividend: f32, divisor: f32) -> Instruction {
159178
}
160179
}
161180

162-
/// Create PreciseSquareRoot instruction
181+
/// Create F32 Exponentiate instruction
182+
pub fn f32_exponentiate(base: f32, exponent: f32) -> Instruction {
183+
Instruction {
184+
program_id: id(),
185+
accounts: vec![],
186+
data: MathInstruction::F32Exponentiate { base, exponent }
187+
.try_to_vec()
188+
.unwrap(),
189+
}
190+
}
191+
192+
/// Create F32 Natural Log instruction
193+
pub fn f32_natural_log(argument: f32) -> Instruction {
194+
Instruction {
195+
program_id: id(),
196+
accounts: vec![],
197+
data: MathInstruction::F32NaturalLog { argument }
198+
.try_to_vec()
199+
.unwrap(),
200+
}
201+
}
202+
203+
/// Create Noop instruction
163204
pub fn noop() -> Instruction {
164205
Instruction {
165206
program_id: id(),
@@ -277,6 +318,35 @@ mod tests {
277318
assert_eq!(instruction.program_id, crate::id());
278319
}
279320

321+
#[test]
322+
fn test_f32_exponentiate() {
323+
let instruction = f32_exponentiate(f32::MAX, f32::MAX);
324+
assert_eq!(0, instruction.accounts.len());
325+
assert_eq!(
326+
instruction.data,
327+
MathInstruction::F32Exponentiate {
328+
base: f32::MAX,
329+
exponent: f32::MAX
330+
}
331+
.try_to_vec()
332+
.unwrap()
333+
);
334+
assert_eq!(instruction.program_id, crate::id())
335+
}
336+
337+
#[test]
338+
fn test_f32_natural_log() {
339+
let instruction = f32_natural_log(f32::MAX);
340+
assert_eq!(0, instruction.accounts.len());
341+
assert_eq!(
342+
instruction.data,
343+
MathInstruction::F32NaturalLog { argument: f32::MAX }
344+
.try_to_vec()
345+
.unwrap()
346+
);
347+
assert_eq!(instruction.program_id, crate::id())
348+
}
349+
280350
#[test]
281351
fn test_noop() {
282352
let instruction = noop();

libraries/math/src/processor.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ fn f32_divide(dividend: f32, divisor: f32) -> f32 {
3333
dividend / divisor
3434
}
3535

36+
#[inline(never)]
37+
fn f32_exponentiate(base: f32, exponent: f32) -> f32 {
38+
base.powf(exponent)
39+
}
40+
41+
#[inline(never)]
42+
fn f32_natural_log(argument: f32) -> f32 {
43+
argument.ln()
44+
}
45+
3646
/// Instruction processor
3747
pub fn process_instruction(
3848
_program_id: &Pubkey,
@@ -104,6 +114,22 @@ pub fn process_instruction(
104114
msg!("{}", result as u64);
105115
Ok(())
106116
}
117+
MathInstruction::F32Exponentiate { base, exponent } => {
118+
msg!("Calculating f32 Exponent");
119+
sol_log_compute_units();
120+
let result = f32_exponentiate(base, exponent);
121+
sol_log_compute_units();
122+
msg!("{}", result as u64);
123+
Ok(())
124+
}
125+
MathInstruction::F32NaturalLog { argument } => {
126+
msg!("Calculating f32 Natural Log");
127+
sol_log_compute_units();
128+
let result = f32_natural_log(argument);
129+
sol_log_compute_units();
130+
msg!("{}", result as u64);
131+
Ok(())
132+
}
107133
MathInstruction::Noop => {
108134
msg!("Do nothing");
109135
msg!("{}", 0_u64);
@@ -142,6 +168,24 @@ mod tests {
142168
assert_eq!(2.0, f32_divide(2.0, 1.0));
143169
}
144170

171+
#[test]
172+
fn test_f32_exponentiate() {
173+
assert_eq!(16.0, f32_exponentiate(4.0, 2.0));
174+
assert_eq!(4.0, f32_exponentiate(16.0, 0.5))
175+
}
176+
177+
#[test]
178+
fn test_f32_natural_log() {
179+
let one = 1.0f32;
180+
// e^1
181+
let e = one.exp();
182+
183+
// ln(e) - 1 == 0
184+
let abs_difference = (f32_natural_log(e) - 1.0).abs();
185+
186+
assert!(abs_difference <= f32::EPSILON);
187+
}
188+
145189
#[test]
146190
fn test_process_instruction() {
147191
let program_id = Pubkey::new_unique();
@@ -167,6 +211,13 @@ mod tests {
167211
dividend: 2.0,
168212
divisor: 2.0,
169213
},
214+
MathInstruction::F32Exponentiate {
215+
base: 4.0,
216+
exponent: 2.0,
217+
},
218+
MathInstruction::F32NaturalLog {
219+
argument: std::f32::consts::E,
220+
},
170221
MathInstruction::Noop,
171222
] {
172223
let input = math_instruction.try_to_vec().unwrap();

libraries/math/tests/instruction_count.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,38 @@ async fn test_f32_divide() {
147147
banks_client.process_transaction(transaction).await.unwrap();
148148
}
149149

150+
#[tokio::test]
151+
async fn test_f32_exponentiate() {
152+
let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction));
153+
154+
pc.set_compute_max_units(1400);
155+
156+
let (mut banks_client, payer, recent_blockhash) = pc.start().await;
157+
158+
let mut transaction = Transaction::new_with_payer(
159+
&[instruction::f32_exponentiate(4_f32, 2_f32)],
160+
Some(&payer.pubkey()),
161+
);
162+
transaction.sign(&[&payer], recent_blockhash);
163+
banks_client.process_transaction(transaction).await.unwrap();
164+
}
165+
166+
#[tokio::test]
167+
async fn test_f32_natural_log() {
168+
let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction));
169+
170+
pc.set_compute_max_units(3500);
171+
172+
let (mut banks_client, payer, recent_blockhash) = pc.start().await;
173+
174+
let mut transaction = Transaction::new_with_payer(
175+
&[instruction::f32_natural_log(1_f32.exp())],
176+
Some(&payer.pubkey()),
177+
);
178+
transaction.sign(&[&payer], recent_blockhash);
179+
banks_client.process_transaction(transaction).await.unwrap();
180+
}
181+
150182
#[tokio::test]
151183
async fn test_noop() {
152184
let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction));

0 commit comments

Comments
 (0)