コード例 #1
0
ファイル: fpu_trig.c プロジェクト: 0-T-0/ps4-linux
/* Limited measurements show no results worse than 64 bit precision
   except for the results for arguments close to 2^63, where the
   precision of the result sometimes degrades to about 63.9 bits */
static int trig_arg(FPU_REG *st0_ptr, int even)
{
	FPU_REG tmp;
	u_char tmptag;
	unsigned long long q;
	int old_cw = control_word, saved_status = partial_status;
	int tag, st0_tag = TAG_Valid;

	if (exponent(st0_ptr) >= 63) {
		partial_status |= SW_C2;	/* Reduction incomplete. */
		return -1;
	}

	control_word &= ~CW_RC;
	control_word |= RC_CHOP;

	setpositive(st0_ptr);
	tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
			SIGN_POS);

	FPU_round_to_int(&tmp, tag);	/* Fortunately, this can't overflow
					   to 2^64 */
	q = significand(&tmp);
	if (q) {
		rem_kernel(significand(st0_ptr),
			   &significand(&tmp),
			   significand(&CONST_PI2),
			   q, exponent(st0_ptr) - exponent(&CONST_PI2));
		setexponent16(&tmp, exponent(&CONST_PI2));
		st0_tag = FPU_normalize(&tmp);
		FPU_copy_to_reg0(&tmp, st0_tag);
	}

	if ((even && !(q & 1)) || (!even && (q & 1))) {
		st0_tag =
		    FPU_sub(REV | LOADED | TAG_Valid, (int)&CONST_PI2,
			    FULL_PRECISION);

#ifdef BETTER_THAN_486
		/* So far, the results are exact but based upon a 64 bit
		   precision approximation to pi/2. The technique used
		   now is equivalent to using an approximation to pi/2 which
		   is accurate to about 128 bits. */
		if ((exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)
		    || (q > 1)) {
			/* This code gives the effect of having pi/2 to better than
			   128 bits precision. */

			significand(&tmp) = q + 1;
			setexponent16(&tmp, 63);
			FPU_normalize(&tmp);
			tmptag =
			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
				      FULL_PRECISION, SIGN_POS,
				      exponent(&CONST_PI2extra) +
				      exponent(&tmp));
			setsign(&tmp, getsign(&CONST_PI2extra));
			st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
			if (signnegative(st0_ptr)) {
				/* CONST_PI2extra is negative, so the result of the addition
				   can be negative. This means that the argument is actually
				   in a different quadrant. The correction is always < pi/2,
				   so it can't overflow into yet another quadrant. */
				setpositive(st0_ptr);
				q++;
			}
		}
#endif /* BETTER_THAN_486 */
	}
#ifdef BETTER_THAN_486
	else {
		/* So far, the results are exact but based upon a 64 bit
		   precision approximation to pi/2. The technique used
		   now is equivalent to using an approximation to pi/2 which
		   is accurate to about 128 bits. */
		if (((q > 0)
		     && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
		    || (q > 1)) {
			/* This code gives the effect of having p/2 to better than
			   128 bits precision. */

			significand(&tmp) = q;
			setexponent16(&tmp, 63);
			FPU_normalize(&tmp);	/* This must return TAG_Valid */
			tmptag =
			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
				      FULL_PRECISION, SIGN_POS,
				      exponent(&CONST_PI2extra) +
				      exponent(&tmp));
			setsign(&tmp, getsign(&CONST_PI2extra));
			st0_tag = FPU_sub(LOADED | (tmptag & 0x0f), (int)&tmp,
					  FULL_PRECISION);
			if ((exponent(st0_ptr) == exponent(&CONST_PI2)) &&
			    ((st0_ptr->sigh > CONST_PI2.sigh)
			     || ((st0_ptr->sigh == CONST_PI2.sigh)
				 && (st0_ptr->sigl > CONST_PI2.sigl)))) {
				/* CONST_PI2extra is negative, so the result of the
				   subtraction can be larger than pi/2. This means
				   that the argument is actually in a different quadrant.
				   The correction is always < pi/2, so it can't overflow
				   into yet another quadrant. */
				st0_tag =
				    FPU_sub(REV | LOADED | TAG_Valid,
					    (int)&CONST_PI2, FULL_PRECISION);
				q++;
			}
		}
	}
#endif /* BETTER_THAN_486 */

	FPU_settag0(st0_tag);
	control_word = old_cw;
	partial_status = saved_status & ~SW_C2;	/* Reduction complete. */

	return (q & 3) | even;
}
コード例 #2
0
static int trig_arg(FPU_REG *st0_ptr, int even)
{
	FPU_REG tmp;
	u_char tmptag;
	unsigned long long q;
	int old_cw = control_word, saved_status = partial_status;
	int tag, st0_tag = TAG_Valid;

	if (exponent(st0_ptr) >= 63) {
		partial_status |= SW_C2;	
		return -1;
	}

	control_word &= ~CW_RC;
	control_word |= RC_CHOP;

	setpositive(st0_ptr);
	tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
			SIGN_POS);

	FPU_round_to_int(&tmp, tag);	
	q = significand(&tmp);
	if (q) {
		rem_kernel(significand(st0_ptr),
			   &significand(&tmp),
			   significand(&CONST_PI2),
			   q, exponent(st0_ptr) - exponent(&CONST_PI2));
		setexponent16(&tmp, exponent(&CONST_PI2));
		st0_tag = FPU_normalize(&tmp);
		FPU_copy_to_reg0(&tmp, st0_tag);
	}

	if ((even && !(q & 1)) || (!even && (q & 1))) {
		st0_tag =
		    FPU_sub(REV | LOADED | TAG_Valid, (int)&CONST_PI2,
			    FULL_PRECISION);

#ifdef BETTER_THAN_486
		
		if ((exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)
		    || (q > 1)) {
			

			significand(&tmp) = q + 1;
			setexponent16(&tmp, 63);
			FPU_normalize(&tmp);
			tmptag =
			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
				      FULL_PRECISION, SIGN_POS,
				      exponent(&CONST_PI2extra) +
				      exponent(&tmp));
			setsign(&tmp, getsign(&CONST_PI2extra));
			st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
			if (signnegative(st0_ptr)) {
				
				setpositive(st0_ptr);
				q++;
			}
		}
#endif 
	}
#ifdef BETTER_THAN_486
	else {
		
		if (((q > 0)
		     && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
		    || (q > 1)) {
			

			significand(&tmp) = q;
			setexponent16(&tmp, 63);
			FPU_normalize(&tmp);	
			tmptag =
			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
				      FULL_PRECISION, SIGN_POS,
				      exponent(&CONST_PI2extra) +
				      exponent(&tmp));
			setsign(&tmp, getsign(&CONST_PI2extra));
			st0_tag = FPU_sub(LOADED | (tmptag & 0x0f), (int)&tmp,
					  FULL_PRECISION);
			if ((exponent(st0_ptr) == exponent(&CONST_PI2)) &&
			    ((st0_ptr->sigh > CONST_PI2.sigh)
			     || ((st0_ptr->sigh == CONST_PI2.sigh)
				 && (st0_ptr->sigl > CONST_PI2.sigl)))) {
				
				st0_tag =
				    FPU_sub(REV | LOADED | TAG_Valid,
					    (int)&CONST_PI2, FULL_PRECISION);
				q++;
			}
		}
	}
#endif 

	FPU_settag0(st0_tag);
	control_word = old_cw;
	partial_status = saved_status & ~SW_C2;	

	return (q & 3) | even;
}
コード例 #3
0
int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
{
	FPU_REG *a = &st(deststnr);
	FPU_REG *dest = a;
	u_char taga = FPU_gettagi(deststnr);
	u_char saved_sign = getsign(dest);
	u_char sign = (getsign(a) ^ getsign(b));
	int tag;

	if (!(taga | tagb)) {
		

		tag =
		    FPU_u_mul(a, b, dest, control_w, sign,
			      exponent(a) + exponent(b));
		if (tag < 0) {
			setsign(dest, saved_sign);
			return tag;
		}
		FPU_settagi(deststnr, tag);
		return tag;
	}

	if (taga == TAG_Special)
		taga = FPU_Special(a);
	if (tagb == TAG_Special)
		tagb = FPU_Special(b);

	if (((taga == TAG_Valid) && (tagb == TW_Denormal))
	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
	    || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
		FPU_REG x, y;
		if (denormal_operand() < 0)
			return FPU_Exception;

		FPU_to_exp16(a, &x);
		FPU_to_exp16(b, &y);
		tag = FPU_u_mul(&x, &y, dest, control_w, sign,
				exponent16(&x) + exponent16(&y));
		if (tag < 0) {
			setsign(dest, saved_sign);
			return tag;
		}
		FPU_settagi(deststnr, tag);
		return tag;
	} else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
		if (((tagb == TW_Denormal) || (taga == TW_Denormal))
		    && (denormal_operand() < 0))
			return FPU_Exception;

		FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
		setsign(dest, sign);
		return TAG_Zero;
	}
	
	else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
		return real_2op_NaN(b, tagb, deststnr, &st(0));
	} else if (((taga == TW_Infinity) && (tagb == TAG_Zero))
		   || ((tagb == TW_Infinity) && (taga == TAG_Zero))) {
		return arith_invalid(deststnr);	
	} else if (((taga == TW_Denormal) || (tagb == TW_Denormal))
		   && (denormal_operand() < 0)) {
		return FPU_Exception;
	} else if (taga == TW_Infinity) {
		FPU_copy_to_regi(a, TAG_Special, deststnr);
		setsign(dest, sign);
		return TAG_Special;
	} else if (tagb == TW_Infinity) {
		FPU_copy_to_regi(b, TAG_Special, deststnr);
		setsign(dest, sign);
		return TAG_Special;
	}
#ifdef PARANOID
	else {
		EXCEPTION(EX_INTERNAL | 0x102);
		return FPU_Exception;
	}
#endif 

	return 0;
}