/* * arccos(x) = pi/2 - arcsin(x) */ struct fpn * fpu_acos(struct fpemu *fe) { struct fpn *r; if (ISNAN(&fe->fe_f2)) return &fe->fe_f2; if (ISINF(&fe->fe_f2)) return fpu_newnan(fe); r = fpu_asin(fe); CPYFPN(&fe->fe_f2, r); /* pi/2 - asin(x) */ fpu_const(&fe->fe_f1, FPU_CONST_PI); fe->fe_f1.fp_exp--; fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; r = fpu_add(fe); return r; }
/* * x * arcsin(x) = arctan(---------------) * sqrt(1 - x^2) */ struct fpn * fpu_asin(struct fpemu *fe) { struct fpn x; struct fpn *r; if (ISNAN(&fe->fe_f2)) return &fe->fe_f2; if (ISZERO(&fe->fe_f2)) return &fe->fe_f2; if (ISINF(&fe->fe_f2)) return fpu_newnan(fe); CPYFPN(&x, &fe->fe_f2); /* x^2 */ CPYFPN(&fe->fe_f1, &fe->fe_f2); r = fpu_mul(fe); /* 1 - x^2 */ CPYFPN(&fe->fe_f2, r); fe->fe_f2.fp_sign = 1; fpu_const(&fe->fe_f1, FPU_CONST_1); r = fpu_add(fe); /* sqrt(1-x^2) */ CPYFPN(&fe->fe_f2, r); r = fpu_sqrt(fe); /* x/sqrt */ CPYFPN(&fe->fe_f2, r); CPYFPN(&fe->fe_f1, &x); r = fpu_div(fe); /* arctan */ CPYFPN(&fe->fe_f2, r); return fpu_atan(fe); }
int main(int argc, char * argv[]) { unsigned short int fpucw = 0x1234; double dbls[3] = {123.45, 0.123, 0.0}; /* generate double constants */ unsigned long dbl = 0x4000000000000000; double * wsk = &dbl; dbls[1] = *wsk; printf("unsigned long: %lx\n", dbl); printf("unsigned long: %lf\n", *wsk); /* add two numbers */ dbls[2] = fpu_add(dbls[0], dbls[1]); printf("default: %lf + %lf = %lf\n", dbls[0], dbls[1], dbls[2]); /* print FPU control word */ fpucw = get_fpu(); printf("FPU CW: %04hx\n", fpucw); /* Return 0 if exiting normally. */ return 0; }
static struct fpn * __fpu_modrem(struct fpemu *fe, int is_mod) { static struct fpn X, Y; struct fpn *x, *y, *r; uint32_t signX, signY, signQ; int j, k, l, q; int cmp; if (ISNAN(&fe->fe_f1) || ISNAN(&fe->fe_f2)) return fpu_newnan(fe); if (ISINF(&fe->fe_f1) || ISZERO(&fe->fe_f2)) return fpu_newnan(fe); CPYFPN(&X, &fe->fe_f1); CPYFPN(&Y, &fe->fe_f2); x = &X; y = &Y; q = 0; r = &fe->fe_f2; /* * Step 1 */ signX = x->fp_sign; signY = y->fp_sign; signQ = (signX ^ signY); x->fp_sign = y->fp_sign = 0; /* Special treatment that just return input value but Q is necessary */ if (ISZERO(x) || ISINF(y)) { r = &fe->fe_f1; goto Step7; } /* * Step 2 */ l = x->fp_exp - y->fp_exp; k = 0; CPYFPN(r, x); if (l >= 0) { r->fp_exp -= l; j = l; /* * Step 3 */ for (;;) { cmp = abscmp3(r, y); /* Step 3.1 */ if (cmp == 0) break; /* Step 3.2 */ if (cmp > 0) { CPYFPN(&fe->fe_f1, r); CPYFPN(&fe->fe_f2, y); fe->fe_f2.fp_sign = 1; r = fpu_add(fe); q++; } /* Step 3.3 */ if (j == 0) goto Step4; /* Step 3.4 */ k++; j--; q += q; r->fp_exp++; } /* R == Y */ q++; r->fp_class = FPC_ZERO; goto Step7; } Step4: r->fp_sign = signX; /* * Step 5 */ if (is_mod) goto Step7; /* * Step 6 */ /* y = y / 2 */ y->fp_exp--; /* abscmp3 ignore sign */ cmp = abscmp3(r, y); /* revert y */ y->fp_exp++; if (cmp > 0 || (cmp == 0 && q % 2)) { q++; CPYFPN(&fe->fe_f1, r); CPYFPN(&fe->fe_f2, y); fe->fe_f2.fp_sign = !signX; r = fpu_add(fe); } /* * Step 7 */ Step7: q &= 0x7f; q |= (signQ << 7); fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = (fe->fe_fpsr & ~FPSR_QTT) | (q << 16); return r; }
/* * sin(x): * * if (x < 0) { * x = abs(x); * sign = 1; * } * if (x > 2*pi) { * x %= 2*pi; * } * if (x > pi) { * x -= pi; * sign inverse; * } * if (x > pi/2) { * y = cos(x - pi/2); * } else { * y = sin(x); * } * if (sign) { * y = -y; * } */ struct fpn * fpu_sin(struct fpemu *fe) { struct fpn x; struct fpn p; struct fpn *r; int sign; if (ISNAN(&fe->fe_f2)) return &fe->fe_f2; if (ISINF(&fe->fe_f2)) return fpu_newnan(fe); /* if x is +0/-0, return +0/-0 */ if (ISZERO(&fe->fe_f2)) return &fe->fe_f2; CPYFPN(&x, &fe->fe_f2); /* x = abs(input) */ sign = x.fp_sign; x.fp_sign = 0; /* p <- 2*pi */ fpu_const(&p, FPU_CONST_PI); p.fp_exp++; /* * if (x > 2*pi*N) * sin(x) is sin(x - 2*pi*N) */ CPYFPN(&fe->fe_f1, &x); CPYFPN(&fe->fe_f2, &p); r = fpu_cmp(fe); if (r->fp_sign == 0) { CPYFPN(&fe->fe_f1, &x); CPYFPN(&fe->fe_f2, &p); r = fpu_mod(fe); CPYFPN(&x, r); } /* p <- pi */ p.fp_exp--; /* * if (x > pi) * sin(x) is -sin(x - pi) */ CPYFPN(&fe->fe_f1, &x); CPYFPN(&fe->fe_f2, &p); fe->fe_f2.fp_sign = 1; r = fpu_add(fe); if (r->fp_sign == 0) { CPYFPN(&x, r); sign ^= 1; } /* p <- pi/2 */ p.fp_exp--; /* * if (x > pi/2) * sin(x) is cos(x - pi/2) * else * sin(x) */ CPYFPN(&fe->fe_f1, &x); CPYFPN(&fe->fe_f2, &p); fe->fe_f2.fp_sign = 1; r = fpu_add(fe); if (r->fp_sign == 0) { __fpu_sincos_cordic(fe, r); r = &fe->fe_f2; } else { __fpu_sincos_cordic(fe, &x); r = &fe->fe_f1; } r->fp_sign = sign; return r; }