Example #1
0
static void convert_l2reg(long const *arg, int deststnr)
{
	int tag;
	long num = *arg;
	u_char sign;
	FPU_REG *dest = &st(deststnr);

	if (num == 0) {
		FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
		return;
	}

	if (num > 0) {
		sign = SIGN_POS;
	} else {
		num = -num;
		sign = SIGN_NEG;
	}

	dest->sigh = num;
	dest->sigl = 0;
	setexponent16(dest, 31);
	tag = FPU_normalize(dest);
	FPU_settagi(deststnr, tag);
	setsign(dest, sign);
	return;
}
Example #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;
}
Example #3
0
/* 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;
}