calculate.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /******************************************************************************
  2. 版权所有:
  3. 文件名称: calculate.c
  4. 文件版本: 01.01
  5. 创建作者: sunxi
  6. 创建日期: 2008-08-25
  7. 功能说明: 算术计算公式。
  8. 其它说明: Q16定点数定义----如果一个32bits数,高16代表整数部分,低16位代表小数部分,
  9. 我们就将它称为Q16定点数(Qxx代表xx位小数).
  10. 修改记录:
  11. */
  12. /*------------------------------- 头文件 --------------------------------------
  13. */
  14. #ifndef WIN32 //VC6.0 中定义的宏
  15. #include "bspconfig.h"
  16. #include "calculate.h"
  17. #define __int64 long long
  18. #endif
  19. #include "rt.h"
  20. /*------------------------------- 宏定义 --------------------------------------
  21. */
  22. #if CFG_BSP_DEBUG
  23. #define _CAL_DEBUG
  24. #endif
  25. /*------------------------------ 全局变量 -------------------------------------
  26. */
  27. const long asin_table[257]=
  28. {
  29. 0x00000000,0x0000394B,0x00007297,0x0000ABE4,0x0000E531,
  30. 0x00011E7F,0x000157CE,0x0001911E,0x0001CA70,0x000203C4,
  31. 0x00023D1A,0x00027672,0x0002AFCD,0x0002E92A,0x0003228A,
  32. 0x00035BED,0x00039554,0x0003CEBE,0x0004082C,0x0004419F,
  33. 0x00047B15,0x0004B490,0x0004EE10,0x00052795,0x0005611E,
  34. 0x00059AAE,0x0005D443,0x00060DDE,0x0006477F,0x00068126,
  35. 0x0006BAD5,0x0006F489,0x00072E46,0x00076809,0x0007A1D4,
  36. 0x0007DBA7,0x00081581,0x00084F65,0x00088950,0x0008C345,
  37. 0x0008FD42,0x00093749,0x00097159,0x0009AB74,0x0009E598,
  38. 0x000A1FC6,0x000A59FF,0x000A9443,0x000ACE92,0x000B08EC,
  39. 0x000B4352,0x000B7DC4,0x000BB842,0x000BF2CC,0x000C2D63,
  40. 0x000C6807,0x000CA2B8,0x000CDD76,0x000D1843,0x000D531D,
  41. 0x000D8E06,0x000DC8FD,0x000E0403,0x000E3F19,0x000E7A3E,
  42. 0x000EB572,0x000EF0B7,0x000F2C0C,0x000F6772,0x000FA2E9,
  43. 0x000FDE71,0x00101A0B,0x001055B6,0x00109174,0x0010CD45,
  44. 0x00110928,0x0011451F,0x00118129,0x0011BD46,0x0011F979,
  45. 0x001235BF,0x0012721B,0x0012AE8C,0x0012EB12,0x001327AE,
  46. 0x00136461,0x0013A12A,0x0013DE0A,0x00141B02,0x00145812,
  47. 0x00149539,0x0014D27A,0x00150FD3,0x00154D45,0x00158AD2,
  48. 0x0015C878,0x00160639,0x00164415,0x0016820C,0x0016C01F,
  49. 0x0016FE4F,0x00173C9B,0x00177B04,0x0017B98B,0x0017F830,
  50. 0x001836F3,0x001875D5,0x0018B4D7,0x0018F3F9,0x0019333B,
  51. 0x0019729E,0x0019B222,0x0019F1C9,0x001A3192,0x001A717E,
  52. 0x001AB18D,0x001AF1C1,0x001B3219,0x001B7297,0x001BB33A,
  53. 0x001BF404,0x001C34F4,0x001C760C,0x001CB74D,0x001CF8B6,
  54. 0x001D3A48,0x001D7C05,0x001DBDED,0x001E0000,0x001E423F,
  55. 0x001E84AA,0x001EC744,0x001F0A0B,0x001F4D02,0x001F9028,
  56. 0x001FD37F,0x00201707,0x00205AC1,0x00209EAD,0x0020E2CE,
  57. 0x00212723,0x00216BAE,0x0021B06F,0x0021F566,0x00223A97,
  58. 0x00228000,0x0022C5A3,0x00230B81,0x0023519B,0x002397F2,
  59. 0x0023DE87,0x0024255B,0x00246C6F,0x0024B3C4,0x0024FB5C,
  60. 0x00254338,0x00258B58,0x0025D3BF,0x00261C6D,0x00266563,
  61. 0x0026AEA3,0x0026F82F,0x00274207,0x00278C2E,0x0027D6A4,
  62. 0x0028216B,0x00286C84,0x0028B7F2,0x002903B6,0x00294FD1,
  63. 0x00299C46,0x0029E915,0x002A3641,0x002A83CD,0x002AD1B8,
  64. 0x002B2007,0x002B6EBA,0x002BBDD4,0x002C0D58,0x002C5D46,
  65. 0x002CADA2,0x002CFE6E,0x002D4FAD,0x002DA161,0x002DF38D,
  66. 0x002E4633,0x002E9957,0x002EECFB,0x002F4122,0x002F95D0,
  67. 0x002FEB08,0x003040CD,0x00309723,0x0030EE0D,0x00314590,
  68. 0x00319DAF,0x0031F66E,0x00324FD3,0x0032A9E0,0x0033049C,
  69. 0x0033600B,0x0033BC31,0x00341915,0x003476BC,0x0034D52C,
  70. 0x0035346B,0x00359480,0x0035F571,0x00365746,0x0036BA05,
  71. 0x00371DB8,0x00378265,0x0037E817,0x00384ED6,0x0038B6AD,
  72. 0x00391FA5,0x003989CB,0x0039F529,0x003A61CC,0x003ACFC2,
  73. 0x003B3F19,0x003BAFE0,0x003C2228,0x003C9603,0x003D0B83,
  74. 0x003D82BD,0x003DFBC7,0x003E76BA,0x003EF3AF,0x003F72C2,
  75. 0x003FF414,0x004077C6,0x0040FDFE,0x004186E6,0x004212AC,
  76. 0x0042A183,0x004333A6,0x0043C955,0x004462DB,0x0045008B,
  77. 0x0045A2C8,0x00464A00,0x0046F6B9,0x0047A98D,0x00486337,
  78. 0x00492498,0x0049EEC8,0x004AC325,0x004BA374,0x004C9209,
  79. 0x004D921C,0x004EA84C,0x004FDBB3,0x00513846,0x0052D556,
  80. 0x0054EF1F,0x005A0000,
  81. };
  82. /*------------------------------ 函数声明 -------------------------------------
  83. */
  84. long _cal_asin(long x);
  85. /*------------------------------ 外部函数 -------------------------------------
  86. */
  87. /******************************************************************************
  88. 函数名称: cal_complex_magnitude
  89. 函数版本: 01.01
  90. 创建作者: sunxi
  91. 创建日期: 2008-08-26
  92. 函数说明: 得到复数的幅值(sqrt(real*real + imag*imag))。算法如下:
  93. l=max{|real|,|imag|},s=min{|real|,|imag|}
  94. m = l + 5*s*s/(9*l+3*s);
  95. 此公式的实数算法精度(最大相对误差值)为0.1735%.
  96. 参数说明:
  97. real: 复数的实部
  98. imag: 复数的虚部
  99. 返回值: 复数的幅值.
  100. 修改记录:
  101. */
  102. unsigned long cal_complex_magnitude(long real,long imag)
  103. {
  104. unsigned long m=0,l,t,s;
  105. if(real == 0 && imag == 0)
  106. {
  107. return 0;
  108. }
  109. if(real < 0)
  110. {
  111. real = -real;
  112. }
  113. if(imag < 0)
  114. {
  115. imag = -imag;
  116. }
  117. if(real < imag)
  118. {
  119. l = (unsigned long)imag;
  120. s = (unsigned long)real;
  121. }
  122. else
  123. {
  124. l = (unsigned long)real;
  125. s = (unsigned long)imag;
  126. }
  127. //计算结果,并进行四舍五入.
  128. t = 9*l+3*s;
  129. if(t)
  130. {
  131. m= (unsigned long)(l + (5*(__int64)s*s + (t>>1))/t);
  132. }
  133. return m;
  134. }
  135. /******************************************************************************
  136. 函数名称: cal_complex_phase_cos
  137. 函数版本: 01.01
  138. 创建作者: sunxi
  139. 创建日期: 2008-08-26
  140. 函数说明: 得到复数极坐标表示法的相位角的余弦
  141. 参数说明:
  142. real: 复数的实部
  143. imag: 复数的虚部
  144. 返回值: 复数相位角的余弦值(Q16定点数)
  145. 修改记录:
  146. */
  147. long cal_complex_phase_cos(long real,long imag)
  148. {
  149. unsigned long m;
  150. m = cal_complex_magnitude(real,imag);
  151. if(m == 0)
  152. {
  153. return 0;
  154. }
  155. return (long)((((__int64)real<<16)+(m>>1))/m);
  156. }
  157. /******************************************************************************
  158. 函数名称: cal_complex_phase
  159. 函数版本: 01.01
  160. 创建作者: sunxi
  161. 创建日期: 2008-08-26
  162. 函数说明: 得到复数的相位角.
  163. 参数说明:
  164. real: 复数的实部
  165. imag: 复数的虚部
  166. 返回值: 复数的相位角(-180~180,Q16定点数)
  167. 修改记录:
  168. */
  169. #define ANGLE_90 (90<<16)
  170. #define ANGLE_180 (180<<16)
  171. long cal_complex_phase(long real,long imag)
  172. {
  173. long real_abs,imag_abs;
  174. long angle;
  175. //得到绝对值
  176. real_abs=real >= 0 ? real : -real;
  177. imag_abs=imag >= 0 ? imag : -imag;
  178. //对于sin函数来说,0~45度的线性要好于45~90度的线性。
  179. //所以我们只使用0~45度。
  180. if(real_abs>=imag_abs)
  181. {
  182. //<=45度,用sin去算
  183. angle = _cal_asin(cal_complex_phase_cos(imag_abs,real_abs));
  184. }
  185. else
  186. {
  187. //>45度,用cos去算
  188. angle = _cal_asin(cal_complex_phase_cos(real_abs,imag_abs));
  189. angle = ANGLE_90-angle;
  190. }
  191. //象限处理
  192. if(real>=0)
  193. {
  194. if(imag>=0)
  195. {
  196. return angle; //第一象限
  197. }
  198. else
  199. {
  200. return (0 - angle); //第四象限
  201. }
  202. }
  203. else
  204. {
  205. if(imag>=0)
  206. {
  207. return ANGLE_180 - angle; //第二象限
  208. }
  209. else
  210. {
  211. return (-ANGLE_180 + angle); //第三象限
  212. }
  213. }
  214. }
  215. /******************************************************************************
  216. 函数名称: cal_q16_multi
  217. 函数版本: 01.01
  218. 创建作者: sunxi
  219. 创建日期: 2008-08-26
  220. 函数说明: 两个Q16定点数相乘,得到一个Q16数.计算公式为:
  221. (a*b)>>16
  222. 参数说明:
  223. a: Q16定点数1
  224. b: Q16定点数2
  225. 返回值: 乘积(Q16定点数).注:相乘后的结果应不超过48位,否则出现溢出错误
  226. 修改记录:
  227. */
  228. long cal_q16_multi(long a,long b)
  229. {
  230. __int64 ll;
  231. ll = (__int64)a*b;
  232. return (long)(ll>>16);
  233. }
  234. /******************************************************************************
  235. 函数名称: cal_multi_divide
  236. 函数版本: 01.01
  237. 创建作者: sunxi
  238. 创建日期: 2008-08-26
  239. 函数说明: 使用64位算法计算a*b/c.有符号算法.注意:结果仍有可能溢出.
  240. 参数说明:
  241. a: 被乘数
  242. b: 乘数
  243. c: 除数
  244. 返回值: 结果
  245. 修改记录:
  246. */
  247. long cal_multi_divide(long a,long b,long c)
  248. {
  249. __int64 ll;
  250. #ifdef __KERNEL__
  251. ll = a*b;
  252. div_s64(ll,c);
  253. #else
  254. ll = (__int64)a*b/c;
  255. #endif
  256. return (long)ll;
  257. }
  258. /******************************************************************************
  259. 函数名称: cal_multi_divide_unsigned
  260. 函数版本: 01.01
  261. 创建作者: sunxi
  262. 创建日期: 2008-08-26
  263. 函数说明: 使用64位算法计算a*b/c.无符号算法.注意:结果仍有可能溢出.
  264. 参数说明:
  265. a: 被乘数
  266. b: 乘数
  267. c: 除数
  268. 返回值: 结果
  269. 修改记录:
  270. */
  271. unsigned long cal_multi_divide_unsigned(unsigned long a,unsigned long b,unsigned long c)
  272. {
  273. unsigned __int64 ll;
  274. ll = (unsigned __int64)a*b/c;
  275. return (unsigned long)ll;
  276. }
  277. /*------------------------------ 内部函数 -------------------------------------
  278. */
  279. /******************************************************************************
  280. 函数名称: _cal_asin
  281. 函数版本: 01.01
  282. 创建作者: sunxi
  283. 创建日期: 2008-08-26
  284. 函数说明: 反sin函数
  285. 参数说明:
  286. x: 反sin函数输入值,Q16定点数,0<=x<=1。
  287. 返回值: 结果y,Q16定点数,0<=y<=90.
  288. 修改记录:
  289. */
  290. long _cal_asin(long x)
  291. {
  292. int high,low;
  293. //x>=1,返回90度。
  294. if(x >= 0x10000)
  295. {
  296. return asin_table[256];
  297. }
  298. high = (x>>8) & 0xff;
  299. low = x & 0xff;
  300. return ((asin_table[high + 1] - asin_table[high])*low + (256>>1))/256 + asin_table[high];
  301. }
  302. /*------------------------------ 测试函数 -------------------------------------
  303. */
  304. #ifndef WIN32 //VC6.0 中定义的宏
  305. #ifdef _CAL_DEBUG
  306. #include "rt.h"
  307. int cal_test(void)
  308. {
  309. long angle,a,b,ans;
  310. // int i1,i2;
  311. rt_printf("cal_test begin!\r\n");
  312. a = 0x77777;
  313. b = 0x66666;
  314. ans = cal_q16_multi(a,b);
  315. rt_printf("cal_q16_multi:%d*%d=%d\r\n",a,b,ans);
  316. a = 234;
  317. b = 567;
  318. angle = cal_complex_phase(a,b);
  319. rt_printf("angle=%d.%04d(real=%d,imag=%d)\r\n",angle>>16,(angle&0xffff)*10000/0x10000,a,b);
  320. rt_printf("cal_test end!\r\n\r\n");
  321. return 0;
  322. }
  323. #endif
  324. #else
  325. #include "stdio.h"
  326. #include "math.h"
  327. int cal_test_vc(void)
  328. {
  329. long i,j,angle;
  330. double angle_db1,angle_db2,diff,diff_max;
  331. angle = cal_complex_phase(136,-8010);
  332. diff_max = 0;
  333. for(i=100;i<65536;i++)
  334. {
  335. for(j=100;j<65536;j++)
  336. {
  337. angle = cal_complex_phase(i,j);
  338. angle_db1 = (double)angle/65536;
  339. angle_db2 = atan((double)j/i);
  340. angle_db2 = angle_db2 *180/3.1416;
  341. diff = angle_db2 - angle_db1;
  342. if(diff < 0)
  343. {
  344. diff = -diff;
  345. }
  346. if(diff > diff_max)
  347. {
  348. diff_max = diff;
  349. rt_printf("cal_test_vc:i=%d,j=%d,diff_max=%f\n",i,j,diff);
  350. }
  351. }
  352. }
  353. return 0;
  354. }
  355. #endif