-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add support for some math functions
- Loading branch information
1 parent
5d00e2c
commit 9a61ade
Showing
9 changed files
with
201,408 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,9 +10,19 @@ license = "Apache-2.0" | |
readme = "README.md" | ||
authors = ["Andrew Westberg <[email protected]>"] | ||
|
||
[features] | ||
default = ["gmp"] | ||
gmp = ["dep:gmp-mpfr-sys"] | ||
num = ["dep:num-bigint", "dep:num-integer", "dep:num-traits"] | ||
|
||
[dependencies] | ||
# rug = "1.24.1" | ||
gmp-mpfr-sys = { version = "1.6.4", features = ["mpc"], default-features = false, optional = true } | ||
once_cell = "1.19.0" | ||
num-bigint = { version = "0.4.6", optional = true } | ||
num-integer = { version = "0.1.46", optional = true } | ||
num-traits = { version = "0.2.19", optional = true } | ||
regex = "1.10.5" | ||
thiserror = "1.0.61" | ||
|
||
[dev-dependencies] | ||
quickcheck = "1.0" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,14 @@ | ||
pub mod math; | ||
|
||
// Ensure only one of `gmp` or `num` is enabled, not both. | ||
#[cfg(all(feature = "gmp", feature = "num"))] | ||
compile_error!("Features `gmp` and `num` are mutually exclusive."); | ||
|
||
#[cfg(all(not(feature = "gmp"), not(feature = "num")))] | ||
compile_error!("One of the features `gmp` or `num` must be enabled."); | ||
|
||
#[cfg(feature = "gmp")] | ||
pub mod math_gmp; | ||
|
||
#[cfg(feature = "num")] | ||
pub mod math_num; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,133 @@ | ||
/*! | ||
# Cardano Math functions | ||
*/ | ||
*/ | ||
|
||
pub fn add(a: i32, b: i32) -> i32 { | ||
a + b | ||
use std::fmt::{Debug, Display}; | ||
use std::ops::Neg; | ||
|
||
use thiserror::Error; | ||
|
||
#[derive(Debug, Error)] | ||
pub enum Error { | ||
#[error("error in regex")] | ||
RegexFailure(#[from] regex::Error), | ||
|
||
#[error("string contained a nul byte")] | ||
NulFailure(#[from] std::ffi::NulError), | ||
} | ||
|
||
pub const DEFAULT_PRECISION: u64 = 34; | ||
|
||
pub trait FixedPrecision: | ||
Neg + Display + Clone + PartialEq + Debug + From<u64> + From<i64> | ||
{ | ||
/// Creates a new fixed point number with the given precision | ||
fn new(precision: u64) -> Self; | ||
|
||
/// Creates a new fixed point number from an integer string. Precision tells us how many decimals | ||
fn from_str(s: &str, precision: u64) -> Result<Self, Error>; | ||
|
||
/// Returns the precision of the fixed point number | ||
fn precision(&self) -> u64; | ||
|
||
/// Performs the 'exp' approximation. First does the scaling of 'x' to [0,1] | ||
/// and then calls the continued fraction approximation function. | ||
fn exp(&self) -> Self; | ||
|
||
/// Entry point for 'ln' approximation. First does the necessary scaling, and | ||
/// then calls the continued fraction calculation. For any value outside the | ||
/// domain, i.e., 'x in (-inf,0]', the function returns '-INFINITY'. | ||
fn ln(&self) -> Self; | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::fs::File; | ||
use std::io::BufRead; | ||
use std::path::PathBuf; | ||
|
||
#[cfg(feature = "gmp")] | ||
use crate::math_gmp::Decimal; | ||
#[cfg(feature = "num")] | ||
use crate::math_num::Decimal; | ||
|
||
use super::*; | ||
|
||
#[test] | ||
fn test_add() { | ||
assert_eq!(add(1, 2), 3); | ||
fn test_fixed_precision() { | ||
let fp: Decimal = Decimal::new(34); | ||
assert_eq!(fp.precision(), 34); | ||
assert_eq!(fp.to_string(), "0.0000000000000000000000000000000000"); | ||
} | ||
|
||
#[test] | ||
fn test_fixed_precision_eq() { | ||
let fp1: Decimal = Decimal::new(34); | ||
let fp2: Decimal = Decimal::new(34); | ||
assert_eq!(fp1, fp2); | ||
} | ||
|
||
#[test] | ||
fn test_fixed_precision_from_str() { | ||
let fp: Decimal = Decimal::from_str("1234567890123456789012345678901234", 34).unwrap(); | ||
assert_eq!(fp.precision(), 34); | ||
assert_eq!(fp.to_string(), "0.1234567890123456789012345678901234"); | ||
|
||
let fp: Decimal = Decimal::from_str("-1234567890123456789012345678901234", 30).unwrap(); | ||
assert_eq!(fp.precision(), 30); | ||
assert_eq!(fp.to_string(), "-1234.567890123456789012345678901234"); | ||
|
||
let fp: Decimal = Decimal::from_str("-1234567890123456789012345678901234", 34).unwrap(); | ||
assert_eq!(fp.precision(), 34); | ||
assert_eq!(fp.to_string(), "-0.1234567890123456789012345678901234"); | ||
} | ||
|
||
#[test] | ||
fn test_fixed_precision_exp() { | ||
let fp: Decimal = Decimal::from(1u64); | ||
assert_eq!(fp.to_string(), "1.0000000000000000000000000000000000"); | ||
let exp_fp = fp.exp(); | ||
assert_eq!(exp_fp.to_string(), "2.7182818284590452353602874043083282"); | ||
} | ||
|
||
#[test] | ||
fn golden_tests() { | ||
let mut data_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); | ||
data_path.push("tests/data/golden_tests.txt"); | ||
|
||
// read each line of golden_tests.txt | ||
let file = File::open(data_path).expect("golden_tests.txt: file not found"); | ||
let reader = std::io::BufReader::new(file); | ||
|
||
// read each line of golden_tests_result.txt | ||
let mut data_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); | ||
data_path.push("tests/data/golden_tests_result.txt"); | ||
let file = File::open(data_path).expect("golden_tests_result.txt: file not found"); | ||
let result_reader = std::io::BufReader::new(file); | ||
|
||
for (test_line, result_line) in reader.lines().zip(result_reader.lines()) { | ||
let test_line = test_line.expect("failed to read line"); | ||
// println!("test_line: {}", test_line); | ||
let mut parts = test_line.split_whitespace(); | ||
let x = Decimal::from_str(parts.next().unwrap(), DEFAULT_PRECISION) | ||
.expect("failed to parse x"); | ||
let a = Decimal::from_str(parts.next().unwrap(), DEFAULT_PRECISION) | ||
.expect("failed to parse a"); | ||
let _b = Decimal::from_str(parts.next().unwrap(), DEFAULT_PRECISION) | ||
.expect("failed to parse b"); | ||
let result_line = result_line.expect("failed to read line"); | ||
// println!("result_line: {}", result_line); | ||
let mut result_parts = result_line.split_whitespace(); | ||
let expected_exp_x = result_parts.next().expect("expected_exp_x not found"); | ||
let expected_ln_a = result_parts.next().expect("expected_ln_a not found"); | ||
|
||
// calculate exp' x | ||
let exp_x = x.exp(); | ||
assert_eq!(exp_x.to_string(), expected_exp_x); | ||
|
||
// calculate ln' a, print -ln' a | ||
let ln_a = a.ln(); | ||
assert_eq!((-ln_a).to_string(), expected_ln_a); | ||
} | ||
} | ||
} |
Oops, something went wrong.