real.c
来自「GCC编译器源代码」· C语言 代码 · 共 2,875 行 · 第 1/5 页
C
2,875 行
eshup6(num); } /* test for nonzero remainder after roundoff bit */ p = &num[M]; j = 0; for (i=M; i<NI; i++) { j |= *p++; } if (j) j = 1; for (i=0; i<NI; i++) num[i] = equot[i]; return ((int)j);}/* Multiply significands of exploded e-type A and B, result in B. */static intemulm (a, b) unsigned EMUSHORT a[], b[];{ unsigned EMUSHORT *p, *q; unsigned EMUSHORT pprod[NI]; unsigned EMUSHORT j; int i; equot[0] = b[0]; equot[1] = b[1]; for (i=M; i<NI; i++) equot[i] = 0; j = 0; p = &a[NI-1]; q = &equot[NI-1]; for (i=M+1; i<NI; i++) { if (*p == 0) { --p; } else { m16m ((unsigned int) *p--, b, pprod); eaddm(pprod, equot); } j |= *q; eshdn6(equot); } for (i=0; i<NI; i++) b[i] = equot[i]; /* return flag for lost nonzero bits */ return ((int)j);}#endif/* Normalize and round off. The internal format number to be rounded is S. Input LOST is 0 if the value is exact. This is the so-called sticky bit. Input SUBFLG indicates whether the number was obtained by a subtraction operation. In that case if LOST is nonzero then the number is slightly smaller than indicated. Input EXP is the biased exponent, which may be negative. the exponent field of S is ignored but is replaced by EXP as adjusted by normalization and rounding. Input RCNTRL is the rounding control. If it is nonzero, the returned value will be rounded to RNDPRC bits. For future reference: In order for emdnorm to round off denormal significands at the right point, the input exponent must be adjusted to be the actual value it would have after conversion to the final floating point type. This adjustment has been implemented for all type conversions (etoe53, etc.) and decimal conversions, but not for the arithmetic functions (eadd, etc.). Data types having standard 15-bit exponents are not affected by this, but SFmode and DFmode are affected. For example, ediv with rndprc = 24 will not round correctly to 24-bit precision if the result is denormal. */static int rlast = -1;static int rw = 0;static unsigned EMUSHORT rmsk = 0;static unsigned EMUSHORT rmbit = 0;static unsigned EMUSHORT rebit = 0;static int re = 0;static unsigned EMUSHORT rbit[NI];static void emdnorm (s, lost, subflg, exp, rcntrl) unsigned EMUSHORT s[]; int lost; int subflg; EMULONG exp; int rcntrl;{ int i, j; unsigned EMUSHORT r; /* Normalize */ j = enormlz (s); /* a blank significand could mean either zero or infinity. */#ifndef INFINITY if (j > NBITS) { ecleazs (s); return; }#endif exp -= j;#ifndef INFINITY if (exp >= 32767L) goto overf;#else if ((j > NBITS) && (exp < 32767)) { ecleazs (s); return; }#endif if (exp < 0L) { if (exp > (EMULONG) (-NBITS - 1)) { j = (int) exp; i = eshift (s, j); if (i) lost = 1; } else { ecleazs (s); return; } } /* Round off, unless told not to by rcntrl. */ if (rcntrl == 0) goto mdfin; /* Set up rounding parameters if the control register changed. */ if (rndprc != rlast) { ecleaz (rbit); switch (rndprc) { default: case NBITS: rw = NI - 1; /* low guard word */ rmsk = 0xffff; rmbit = 0x8000; re = rw - 1; rebit = 1; break; case 113: rw = 10; rmsk = 0x7fff; rmbit = 0x4000; rebit = 0x8000; re = rw; break; case 64: rw = 7; rmsk = 0xffff; rmbit = 0x8000; re = rw - 1; rebit = 1; break; /* For DEC or IBM arithmetic */ case 56: rw = 6; rmsk = 0xff; rmbit = 0x80; rebit = 0x100; re = rw; break; case 53: rw = 6; rmsk = 0x7ff; rmbit = 0x0400; rebit = 0x800; re = rw; break; case 24: rw = 4; rmsk = 0xff; rmbit = 0x80; rebit = 0x100; re = rw; break; } rbit[re] = rebit; rlast = rndprc; } /* Shift down 1 temporarily if the data structure has an implied most significant bit and the number is denormal. Intel long double denormals also lose one bit of precision. */ if ((exp <= 0) && (rndprc != NBITS) && ((rndprc != 64) || ((rndprc == 64) && ! REAL_WORDS_BIG_ENDIAN))) { lost |= s[NI - 1] & 1; eshdn1 (s); } /* Clear out all bits below the rounding bit, remembering in r if any were nonzero. */ r = s[rw] & rmsk; if (rndprc < NBITS) { i = rw + 1; while (i < NI) { if (s[i]) r |= 1; s[i] = 0; ++i; } } s[rw] &= ~rmsk; if ((r & rmbit) != 0) { if (r == rmbit) { if (lost == 0) { /* round to even */ if ((s[re] & rebit) == 0) goto mddone; } else { if (subflg != 0) goto mddone; } } eaddm (rbit, s); } mddone:/* Undo the temporary shift for denormal values. */ if ((exp <= 0) && (rndprc != NBITS) && ((rndprc != 64) || ((rndprc == 64) && ! REAL_WORDS_BIG_ENDIAN))) { eshup1 (s); } if (s[2] != 0) { /* overflow on roundoff */ eshdn1 (s); exp += 1; } mdfin: s[NI - 1] = 0; if (exp >= 32767L) {#ifndef INFINITY overf:#endif#ifdef INFINITY s[1] = 32767; for (i = 2; i < NI - 1; i++) s[i] = 0; if (extra_warnings) warning ("floating point overflow");#else s[1] = 32766; s[2] = 0; for (i = M + 1; i < NI - 1; i++) s[i] = 0xffff; s[NI - 1] = 0; if ((rndprc < 64) || (rndprc == 113)) { s[rw] &= ~rmsk; if (rndprc == 24) { s[5] = 0; s[6] = 0; } }#endif return; } if (exp < 0) s[1] = 0; else s[1] = (unsigned EMUSHORT) exp;}/* Subtract. C = B - A, all e type numbers. */static int subflg = 0;static void esub (a, b, c) unsigned EMUSHORT *a, *b, *c;{#ifdef NANS if (eisnan (a)) { emov (a, c); return; } if (eisnan (b)) { emov (b, c); return; }/* Infinity minus infinity is a NaN. Test for subtracting infinities of the same sign. */ if (eisinf (a) && eisinf (b) && ((eisneg (a) ^ eisneg (b)) == 0)) { mtherr ("esub", INVALID); enan (c, 0); return; }#endif subflg = 1; eadd1 (a, b, c);}/* Add. C = A + B, all e type. */static void eadd (a, b, c) unsigned EMUSHORT *a, *b, *c;{#ifdef NANS/* NaN plus anything is a NaN. */ if (eisnan (a)) { emov (a, c); return; } if (eisnan (b)) { emov (b, c); return; }/* Infinity minus infinity is a NaN. Test for adding infinities of opposite signs. */ if (eisinf (a) && eisinf (b) && ((eisneg (a) ^ eisneg (b)) != 0)) { mtherr ("esub", INVALID); enan (c, 0); return; }#endif subflg = 0; eadd1 (a, b, c);}/* Arithmetic common to both addition and subtraction. */static void eadd1 (a, b, c) unsigned EMUSHORT *a, *b, *c;{ unsigned EMUSHORT ai[NI], bi[NI], ci[NI]; int i, lost, j, k; EMULONG lt, lta, ltb;#ifdef INFINITY if (eisinf (a)) { emov (a, c); if (subflg) eneg (c); return; } if (eisinf (b)) { emov (b, c); return; }#endif emovi (a, ai); emovi (b, bi); if (subflg) ai[0] = ~ai[0]; /* compare exponents */ lta = ai[E]; ltb = bi[E]; lt = lta - ltb; if (lt > 0L) { /* put the larger number in bi */ emovz (bi, ci); emovz (ai, bi); emovz (ci, ai); ltb = bi[E]; lt = -lt; } lost = 0; if (lt != 0L) { if (lt < (EMULONG) (-NBITS - 1)) goto done; /* answer same as larger addend */ k = (int) lt; lost = eshift (ai, k); /* shift the smaller number down */ } else { /* exponents were the same, so must compare significands */ i = ecmpm (ai, bi); if (i == 0) { /* the numbers are identical in magnitude */ /* if different signs, result is zero */ if (ai[0] != bi[0]) { eclear (c); return; } /* if same sign, result is double */ /* double denormalized tiny number */ if ((bi[E] == 0) && ((bi[3] & 0x8000) == 0)) { eshup1 (bi); goto done; } /* add 1 to exponent unless both are zero! */ for (j = 1; j < NI - 1; j++) { if (bi[j] != 0) { ltb += 1; if (ltb >= 0x7fff) { eclear (c); if (ai[0] != 0) eneg (c); einfin (c); return; } break; } } bi[E] = (unsigned EMUSHORT) ltb; goto done; } if (i > 0) { /* put the larger number in bi */ emovz (bi, ci); emovz (ai, bi); emovz (ci, ai); } } if (ai[0] == bi[0]) { eaddm (ai, bi); subflg = 0; } else { esubm (ai, bi); subflg = 1; } emdnorm (bi, lost, subflg, ltb, 64); done: emovo (bi, c);}/* Divide: C = B/A, all e type. */static void ediv (a, b, c) unsigned EMUSHORT *a, *b, *c;{ unsigned EMUSHORT ai[NI], bi[NI]; int i, sign; EMULONG lt, lta, ltb;/* IEEE says if result is not a NaN, the sign is "-" if and only if operands have opposite signs -- but flush -0 to 0 later if not IEEE. */ sign = eisneg(a) ^ eisneg(b);#ifdef NANS/* Return any NaN input. */ if (eisnan (a)) { emov (a, c); return; } if (eisnan (b)) { emov (b, c); return; }/* Zero over zero, or infinity over infinity, is a NaN. */ if (((ecmp (a, ezero) == 0) && (ecmp (b, ezero) == 0)) || (eisinf (a) && eisinf (b))) { mtherr ("ediv", INVALID); enan (c, sign); return; }#endif/* Infinity over anything else is infinity. */#ifdef INFINITY if (eisinf (b)) { einfin (c); goto divsign; }/* Anything else over infinity is zero. */ if (eisinf (a)) { eclear (c); goto divsign; }#endif emovi (a, ai); emovi (b, bi); lta = ai[E]; ltb = bi[E]; if (bi[E] == 0) { /* See if numerator is zero. */ for (i = 1; i < NI - 1; i++) { if (bi[i] != 0) { ltb -= enormlz (bi); goto dnzro1; } } eclear (c); goto divsign; } dnzro1: if (ai[E] == 0) { /* possible divide by zero */ for (i = 1; i < NI - 1; i++) { if (ai[i] != 0) { lta -= enormlz (ai); goto dnzro2; } }/* Divide by zero is not an invalid operation. It is a divide-by-zero operation! */ einfin (c); mtherr ("ediv", SING); goto divsign; } dnzro2: i = edivm (ai, bi); /* calculate exponent */ lt = ltb - lta + EXONE; emdnorm (bi, i, 0, lt, 64); emovo (bi, c); divsign: if (sign#ifndef IEEE && (ecmp (c, ezero) != 0)#endif ) *(c+(NE-1)) |= 0x8000; else *(c+(NE-1)) &= ~0x8000;}/* Multiply
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?