struct fp_ext *fp_fmul(struct fp_ext *dest, struct fp_ext *src)
{ union fp_mant128 temp; int exp;
dprint(PINSTR, "fmul\n");
fp_dyadic_check(dest, src);
/* calculate the correct sign now, as it's necessary for infinities */
dest->sign = src->sign ^ dest->sign;
/* Handle infinities */ if (IS_INF(dest)) { if (IS_ZERO(src))
fp_set_nan(dest); return dest;
} if (IS_INF(src)) { if (IS_ZERO(dest))
fp_set_nan(dest); else
fp_copy_ext(dest, src); return dest;
}
/* Of course, as we all know, zero * anything = zero. You may nothaveknownthatitmightbeapositiveornegative
zero... */ if (IS_ZERO(dest) || IS_ZERO(src)) {
dest->exp = 0;
dest->mant.m64 = 0;
dest->lowmant = 0;
return dest;
}
exp = dest->exp + src->exp - 0x3ffe;
/* shift up the mantissa for denormalized numbers, sothatthehighestbitisset,thismakesthe
shift of the result below easier */ if ((long)dest->mant.m32[0] >= 0)
exp -= fp_overnormalize(dest); if ((long)src->mant.m32[0] >= 0)
exp -= fp_overnormalize(src);
/* now, do a 64-bit multiply with expansion */
fp_multiplymant(&temp, dest, src);
/* normalize it back to 64 bits and stuff it back into the
destination struct */ if ((long)temp.m32[0] > 0) {
exp--;
fp_putmant128(dest, &temp, 1);
} else
fp_putmant128(dest, &temp, 0);
/* fp_fdiv: Implements the "kernel" of the FDIV, FSDIV, FDDIV and FSGLDIVinstructions.
Notethattheorderoftheoperandsiscounter-intuitive:instead
of src / dest, the result is actually dest / src. */
struct fp_ext *fp_fdiv(struct fp_ext *dest, struct fp_ext *src)
{ union fp_mant128 temp; int exp;
dprint(PINSTR, "fdiv\n");
fp_dyadic_check(dest, src);
/* calculate the correct sign now, as it's necessary for infinities */
dest->sign = src->sign ^ dest->sign;
/* Handle infinities */ if (IS_INF(dest)) { /* infinity / infinity = NaN (quiet, as always) */ if (IS_INF(src))
fp_set_nan(dest); /* infinity / anything else = infinity (with appropriate sign) */ return dest;
} if (IS_INF(src)) { /* anything / infinity = zero (with appropriate sign) */
dest->exp = 0;
dest->mant.m64 = 0;
dest->lowmant = 0;
return dest;
}
/* zeroes */ if (IS_ZERO(dest)) { /* zero / zero = NaN */ if (IS_ZERO(src))
fp_set_nan(dest); /* zero / anything else = zero */ return dest;
} if (IS_ZERO(src)) { /* anything / zero = infinity (with appropriate sign) */
fp_set_sr(FPSR_EXC_DZ);
dest->exp = 0x7fff;
dest->mant.m64 = 0;
return dest;
}
exp = dest->exp - src->exp + 0x3fff;
/* shift up the mantissa for denormalized numbers, sothatthehighestbitisset,thismakeslots
of things below easier */ if ((long)dest->mant.m32[0] >= 0)
exp -= fp_overnormalize(dest); if ((long)src->mant.m32[0] >= 0)
exp -= fp_overnormalize(src);
/* now, do the 64-bit divide */
fp_dividemant(&temp, dest, src);
/* normalize it back to 64 bits and stuff it back into the
destination struct */ if (!temp.m32[0]) {
exp--;
fp_putmant128(dest, &temp, 32);
} else
fp_putmant128(dest, &temp, 31);
/* calculate the correct sign now, as it's necessary for infinities */
dest->sign = src->sign ^ dest->sign;
/* Handle infinities */ if (IS_INF(dest)) { if (IS_ZERO(src))
fp_set_nan(dest); return dest;
} if (IS_INF(src)) { if (IS_ZERO(dest))
fp_set_nan(dest); else
fp_copy_ext(dest, src); return dest;
}
/* Of course, as we all know, zero * anything = zero. You may nothaveknownthatitmightbeapositiveornegative
zero... */ if (IS_ZERO(dest) || IS_ZERO(src)) {
dest->exp = 0;
dest->mant.m64 = 0;
dest->lowmant = 0;
return dest;
}
exp = dest->exp + src->exp - 0x3ffe;
/* do a 32-bit multiply */
fp_mul64(dest->mant.m32[0], dest->mant.m32[1],
dest->mant.m32[0] & 0xffffff00,
src->mant.m32[0] & 0xffffff00);
/* We might want to normalize upwards here... however, since weknowthatthisisonlycalledontheoutputoffp_fdiv, orwiththeinputtofp_fintorfp_fintrz,andtheinputs toallthesefunctionsareeithernormalordenormalized (nosubnormalsallowed!),there'sreallynoneed.
Inthecaseoffp_fdiv,observethat0x80000000/0xffff= 0xffff8000,andthesameholdsfor128-bit/64-bit.(i.e.the smallestpossiblenormaldividendandthelargestpossiblenormal divisorwillstillproduceanormalquotient,therefore,(normal
<< 64) / normal is normal in all cases) */
switch (mode) { case FPCR_ROUND_RN: switch (dest->exp) { case0 ... 0x3ffd: return; case0x3ffe: /* As noted above, the input is always normal, so the guardbit(bit63)isalwaysset.therefore,the onlycaseinwhichwewillNOTroundto1.0iswhen
the input is exactly 0.5. */ if (oldmant.m64 == (1ULL << 63)) return; break; case0x3fff ... 0x401d:
mask = 1 << (0x401d - dest->exp); if (!(oldmant.m32[0] & mask)) return; if (oldmant.m32[0] & (mask << 1)) break; if (!(oldmant.m32[0] << (dest->exp - 0x3ffd)) &&
!oldmant.m32[1]) return; break; case0x401e: if (oldmant.m32[1] & 0x80000000) return; if (oldmant.m32[0] & 1) break; if (!(oldmant.m32[1] << 1)) return; break; case0x401f ... 0x403d:
mask = 1 << (0x403d - dest->exp); if (!(oldmant.m32[1] & mask)) return; if (oldmant.m32[1] & (mask << 1)) break; if (!(oldmant.m32[1] << (dest->exp - 0x401d))) return; break; default: return;
} break; case FPCR_ROUND_RZ: return; default: if (dest->sign ^ (mode - FPCR_ROUND_RM)) break; return;
}
/* Infinities and zeros */ if (IS_INF(dest) || IS_ZERO(src)) {
fp_set_nan(dest); return dest;
} if (IS_ZERO(dest) || IS_INF(src)) return dest;
/* FIXME: there is almost certainly a smarter way to do this */
fp_copy_ext(&tmp, dest);
fp_fdiv(&tmp, src); /* NOTE: src might be modified */
fp_roundint(&tmp, mode);
fp_fmul(&tmp, src);
fp_fsub(dest, &tmp);
/* set the quotient byte */
fp_set_quotient((dest->mant.m64 & 0x7f) | (dest->sign << 7)); return dest;
}
/* fp_fmod: Implements the kernel of the FMOD instruction.
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.