diff --git a/libraries/math/src/instruction.rs b/libraries/math/src/instruction.rs index 5fd4dc6c4e4..c9e3b40c4ce 100644 --- a/libraries/math/src/instruction.rs +++ b/libraries/math/src/instruction.rs @@ -107,6 +107,43 @@ pub enum MathInstruction { exponent: f64, }, + /// Multiply two u128 values + /// + /// No accounts required for this instruction + U128Multiply { + /// The multiplicand + multiplicand: u128, + /// The multipier + multiplier: u128, + }, + /// Divide two u128 values + /// + /// No accounts required for this instruction + U128Divide { + /// The dividend + dividend: u128, + /// The divisor + divisor: u128, + }, + /// Multiply two f64 values + /// + /// No accounts required for this instruction + F64Multiply { + /// The multiplicand + multiplicand: f64, + /// The multipier + multiplier: f64, + }, + /// Divide two f64 values + /// + /// No accounts required for this instruction + F64Divide { + /// The dividend + dividend: f64, + /// The divisor + divisor: f64, + }, + /// Don't do anything for comparison /// /// No accounts required for this instruction @@ -220,6 +257,50 @@ pub fn f64_pow(base: f64, exponent: f64) -> Instruction { } } +/// Create U128 Multiplication instruction +pub fn u128_multiply(multiplicand: u128, multiplier: u128) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::U128Multiply { + multiplicand, + multiplier, + }) + .unwrap(), + } +} + +/// Create U128 Division instruction +pub fn u128_divide(dividend: u128, divisor: u128) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::U128Divide { dividend, divisor }).unwrap(), + } +} + +/// Create F64 Multiplication instruction +pub fn f64_multiply(multiplicand: f64, multiplier: f64) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::F64Multiply { + multiplicand, + multiplier, + }) + .unwrap(), + } +} + +/// Create F64 Division instruction +pub fn f64_divide(dividend: f64, divisor: f64) -> Instruction { + Instruction { + program_id: id(), + accounts: vec![], + data: borsh::to_vec(&MathInstruction::F64Divide { dividend, divisor }).unwrap(), + } +} + /// Create Noop instruction pub fn noop() -> Instruction { Instruction { diff --git a/libraries/math/src/processor.rs b/libraries/math/src/processor.rs index fff69dd9703..dfc2bb176b6 100644 --- a/libraries/math/src/processor.rs +++ b/libraries/math/src/processor.rs @@ -50,6 +50,30 @@ fn f32_natural_log(argument: f32) -> f32 { argument.ln() } +/// u128_multiply +#[inline(never)] +fn u128_multiply(multiplicand: u128, multiplier: u128) -> u128 { + multiplicand * multiplier +} + +/// u128_divide +#[inline(never)] +fn u128_divide(dividend: u128, divisor: u128) -> u128 { + dividend / divisor +} + +/// f64_multiply +#[inline(never)] +fn f64_multiply(multiplicand: f64, multiplier: f64) -> f64 { + multiplicand * multiplier +} + +/// f64_divide +#[inline(never)] +fn f64_divide(dividend: f64, divisor: f64) -> f64 { + dividend / divisor +} + /// Instruction processor pub fn process_instruction( _program_id: &Pubkey, @@ -157,6 +181,44 @@ pub fn process_instruction( msg!("{}", result as u64); Ok(()) } + MathInstruction::U128Multiply { + multiplicand, + multiplier, + } => { + msg!("Calculating u128 Multiply"); + sol_log_compute_units(); + let result = u128_multiply(multiplicand, multiplier); + sol_log_compute_units(); + msg!("{}", result); + Ok(()) + } + MathInstruction::U128Divide { dividend, divisor } => { + msg!("Calculating u128 Divide"); + sol_log_compute_units(); + let result = u128_divide(dividend, divisor); + sol_log_compute_units(); + msg!("{}", result); + Ok(()) + } + MathInstruction::F64Multiply { + multiplicand, + multiplier, + } => { + msg!("Calculating f64 Multiply"); + sol_log_compute_units(); + let result = f64_multiply(multiplicand, multiplier); + sol_log_compute_units(); + msg!("{}", result as u64); + Ok(()) + } + MathInstruction::F64Divide { dividend, divisor } => { + msg!("Calculating f64 Divide"); + sol_log_compute_units(); + let result = f64_divide(dividend, divisor); + sol_log_compute_units(); + msg!("{}", result as u64); + Ok(()) + } MathInstruction::Noop => { msg!("Do nothing"); msg!("{}", 0_u64); diff --git a/libraries/math/tests/instruction_count.rs b/libraries/math/tests/instruction_count.rs index 4d414645c72..3604325d4cf 100644 --- a/libraries/math/tests/instruction_count.rs +++ b/libraries/math/tests/instruction_count.rs @@ -214,6 +214,70 @@ async fn test_f64_pow() { banks_client.process_transaction(transaction).await.unwrap(); } +#[tokio::test] +async fn test_u128_multiply() { + let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); + + pc.set_compute_max_units(10000); + + let (mut banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::u128_multiply(u64::MAX.into(), u64::MAX.into())], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_u128_divide() { + let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); + + pc.set_compute_max_units(10000); + + let (mut banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::u128_divide(u128::MAX, u128::MAX / 69)], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_f64_multiply() { + let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); + + pc.set_compute_max_units(10000); + + let (mut banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::f64_multiply(f64::powf(2., 42.), 1e-4)], + Some(&payer.pubkey()), + ); + transaction.sign(&[&payer], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn test_f64_divide() { + let mut pc = ProgramTest::new("spl_math", id(), processor!(process_instruction)); + + pc.set_compute_max_units(10000); + + let (mut banks_client, payer, recent_blockhash) = pc.start().await; + + let mut transaction = Transaction::new_with_payer( + &[instruction::f64_divide(f64::powf(2., 42.), 420420.6969)], + 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));