@@ -8,7 +8,7 @@ use std::mem::swap;
8
8
pub struct SeriesApproximation {
9
9
pub current_iteration : usize ,
10
10
maximum_iteration : usize ,
11
- delta_pixel : FloatExtended ,
11
+ delta_pixel_square : FloatExtended ,
12
12
z : ComplexArbitrary ,
13
13
c : ComplexArbitrary ,
14
14
pub order : usize ,
@@ -22,7 +22,7 @@ pub struct SeriesApproximation {
22
22
}
23
23
24
24
impl SeriesApproximation {
25
- pub fn new ( c : ComplexArbitrary , order : usize , maximum_iteration : usize , delta_pixel : FloatExtended , delta_top_left : ComplexExtended ) -> Self {
25
+ pub fn new ( c : ComplexArbitrary , order : usize , maximum_iteration : usize , delta_pixel_square : FloatExtended , delta_top_left : ComplexExtended ) -> Self {
26
26
let mut coefficients = vec ! [ ComplexExtended :: new2( 0.0 , 0.0 , 0 ) ; order as usize + 1 ] ;
27
27
28
28
coefficients[ 0 ] = to_extended ( & c) ;
@@ -32,7 +32,7 @@ impl SeriesApproximation {
32
32
SeriesApproximation {
33
33
current_iteration : 1 ,
34
34
maximum_iteration,
35
- delta_pixel ,
35
+ delta_pixel_square ,
36
36
z : c. clone ( ) ,
37
37
c,
38
38
order,
@@ -61,9 +61,9 @@ impl SeriesApproximation {
61
61
62
62
// Calculate the new coefficents
63
63
for k in 2 ..=self . order {
64
- let mut sum = ComplexExtended :: new2 ( 0.0 , 0.0 , 0 ) ;
64
+ let mut sum = self . coefficients [ 0 ] * self . coefficients [ k ] ;
65
65
66
- for j in 0 ..=( ( k - 1 ) / 2 ) {
66
+ for j in 1 ..=( ( k - 1 ) / 2 ) {
67
67
sum += self . coefficients [ j] * self . coefficients [ k - j] ;
68
68
}
69
69
sum *= 2.0 ;
@@ -80,33 +80,31 @@ impl SeriesApproximation {
80
80
// this section takes about half of the time
81
81
for i in 0 ..self . original_probes . len ( ) {
82
82
// step the probe points using perturbation
83
- self . current_probes [ i] = self . coefficients [ 0 ] * self . current_probes [ i] * 2.0 + self . current_probes [ i] * self . current_probes [ i] + self . original_probes [ i] ;
83
+ self . current_probes [ i] = self . current_probes [ i] * ( self . coefficients [ 0 ] * 2.0 + self . current_probes [ i] ) ;
84
+ self . current_probes [ i] += self . original_probes [ i] ;
85
+
86
+ // TODO this probably does not need to be done every iteration
84
87
self . current_probes [ i] . reduce ( ) ;
85
88
86
89
// get the new approximations
87
- let mut series_probe = ComplexExtended :: new2 ( 0.0 , 0.0 , 0 ) ;
88
- let mut derivative_probe = ComplexExtended :: new2 ( 0.0 , 0.0 , 0 ) ;
90
+ let mut series_probe = self . next_coefficients [ 1 ] * self . approximation_probes [ i ] [ 0 ] ;
91
+ let mut derivative_probe = self . next_coefficients [ 1 ] * self . approximation_probes_derivative [ i ] [ 0 ] ;
89
92
90
- for k in 1 ..=self . order {
93
+ for k in 2 ..=self . order {
91
94
series_probe += self . next_coefficients [ k] * self . approximation_probes [ i] [ k - 1 ] ;
92
- derivative_probe += self . next_coefficients [ k] * self . approximation_probes_derivative [ i] [ k - 1 ] * k as f64 ;
93
-
94
- if k % 16 == 0 {
95
- series_probe. reduce ( ) ;
96
- derivative_probe. reduce ( ) ;
97
- }
95
+ derivative_probe += self . next_coefficients [ k] * self . approximation_probes_derivative [ i] [ k - 1 ] ;
98
96
} ;
99
97
100
- let relative_error = ( self . current_probes [ i] - series_probe) . norm ( ) ;
101
- let mut derivative = derivative_probe. norm ( ) ;
98
+ let relative_error = ( self . current_probes [ i] - series_probe) . norm_square ( ) ;
99
+ let mut derivative = derivative_probe. norm_square ( ) ;
102
100
103
101
// Check to make sure that the derivative is greater than or equal to 1
104
102
if derivative. to_float ( ) < 1.0 {
105
103
derivative = FloatExtended :: new ( 1.0 , 0 ) ;
106
104
}
107
105
108
106
// Check that the error over the derivative is less than the pixel spacing
109
- if relative_error / derivative > self . delta_pixel {
107
+ if relative_error / derivative > self . delta_pixel_square {
110
108
self . z -= & self . c ;
111
109
self . z . sqrt_mut ( ) ;
112
110
return false ;
@@ -138,24 +136,23 @@ impl SeriesApproximation {
138
136
self . original_probes . push ( delta_probe) ;
139
137
self . current_probes . push ( delta_probe) ;
140
138
141
- let mut delta_probe_n = Vec :: with_capacity ( self . order + 1 ) ;
142
- let mut delta_probe_n_derivative = Vec :: with_capacity ( self . order + 1 ) ;
139
+ let mut delta_probe_n = delta_probe;
140
+
141
+ let mut delta_probe_n_2 = Vec :: with_capacity ( self . order + 1 ) ;
142
+ let mut delta_probe_n_derivative_2 = Vec :: with_capacity ( self . order + 1 ) ;
143
143
144
144
// The first element will be 1, in order for the derivative to be calculated
145
- delta_probe_n . push ( delta_probe ) ;
146
- delta_probe_n_derivative . push ( ComplexExtended :: new2 ( 1.0 , 0.0 , 0 ) ) ;
145
+ delta_probe_n_2 . push ( delta_probe_n ) ;
146
+ delta_probe_n_derivative_2 . push ( ComplexExtended :: new2 ( 1.0 , 0.0 , 0 ) ) ;
147
147
148
148
for i in 1 ..=self . order {
149
- let mut delta_probe1 = delta_probe_n[ i - 1 ] * delta_probe;
150
- let mut delta_probe2 = delta_probe_n_derivative[ i - 1 ] * delta_probe;
151
- delta_probe1. reduce ( ) ;
152
- delta_probe2. reduce ( ) ;
153
- delta_probe_n. push ( delta_probe1) ;
154
- delta_probe_n_derivative. push ( delta_probe2) ;
149
+ delta_probe_n_derivative_2. push ( delta_probe_n * ( i + 1 ) as f64 ) ;
150
+ delta_probe_n *= delta_probe;
151
+ delta_probe_n_2. push ( delta_probe_n) ;
155
152
}
156
153
157
- self . approximation_probes . push ( delta_probe_n ) ;
158
- self . approximation_probes_derivative . push ( delta_probe_n_derivative ) ;
154
+ self . approximation_probes . push ( delta_probe_n_2 ) ;
155
+ self . approximation_probes_derivative . push ( delta_probe_n_derivative_2 ) ;
159
156
}
160
157
161
158
// Get the current reference, and the current number of iterations done
@@ -181,31 +178,43 @@ impl SeriesApproximation {
181
178
}
182
179
183
180
pub fn evaluate ( & self , point_delta : ComplexExtended ) -> ComplexExtended {
184
- let mut approximation = self . coefficients [ 1 ] * point_delta;
185
- let mut original_point_n = point_delta * point_delta;
181
+ // 1907 ms packing opus 4K
182
+ // Horner's rule
183
+ let mut approximation = self . coefficients [ self . order ] ;
186
184
187
- for k in 2 ..=self . order {
188
- approximation += self . coefficients [ k] * original_point_n;
189
- original_point_n *= point_delta;
190
-
191
- if k % 16 == 0 {
192
- approximation. reduce ( ) ;
193
- original_point_n. reduce ( ) ;
194
- }
195
- } ;
185
+ for k in ( 1 ..=( self . order - 1 ) ) . rev ( ) {
186
+ approximation *= point_delta;
187
+ approximation += self . coefficients [ k] ;
188
+ }
196
189
190
+ approximation *= point_delta;
191
+ approximation. reduce ( ) ;
197
192
approximation
198
193
}
199
194
200
- // pub fn evaluate_derivative(&self, point_delta: ComplexFixed<f64> ) -> ComplexFixed<f64> {
195
+ // pub fn evaluate_derivative(&self, point_delta: ComplexExtended ) -> FloatExtended {
201
196
// let mut original_point_derivative_n = ComplexExtended::new(1.0, 0, 0.0, 0);
202
197
// let mut approximation_derivative = ComplexExtended::new(0.0, 0, 0.0, 0);
203
- //
198
+
204
199
// for k in 1..=self.order {
205
200
// approximation_derivative += k as f64 * self.coefficients[k] * original_point_derivative_n;
206
201
// original_point_derivative_n *= ComplexExtended::new(point_delta.re, 0, point_delta.im, 0);
207
202
// };
208
- //
203
+
209
204
// approximation_derivative.to_float()
205
+
206
+
207
+ // let mut approximation_derivative = self.coefficients[self.order] * self.order as f64;
208
+
209
+ // for k in (1..=(self.order - 1)).rev() {
210
+ // approximation *= point_delta;
211
+ // approximation += self.coefficients[k] * k as f64;
212
+ // }
213
+
214
+ // approximation *= point_delta;
215
+ // approximation.reduce();
216
+ // approximation
217
+
218
+
210
219
// }
211
220
}
0 commit comments