diff --git a/source/maths/Fixed.cpp b/source/maths/Fixed.cpp
index e9e3c8c..e73de40 100644
a
|
b
|
CFixed_15_16 CFixed_15_16::Pi()
|
184 | 184 | return CFixed_15_16(205887); // = pi << 16 |
185 | 185 | } |
186 | 186 | |
| 187 | // Based on sup-norm optimal approximations of sin+cos, sin-cos on [0,pi/2] (Remez algorithm) |
| 188 | // 2^15*(sin(pi/4*x)-cos(pi/4*x)) ~ 36361*(x-1) - 3600*(x-1)^3 |
| 189 | // 2^15*(sin(pi/4*x)+cos(pi/4*x)) ~ 46340 - 14281*(x-1)^2 + 709 * (x-1)^4 |
| 190 | // The idea is to use these symmetric terms in order to get both sin and cos |
| 191 | // Errors: e ~ 1.1*10^-4 in both cases. |
| 192 | // TODO : Check if this breaks parts of the program that rely on special cases. |
187 | 193 | void sincos_approx(CFixed_15_16 a, CFixed_15_16& sin_out, CFixed_15_16& cos_out) |
188 | 194 | { |
189 | | // Based on http://www.coranac.com/2009/07/sines/ |
190 | | |
191 | | // TODO: this could be made a bit more precise by being careful about scaling |
192 | | |
193 | 195 | typedef CFixed_15_16 fixed; |
194 | 196 | |
195 | | fixed c2_pi; |
196 | | c2_pi.SetInternalValue(41721); // = 2/pi << 16 |
| 197 | fixed c4_pi; |
| 198 | c4_pi.SetInternalValue(83443); // = 4/pi << 16 |
197 | 199 | |
198 | | // Map radians onto the range [0, 4) |
199 | | fixed z = a.Multiply(c2_pi) % fixed::FromInt(4); |
| 200 | // Map radians onto the range [0, 8) |
| 201 | fixed z = a.Multiply(c4_pi) % fixed::FromInt(8); |
200 | 202 | |
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) |
| 203 | // Map z onto the range [0, 2], compute (sin+cos)/2 and (sin-cos)/2 |
| 204 | fixed c1,c2,c3,c4,c5; |
| 205 | c1.SetInternalValue(36361); |
| 206 | c2.SetInternalValue(3600); |
| 207 | c3.SetInternalValue(46340); |
| 208 | c4.SetInternalValue(14281); |
| 209 | c5.SetInternalValue(709); |
| 210 | |
| 211 | if (z >= fixed::FromInt(4)) // [4,8) |
214 | 212 | { |
215 | | sz = fixed::FromInt(2) - z; |
216 | | cz = fixed::FromInt(1) - z; |
| 213 | if (z >= fixed::FromInt(6)) // [6,8) |
| 214 | { |
| 215 | // sin(3*pi/2+x) = -cos(x), cos(3*pi/2+x) = sin(x) |
| 216 | fixed zn = z - fixed::FromInt(7); |
| 217 | z = zn.Multiply(zn); |
| 218 | fixed scdif = zn.Multiply(c1 - z.Multiply(c2)); |
| 219 | fixed scsum = c3 - z.Multiply(c4 - z.Multiply(c5)); |
| 220 | cos_out = scsum + scdif; |
| 221 | sin_out = scdif - scsum; |
| 222 | } |
| 223 | else // [4,6) |
| 224 | { |
| 225 | // sin(pi+x) = -sin(x), cos(pi+x) = -cos(x) |
| 226 | fixed zn = z - fixed::FromInt(5); |
| 227 | z = zn.Multiply(zn); |
| 228 | fixed scdif= zn.Multiply(c1 - z.Multiply(c2)); |
| 229 | fixed scsum = c3 - z.Multiply(c4 - z.Multiply(c5)); |
| 230 | sin_out = -scsum - scdif; |
| 231 | cos_out = scdif - scsum; |
| 232 | } |
217 | 233 | } |
218 | | else // [0, 1) |
| 234 | else // [0,4) |
219 | 235 | { |
220 | | sz = z; |
221 | | cz = fixed::FromInt(1) - z; |
| 236 | if (z >= fixed::FromInt(2)) // [2,4) |
| 237 | { |
| 238 | // sin (pi/2+x) = cos(x), cos(pi/2+x) = -sin(x) |
| 239 | fixed zn = z - fixed::FromInt(3); |
| 240 | z = zn.Multiply(zn); |
| 241 | fixed scdif = zn.Multiply(c1 - z.Multiply(c2)); |
| 242 | fixed scsum = c3 - z.Multiply(c4 - z.Multiply(c5)); |
| 243 | cos_out = -scsum - scdif; |
| 244 | sin_out = scsum - scdif; |
| 245 | } |
| 246 | else // [0,2) |
| 247 | { |
| 248 | fixed zn = z - fixed::FromInt(1); |
| 249 | z = zn.Multiply(zn); |
| 250 | fixed scdif = zn.Multiply(c1 - z.Multiply(c2)); |
| 251 | fixed scsum = c3 - z.Multiply(c4 - z.Multiply(c5)); |
| 252 | sin_out = scsum + scdif; |
| 253 | cos_out = scsum - scdif; |
| 254 | } |
222 | 255 | } |
223 | | |
224 | | // Third-order (max absolute error ~0.02) |
225 | | |
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; |
236 | | } |
| 256 | } |
| 257 | No newline at end of file |