找回密码
 欢迎注册
查看: 29686|回复: 14

[讨论] 正余弦的近似计算

[复制链接]
发表于 2011-2-18 18:35:07 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?欢迎注册

×
1.FSIN,FCOS指令 2.Taylor series expansion 泰勒展开 http://en.wikipedia.org/wiki/Sine http://www.cnblogs.com/sun11086/archive/2009/03/20/1417944.html http://blog.csdn.net/ben_jiang/archive/2009/04/28/4133108.aspx (SSE2版本) 3.the CORDIC algorithm cordic_C语言.rar (15.01 KB, 下载次数: 1) ..... 有好的想法讨论一下吧。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-2-18 18:51:03 | 显示全部楼层
以上给的TestCord.c 计算的是误差,改一下目的更明确了。 ------------------------------------------------------------------------------
  1. /****************************************************************************
  2. *
  3. * Name: TestCord.c
  4. *
  5. * Synopsis: Test program for the Cordic module
  6. *
  7. * Copyright 1999 Grant R. Griffin
  8. *
  9. * The Wide Open License (WOL)
  10. *
  11. * Permission to use, copy, modify, distribute and sell this software and its
  12. * documentation for any purpose is hereby granted without fee, provided that
  13. * the above copyright notice and this license appear in all source copies.
  14. * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
  15. * ANY KIND. See http://www.dspguru.com/wol.htm for more information.
  16. *
  17. *****************************************************************************/
  18. //win7自带计算器得到:
  19. //sin(11°)=0.19080899537654481240514048795839
  20. //cos(11°)=0.98162718344766395349650489981814
  21. #include <stdio.h>
  22. #include "cordic.h"
  23. /****************************************************************************/
  24. int main(void)
  25. {
  26. #define DEGREES_TO_RADS(x) (x / 180.0 * PI) /*x为角度,DEGREES_TO_RADS(x)转成弧度*/
  27. int max_L; /*精度依赖于max_L的值,如取45*/
  28. double Cos_out, Sin_out;
  29. for (;;) {
  30. do {
  31. max_L = 0;
  32. printf("\nEnter maximum L >= 3, (0 to quit) : ");
  33. scanf("%i", &max_L);
  34. if (max_L == 0) {
  35. exit(0);
  36. }
  37. } while (max_L < 3);
  38. cordic_construct(max_L);
  39. cordic_get_cos_sin(DEGREES_TO_RADS(11.0), &Cos_out, &Sin_out);
  40. /*以上函数用于计算cos(11°) ,sin(11°) */
  41. printf("Cos_out = %20.15lf dB, Sin_out = %20.15lf dB\n",Cos_out,Sin_out);
  42. cordic_destruct();
  43. }
  44. return 0;
  45. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-2-18 21:29:32 | 显示全部楼层
cordic.c中 ... mp_cordic_table = (CORDIC_TABLE *) calloc(max_L + 1, sizeof(CORDIC_TABLE)); ... K = 1.0f; for (L = 0; L <= max_L; L++) { mp_cordic_table[L].K = K; mp_cordic_table[L].phase_rads = (double) atan(K); //arctan(k)计算 K *= 0.5f; //因为C doesn't let you shift "doubles" } 对于固定的max_L ,如max_L=45(可以得到14~15位的精度)时,可以给一个固定的mp_cordic_table表空间而不用动态分配,mp_cordic_table[L]也是确定的,可以预先给出,所以也省去了arctan(k)和 K *= 0.5f的计算。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-2-19 13:50:52 | 显示全部楼层
the CORDIC algorithm, which can calculate the trigonometric functions of sin, cos, magnitude and phase using multiplying factors which are powers of two. Therefore, the multiplies can be implemented in hardware as shift/adds. (Since C doesn't let you shift "doubles", the shift/add multiplies appear here as literal multiplies, but you can get idea.) 由于c中无法对double数据进行移位操作,则乘法运算不可避免,以即下面的程序片段
  1. /* rotate using "1 + jK" factors */
  2. for (L = 0; L < m_max_L; L++) {
  3. K = K_phase_rads[L][0];
  4. phase_rads = K_phase_rads[L][1];
  5. tmp_I = I;
  6. if (desired_phase_rads - acc_phase_rads < 0.0) {
  7. /* do negative roation */
  8. I += Q * K;
  9. Q -= tmp_I * K;
  10. acc_phase_rads -= phase_rads;
  11. } else {
  12. /* do positive rotation */
  13. I -= Q * K;
  14. Q += tmp_I * K;
  15. acc_phase_rads += phase_rads;
  16. }
  17. }
复制代码
中的Q*K 和tmp_I*K不能通过移位实现,这样一来若取 m_max_L=46 比泰勒来的还要慢,在FPGA中是可行的,所以说“you can get idea”。 改写最初的程序: cordic.zip (118.32 KB, 下载次数: 0)
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-2-21 20:19:56 | 显示全部楼层
可以看看fastfunlib http://code.google.com/p/fastfunlib/
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-2-22 12:15:11 | 显示全部楼层
试了下fsincos指令,用在fft中应该可以。
  1. .386
  2. .model flat,stdcall
  3. option casemap:none
  4. ;-----------------------------------------------------------
  5. .data
  6. ConsPi_180 real8 0.017453292519943295769
  7. ;***********************************************************
  8. .code
  9. ;-----------------------------------------------------------
  10. _Degree2SinCos proc deg:real4,lpsin:dword,lpcos:dword
  11. mov esi,lpcos
  12. mov edi,lpsin
  13. finit
  14. fld real4 ptr[deg]
  15. fld qword ptr [ConsPi_180]
  16. fmul st(0),st(1)
  17. fsincos
  18. fstp QWORD ptr[esi]
  19. fst QWORD ptr[edi]
  20. ret
  21. _Degree2SinCos endp
  22. _Rad2SinCos proc rad:real8,lpsin:dword,lpcos:dword
  23. mov esi,lpcos
  24. mov edi,lpsin
  25. finit
  26. fld real8 ptr[rad]
  27. fsincos
  28. fstp QWORD ptr[esi]
  29. fst QWORD ptr[edi]
  30. ret
  31. _Rad2SinCos endp
  32. end
复制代码
c中调用一下:
  1. #include <stdio.h>
  2. #define PI 3.1415926535897932
  3. #ifdef __cplusplus
  4. #include <windows.h>
  5. extern "C" {
  6. #endif
  7. void _stdcall _Degree2SinCos(float degree,double *sin,double *cos);
  8. void _stdcall _Rad2SinCos(double Rad,double *sin,double *cos);
  9. #ifdef __cplusplus
  10. }
  11. #endif
  12. int main()
  13. {
  14. float deg=30.0;
  15. double rad=30.0*PI/180.0;
  16. double sin,cos;
  17. _Degree2SinCos(deg,&sin,&cos);
  18. printf("_Degree2SinCos:\ncos(%.4f)=%18.16lf\nsin(%.4f)=%18.16lf\n",deg,cos,deg,sin);
  19. _Rad2SinCos(rad,&sin,&cos);
  20. printf("_Rad2SinCos:\ncos(%.4f)=%18.16lf\nsin(%.4f)=%18.16lf\n",rad,cos,rad,sin);
  21. //system("PAUSE");
  22. getch();
  23. return 0;
  24. }
复制代码
_Degree2SinCos: cos(30.0000)=0.8660254037844386 sin(30.0000)=0.5000000000000000 _Rad2SinCos: cos(0.5236)=0.8660254037844387 sin(0.5236)=0.4999999999999999 唯一不爽的是上面代码生成的可执行文件,360竟然报毒,没法蛋定了,你懂的。 test_src.zip (22.79 KB, 下载次数: 0)
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-2-22 12:21:01 | 显示全部楼层
6# G-Spider python 3.2 昨天释出,我从官网 下载了安装的时候,360还很积极的拦截呢,说是
发现木马:Win32/Trojan.e8c 详细描述: 木马名称:Win32/Trojan.e8c 所在路径:G:\Documents and Settings\yoyo\桌面\stardict\python-3.2.msi
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-2-22 12:31:04 | 显示全部楼层
7# wayne “永久免费”背后的生财之道。。。你懂的。。。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-2-22 15:54:02 | 显示全部楼层
上面的fsincos与math.h 中的sin(),cos()时间测试。 j=10~30 N=2^j,对于每次的j++ ,计算N0=N/4个sin,cos值的时间,随j增加,时间减少接近于40%。
  1. Elapsed time:
  2. _Rad2SinCos Std_SinCos (seconds)
  3. 0.00000000 0.00000000
  4. 0.00000000 0.00000000
  5. 0.00000000 0.00000000
  6. 0.00000000 0.00000000
  7. 0.00000000 0.00000000
  8. 0.00000000 0.00000000
  9. 0.01600000 0.01500000
  10. 0.01600000 0.01600000
  11. 0.03100000 0.04700000
  12. 0.06200000 0.07800000
  13. 0.12500000 0.18800000
  14. 0.23400000 0.37500000
  15. 0.43800000 0.73400000
  16. 0.87500000 1.46900000
  17. 1.81200000 3.00000000
  18. 3.86000000 6.25000000
  19. 7.04700000 11.84300000
  20. 14.06300000 23.81200000
  21. 28.17200000 47.43800000
  22. 56.42200000 94.78100000
  23. 请按任意键继续. . .
复制代码
测试代码:
  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <time.h>
  4. #define PI 3.1415926535897932
  5. #define _2PI (2.0*PI)
  6. #ifdef __cplusplus
  7. #include <windows.h>
  8. extern "C" {
  9. #endif
  10. void _stdcall _Degree2SinCos(float degree,double *sin,double *cos);
  11. void _stdcall _Rad2SinCos(double Rad,double *sin,double *cos);
  12. #ifdef __cplusplus
  13. }
  14. #endif
  15. int main()
  16. {
  17. double cos0,sin0,cos1,sin1;
  18. double t0,t1;
  19. double i,N,N0,N1,theta;//1/N
  20. int j;
  21. printf("Elapsed time: \n_Rad2SinCos Std_SinCos (seconds)\n");
  22. for(j=10;j<30;j++)
  23. {
  24. N=(unsigned int)1<<j;
  25. N0=N/4.0;
  26. N1=1.0/N;
  27. //=======================================================
  28. t0=clock();
  29. for(i=0;i<=N0;i++)
  30. {
  31. theta=(double)i*N1*_2PI;
  32. _Rad2SinCos(theta,&sin0,&cos0);
  33. //printf("%18.16lf %18.16lf %18.16lf\n",theta,sin0,cos0);
  34. }
  35. printf("%.8f ",(clock()-t0)/CLOCKS_PER_SEC);
  36. //=======================================================
  37. t1=clock();
  38. for(i=0;i<=N0;i++)
  39. {
  40. theta=(double)i*N1*_2PI;
  41. sin1=sin(theta);
  42. cos1=cos(theta);
  43. //printf("%18.16lf %18.16lf %18.16lf\n",theta,sin1,cos1);
  44. }
  45. printf("%.8f \n",(clock()-t1)/CLOCKS_PER_SEC);
  46. //=======================================================
  47. }
  48. system("PAUSE");
  49. return 0;
  50. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-2-22 16:44:17 | 显示全部楼层
9# G-Spider 上面的弧度都是倍数关系,看来可以用倍角公式之类的解决。 sin(2x)=2sin(x)*cos(x); cos(2x)=1 -2(sinx)^2; sin(x+y)=sin(x)cos(y)+cos(x)sin(y); cos(x+y)=cos(x)cos(y)-sin(x)sin(y); 对于弧度x,2x,3x,4x,5x,6x,7x,........ 偶数项2x,4x,6x,..... 奇数项3x ,5x ,7x,....改成(2x+x), (4x+x),(6x+x),...... 于是 sin(a+x)=sin(a)cos(x)+cos(a)sin(x)=c0*sin(a)+c1*cos(a); cos(a+x)=cos(a)cos(x)-sin(a)sin(x)=c0*cos(a)-c1*sin(a); 奇数项的sin,cos值只与前一项的正余弦有关。 偶数项的sin,cos值由n/2的正余弦得到。 按奇偶交替(数组下标定位)应该可以得到结果。 这样对于弧度x,2x,3x,4x,........所有的sin,cos值均可由sin(x),cos(x)得出,不知精度如何,有时间试试。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-11-22 05:10 , Processed in 0.030727 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表