如何用边界值做一个'for'循环,并作为浮点值来执行?

我需要实现一个for循环,该循环从一个浮点数转到另一个浮点数。如何用边界值做一个'for'循环,并作为浮点值来执行?

我知道如何实现,在C类语言:

for (float i = -1.0; i < 1.0; i += 0.01) { /* ... */ } 

我也知道,在鲁斯特我可以指定使用step_by循环一步,这给了我我想要的,如果我有边界价值观和步为整数:

#![feature(iterator_step_by)] 

fn main() {

for i in (0..30).step_by(3) {

println!("Index {}", i);

}

}

当我这样做,浮点数,它会导致编译错误:

#![feature(iterator_step_by)] 

fn main() {

for i in (-1.0..1.0).step_by(0.01) {

println!("Index {}", i);

}

}

这里是编译输出:

error[E0599]: no method named `step_by` found for type `std::ops::Range<{float}>` in the current scope 

--> src/main.rs:4:26

|

4 | for i in (-1.0..1.0).step_by(0.01) {

| ^^^^^^^

|

= note: the method `step_by` exists but the following trait bounds were not satisfied:

`std::ops::Range<{float}> : std::iter::Iterator`

`&mut std::ops::Range<{float}> : std::iter::Iterator`

我如何能实现这个循环中,锈?

回答:

如果你还没有,我请你读戈德堡的What Every Computer Scientist Should Know About Floating-Point Arithmetic。

与浮点的问题,是你的代码可以做200或201次迭代,这取决于循环的最后一个步骤是否结束是i = 0.99i = 0.999999(这仍然是< 1即使真的很近)。

为了避免这个脚枪,Rust不允许迭代f32f64的范围。相反,它强迫你使用积分步骤:

for i in -100..100 { 

let i = i as f32 * 0.01;

// ...

}

回答:

作为一个真正的迭代器:

Playground

/// produces: [ linear_interpol(start, end, i/steps) | i <- 0..steps ] 

/// (does NOT include "end")

///

/// linear_interpol(a, b, p) = (1 - p) * a + p * b

pub struct FloatIterator {

current: u64,

current_back: u64,

steps: u64,

start: f64,

end: f64,

}

impl FloatIterator {

pub fn new(start: f64, end: f64, steps: u64) -> Self {

FloatIterator {

current: 0,

current_back: steps,

steps: steps,

start: start,

end: end,

}

}

/// calculates number of steps from (end - start)/step

pub fn new_with_step(start: f64, end: f64, step: f64) -> Self {

let steps = ((end - start)/step).abs().round() as u64;

Self::new(start, end, steps)

}

pub fn length(&self) -> u64 {

self.current_back - self.current

}

fn at(&self, pos: u64) -> f64 {

let f_pos = pos as f64/self.steps as f64;

(1. - f_pos) * self.start + f_pos * self.end

}

/// panics (in debug) when len doesn't fit in usize

fn usize_len(&self) -> usize {

let l = self.length();

debug_assert!(l <= ::std::usize::MAX as u64);

l as usize

}

}

impl Iterator for FloatIterator {

type Item = f64;

fn next(&mut self) -> Option<Self::Item> {

if self.current >= self.current_back {

return None;

}

let result = self.at(self.current);

self.current += 1;

Some(result)

}

fn size_hint(&self) -> (usize, Option<usize>) {

let l = self.usize_len();

(l, Some(l))

}

fn count(self) -> usize {

self.usize_len()

}

}

impl DoubleEndedIterator for FloatIterator {

fn next_back(&mut self) -> Option<Self::Item> {

if self.current >= self.current_back {

return None;

}

self.current_back -= 1;

let result = self.at(self.current_back);

Some(result)

}

}

impl ExactSizeIterator for FloatIterator {

fn len(&self) -> usize {

self.usize_len()

}

//fn is_empty(&self) -> bool {

// self.length() == 0u64

//}

}

pub fn main() {

println!(

"count: {}",

FloatIterator::new_with_step(-1.0, 1.0, 0.01).count()

);

for f in FloatIterator::new_with_step(-1.0, 1.0, 0.01) {

println!("{}", f);

}

}

回答:

另一个答案使用迭代器,但在一个稍微不同的方式playground

extern crate num; 

use num::{Float, FromPrimitive};

fn linspace<T>(start: T, stop: T, nstep: u32) -> Vec<T>

where

T: Float + FromPrimitive,

{

let delta: T = (stop - start)/T::from_u32(nstep - 1).expect("out of range");

return (0..(nstep))

.map(|i| start + T::from_u32(i).expect("out of range") * delta)

.collect();

}

fn main() {

for f in linspace(-1f32, 1f32, 3) {

println!("{}", f);

}

}

在夜间,您可以使用conservative impl trait功能,以避免Vec分配playground

#![feature(conservative_impl_trait)] 

extern crate num;

use num::{Float, FromPrimitive};

fn linspace<T>(start: T, stop: T, nstep: u32) -> impl Iterator<Item = T>

where

T: Float + FromPrimitive,

{

let delta: T = (stop - start)/T::from_u32(nstep - 1).expect("out of range");

return (0..(nstep))

.map(move |i| start + T::from_u32(i).expect("out of range") * delta);

}

fn main() {

for f in linspace(-1f32, 1f32, 3) {

println!("{}", f);

}

}

以上是 如何用边界值做一个'for'循环,并作为浮点值来执行? 的全部内容, 来源链接: utcz.com/qa/262931.html

回到顶部