4

Trying to convert this for loop from c++ to rust and i'm having a hard time figuring it out as I'm very new to Rust syntax.

double sinError = 0;
for (float x = -10 * M_PI; x < 10 * M_PI; x += M_PI / 300) {
    double approxResult = sin_approx(x);
    double libmResult = sinf(x);
    sinError = MAX(sinError, fabs(approxResult - libmResult));
}
5
  • 2
    Can you show your attempt? What particular bit are you stuck on? Commented Apr 20, 2020 at 16:31
  • The easiest solution is to convert this to a while loop, which works roughly the same in Rust and C++. Commented Apr 20, 2020 at 16:39
  • 3
    Iterating over floats that way is probably a bad idea (regardless of language); you accumulate some amount of rounding error every time you add 𝜋/300 to x. If the x values should be evenly spaced, what you usually want is to iterate over an integer range and multiply each value by a scalar, like for x in (-3000..3000).map(|i| (i as f32)*PI/300.0) {...} Commented Apr 20, 2020 at 16:40
  • Aloso, that's what I figured as well and what I have done in the short term. Was curious if there was a way to replicate the for loop. Thanks. Also, that's good info, trenctl. Thank you. Commented Apr 20, 2020 at 16:44
  • @blindside044 There is, by using std::iter::successors and Iterator::take_while. But I agree with @trentcl that iterating over integers would be better. Commented Apr 20, 2020 at 17:13

1 Answer 1

8

Iterate over integers

As @trentcl already pointed out, it's usually better to iterate over integers instead of floats, to prevent numerical errors from adding up:

use std::f32::consts::PI;

let mut sin_error = 0.0;

for x in (-3000..3000).map(|i| (i as f32) * PI / 300.0) {
    sin_error = todo!();
}

Just replace todo!() with the code that computes the next sin_error.

A more functional way

use std::f32::consts::PI;

let sin_error = (-3000..3000)
    .map(|i| (i as f32) * PI / 300.0)
    .fold(0.0, |sin_error, x| todo!());

In case you don't care about numerical errors, or want to iterate over something else, here are some other options:

Use a while loop

It's not as nice, but does the job!

use std::f32::consts::PI;

let mut sin_error = 0.0;
let mut x = -10.0 * PI;

while (x < 10.0 * PI) {
    sin_error = todo!();
    x += PI / 300.0;
}

Create your iterator with successors()

The successors() function creates a new iterator where each successive item is computed based on the preceding one:

use std::f32::consts::PI;
use std::iter::successors;

let mut sin_error = 0.0;

let iter = successors(Some(-10.0 * PI), |x| Some(x + PI / 300.0));

for x in iter.take_while(|&x| x < 10.0 * PI) {
    sin_error = todo!();
}

A more functional way

use std::f32::consts::PI;
use std::iter::successors;

let sin_error = successors(Some(-10.0 * PI), |x| Some(x + PI / 300.0))
   .take_while(|&x| x < 10.0 * PI)
   .fold(0.0, |sin_error, x| todo!());
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

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.