11//! Linear converter
22
3+ use num_rational:: Rational64 ;
4+
5+ use crate :: supported_ratio;
6+
37use super :: { Convert , Error , Result } ;
48
59enum State {
@@ -9,18 +13,28 @@ enum State {
913}
1014
1115pub struct Converter {
12- step : f64 ,
13- pos : f64 ,
16+ numer : usize ,
17+ denom : usize ,
18+ pos : usize ,
19+ coefs : Vec < f64 > ,
1420 last_in : [ f64 ; 2 ] ,
1521 state : State ,
1622}
1723
1824impl Converter {
1925 #[ inline]
20- fn new ( step : f64 ) -> Self {
26+ fn new ( step : Rational64 ) -> Self {
27+ let numer = * step. numer ( ) as usize ;
28+ let denom = * step. denom ( ) as usize ;
29+ let mut coefs = Vec :: with_capacity ( denom) ;
30+ for i in 0 ..denom {
31+ coefs. push ( i as f64 / denom as f64 ) ;
32+ }
2133 Self {
22- step,
23- pos : 0.0 ,
34+ numer,
35+ denom,
36+ pos : 0 ,
37+ coefs,
2438 last_in : [ 0.0 ; 2 ] ,
2539 state : State :: First ,
2640 }
@@ -38,15 +52,15 @@ impl Convert for Converter {
3852 State :: First => {
3953 if let Some ( s) = iter. next ( ) {
4054 self . last_in [ 1 ] = s;
41- self . pos = 1.0 ;
55+ self . pos = self . numer ;
4256 self . state = State :: Normal ;
4357 } else {
4458 return None ;
4559 }
4660 }
4761 State :: Normal => {
48- while self . pos >= 1.0 {
49- self . pos -= 1.0 ;
62+ while self . pos >= self . denom {
63+ self . pos -= self . denom ;
5064 self . last_in [ 0 ] = self . last_in [ 1 ] ;
5165 if let Some ( s) = iter. next ( ) {
5266 self . last_in [ 1 ] = s;
@@ -55,8 +69,9 @@ impl Convert for Converter {
5569 return None ;
5670 }
5771 }
58- let interp = self . last_in [ 0 ] + ( self . last_in [ 1 ] - self . last_in [ 0 ] ) * self . pos ;
59- self . pos += self . step ;
72+ let coef = self . coefs [ self . pos ] ;
73+ let interp = self . last_in [ 0 ] + ( self . last_in [ 1 ] - self . last_in [ 0 ] ) * coef;
74+ self . pos += self . numer ;
6075 return Some ( interp) ;
6176 }
6277 State :: Suspend => {
@@ -72,20 +87,19 @@ impl Convert for Converter {
7287 }
7388}
7489
75- use super :: { MAX_RATIO , MIN_RATIO } ;
76-
7790#[ derive( Clone , Copy ) ]
7891pub struct Manager {
79- ratio : f64 ,
92+ ratio : Rational64 ,
8093}
8194
8295impl Manager {
8396 #[ inline]
8497 pub fn new ( ratio : f64 ) -> Result < Self > {
85- if ( MIN_RATIO ..=MAX_RATIO ) . contains ( & ratio) {
98+ let ratio = Rational64 :: approximate_float ( ratio) . unwrap_or_default ( ) ;
99+ if supported_ratio ( ratio) {
86100 Ok ( Self { ratio } )
87101 } else {
88- Err ( Error :: InvalidRatio )
102+ Err ( Error :: UnsupportedRatio )
89103 }
90104 }
91105
@@ -101,7 +115,7 @@ mod tests {
101115
102116 #[ test]
103117 fn test_manager_ok ( ) {
104- let ratio_ok = vec ! [ 0.01 , 1.0 , 10 .0, 99.99 , 100 .0] ;
118+ let ratio_ok = vec ! [ 0.0625 , 0.063 , 1 .0, 15.9 , 16 .0] ;
105119 for ratio in ratio_ok {
106120 assert ! ( Manager :: new( ratio) . is_ok( ) ) ;
107121 }
@@ -112,8 +126,9 @@ mod tests {
112126 let ratio_err = vec ! [
113127 -1.0 ,
114128 0.0 ,
115- 100.01 ,
116- 1000.0 ,
129+ 0.0624 ,
130+ 16.01 ,
131+ 0.123456 ,
117132 f64 :: INFINITY ,
118133 f64 :: NEG_INFINITY ,
119134 f64 :: NAN ,
0 commit comments