| 146 | //angles: 45, 26.565, 14.036, 7.125, 3.576, 1.790, 0.895, 0.448 |
| 147 | static const CFixed_15_16 tan_angle_table_rad[8] = {CFixed_15_16(51472), CFixed_15_16(30386), CFixed_15_16(16055), CFixed_15_16(8150), CFixed_15_16(4091), CFixed_15_16(2047), CFixed_15_16(1042), CFixed_15_16(512) }; |
| 148 | //angles 90 and 180 |
| 149 | static const CFixed_15_16 angle_0_5_pi = CFixed_15_16(102944); |
| 150 | static const CFixed_15_16 angle_1_0_pi = CFixed_15_16(205887); |
| 151 | static const CFixed_15_16 angle_1_5_pi = CFixed_15_16(308830); |
| 152 | static const CFixed_15_16 zero = CFixed_15_16(); |
| 153 | |
198 | | // Map radians onto the range [0, 4) |
199 | | fixed z = a.Multiply(c2_pi) % fixed::FromInt(4); |
| 239 | for(loop_var = 0; loop_var < 8; ++loop_var) |
| 240 | { |
| 241 | i32 factor; |
| 242 | //these divisions should be optimised by the compiler to shifts because the operations are always division by a power of two |
| 243 | //this makes the cost of each division 1 cycle. |
| 244 | if( angle > a ) |
| 245 | { |
| 246 | factor = (1 << loop_var); |
| 247 | previous_x_val = x.GetInternalValue(); |
| 248 | x -= (y/factor); |
| 249 | new_x_val = x.GetInternalValue(); |
| 250 | x.SetInternalValue(previous_x_val); |
| 251 | y += (x/factor); |
| 252 | x.SetInternalValue(new_x_val); |
201 | | // Map z onto the range [-1, +1] for sin, and the same with z+1 to compute cos |
202 | | fixed sz, cz; |
203 | | if (z >= fixed::FromInt(3)) // [3, 4) |
204 | | { |
205 | | sz = z - fixed::FromInt(4); |
206 | | cz = z - fixed::FromInt(3); |
207 | | } |
208 | | else if (z >= fixed::FromInt(2)) // [2, 3) |
209 | | { |
210 | | sz = fixed::FromInt(2) - z; |
211 | | cz = z - fixed::FromInt(3); |
212 | | } |
213 | | else if (z >= fixed::FromInt(1)) // [1, 2) |
214 | | { |
215 | | sz = fixed::FromInt(2) - z; |
216 | | cz = fixed::FromInt(1) - z; |
217 | | } |
218 | | else // [0, 1) |
219 | | { |
220 | | sz = z; |
221 | | cz = fixed::FromInt(1) - z; |
222 | | } |
| 254 | angle -= tan_angle_table_rad[loop_var]; |
| 255 | } |
| 256 | else |
| 257 | { |
| 258 | factor = (1 << loop_var); |
| 259 | previous_x_val = x.GetInternalValue(); |
| 260 | x += (y/factor); |
| 261 | new_x_val = x.GetInternalValue(); |
| 262 | x.SetInternalValue(previous_x_val); |
| 263 | y -= (x/factor); |
| 264 | x.SetInternalValue(new_x_val); |
226 | | // sin_out = (sz / 2).Multiply(fixed::FromInt(3) - sz.Multiply(sz)); |
227 | | // cos_out = (cz / 2).Multiply(fixed::FromInt(3) - cz.Multiply(cz)); |
228 | | |
229 | | // Fifth-order (max absolute error ~0.0005) |
230 | | |
231 | | fixed sz2 = sz.Multiply(sz); |
232 | | sin_out = sz.Multiply(fixed::Pi() - sz2.Multiply(fixed::Pi()*2 - fixed::FromInt(5) - sz2.Multiply(fixed::Pi() - fixed::FromInt(3)))) / 2; |
233 | | |
234 | | fixed cz2 = cz.Multiply(cz); |
235 | | cos_out = cz.Multiply(fixed::Pi() - cz2.Multiply(fixed::Pi()*2 - fixed::FromInt(5) - cz2.Multiply(fixed::Pi() - fixed::FromInt(3)))) / 2; |
| 270 | //the cases are contiguous therefore this should be optimised to a jump table |
| 271 | switch(output_state) |
| 272 | { |
| 273 | case QUAD1: |
| 274 | sin_out.SetInternalValue(y.GetInternalValue() * -1); |
| 275 | cos_out.SetInternalValue(x.GetInternalValue()); |
| 276 | return; |
| 277 | case QUAD2: |
| 278 | sin_out.SetInternalValue(y.GetInternalValue() * -1); |
| 279 | cos_out.SetInternalValue(x.GetInternalValue() * -1); |
| 280 | return; |
| 281 | case QUAD3: |
| 282 | sin_out.SetInternalValue(y.GetInternalValue()); |
| 283 | cos_out.SetInternalValue(x.GetInternalValue() * -1); |
| 284 | return; |
| 285 | case QUAD4: |
| 286 | sin_out.SetInternalValue(y.GetInternalValue()); |
| 287 | cos_out.SetInternalValue(x.GetInternalValue()); |
| 288 | return; |
| 289 | default: |
| 290 | return; |
| 291 | } |