#!/usr/bin/env python3 # genFpTables.py - expected-value tables for the soft-float smoke checks in # scripts/smokeTest.sh ("float/double compares" and "float/double NaN and # infinity"). Paste the output over the matching table in smokeTest.sh. # # python3 tests/fpNan/genFpTables.py cmp # kFBits / kDBits / kExp # python3 tests/fpNan/genFpTables.py special # kCases # # Comparisons come from Python's own float compares, which are IEEE 754 # (every ordered compare with a NaN is false). Float operands are widened # to double exactly, so float and double share one truth table per value. # # The special-value table is a model of the documented runtime rules, not # of the host FPU: a NaN operand comes back quieted with its payload kept # (the first NaN operand when both are), an invalid operation gives the # default NaN 0x7FC00000 / 0x7FF8000000000000 (x86 would give the negative # one), and float/double to integer saturates with NaN converting to 0. # Finite cases use operands whose results are exact, because softFloat.c # truncates instead of rounding. # # The math.c cases follow C99 Annex F's special values (modelled here where # Python raises instead of answering). The series-based functions (exp, # pow with a non-integer exponent, sinh, cbrt, ...) are only ~1e-6 # accurate, so their ordinary-value cases carry an `approx` flag: the check # accepts a result within 1e-6 relative of the host's value. import math import struct import sys from fractions import Fraction F_QUIET = 0x00400000 D_QUIET = 0x0008000000000000 F_DNAN = 0x7FC00000 D_DNAN = 0x7FF8000000000000 F_INF = 0x7F800000 D_INF = 0x7FF0000000000000 F_SIGN = 0x80000000 D_SIGN = 0x8000000000000000 # The compare operand set: signed infinities and zeros, normals of both # signs, a quiet NaN, a negative quiet NaN and a signaling-pattern NaN. CMP_F = [0xFF800000, 0xC0200000, 0xBF800000, 0x80000000, 0x00000000, 0x3F800000, 0x41200000, 0x7149F2CA, 0x7F800000, 0x7FC00000, 0xFFC00000, 0x7F800001] # The same values as doubles (1e30f widened exactly, so both tables share # one truth table). CMP_D = [0xFFF0000000000000, 0xC004000000000000, 0xBFF0000000000000, 0x8000000000000000, 0x0000000000000000, 0x3FF0000000000000, 0x4024000000000000, 0x46293E5940000000, 0x7FF0000000000000, 0x7FF8000000000000, 0xFFF8000000000000, 0x7FF0000000000001] # Predicate order matches ALL() in the check: the six C operators, their # negations (the unordered LLVM predicates uge/ugt/ule/ult), then the C99 # isunordered / !isunordered / islessgreater / !islessgreater. PREDS = [ lambda a, b: a < b, lambda a, b: a <= b, lambda a, b: a > b, lambda a, b: a >= b, lambda a, b: a == b, lambda a, b: a != b, lambda a, b: not (a < b), lambda a, b: not (a <= b), lambda a, b: not (a > b), lambda a, b: not (a >= b), lambda a, b: math.isnan(a) or math.isnan(b), lambda a, b: not (math.isnan(a) or math.isnan(b)), lambda a, b: a < b or a > b, lambda a, b: not (a < b or a > b), ] def fval(bits): return struct.unpack('> 23) & 0xFF m = b & 0x7FFFFF if e == 0: return 'zero' if e == 0xFF: return 'inf' if m == 0 else 'nan' return 'normal' def dclass(b): e = (b >> 52) & 0x7FF m = b & 0xFFFFFFFFFFFFF if e == 0: return 'zero' if e == 0x7FF: return 'inf' if m == 0 else 'nan' return 'normal' def binop(isD, op, a, b): cls = dclass if isD else fclass quiet, dnan, inf, sign = ((D_QUIET, D_DNAN, D_INF, D_SIGN) if isD else (F_QUIET, F_DNAN, F_INF, F_SIGN)) val, tobits = (dval, dbits) if isD else (fval, fbits) if op == 'sub': # __subXf3(a, b) is __addXf3(a, b with its sign flipped), as in # compiler-rt, so a NaN b comes back with its sign flipped too. b ^= sign op = 'add' ca, cb = cls(a), cls(b) if ca == 'nan': return a | quiet if cb == 'nan': return b | quiet s = (a ^ b) & sign if op == 'add': if ca == 'inf': return dnan if cb == 'inf' and s else a if cb == 'inf': return b if ca == 'zero' and cb == 'zero': return a & b & sign elif op == 'mul': if ca == 'inf' or cb == 'inf': return dnan if 'zero' in (ca, cb) else s | inf if ca == 'zero' or cb == 'zero': return s elif op == 'div': if ca == 'inf': return dnan if cb == 'inf' else s | inf if cb == 'inf': return s if cb == 'zero': return dnan if ca == 'zero' else s | inf if ca == 'zero': return s x, y = val(a), val(b) if op == 'add': r = x + y elif op == 'mul': r = x * y else: r = x / y if not isD and abs(r) > 3.4028234663852886e38: r = math.copysign(math.inf, r) got = tobits(r) assert val(got) == r or math.isinf(r), (op, hex(a), hex(b), r) return got def f2d(a): if fclass(a) == 'nan': return ((a & F_SIGN) << 32) | D_INF | ((a & 0x7FFFFF) << 29) | D_QUIET return dbits(fval(a)) def d2f(a): if dclass(a) == 'nan': return ((a >> 32) & F_SIGN) | F_DNAN | (((a & 0xFFFFFFFFFFFFF) >> 29) & 0x7FFFFF) v = dval(a) if abs(v) > 3.4028234663852886e38: return fbits(math.copysign(math.inf, v)) got = fbits(v) assert fval(got) == v return got def toInt(v, unsigned): if math.isnan(v): return 0 lo, hi = (0, 0xFFFFFFFF) if unsigned else (-0x80000000, 0x7FFFFFFF) if math.isinf(v): r = hi if v > 0 else lo else: r = max(lo, min(hi, int(v))) return r & 0xFFFFFFFF def classify(v, bitsSign): nan = 1 if math.isnan(v) else 0 inf = 1 if math.isinf(v) else 0 fin = 1 if not (nan or inf) else 0 cls = 0 if nan else 1 if inf else 4 if v == 0 else 2 return nan | (inf << 1) | (fin << 2) | (bitsSign << 3) | (cls << 4) # Operation codes, matching the switch in the check's run(). OPS = ['fadd', 'fsub', 'fmul', 'fdiv', 'dadd', 'dsub', 'dmul', 'ddiv', 'f2d', 'd2f', 'f2i', 'f2u', 'd2i', 'd2u', 'fcls', 'dcls', 'sqrt', 'log', 'asin', 'acos', 'atanh', 'floor', 'ceil', 'trunc', 'round', 'rint', 'nearbyint', 'floorf', 'ceilf', 'truncf', 'roundf', 'rintf', 'exp', 'exp2', 'expm1', 'sinh', 'cosh', 'tanh', 'log1p', 'cbrt', 'pow', 'fmod', 'fdim', 'hypot', 'remainder', 'nearbyintf', 'fmaxf', 'fminf'] FQ = 0x7FC00123 # quiet NaN with a payload FS = 0x7F800005 # signaling-pattern NaN FNQ = 0xFFC00000 # negative quiet NaN DQ = 0x7FF8000000000123 DS = 0x7FF0000000000005 DNQ = 0xFFF8000000000000 F1, FM1, F15, F2, F225, FM2, F3E38 = (fbits(1.0), fbits(-1.0), fbits(1.5), fbits(2.0), fbits(2.25), fbits(-2.0), fbits(3e38)) D1, DM1, D15, D2, D225, DM2, D1E300 = (dbits(1.0), dbits(-1.0), dbits(1.5), dbits(2.0), dbits(2.25), dbits(-2.0), dbits(1e300)) FZ, FNZ, FI, FNI = 0, F_SIGN, F_INF, F_INF | F_SIGN DZ, DNZ, DI, DNI = 0, D_SIGN, D_INF, D_INF | D_SIGN def fpairs(): return [(FQ, F1), (F1, FS), (FS, FQ), (FNQ, F2), (FZ, FQ), (FI, F1), (FI, FI), (FI, FNI), (FNI, F2), (F2, FNI), (F1, FM1), (FM1, F1), (FNZ, FNZ), (FNZ, FZ), (FZ, FNZ), (FZ, FZ), (F225, F15), (F3E38, F3E38), (FZ, FI), (FI, FZ), (FNI, FM2), (FNI, FNI), (FNZ, F2), (FZ, FZ), (F1, FZ), (FM1, FZ), (F1, FNZ), (F1, FI), (FM1, FI), (FI, F2), (F15, F2)] def dpairs(): return [(DQ, D1), (D1, DS), (DS, DQ), (DNQ, D2), (DZ, DQ), (DI, D1), (DI, DI), (DI, DNI), (DNI, D2), (D2, DNI), (D1, DM1), (DM1, D1), (DNZ, DNZ), (DNZ, DZ), (DZ, DNZ), (DZ, DZ), (D225, D15), (D1E300, D1E300), (DZ, DI), (DI, DZ), (DNI, DM2), (DNI, DNI), (DNZ, D2), (DZ, DZ), (D1, DZ), (DM1, DZ), (D1, DNZ), (D1, DI), (DM1, DI), (DI, D2), (D15, D2)] def emitSpecial(): cases = [] for isD, prefix, pairs in ((False, 'f', fpairs()), (True, 'd', dpairs())): for op in ('add', 'sub', 'mul', 'div'): for a, b in pairs: cases.append((OPS.index(prefix + op), a, b, binop(isD, op, a, b))) for a in (FQ, FS, 0xFFC00001, FI, FNI, FNZ, FZ, F15, FM2): cases.append((OPS.index('f2d'), a, 0, f2d(a))) for a in (DQ, 0xFFF8000020000000, DS, DI, DNI, DNZ, DZ, D15, DM2, D1E300, dbits(-1e300)): cases.append((OPS.index('d2f'), a, 0, d2f(a))) fconv = (FQ, FNQ, FS, FI, FNI, fbits(3e9), fbits(-3e9), fbits(5e9), fbits(-2.5), fbits(3.5), FM1, FNZ) dconv = (DQ, DNQ, DS, DI, DNI, dbits(3e9), dbits(-3e9), dbits(5e9), dbits(-2.5), dbits(3.5), DM1, DNZ) for a in fconv: cases.append((OPS.index('f2i'), a, 0, toInt(fval(a), False))) cases.append((OPS.index('f2u'), a, 0, toInt(fval(a), True))) for a in dconv: cases.append((OPS.index('d2i'), a, 0, toInt(dval(a), False))) cases.append((OPS.index('d2u'), a, 0, toInt(dval(a), True))) for a in (FQ, FNQ, FS, FI, FNI, FZ, FNZ, F15, FM2): cases.append((OPS.index('fcls'), a, 0, classify(fval(a), a >> 31))) for a in (DQ, DNQ, DS, DI, DNI, DZ, DNZ, D15, DM2): cases.append((OPS.index('dcls'), a, 0, classify(dval(a), a >> 63))) # math.c's domain edges. The check folds every NaN result to the # default NaN, because how a NaN travels through a series (and so its # sign) is not part of these functions' contract. halfPi = dbits(math.pi / 2) mathCases = [ ('sqrt', dbits(-1.0), D_DNAN), ('sqrt', DI, DI), ('sqrt', DNI, D_DNAN), ('sqrt', DQ, D_DNAN), ('sqrt', dbits(4.0), dbits(2.0)), ('sqrt', DNZ, DNZ), ('log', DI, DI), ('log', DNI, D_DNAN), ('log', DQ, D_DNAN), ('log', DM1, D_DNAN), ('log', DZ, DNI), ('log', D1, DZ), ('asin', D2, D_DNAN), ('asin', DM2, D_DNAN), ('asin', D1, halfPi), ('asin', DM1, halfPi | D_SIGN), ('asin', DQ, D_DNAN), ('acos', D2, D_DNAN), ('acos', D1, DZ), ('atanh', D2, D_DNAN), ('atanh', DM2, D_DNAN), ('atanh', D1, DI), ('atanh', DM1, DNI), ('atanh', DQ, D_DNAN), ] cases = [c + (0,) for c in cases] for name, a, want in mathCases: cases.append((OPS.index(name), a, 0, want, 0)) # Two tables, one per build of the check: both together (with the math # functions they pull in) overflow a bank-0 test binary. for part, table in ((1, cases), (2, annexFCases())): print('#if FP_TABLE == 1' if part == 1 else '#else') print('#define NC %d' % len(table)) print('static const CaseT kCases[NC] = {') for op, a, b, want, approx in table: print(' { %-12s 0x%016XULL, 0x%016XULL, 0x%016XULL, %d },' % ('O_' + OPS[op].upper() + ',', a, b, want, approx)) print('};') print('#endif') # ---- math.c Annex F cases ---------------------------------------------- INF = math.inf NAN = math.nan def signedZero(r, x): # An integral result of zero keeps x's sign (floor(-0.0) is -0.0, # ceil(-0.5) is -0.0). return math.copysign(0.0, x) if r == 0 else r def cfloor(x): return x if not math.isfinite(x) else signedZero(float(math.floor(x)), x) def cceil(x): return x if not math.isfinite(x) else signedZero(float(math.ceil(x)), x) def ctrunc(x): return x if not math.isfinite(x) else signedZero(float(math.trunc(x)), x) def cround(x): # C round: half away from zero, computed exactly. if not math.isfinite(x): return x r = float(math.floor(Fraction(abs(x)) + Fraction(1, 2))) return math.copysign(r, x) def crint(x): # Round to nearest, ties to even (Python's round() on a float is exact). if not math.isfinite(x): return x return math.copysign(float(round(x)), x) def guard(f, *args): # Python raises where C returns: a domain error is NaN, an overflow is # an infinity of the true result's sign. try: return f(*args) except ValueError: return NAN except OverflowError: return INF def isOddInt(y): return math.isfinite(y) and y == math.floor(y) and abs(y) < 2.0 ** 53 and int(y) % 2 == 1 def cpow(x, y): # C99 F.9.4.4. if y == 0 or x == 1.0: return 1.0 if math.isnan(x) or math.isnan(y): return NAN if math.isinf(y): if abs(x) == 1: return 1.0 return INF if (abs(x) > 1) == (y > 0) else 0.0 if x == 0: r = INF if y < 0 else 0.0 return math.copysign(r, x) if isOddInt(y) else r if math.isinf(x): r = INF if y > 0 else 0.0 return -r if (x < 0 and isOddInt(y)) else r if x < 0 and y != math.floor(y): return NAN r = guard(math.pow, x, y) # guard() cannot know an overflow's sign: a negative x to an odd power. return -r if (math.isinf(r) and x < 0 and isOddInt(y)) else r def cfmod(x, y): # C99 F.9.7.1. if math.isnan(x) or math.isnan(y) or math.isinf(x) or y == 0: return NAN if math.isinf(y): return x return math.fmod(x, y) def cfdim(x, y): if math.isnan(x) or math.isnan(y): return NAN return x - y if x > y else 0.0 def cremainder(x, y): # C99 F.9.7.2 (Python's math.remainder raises for the NaN cases). if math.isnan(x) or math.isnan(y) or math.isinf(x) or y == 0: return NAN return math.remainder(x, y) def ccbrt(x): if not math.isfinite(x) or x == 0: return x return math.copysign(abs(x) ** (1.0 / 3.0), x) def fround32(v): return fval(fbits(v)) MATH1 = { 'floor': cfloor, 'ceil': cceil, 'trunc': ctrunc, 'round': cround, 'rint': crint, 'nearbyint': crint, 'exp': lambda x: guard(math.exp, x), 'exp2': lambda x: guard(math.pow, 2.0, x), 'expm1': lambda x: guard(math.expm1, x), 'sinh': lambda x: guard(math.sinh, x) if not (math.isinf(x) or abs(x) > 700) else math.copysign(INF, x), 'cosh': lambda x: guard(math.cosh, x), 'tanh': math.tanh, 'log1p': lambda x: -INF if x == -1 else guard(math.log1p, x), 'cbrt': ccbrt, } MATH2 = {'pow': cpow, 'fmod': cfmod, 'fdim': cfdim, 'hypot': math.hypot, 'remainder': cremainder} FLOATOPS = {'floorf': cfloor, 'ceilf': cceil, 'truncf': ctrunc, 'roundf': cround, 'rintf': crint, 'nearbyintf': crint} def cfmax(x, y): # C99 F.9.9.2: a NaN operand is ignored in favour of the other. if math.isnan(x): return y if math.isnan(y): return x return max(x, y) def cfmin(x, y): if math.isnan(x): return y if math.isnan(y): return x return min(x, y) FLOAT2 = {'fmaxf': cfmax, 'fminf': cfmin} # (op, x[, y], approx). Every function gets its special values and a few # ordinary ones, so a normal-path regression shows too. MATH_CASES = [ ('floor', 2.7, 0), ('floor', -2.7, 0), ('floor', -0.0, 0), ('floor', 0.0, 0), ('floor', -0.3, 0), ('floor', 0.3, 0), ('floor', INF, 0), ('floor', -INF, 0), ('floor', NAN, 0), ('floor', 1e300, 0), ('floor', -0.5, 0), ('ceil', 2.3, 0), ('ceil', -2.3, 0), ('ceil', 0.0, 0), ('ceil', -0.0, 0), ('ceil', -0.5, 0), ('ceil', 0.5, 0), ('ceil', INF, 0), ('ceil', NAN, 0), ('trunc', -2.7, 0), ('trunc', 2.7, 0), ('trunc', -0.5, 0), ('trunc', -0.0, 0), ('trunc', INF, 0), ('round', 2.5, 0), ('round', -2.5, 0), ('round', 0.49999999999999994, 0), ('round', -0.49999999999999994, 0), ('round', 4503599627370497.0, 0), ('round', -0.0, 0), ('round', 0.5, 0), ('round', 1.5, 0), ('round', INF, 0), ('round', NAN, 0), ('round', -0.4, 0), ('rint', 2.5, 0), ('rint', 3.5, 0), ('rint', -2.5, 0), ('rint', -0.3, 0), ('rint', 0.3, 0), ('rint', 1.5, 0), ('rint', 4503599627370497.0, 0), ('rint', INF, 0), ('rint', NAN, 0), ('rint', -0.0, 0), ('nearbyint', 2.5, 0), ('nearbyint', -3.5, 0), ('floorf', -0.0, 0), ('floorf', 2.75, 0), ('floorf', -2.75, 0), ('ceilf', 0.0, 0), ('ceilf', -0.5, 0), ('truncf', -2.5, 0), ('roundf', 2.5, 0), ('roundf', -0.0, 0), ('rintf', 2.5, 0), ('rintf', 3.5, 0), ('rintf', -0.25, 0), ('nearbyintf', 2.5, 0), ('nearbyintf', -1.5, 0), ('fmaxf', 1.0, NAN, 0), ('fmaxf', NAN, -2.0, 0), ('fmaxf', -0.5, 2.0, 0), ('fminf', 1.0, NAN, 0), ('fminf', -0.5, 2.0, 0), ('fminf', 3.0, -INF, 0), ('exp', NAN, 0), ('exp', INF, 0), ('exp', -INF, 0), ('exp', 1e5, 0), ('exp', -1e5, 0), ('exp', 1024.0, 0), ('exp', -1024.0, 0), ('exp', 800.0, 0), ('exp', -800.0, 0), ('exp', 0.0, 0), ('exp', -0.0, 0), ('exp', 1.5, 1), ('exp', -2.0, 1), ('exp2', 3.0, 1), ('exp2', NAN, 0), ('exp2', INF, 0), ('exp2', -INF, 0), ('expm1', -INF, 0), ('expm1', INF, 0), ('expm1', NAN, 0), ('expm1', -0.0, 0), ('expm1', 0.5, 1), ('sinh', INF, 0), ('sinh', -INF, 0), ('sinh', NAN, 0), ('sinh', -0.0, 0), ('sinh', 800.0, 0), ('sinh', -800.0, 0), ('sinh', 1.0, 1), ('sinh', -1.0, 1), ('cosh', INF, 0), ('cosh', -INF, 0), ('cosh', NAN, 0), ('cosh', 0.0, 0), ('cosh', 1.0, 1), ('tanh', INF, 0), ('tanh', -INF, 0), ('tanh', NAN, 0), ('tanh', -0.0, 0), ('tanh', 40.0, 0), ('tanh', -40.0, 0), ('tanh', 400.0, 0), ('tanh', 0.5, 1), ('tanh', -0.5, 1), ('log1p', -0.0, 0), ('log1p', 0.0, 0), ('log1p', -1.0, 0), ('log1p', INF, 0), ('log1p', NAN, 0), ('log1p', 1.0, 1), ('cbrt', INF, 0), ('cbrt', -INF, 0), ('cbrt', NAN, 0), ('cbrt', -0.0, 0), ('cbrt', 27.0, 1), ('pow', NAN, 0.0, 0), ('pow', NAN, -0.0, 0), ('pow', 1.0, NAN, 0), ('pow', 1.0, INF, 0), ('pow', -1.0, INF, 0), ('pow', -1.0, -INF, 0), ('pow', 2.0, NAN, 0), ('pow', NAN, 2.0, 0), ('pow', 0.0, -3.0, 0), ('pow', -0.0, -3.0, 0), ('pow', -0.0, -2.0, 0), ('pow', -0.0, -INF, 0), ('pow', 0.0, -0.5, 0), ('pow', -0.0, 3.0, 0), ('pow', -0.0, 2.0, 0), ('pow', 0.0, 0.5, 0), ('pow', 0.5, -INF, 0), ('pow', 2.0, -INF, 0), ('pow', 0.5, INF, 0), ('pow', 2.0, INF, 0), ('pow', -INF, -3.0, 0), ('pow', -INF, -2.0, 0), ('pow', -INF, 3.0, 0), ('pow', -INF, 2.0, 0), ('pow', -INF, 0.5, 0), ('pow', INF, -1.0, 0), ('pow', INF, 2.0, 0), ('pow', -8.0, 1.0 / 3.0, 0), ('pow', -2.0, 0.5, 0), ('pow', 2.0, 10.0, 0), ('pow', 2.0, -3.0, 0), ('pow', -2.0, 3.0, 0), ('pow', -2.0, 2.0, 0), ('pow', 10.0, 20.0, 0), ('pow', -2.0, 1e20, 0), ('pow', -2.0, 40001.0, 0), ('pow', 2.0, 0.5, 1), ('pow', 2.0, 1.5, 1), ('pow', 10.0, 0.3, 1), ('pow', 1.0000001, 100000.0, 1), ('fmod', 7.5, 2.0, 0), ('fmod', -7.5, 2.0, 0), ('fmod', -4.0, 2.0, 0), ('fmod', 4.0, 2.0, 0), ('fmod', 5.0, 3.0, 0), ('fmod', 1.0, INF, 0), ('fmod', -1.0, -INF, 0), ('fmod', 1.0, 0.0, 0), ('fmod', 1.0, -0.0, 0), ('fmod', INF, 2.0, 0), ('fmod', -INF, 2.0, 0), ('fmod', NAN, 2.0, 0), ('fmod', 2.0, NAN, 0), ('fmod', 0.0, 5.0, 0), ('fmod', -0.0, 5.0, 0), ('fmod', 0.0, 0.0, 0), ('fmod', INF, INF, 0), ('fdim', NAN, 1.0, 0), ('fdim', 1.0, NAN, 0), ('fdim', 5.0, 3.0, 0), ('fdim', 3.0, 5.0, 0), ('fdim', INF, 1.0, 0), ('fdim', 1.0, INF, 0), ('fdim', INF, INF, 0), ('hypot', INF, NAN, 0), ('hypot', NAN, -INF, 0), ('hypot', -INF, 1.0, 0), ('hypot', NAN, 1.0, 0), ('hypot', 3.0, 4.0, 1), ('hypot', 0.0, 0.0, 0), ('remainder', 5.0, 2.0, 0), ('remainder', 7.0, 2.0, 0), ('remainder', 7.0, 4.0, 0), ('remainder', 1.0, INF, 0), ('remainder', -3.0, -INF, 0), ('remainder', 1.0, 0.0, 0), ('remainder', INF, 2.0, 0), ('remainder', NAN, 1.0, 0), ] def nanFold(bits, isF): # The check folds every NaN a math function returns to the default NaN. v = fval(bits) if isF else dval(bits) if math.isnan(v): return F_DNAN if isF else D_DNAN return bits def annexFCases(): out = [] for c in MATH_CASES: name = c[0] if name in FLOAT2: x, y, approx = fround32(c[1]), fround32(c[2]), c[3] want = fround32(FLOAT2[name](x, y)) out.append((OPS.index(name), fbits(x), fbits(y), nanFold(fbits(want), True), approx)) continue if name in MATH2: x, y, approx = c[1], c[2], c[3] want = MATH2[name](x, y) a, b = dbits(x), dbits(y) else: x, approx = c[1], c[2] y = 0.0 if name in FLOATOPS: x = fround32(x) want = fround32(FLOATOPS[name](x)) out.append((OPS.index(name), fbits(x), 0, nanFold(fbits(want), True), approx)) continue want = MATH1[name](x) a, b = dbits(x), 0 out.append((OPS.index(name), a, b, nanFold(dbits(want), False), approx)) return out if __name__ == '__main__': if len(sys.argv) != 2 or sys.argv[1] not in ('cmp', 'special'): sys.exit('usage: genFpTables.py cmp|special') emitCmp() if sys.argv[1] == 'cmp' else emitSpecial()