1#![cfg(feature = "std")]
9use num_traits::Float;
10
11pub struct Linspace<F>
15{
16 start: F,
17 step: F,
18 index: usize,
19 len: usize,
20}
21
22impl<F> Iterator for Linspace<F>
23where F: Float
24{
25 type Item = F;
26
27 #[inline]
28 fn next(&mut self) -> Option<F>
29 {
30 if self.index >= self.len {
31 None
32 } else {
33 let i = self.index;
35 self.index += 1;
36 Some(self.start + self.step * F::from(i).unwrap())
37 }
38 }
39
40 #[inline]
41 fn size_hint(&self) -> (usize, Option<usize>)
42 {
43 let n = self.len - self.index;
44 (n, Some(n))
45 }
46}
47
48impl<F> DoubleEndedIterator for Linspace<F>
49where F: Float
50{
51 #[inline]
52 fn next_back(&mut self) -> Option<F>
53 {
54 if self.index >= self.len {
55 None
56 } else {
57 self.len -= 1;
59 let i = self.len;
60 Some(self.start + self.step * F::from(i).unwrap())
61 }
62 }
63}
64
65impl<F> ExactSizeIterator for Linspace<F> where Linspace<F>: Iterator {}
66
67#[inline]
76pub fn linspace<F>(a: F, b: F, n: usize) -> Linspace<F>
77where F: Float
78{
79 let step = if n > 1 {
80 let num_steps = F::from(n - 1).expect("Converting number of steps to `A` must not fail.");
81 (b - a) / num_steps
82 } else {
83 F::zero()
84 };
85 Linspace {
86 start: a,
87 step,
88 index: 0,
89 len: n,
90 }
91}
92
93#[inline]
103pub fn range<F>(a: F, b: F, step: F) -> Linspace<F>
104where F: Float
105{
106 let len = b - a;
107 let steps = F::ceil(len / step);
108 Linspace {
109 start: a,
110 step,
111 len: steps.to_usize().expect(
112 "Converting the length to `usize` must not fail. The most likely \
113 cause of this failure is if the sign of `end - start` is \
114 different from the sign of `step`.",
115 ),
116 index: 0,
117 }
118}