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 <ronald.hood@yale.edu>
This commit is contained in:
parent
1d1c2b178b
commit
5611ad8bd5
|
@ -70,6 +70,25 @@ pub enum MathInstruction {
|
|||
/// The divisor
|
||||
divisor: f32,
|
||||
},
|
||||
|
||||
/// Exponentiate a float base by a power
|
||||
///
|
||||
/// No accounts required for this instruction
|
||||
F32Exponentiate {
|
||||
/// The base
|
||||
base: f32,
|
||||
/// The exponent
|
||||
exponent: f32,
|
||||
},
|
||||
|
||||
/// Natural Log of a float
|
||||
///
|
||||
/// No accounts required for this instruction
|
||||
F32NaturalLog {
|
||||
/// The argument
|
||||
argument: f32,
|
||||
},
|
||||
|
||||
/// Don't do anything for comparison
|
||||
///
|
||||
/// No accounts required for this instruction
|
||||
|
@ -87,7 +106,7 @@ pub fn precise_sqrt(radicand: u64) -> Instruction {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create SquareRoot instruction
|
||||
/// Create U64 SquareRoot instruction
|
||||
pub fn sqrt_u64(radicand: u64) -> Instruction {
|
||||
Instruction {
|
||||
program_id: id(),
|
||||
|
@ -98,7 +117,7 @@ pub fn sqrt_u64(radicand: u64) -> Instruction {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create SquareRoot instruction
|
||||
/// Create U128 SquareRoot instruction
|
||||
pub fn sqrt_u128(radicand: u128) -> Instruction {
|
||||
Instruction {
|
||||
program_id: id(),
|
||||
|
@ -109,7 +128,7 @@ pub fn sqrt_u128(radicand: u128) -> Instruction {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create PreciseSquareRoot instruction
|
||||
/// Create U64 Multiplication instruction
|
||||
pub fn u64_multiply(multiplicand: u64, multiplier: u64) -> Instruction {
|
||||
Instruction {
|
||||
program_id: id(),
|
||||
|
@ -123,7 +142,7 @@ pub fn u64_multiply(multiplicand: u64, multiplier: u64) -> Instruction {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create PreciseSquareRoot instruction
|
||||
/// Create U64 Division instruction
|
||||
pub fn u64_divide(dividend: u64, divisor: u64) -> Instruction {
|
||||
Instruction {
|
||||
program_id: id(),
|
||||
|
@ -134,7 +153,7 @@ pub fn u64_divide(dividend: u64, divisor: u64) -> Instruction {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create PreciseSquareRoot instruction
|
||||
/// Create F32 Multiplication instruction
|
||||
pub fn f32_multiply(multiplicand: f32, multiplier: f32) -> Instruction {
|
||||
Instruction {
|
||||
program_id: id(),
|
||||
|
@ -148,7 +167,7 @@ pub fn f32_multiply(multiplicand: f32, multiplier: f32) -> Instruction {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create PreciseSquareRoot instruction
|
||||
/// Create F32 Division instruction
|
||||
pub fn f32_divide(dividend: f32, divisor: f32) -> Instruction {
|
||||
Instruction {
|
||||
program_id: id(),
|
||||
|
@ -159,7 +178,29 @@ pub fn f32_divide(dividend: f32, divisor: f32) -> Instruction {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create PreciseSquareRoot instruction
|
||||
/// Create F32 Exponentiate instruction
|
||||
pub fn f32_exponentiate(base: f32, exponent: f32) -> Instruction {
|
||||
Instruction {
|
||||
program_id: id(),
|
||||
accounts: vec![],
|
||||
data: MathInstruction::F32Exponentiate { base, exponent }
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create F32 Natural Log instruction
|
||||
pub fn f32_natural_log(argument: f32) -> Instruction {
|
||||
Instruction {
|
||||
program_id: id(),
|
||||
accounts: vec![],
|
||||
data: MathInstruction::F32NaturalLog { argument }
|
||||
.try_to_vec()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create Noop instruction
|
||||
pub fn noop() -> Instruction {
|
||||
Instruction {
|
||||
program_id: id(),
|
||||
|
@ -277,6 +318,35 @@ mod tests {
|
|||
assert_eq!(instruction.program_id, crate::id());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32_exponentiate() {
|
||||
let instruction = f32_exponentiate(f32::MAX, f32::MAX);
|
||||
assert_eq!(0, instruction.accounts.len());
|
||||
assert_eq!(
|
||||
instruction.data,
|
||||
MathInstruction::F32Exponentiate {
|
||||
base: f32::MAX,
|
||||
exponent: f32::MAX
|
||||
}
|
||||
.try_to_vec()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(instruction.program_id, crate::id())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32_natural_log() {
|
||||
let instruction = f32_natural_log(f32::MAX);
|
||||
assert_eq!(0, instruction.accounts.len());
|
||||
assert_eq!(
|
||||
instruction.data,
|
||||
MathInstruction::F32NaturalLog { argument: f32::MAX }
|
||||
.try_to_vec()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(instruction.program_id, crate::id())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_noop() {
|
||||
let instruction = noop();
|
||||
|
|
|
@ -33,6 +33,16 @@ fn f32_divide(dividend: f32, divisor: f32) -> f32 {
|
|||
dividend / divisor
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn f32_exponentiate(base: f32, exponent: f32) -> f32 {
|
||||
base.powf(exponent)
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn f32_natural_log(argument: f32) -> f32 {
|
||||
argument.ln()
|
||||
}
|
||||
|
||||
/// Instruction processor
|
||||
pub fn process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
|
@ -104,6 +114,22 @@ pub fn process_instruction(
|
|||
msg!("{}", result as u64);
|
||||
Ok(())
|
||||
}
|
||||
MathInstruction::F32Exponentiate { base, exponent } => {
|
||||
msg!("Calculating f32 Exponent");
|
||||
sol_log_compute_units();
|
||||
let result = f32_exponentiate(base, exponent);
|
||||
sol_log_compute_units();
|
||||
msg!("{}", result as u64);
|
||||
Ok(())
|
||||
}
|
||||
MathInstruction::F32NaturalLog { argument } => {
|
||||
msg!("Calculating f32 Natural Log");
|
||||
sol_log_compute_units();
|
||||
let result = f32_natural_log(argument);
|
||||
sol_log_compute_units();
|
||||
msg!("{}", result as u64);
|
||||
Ok(())
|
||||
}
|
||||
MathInstruction::Noop => {
|
||||
msg!("Do nothing");
|
||||
msg!("{}", 0_u64);
|
||||
|
@ -142,6 +168,24 @@ mod tests {
|
|||
assert_eq!(2.0, f32_divide(2.0, 1.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32_exponentiate() {
|
||||
assert_eq!(16.0, f32_exponentiate(4.0, 2.0));
|
||||
assert_eq!(4.0, f32_exponentiate(16.0, 0.5))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32_natural_log() {
|
||||
let one = 1.0f32;
|
||||
// e^1
|
||||
let e = one.exp();
|
||||
|
||||
// ln(e) - 1 == 0
|
||||
let abs_difference = (f32_natural_log(e) - 1.0).abs();
|
||||
|
||||
assert!(abs_difference <= f32::EPSILON);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_instruction() {
|
||||
let program_id = Pubkey::new_unique();
|
||||
|
@ -167,6 +211,13 @@ mod tests {
|
|||
dividend: 2.0,
|
||||
divisor: 2.0,
|
||||
},
|
||||
MathInstruction::F32Exponentiate {
|
||||
base: 4.0,
|
||||
exponent: 2.0,
|
||||
},
|
||||
MathInstruction::F32NaturalLog {
|
||||
argument: std::f32::consts::E,
|
||||
},
|
||||
MathInstruction::Noop,
|
||||
] {
|
||||
let input = math_instruction.try_to_vec().unwrap();
|
||||
|
|
|
@ -147,6 +147,38 @@ async fn test_f32_divide() {
|
|||
banks_client.process_transaction(transaction).await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_f32_exponentiate() {
|
||||
let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction));
|
||||
|
||||
pc.set_compute_max_units(1400);
|
||||
|
||||
let (mut banks_client, payer, recent_blockhash) = pc.start().await;
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(
|
||||
&[instruction::f32_exponentiate(4_f32, 2_f32)],
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
transaction.sign(&[&payer], recent_blockhash);
|
||||
banks_client.process_transaction(transaction).await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_f32_natural_log() {
|
||||
let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction));
|
||||
|
||||
pc.set_compute_max_units(3500);
|
||||
|
||||
let (mut banks_client, payer, recent_blockhash) = pc.start().await;
|
||||
|
||||
let mut transaction = Transaction::new_with_payer(
|
||||
&[instruction::f32_natural_log(1_f32.exp())],
|
||||
Some(&payer.pubkey()),
|
||||
);
|
||||
transaction.sign(&[&payer], recent_blockhash);
|
||||
banks_client.process_transaction(transaction).await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_noop() {
|
||||
let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction));
|
||||
|
|
Loading…
Reference in New Issue