poly_sin.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:11k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*---------------------------------------------------------------------------+
  2.  |  poly_sin.c                                                               |
  3.  |                                                                           |
  4.  |  Computation of an approximation of the sin function and the cosine       |
  5.  |  function by a polynomial.                                                |
  6.  |                                                                           |
  7.  | Copyright (C) 1992,1993,1994,1997,1999                                    |
  8.  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  9.  |                  E-mail   billm@melbpc.org.au                             |
  10.  |                                                                           |
  11.  |                                                                           |
  12.  +---------------------------------------------------------------------------*/
  13. #include "exception.h"
  14. #include "reg_constant.h"
  15. #include "fpu_emu.h"
  16. #include "fpu_system.h"
  17. #include "control_w.h"
  18. #include "poly.h"
  19. #define N_COEFF_P 4
  20. #define N_COEFF_N 4
  21. static const unsigned long long pos_terms_l[N_COEFF_P] =
  22. {
  23.   0xaaaaaaaaaaaaaaabLL,
  24.   0x00d00d00d00cf906LL,
  25.   0x000006b99159a8bbLL,
  26.   0x000000000d7392e6LL
  27. };
  28. static const unsigned long long neg_terms_l[N_COEFF_N] =
  29. {
  30.   0x2222222222222167LL,
  31.   0x0002e3bc74aab624LL,
  32.   0x0000000b09229062LL,
  33.   0x00000000000c7973LL
  34. };
  35. #define N_COEFF_PH 4
  36. #define N_COEFF_NH 4
  37. static const unsigned long long pos_terms_h[N_COEFF_PH] =
  38. {
  39.   0x0000000000000000LL,
  40.   0x05b05b05b05b0406LL,
  41.   0x000049f93edd91a9LL,
  42.   0x00000000c9c9ed62LL
  43. };
  44. static const unsigned long long neg_terms_h[N_COEFF_NH] =
  45. {
  46.   0xaaaaaaaaaaaaaa98LL,
  47.   0x001a01a01a019064LL,
  48.   0x0000008f76c68a77LL,
  49.   0x0000000000d58f5eLL
  50. };
  51. /*--- poly_sine() -----------------------------------------------------------+
  52.  |                                                                           |
  53.  +---------------------------------------------------------------------------*/
  54. void poly_sine(FPU_REG *st0_ptr)
  55. {
  56.   int                 exponent, echange;
  57.   Xsig                accumulator, argSqrd, argTo4;
  58.   unsigned long       fix_up, adj;
  59.   unsigned long long  fixed_arg;
  60.   FPU_REG       result;
  61.   exponent = exponent(st0_ptr);
  62.   accumulator.lsw = accumulator.midw = accumulator.msw = 0;
  63.   /* Split into two ranges, for arguments below and above 1.0 */
  64.   /* The boundary between upper and lower is approx 0.88309101259 */
  65.   if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xe21240aa)) )
  66.     {
  67.       /* The argument is <= 0.88309101259 */
  68.       argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl; argSqrd.lsw = 0;
  69.       mul64_Xsig(&argSqrd, &significand(st0_ptr));
  70.       shr_Xsig(&argSqrd, 2*(-1-exponent));
  71.       argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw;
  72.       argTo4.lsw = argSqrd.lsw;
  73.       mul_Xsig_Xsig(&argTo4, &argTo4);
  74.       polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l,
  75.       N_COEFF_N-1);
  76.       mul_Xsig_Xsig(&accumulator, &argSqrd);
  77.       negate_Xsig(&accumulator);
  78.       polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l,
  79.       N_COEFF_P-1);
  80.       shr_Xsig(&accumulator, 2);    /* Divide by four */
  81.       accumulator.msw |= 0x80000000;  /* Add 1.0 */
  82.       mul64_Xsig(&accumulator, &significand(st0_ptr));
  83.       mul64_Xsig(&accumulator, &significand(st0_ptr));
  84.       mul64_Xsig(&accumulator, &significand(st0_ptr));
  85.       /* Divide by four, FPU_REG compatible, etc */
  86.       exponent = 3*exponent;
  87.       /* The minimum exponent difference is 3 */
  88.       shr_Xsig(&accumulator, exponent(st0_ptr) - exponent);
  89.       negate_Xsig(&accumulator);
  90.       XSIG_LL(accumulator) += significand(st0_ptr);
  91.       echange = round_Xsig(&accumulator);
  92.       setexponentpos(&result, exponent(st0_ptr) + echange);
  93.     }
  94.   else
  95.     {
  96.       /* The argument is > 0.88309101259 */
  97.       /* We use sin(st(0)) = cos(pi/2-st(0)) */
  98.       fixed_arg = significand(st0_ptr);
  99.       if ( exponent == 0 )
  100. {
  101.   /* The argument is >= 1.0 */
  102.   /* Put the binary point at the left. */
  103.   fixed_arg <<= 1;
  104. }
  105.       /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
  106.       fixed_arg = 0x921fb54442d18469LL - fixed_arg;
  107.       /* There is a special case which arises due to rounding, to fix here. */
  108.       if ( fixed_arg == 0xffffffffffffffffLL )
  109. fixed_arg = 0;
  110.       XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0;
  111.       mul64_Xsig(&argSqrd, &fixed_arg);
  112.       XSIG_LL(argTo4) = XSIG_LL(argSqrd); argTo4.lsw = argSqrd.lsw;
  113.       mul_Xsig_Xsig(&argTo4, &argTo4);
  114.       polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h,
  115.       N_COEFF_NH-1);
  116.       mul_Xsig_Xsig(&accumulator, &argSqrd);
  117.       negate_Xsig(&accumulator);
  118.       polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h,
  119.       N_COEFF_PH-1);
  120.       negate_Xsig(&accumulator);
  121.       mul64_Xsig(&accumulator, &fixed_arg);
  122.       mul64_Xsig(&accumulator, &fixed_arg);
  123.       shr_Xsig(&accumulator, 3);
  124.       negate_Xsig(&accumulator);
  125.       add_Xsig_Xsig(&accumulator, &argSqrd);
  126.       shr_Xsig(&accumulator, 1);
  127.       accumulator.lsw |= 1;  /* A zero accumulator here would cause problems */
  128.       negate_Xsig(&accumulator);
  129.       /* The basic computation is complete. Now fix the answer to
  130.  compensate for the error due to the approximation used for
  131.  pi/2
  132.  */
  133.       /* This has an exponent of -65 */
  134.       fix_up = 0x898cc517;
  135.       /* The fix-up needs to be improved for larger args */
  136.       if ( argSqrd.msw & 0xffc00000 )
  137. {
  138.   /* Get about 32 bit precision in these: */
  139.   fix_up -= mul_32_32(0x898cc517, argSqrd.msw) / 6;
  140. }
  141.       fix_up = mul_32_32(fix_up, LL_MSW(fixed_arg));
  142.       adj = accumulator.lsw;    /* temp save */
  143.       accumulator.lsw -= fix_up;
  144.       if ( accumulator.lsw > adj )
  145. XSIG_LL(accumulator) --;
  146.       echange = round_Xsig(&accumulator);
  147.       setexponentpos(&result, echange - 1);
  148.     }
  149.   significand(&result) = XSIG_LL(accumulator);
  150.   setsign(&result, getsign(st0_ptr));
  151.   FPU_copy_to_reg0(&result, TAG_Valid);
  152. #ifdef PARANOID
  153.   if ( (exponent(&result) >= 0)
  154.       && (significand(&result) > 0x8000000000000000LL) )
  155.     {
  156.       EXCEPTION(EX_INTERNAL|0x150);
  157.     }
  158. #endif /* PARANOID */
  159. }
  160. /*--- poly_cos() ------------------------------------------------------------+
  161.  |                                                                           |
  162.  +---------------------------------------------------------------------------*/
  163. void poly_cos(FPU_REG *st0_ptr)
  164. {
  165.   FPU_REG       result;
  166.   long int            exponent, exp2, echange;
  167.   Xsig                accumulator, argSqrd, fix_up, argTo4;
  168.   unsigned long long  fixed_arg;
  169. #ifdef PARANOID
  170.   if ( (exponent(st0_ptr) > 0)
  171.       || ((exponent(st0_ptr) == 0)
  172.   && (significand(st0_ptr) > 0xc90fdaa22168c234LL)) )
  173.     {
  174.       EXCEPTION(EX_Invalid);
  175.       FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
  176.       return;
  177.     }
  178. #endif /* PARANOID */
  179.   exponent = exponent(st0_ptr);
  180.   accumulator.lsw = accumulator.midw = accumulator.msw = 0;
  181.   if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xb00d6f54)) )
  182.     {
  183.       /* arg is < 0.687705 */
  184.       argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl;
  185.       argSqrd.lsw = 0;
  186.       mul64_Xsig(&argSqrd, &significand(st0_ptr));
  187.       if ( exponent < -1 )
  188. {
  189.   /* shift the argument right by the required places */
  190.   shr_Xsig(&argSqrd, 2*(-1-exponent));
  191. }
  192.       argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw;
  193.       argTo4.lsw = argSqrd.lsw;
  194.       mul_Xsig_Xsig(&argTo4, &argTo4);
  195.       polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h,
  196.       N_COEFF_NH-1);
  197.       mul_Xsig_Xsig(&accumulator, &argSqrd);
  198.       negate_Xsig(&accumulator);
  199.       polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h,
  200.       N_COEFF_PH-1);
  201.       negate_Xsig(&accumulator);
  202.       mul64_Xsig(&accumulator, &significand(st0_ptr));
  203.       mul64_Xsig(&accumulator, &significand(st0_ptr));
  204.       shr_Xsig(&accumulator, -2*(1+exponent));
  205.       shr_Xsig(&accumulator, 3);
  206.       negate_Xsig(&accumulator);
  207.       add_Xsig_Xsig(&accumulator, &argSqrd);
  208.       shr_Xsig(&accumulator, 1);
  209.       /* It doesn't matter if accumulator is all zero here, the
  210.  following code will work ok */
  211.       negate_Xsig(&accumulator);
  212.       if ( accumulator.lsw & 0x80000000 )
  213. XSIG_LL(accumulator) ++;
  214.       if ( accumulator.msw == 0 )
  215. {
  216.   /* The result is 1.0 */
  217.   FPU_copy_to_reg0(&CONST_1, TAG_Valid);
  218.   return;
  219. }
  220.       else
  221. {
  222.   significand(&result) = XSIG_LL(accumulator);
  223.       
  224.   /* will be a valid positive nr with expon = -1 */
  225.   setexponentpos(&result, -1);
  226. }
  227.     }
  228.   else
  229.     {
  230.       fixed_arg = significand(st0_ptr);
  231.       if ( exponent == 0 )
  232. {
  233.   /* The argument is >= 1.0 */
  234.   /* Put the binary point at the left. */
  235.   fixed_arg <<= 1;
  236. }
  237.       /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
  238.       fixed_arg = 0x921fb54442d18469LL - fixed_arg;
  239.       /* There is a special case which arises due to rounding, to fix here. */
  240.       if ( fixed_arg == 0xffffffffffffffffLL )
  241. fixed_arg = 0;
  242.       exponent = -1;
  243.       exp2 = -1;
  244.       /* A shift is needed here only for a narrow range of arguments,
  245.  i.e. for fixed_arg approx 2^-32, but we pick up more... */
  246.       if ( !(LL_MSW(fixed_arg) & 0xffff0000) )
  247. {
  248.   fixed_arg <<= 16;
  249.   exponent -= 16;
  250.   exp2 -= 16;
  251. }
  252.       XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0;
  253.       mul64_Xsig(&argSqrd, &fixed_arg);
  254.       if ( exponent < -1 )
  255. {
  256.   /* shift the argument right by the required places */
  257.   shr_Xsig(&argSqrd, 2*(-1-exponent));
  258. }
  259.       argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw;
  260.       argTo4.lsw = argSqrd.lsw;
  261.       mul_Xsig_Xsig(&argTo4, &argTo4);
  262.       polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l,
  263.       N_COEFF_N-1);
  264.       mul_Xsig_Xsig(&accumulator, &argSqrd);
  265.       negate_Xsig(&accumulator);
  266.       polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l,
  267.       N_COEFF_P-1);
  268.       shr_Xsig(&accumulator, 2);    /* Divide by four */
  269.       accumulator.msw |= 0x80000000;  /* Add 1.0 */
  270.       mul64_Xsig(&accumulator, &fixed_arg);
  271.       mul64_Xsig(&accumulator, &fixed_arg);
  272.       mul64_Xsig(&accumulator, &fixed_arg);
  273.       /* Divide by four, FPU_REG compatible, etc */
  274.       exponent = 3*exponent;
  275.       /* The minimum exponent difference is 3 */
  276.       shr_Xsig(&accumulator, exp2 - exponent);
  277.       negate_Xsig(&accumulator);
  278.       XSIG_LL(accumulator) += fixed_arg;
  279.       /* The basic computation is complete. Now fix the answer to
  280.  compensate for the error due to the approximation used for
  281.  pi/2
  282.  */
  283.       /* This has an exponent of -65 */
  284.       XSIG_LL(fix_up) = 0x898cc51701b839a2ll;
  285.       fix_up.lsw = 0;
  286.       /* The fix-up needs to be improved for larger args */
  287.       if ( argSqrd.msw & 0xffc00000 )
  288. {
  289.   /* Get about 32 bit precision in these: */
  290.   fix_up.msw -= mul_32_32(0x898cc517, argSqrd.msw) / 2;
  291.   fix_up.msw += mul_32_32(0x898cc517, argTo4.msw) / 24;
  292. }
  293.       exp2 += norm_Xsig(&accumulator);
  294.       shr_Xsig(&accumulator, 1); /* Prevent overflow */
  295.       exp2++;
  296.       shr_Xsig(&fix_up, 65 + exp2);
  297.       add_Xsig_Xsig(&accumulator, &fix_up);
  298.       echange = round_Xsig(&accumulator);
  299.       setexponentpos(&result, exp2 + echange);
  300.       significand(&result) = XSIG_LL(accumulator);
  301.     }
  302.   FPU_copy_to_reg0(&result, TAG_Valid);
  303. #ifdef PARANOID
  304.   if ( (exponent(&result) >= 0)
  305.       && (significand(&result) > 0x8000000000000000LL) )
  306.     {
  307.       EXCEPTION(EX_INTERNAL|0x151);
  308.     }
  309. #endif /* PARANOID */
  310. }