/* Software floating-point emulation. Common operations. Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Richard Henderson (rth@cygnus.com), Jakub Jelinek (jj@ultra.linux.cz), David S. Miller (davem@redhat.com) and Peter Maydell (pmaydell@chiark.greenend.org.uk).
The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* * Before packing the bits back into the native fp result, take care * of such mundane things as rounding and overflow. Also, for some * kinds of fp values, the original parts may not have been fully * extracted -- but that is ok, we can regenerate them now.
*/
/* This one accepts raw argument and not cooked, returns * 1 if X is a signaling NaN.
*/ #define _FP_ISSIGNAN(fs, wc, X) \
({ \ int __ret = 0; \ if (X##_e == _FP_EXPMAX_##fs) \
{ \ if (!_FP_FRAC_ZEROP_##wc(X) \
&& !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \
__ret = 1; \
} \
__ret; \
})
/* * Main addition routine. The input values should be cooked.
*/
#define _FP_ADD_INTERNAL(fs, wc, R, X, Y, OP) \ do { \ switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \
{ \ case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \
{ \ /* shift the smaller number so that its exponent matches the larger */ \
_FP_I_TYPE diff = X##_e - Y##_e; \
\ if (diff < 0) \
{ \
diff = -diff; \ if (diff <= _FP_WFRACBITS_##fs) \
_FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs); \ elseif (!_FP_FRAC_ZEROP_##wc(X)) \
_FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \
R##_e = Y##_e; \
} \ else \
{ \ if (diff > 0) \
{ \ if (diff <= _FP_WFRACBITS_##fs) \
_FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs); \ elseif (!_FP_FRAC_ZEROP_##wc(Y)) \
_FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc); \
} \
R##_e = X##_e; \
} \
\
R##_c = FP_CLS_NORMAL; \
\ if (X##_s == Y##_s) \
{ \
R##_s = X##_s; \
_FP_FRAC_ADD_##wc(R, X, Y); \ if (_FP_FRAC_OVERP_##wc(fs, R)) \
{ \
_FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \
R##_e++; \
} \
} \ else \
{ \
R##_s = X##_s; \
_FP_FRAC_SUB_##wc(R, X, Y); \ if (_FP_FRAC_ZEROP_##wc(R)) \
{ \ /* return an exact zero */ \ if (FP_ROUNDMODE == FP_RND_MINF) \
R##_s |= Y##_s; \ else \
R##_s &= Y##_s; \
R##_c = FP_CLS_ZERO; \
} \ else \
{ \ if (_FP_FRAC_NEGP_##wc(R)) \
{ \
_FP_FRAC_SUB_##wc(R, Y, X); \
R##_s = Y##_s; \
} \
\ /* renormalize after subtraction */ \
_FP_FRAC_CLZ_##wc(diff, R); \
diff -= _FP_WFRACXBITS_##fs; \ if (diff) \
{ \
R##_e -= diff; \
_FP_FRAC_SLL_##wc(R, diff); \
} \
} \
} \ break; \
} \
\ case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \
_FP_CHOOSENAN(fs, wc, R, X, Y, OP); \ break; \
\ case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \
R##_e = X##_e; \
fallthrough; \ case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \
_FP_FRAC_COPY_##wc(R, X); \
R##_s = X##_s; \
R##_c = X##_c; \ break; \
\ case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \
R##_e = Y##_e; \
fallthrough; \ case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \
_FP_FRAC_COPY_##wc(R, Y); \
R##_s = Y##_s; \
R##_c = Y##_c; \ break; \
\ case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ if (X##_s != Y##_s) \
{ \ /* +INF + -INF => NAN */ \
_FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \
R##_s = _FP_NANSIGN_##fs; \
R##_c = FP_CLS_NAN; \
FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_ISI); \ break; \
} \
fallthrough; \
\ case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \
R##_s = X##_s; \
R##_c = FP_CLS_INF; \ break; \
\ case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \
R##_s = Y##_s; \
R##_c = FP_CLS_INF; \ break; \
\ case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ /* make sure the sign is correct */ \ if (FP_ROUNDMODE == FP_RND_MINF) \
R##_s = X##_s | Y##_s; \ else \
R##_s = X##_s & Y##_s; \
R##_c = FP_CLS_ZERO; \ break; \
\ default: \
abort(); \
} \
} while (0)
#define _FP_ADD(fs, wc, R, X, Y) _FP_ADD_INTERNAL(fs, wc, R, X, Y, '+') #define _FP_SUB(fs, wc, R, X, Y) \ do { \ if (Y##_c != FP_CLS_NAN) Y##_s ^= 1; \
_FP_ADD_INTERNAL(fs, wc, R, X, Y, '-'); \
} while (0)
/* * Main negation routine. FIXME -- when we care about setting exception * bits reliably, this will not do. We should examine all of the fp classes.
*/
/* RSIGNED can have following values: * 0: the number is required to be 0..(2^rsize)-1, if not, NV is set plus * the result is either 0 or (2^rsize)-1 depending on the sign in such case. * 1: the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is * set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending * on the sign in such case. * 2: the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is * set plus the result is truncated to fit into destination. * -1: the number is required to be -(2^(rsize-1))..(2^rsize)-1, if not, NV is * set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending * on the sign in such case.
*/ #define _FP_TO_INT(fs, wc, r, X, rsize, rsigned) \ do { \ switch (X##_c) \
{ \ case FP_CLS_NORMAL: \ if (X##_e < 0) \
{ \
FP_SET_EXCEPTION(FP_EX_INEXACT); \
fallthrough; \ case FP_CLS_ZERO: \
r = 0; \
} \ elseif (X##_e >= rsize - (rsigned > 0 || X##_s) \
|| (!rsigned && X##_s)) \
{ /* overflow */ \
fallthrough; \ case FP_CLS_NAN: \ case FP_CLS_INF: \ if (rsigned == 2) \
{ \ if (X##_c != FP_CLS_NORMAL \
|| X##_e >= rsize - 1 + _FP_WFRACBITS_##fs) \
r = 0; \ else \
{ \
_FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1)); \
_FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
} \
} \ elseif (rsigned) \
{ \
r = 1; \
r <<= rsize - 1; \
r -= 1 - X##_s; \
} \ else \
{ \
r = 0; \ if (!X##_s) \
r = ~r; \
} \
FP_SET_EXCEPTION(FP_EX_INVALID); \
} \ else \
{ \ if (_FP_W_TYPE_SIZE*wc < rsize) \
{ \
_FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
r <<= X##_e - _FP_WFRACBITS_##fs; \
} \ else \
{ \ if (X##_e >= _FP_WFRACBITS_##fs) \
_FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1)); \ elseif (X##_e < _FP_WFRACBITS_##fs - 1) \
{ \
_FP_FRAC_SRS_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 2), \
_FP_WFRACBITS_##fs); \ if (_FP_FRAC_LOW_##wc(X) & 1) \
FP_SET_EXCEPTION(FP_EX_INEXACT); \
_FP_FRAC_SRL_##wc(X, 1); \
} \
_FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
} \ if (rsigned && X##_s) \
r = -r; \
} \ break; \
} \
} while (0)
#define _FP_TO_INT_ROUND(fs, wc, r, X, rsize, rsigned) \ do { \
r = 0; \ switch (X##_c) \
{ \ case FP_CLS_NORMAL: \ if (X##_e >= _FP_FRACBITS_##fs - 1) \
{ \ if (X##_e < rsize - 1 + _FP_WFRACBITS_##fs) \
{ \ if (X##_e >= _FP_WFRACBITS_##fs - 1) \
{ \
_FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
r <<= X##_e - _FP_WFRACBITS_##fs + 1; \
} \ else \
{ \
_FP_FRAC_SRL_##wc(X, _FP_WORKBITS - X##_e \
+ _FP_FRACBITS_##fs - 1); \
_FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
} \
} \
} \ else \
{ \ int _lz0, _lz1; \ if (X##_e <= -_FP_WORKBITS - 1) \
_FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \ else \
_FP_FRAC_SRS_##wc(X, _FP_FRACBITS_##fs - 1 - X##_e, \
_FP_WFRACBITS_##fs); \
_FP_FRAC_CLZ_##wc(_lz0, X); \
_FP_ROUND(wc, X); \
_FP_FRAC_CLZ_##wc(_lz1, X); \ if (_lz1 < _lz0) \
X##_e++; /* For overflow detection. */ \
_FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \
_FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
} \ if (rsigned && X##_s) \
r = -r; \ if (X##_e >= rsize - (rsigned > 0 || X##_s) \
|| (!rsigned && X##_s)) \
{ /* overflow */ \
fallthrough; \ case FP_CLS_NAN: \ case FP_CLS_INF: \ if (!rsigned) \
{ \
r = 0; \ if (!X##_s) \
r = ~r; \
} \ elseif (rsigned != 2) \
{ \
r = 1; \
r <<= rsize - 1; \
r -= 1 - X##_s; \
} \
FP_SET_EXCEPTION(FP_EX_INVALID); \
} \ break; \ case FP_CLS_ZERO: \ break; \
} \
} while (0)
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.