in math-emu/fpu_trig.c [1026:1195]
static void fyl2x(FPU_REG *st0_ptr, u_char st0_tag)
{
FPU_REG *st1_ptr = &st(1), exponent;
u_char st1_tag = FPU_gettagi(1);
u_char sign;
int e, tag;
clear_C1();
if ((st0_tag == TAG_Valid) && (st1_tag == TAG_Valid)) {
both_valid:
/* Both regs are Valid or Denormal */
if (signpositive(st0_ptr)) {
if (st0_tag == TW_Denormal)
FPU_to_exp16(st0_ptr, st0_ptr);
else
/* Convert st(0) for internal use. */
setexponent16(st0_ptr, exponent(st0_ptr));
if ((st0_ptr->sigh == 0x80000000)
&& (st0_ptr->sigl == 0)) {
/* Special case. The result can be precise. */
u_char esign;
e = exponent16(st0_ptr);
if (e >= 0) {
exponent.sigh = e;
esign = SIGN_POS;
} else {
exponent.sigh = -e;
esign = SIGN_NEG;
}
exponent.sigl = 0;
setexponent16(&exponent, 31);
tag = FPU_normalize_nuo(&exponent);
stdexp(&exponent);
setsign(&exponent, esign);
tag =
FPU_mul(&exponent, tag, 1, FULL_PRECISION);
if (tag >= 0)
FPU_settagi(1, tag);
} else {
/* The usual case */
sign = getsign(st1_ptr);
if (st1_tag == TW_Denormal)
FPU_to_exp16(st1_ptr, st1_ptr);
else
/* Convert st(1) for internal use. */
setexponent16(st1_ptr,
exponent(st1_ptr));
poly_l2(st0_ptr, st1_ptr, sign);
}
} else {
/* negative */
if (arith_invalid(1) < 0)
return;
}
FPU_pop();
return;
}
if (st0_tag == TAG_Special)
st0_tag = FPU_Special(st0_ptr);
if (st1_tag == TAG_Special)
st1_tag = FPU_Special(st1_ptr);
if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
FPU_stack_underflow_pop(1);
return;
} else if ((st0_tag <= TW_Denormal) && (st1_tag <= TW_Denormal)) {
if (st0_tag == TAG_Zero) {
if (st1_tag == TAG_Zero) {
/* Both args zero is invalid */
if (arith_invalid(1) < 0)
return;
} else {
u_char sign;
sign = getsign(st1_ptr) ^ SIGN_NEG;
if (FPU_divide_by_zero(1, sign) < 0)
return;
setsign(st1_ptr, sign);
}
} else if (st1_tag == TAG_Zero) {
/* st(1) contains zero, st(0) valid <> 0 */
/* Zero is the valid answer */
sign = getsign(st1_ptr);
if (signnegative(st0_ptr)) {
/* log(negative) */
if (arith_invalid(1) < 0)
return;
} else if ((st0_tag == TW_Denormal)
&& (denormal_operand() < 0))
return;
else {
if (exponent(st0_ptr) < 0)
sign ^= SIGN_NEG;
FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
setsign(st1_ptr, sign);
}
} else {
/* One or both operands are denormals. */
if (denormal_operand() < 0)
return;
goto both_valid;
}
} else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
return;
}
/* One or both arg must be an infinity */
else if (st0_tag == TW_Infinity) {
if ((signnegative(st0_ptr)) || (st1_tag == TAG_Zero)) {
/* log(-infinity) or 0*log(infinity) */
if (arith_invalid(1) < 0)
return;
} else {
u_char sign = getsign(st1_ptr);
if ((st1_tag == TW_Denormal)
&& (denormal_operand() < 0))
return;
FPU_copy_to_reg1(&CONST_INF, TAG_Special);
setsign(st1_ptr, sign);
}
}
/* st(1) must be infinity here */
else if (((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal))
&& (signpositive(st0_ptr))) {
if (exponent(st0_ptr) >= 0) {
if ((exponent(st0_ptr) == 0) &&
(st0_ptr->sigh == 0x80000000) &&
(st0_ptr->sigl == 0)) {
/* st(0) holds 1.0 */
/* infinity*log(1) */
if (arith_invalid(1) < 0)
return;
}
/* else st(0) is positive and > 1.0 */
} else {
/* st(0) is positive and < 1.0 */
if ((st0_tag == TW_Denormal)
&& (denormal_operand() < 0))
return;
changesign(st1_ptr);
}
} else {
/* st(0) must be zero or negative */
if (st0_tag == TAG_Zero) {
/* This should be invalid, but a real 80486 is happy with it. */
#ifndef PECULIAR_486
sign = getsign(st1_ptr);
if (FPU_divide_by_zero(1, sign) < 0)
return;
#endif /* PECULIAR_486 */
changesign(st1_ptr);
} else if (arith_invalid(1) < 0) /* log(negative) */
return;
}
FPU_pop();
}