1
\$\begingroup\$

So, I've tried to make a simple math library in Rust. What do you think about it?

const PRECISION: f64=512.; //Balance between speed and precision here.
fn ln(x:f64) -> f64 {
 let mut sum=0.;
 let epsilon=(x-1.)/(5.*PRECISION);
 let mut i=1.;
 while (epsilon>0. && i<x) || (epsilon<0. && i>x) {
 sum+=epsilon/i;
 i+=epsilon;
 }
 sum
}
fn exp(x:f64) -> f64 {
 let mut i=0.;
 let mut y=1.;
 let epsilon=x/PRECISION;
 while (epsilon>0. && i<x) || (epsilon<0. && i>x) {
 y+=epsilon*y;
 i+=epsilon;
 }
 y
}
fn arctan(x:f64) -> f64 {
 let mut sum=0.;
 let epsilon=x/PRECISION;
 let mut i=0.;
 while i<x {
 sum+=epsilon/(1.+i*i);
 i+=epsilon;
 }
 sum*(180./pi())
}
fn tan(degrees:f64) -> f64 {
 sin(degrees)/cos(degrees)
}
fn sin(degrees:f64) -> f64 {
 if degrees<0. {
 return -sin(-degrees);
 }
 if degrees>90. {
 return cos(degrees-90.);
 }
 let radians=degrees/(180./pi());
 let mut tmpsin=0.;
 let mut tmpcos=1.;
 let epsilon=radians/PRECISION;
 let mut i=0.;
 while (epsilon>0. && i<radians) || (epsilon<0. && i>radians) {
 tmpsin+=epsilon*tmpcos;
 tmpcos-=epsilon*tmpsin;
 i+=epsilon;
 }
 tmpsin
}
fn arcsin(x:f64) -> f64 {
 arctan(x/sqrt(1.-x*x))
}
fn arccos(x:f64) -> f64 {
 90.-arcsin(x)
}
fn cos(degrees:f64) -> f64 {
 sin(90.-degrees)
}
fn sqrt(x:f64) -> f64 {
 let mut max=1000.;
 let mut min=0.;
 let mut i=(min+max)/2.;
 while (max-min)>1./PRECISION {
 if i*i>x {
 max=i;
 }
 else {
 min=i;
 }
 i=(max+min)/2.;
 }
 i
}
fn pi() -> f64 {
 let mut sum=0.;
 let mut i=-1.;
 let epsilon=1./PRECISION;
 while i<1. {
 sum+=epsilon/(1.+i*i);
 i+=epsilon;
 }
 2.*sum
}
fn main() {
 println!("x\tsin(x)\tcos(x)\ttan(x)\tln(x)\tsqrt(x)\tasin\tacos\tatan");
 for i in 0..101 {
 print!("{:.4}\t",i);
 print!("{:.4}\t",sin(i as f64));
 print!("{:.4}\t",cos(i as f64));
 if tan(i as f64)<100. && tan(i as f64)> -10. {
 print!("{:.4}\t",tan(i as f64));
 }
 else if tan(i as f64)< -10. {
 print!("{:.3}\t",tan(i as f64));
 }
 else {
 print!("inf\t");
 }
 if ln(i as f64)> -100. {
 print!("{:.4}\t",ln(i as f64));
 }
 else {
 print!("-inf\t");
 }
 print!("{:.4}\t",sqrt(i as f64));
 if arcsin((i as f64)/100.)<90. {
 print!("{:.4}\t",arcsin((i as f64)/100.));
 }
 else {
 print!("90\t");
 }
 if arccos((i as f64)/100.)<90. && arccos((i as f64)/100.)>0. {
 print!("{:.4}\t",arccos((i as f64)/100.));
 }
 else if arccos((i as f64)/100.)>0. {
 print!("90\t");
 }
 else {
 print!("0\t");
 }
 print!("{:.4}\n",arctan((i as f64)/100.));
 }
 println!("pi={:.4}",pi());
 println!("rad={:.4}",180./pi());
 println!("ln(1/pi)={:.4}",ln(1./pi()));
 println!("e={:.4}",exp(1 as f64));
 println!("1/e={:.4}",exp(-1 as f64));
}
asked May 11, 2020 at 14:14
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I'm not too familiar with the math side of this, so I'll just focus on the Rust part.

Run rustfmt

Running cargo fmt will autoformat your code to the Rust best practices. For example, it will convert

fn arctan(x:f64) -> f64 {
 let mut sum=0.;
 let epsilon=x/PRECISION;
 let mut i=0.;
 while i<x {
 sum+=epsilon/(1.+i*i);
 i+=epsilon;
 }
 sum*(180./pi())
}

to

fn arctan(x: f64) -> f64 {
 let mut sum = 0.;
 let epsilon = x / PRECISION;
 let mut i = 0.;
 while i < x {
 sum += epsilon / (1. + i * i);
 i += epsilon;
 }
 sum * (180. / pi())
}

Notice the spacing added.

Run clippy

Running cargo clippy will point out a few common mistakes. Let's take a look at them here.

warning: using `print!()` with a format string that ends in a single newline
 --> src/main.rs:136:9
 |
136 | print!("{:.4}\n",arctan((i as f64)/100.));
 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 |
 = note: `#[warn(clippy::print_with_newline)]` on by default
 = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#print_with_newline
help: use `println!` instead
 |
136 | println!("{:.4}",arctan((i as f64)/100.));
 | ^^^^^^^

As it suggests, you should replace that line with println!.

warning: casting integer literal to `f64` is unnecessary
 --> src/main.rs:141:28
 |
141 | println!("e={:.4}",exp(1 as f64));
 | ^^^^^^^^ help: try: `1_f64`
 |
 = note: `#[warn(clippy::unnecessary_cast)]` on by default
 = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast

That, and the line that follows it, can be used as a float like you do everywhere else in your code. You can do 1_f64, 1f64, 1.0, or like elsewhere in your code, 1..

Extract repeated operations

When you print things out, you repeat the calculation a lot, and it actually appears to have a difference in assembly (although not when #[inline(never)] is used on ln?). So instead of

if arccos((i as f64) / 100.) < 90. && arccos((i as f64) / 100.) > 0. {
 print!("{:.4}\t", arccos((i as f64) / 100.));
} else if arccos((i as f64) / 100.) > 0. {
 print!("90\t");
} else {
 print!("0\t");
}

Prefer

let inv_cos = arccos((i as f64) / 100.);
if inv_cos < 90. && inv_cos > 0. {
 print!("{:.4}\t", inv_cos);
} else if inv_cos > 0. {
 print!("90\t");
} else {
 print!("0\t");
}
answered May 11, 2020 at 21:59
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.