go.starlark.net@v0.0.0-20231101134539-556fd59b42f6/starlark/testdata/float.star (about)

     1  # Tests of Starlark 'float'
     2  # option:set
     3  
     4  load("assert.star", "assert")
     5  
     6  # TODO(adonovan): more tests:
     7  # - precision
     8  # - limits
     9  
    10  # type
    11  assert.eq(type(0.0), "float")
    12  
    13  # truth
    14  assert.true(123.0)
    15  assert.true(-1.0)
    16  assert.true(not 0.0)
    17  assert.true(-1.0e-45)
    18  assert.true(float("NaN"))
    19  
    20  # not iterable
    21  assert.fails(lambda: len(0.0), 'has no len')
    22  assert.fails(lambda: [x for x in 0.0], 'float value is not iterable')
    23  
    24  # literals
    25  assert.eq(type(1.234), "float")
    26  assert.eq(type(1e10), "float")
    27  assert.eq(type(1e+10), "float")
    28  assert.eq(type(1e-10), "float")
    29  assert.eq(type(1.234e10), "float")
    30  assert.eq(type(1.234e+10), "float")
    31  assert.eq(type(1.234e-10), "float")
    32  
    33  # int/float equality
    34  assert.eq(0.0, 0)
    35  assert.eq(0, 0.0)
    36  assert.eq(1.0, 1)
    37  assert.eq(1, 1.0)
    38  assert.true(1.23e45 != 1229999999999999973814869011019624571608236031)
    39  assert.true(1.23e45 == 1229999999999999973814869011019624571608236032)
    40  assert.true(1.23e45 != 1229999999999999973814869011019624571608236033)
    41  assert.true(1229999999999999973814869011019624571608236031 != 1.23e45)
    42  assert.true(1229999999999999973814869011019624571608236032 == 1.23e45)
    43  assert.true(1229999999999999973814869011019624571608236033 != 1.23e45)
    44  
    45  # loss of precision
    46  p53 = 1<<53
    47  assert.eq(float(p53-1), p53-1)
    48  assert.eq(float(p53+0), p53+0)
    49  assert.eq(float(p53+1), p53+0) #
    50  assert.eq(float(p53+2), p53+2)
    51  assert.eq(float(p53+3), p53+4) #
    52  assert.eq(float(p53+4), p53+4)
    53  assert.eq(float(p53+5), p53+4) #
    54  assert.eq(float(p53+6), p53+6)
    55  assert.eq(float(p53+7), p53+8) #
    56  assert.eq(float(p53+8), p53+8)
    57  
    58  # Regression test for https://github.com/google/starlark-go/issues/375.
    59  maxint64 = (1<<63)-1
    60  assert.eq(int(float(maxint64)), 9223372036854775808)
    61  
    62  assert.true(float(p53+1) != p53+1) # comparisons are exact
    63  assert.eq(float(p53+1) - (p53+1), 0) # arithmetic entails rounding
    64  
    65  assert.fails(lambda: {123.0: "f", 123: "i"}, "duplicate key: 123")
    66  
    67  # equal int/float values have same hash
    68  d = {123.0: "x"}
    69  d[123] = "y"
    70  assert.eq(len(d), 1)
    71  assert.eq(d[123.0], "y")
    72  
    73  # literals (mostly covered by scanner tests)
    74  assert.eq(str(0.), "0.0")
    75  assert.eq(str(.0), "0.0")
    76  assert.true(5.0 != 4.999999999999999)
    77  assert.eq(5.0, 4.9999999999999999) # both literals denote 5.0
    78  assert.eq(1.23e45, 1.23 * 1000000000000000000000000000000000000000000000)
    79  assert.eq(str(1.23e-45 - (1.23 / 1000000000000000000000000000000000000000000000)), "-1.5557538194652854e-61")
    80  
    81  nan = float("NaN")
    82  inf = float("+Inf")
    83  neginf = float("-Inf")
    84  negzero = (-1e-323 / 10)
    85  
    86  # -- arithmetic --
    87  
    88  # +float, -float
    89  assert.eq(+(123.0), 123.0)
    90  assert.eq(-(123.0), -123.0)
    91  assert.eq(-(-(123.0)), 123.0)
    92  assert.eq(+(inf), inf)
    93  assert.eq(-(inf), neginf)
    94  assert.eq(-(neginf), inf)
    95  assert.eq(str(-(nan)), "nan")
    96  # +
    97  assert.eq(1.2e3 + 5.6e7, 5.60012e+07)
    98  assert.eq(1.2e3 + 1, 1201)
    99  assert.eq(1 + 1.2e3, 1201)
   100  assert.eq(str(1.2e3 + nan), "nan")
   101  assert.eq(inf + 0, inf)
   102  assert.eq(inf + 1, inf)
   103  assert.eq(inf + inf, inf)
   104  assert.eq(str(inf + neginf), "nan")
   105  # -
   106  assert.eq(1.2e3 - 5.6e7, -5.59988e+07)
   107  assert.eq(1.2e3 - 1, 1199)
   108  assert.eq(1 - 1.2e3, -1199)
   109  assert.eq(str(1.2e3 - nan), "nan")
   110  assert.eq(inf - 0, inf)
   111  assert.eq(inf - 1, inf)
   112  assert.eq(str(inf - inf), "nan")
   113  assert.eq(inf - neginf, inf)
   114  # *
   115  assert.eq(1.5e6 * 2.2e3, 3.3e9)
   116  assert.eq(1.5e6 * 123, 1.845e+08)
   117  assert.eq(123 * 1.5e6, 1.845e+08)
   118  assert.eq(str(1.2e3 * nan), "nan")
   119  assert.eq(str(inf * 0), "nan")
   120  assert.eq(inf * 1, inf)
   121  assert.eq(inf * inf, inf)
   122  assert.eq(inf * neginf, neginf)
   123  # %
   124  assert.eq(100.0 % 7.0, 2)
   125  assert.eq(100.0 % -7.0, -5) # NB: different from Go / Java
   126  assert.eq(-100.0 % 7.0, 5) # NB: different from Go / Java
   127  assert.eq(-100.0 % -7.0, -2)
   128  assert.eq(-100.0 % 7, 5)
   129  assert.eq(100 % 7.0, 2)
   130  assert.eq(str(1.2e3 % nan), "nan")
   131  assert.eq(str(inf % 1), "nan")
   132  assert.eq(str(inf % inf), "nan")
   133  assert.eq(str(inf % neginf), "nan")
   134  # /
   135  assert.eq(str(100.0 / 7.0), "14.285714285714286")
   136  assert.eq(str(100 / 7.0), "14.285714285714286")
   137  assert.eq(str(100.0 / 7), "14.285714285714286")
   138  assert.eq(str(100.0 / nan), "nan")
   139  # //
   140  assert.eq(100.0 // 7.0, 14)
   141  assert.eq(100 // 7.0, 14)
   142  assert.eq(100.0 // 7, 14)
   143  assert.eq(100.0 // -7.0, -15)
   144  assert.eq(100 // -7.0, -15)
   145  assert.eq(100.0 // -7, -15)
   146  assert.eq(str(1 // neginf), "-0.0")
   147  assert.eq(str(100.0 // nan), "nan")
   148  
   149  # addition
   150  assert.eq(0.0 + 1.0, 1.0)
   151  assert.eq(1.0 + 1.0, 2.0)
   152  assert.eq(1.25 + 2.75, 4.0)
   153  assert.eq(5.0 + 7.0, 12.0)
   154  assert.eq(5.1 + 7, 12.1)  # float + int
   155  assert.eq(7 + 5.1, 12.1)  # int + float
   156  
   157  # subtraction
   158  assert.eq(5.0 - 7.0, -2.0)
   159  assert.eq(5.1 - 7.1, -2.0)
   160  assert.eq(5.5 - 7, -1.5)
   161  assert.eq(5 - 7.5, -2.5)
   162  assert.eq(0.0 - 1.0, -1.0)
   163  
   164  # multiplication
   165  assert.eq(5.0 * 7.0, 35.0)
   166  assert.eq(5.5 * 2.5, 13.75)
   167  assert.eq(5.5 * 7, 38.5)
   168  assert.eq(5 * 7.1, 35.5)
   169  
   170  # real division (like Python 3)
   171  # The / operator is available only when the 'fp' dialect option is enabled.
   172  assert.eq(100.0 / 8.0, 12.5)
   173  assert.eq(100.0 / -8.0, -12.5)
   174  assert.eq(-100.0 / 8.0, -12.5)
   175  assert.eq(-100.0 / -8.0, 12.5)
   176  assert.eq(98.0 / 8.0, 12.25)
   177  assert.eq(98.0 / -8.0, -12.25)
   178  assert.eq(-98.0 / 8.0, -12.25)
   179  assert.eq(-98.0 / -8.0, 12.25)
   180  assert.eq(2.5 / 2.0, 1.25)
   181  assert.eq(2.5 / 2, 1.25)
   182  assert.eq(5 / 4.0, 1.25)
   183  assert.eq(5 / 4, 1.25)
   184  assert.fails(lambda: 1.0 / 0, "floating-point division by zero")
   185  assert.fails(lambda: 1.0 / 0.0, "floating-point division by zero")
   186  assert.fails(lambda: 1 / 0.0, "floating-point division by zero")
   187  
   188  # floored division
   189  assert.eq(100.0 // 8.0, 12.0)
   190  assert.eq(100.0 // -8.0, -13.0)
   191  assert.eq(-100.0 // 8.0, -13.0)
   192  assert.eq(-100.0 // -8.0, 12.0)
   193  assert.eq(98.0 // 8.0, 12.0)
   194  assert.eq(98.0 // -8.0, -13.0)
   195  assert.eq(-98.0 // 8.0, -13.0)
   196  assert.eq(-98.0 // -8.0, 12.0)
   197  assert.eq(2.5 // 2.0, 1.0)
   198  assert.eq(2.5 // 2, 1.0)
   199  assert.eq(5 // 4.0, 1.0)
   200  assert.eq(5 // 4, 1)
   201  assert.eq(type(5 // 4), "int")
   202  assert.fails(lambda: 1.0 // 0, "floored division by zero")
   203  assert.fails(lambda: 1.0 // 0.0, "floored division by zero")
   204  assert.fails(lambda: 1 // 0.0, "floored division by zero")
   205  
   206  # remainder
   207  assert.eq(100.0 % 8.0, 4.0)
   208  assert.eq(100.0 % -8.0, -4.0)
   209  assert.eq(-100.0 % 8.0, 4.0)
   210  assert.eq(-100.0 % -8.0, -4.0)
   211  assert.eq(98.0 % 8.0, 2.0)
   212  assert.eq(98.0 % -8.0, -6.0)
   213  assert.eq(-98.0 % 8.0, 6.0)
   214  assert.eq(-98.0 % -8.0, -2.0)
   215  assert.eq(2.5 % 2.0, 0.5)
   216  assert.eq(2.5 % 2, 0.5)
   217  assert.eq(5 % 4.0, 1.0)
   218  assert.fails(lambda: 1.0 % 0, "floating-point modulo by zero")
   219  assert.fails(lambda: 1.0 % 0.0, "floating-point modulo by zero")
   220  assert.fails(lambda: 1 % 0.0, "floating-point modulo by zero")
   221  
   222  # floats cannot be used as indices, even if integral
   223  assert.fails(lambda: "abc"[1.0], "want int")
   224  assert.fails(lambda: ["A", "B", "C"].insert(1.0, "D"), "want int")
   225  assert.fails(lambda: range(3)[1.0], "got float, want int")
   226  
   227  # -- comparisons --
   228  # NaN
   229  assert.true(nan == nan) # \
   230  assert.true(nan >= nan) #  unlike Python
   231  assert.true(nan <= nan) # /
   232  assert.true(not (nan > nan))
   233  assert.true(not (nan < nan))
   234  assert.true(not (nan != nan)) # unlike Python
   235  # Sort is stable: 0.0 and -0.0 are equal, but they are not permuted.
   236  # Similarly 1 and 1.0.
   237  assert.eq(
   238      str(sorted([inf, neginf, nan, 1e300, -1e300, 1.0, -1.0, 1, -1, 1e-300, -1e-300, 0, 0.0, negzero, 1e-300, -1e-300])),
   239      "[-inf, -1e+300, -1.0, -1, -1e-300, -1e-300, 0, 0.0, -0.0, 1e-300, 1e-300, 1.0, 1, 1e+300, +inf, nan]")
   240  
   241  # Sort is stable, and its result contains no adjacent x, y such that y > x.
   242  # Note: Python's reverse sort is unstable; see https://bugs.python.org/issue36095.
   243  assert.eq(str(sorted([7, 3, nan, 1, 9])), "[1, 3, 7, 9, nan]")
   244  assert.eq(str(sorted([7, 3, nan, 1, 9], reverse=True)), "[nan, 9, 7, 3, 1]")
   245  
   246  # All NaN values compare equal. (Identical objects compare equal.)
   247  nandict = {nan: 1}
   248  nandict[nan] = 2
   249  assert.eq(len(nandict), 1) # (same as Python)
   250  assert.eq(nandict[nan], 2) # (same as Python)
   251  assert.fails(lambda: {nan: 1, nan: 2}, "duplicate key: nan")
   252  
   253  nandict[float('nan')] = 3 # a distinct NaN object
   254  assert.eq(str(nandict), "{nan: 3}") # (Python: {nan: 2, nan: 3})
   255  
   256  assert.eq(str({inf: 1, neginf: 2}), "{+inf: 1, -inf: 2}")
   257  
   258  # zero
   259  assert.eq(0.0, negzero)
   260  
   261  # inf
   262  assert.eq(+inf / +inf, nan)
   263  assert.eq(+inf / -inf, nan)
   264  assert.eq(-inf / +inf, nan)
   265  assert.eq(0.0 / +inf, 0.0)
   266  assert.eq(0.0 / -inf, 0.0)
   267  assert.true(inf > -inf)
   268  assert.eq(inf, -neginf)
   269  # TODO(adonovan): assert inf > any finite number, etc.
   270  
   271  # negative zero
   272  negz = -0
   273  assert.eq(negz, 0)
   274  
   275  # min/max ordering with NaN (the greatest float value)
   276  assert.eq(max([1, nan, 3]), nan)
   277  assert.eq(max([nan, 2, 3]), nan)
   278  assert.eq(min([1, nan, 3]), 1)
   279  assert.eq(min([nan, 2, 3]), 2)
   280  
   281  # float/float comparisons
   282  fltmax = 1.7976931348623157e+308 # approx
   283  fltmin = 4.9406564584124654e-324 # approx
   284  assert.lt(-inf, -fltmax)
   285  assert.lt(-fltmax, -1.0)
   286  assert.lt(-1.0, -fltmin)
   287  assert.lt(-fltmin, 0.0)
   288  assert.lt(0, fltmin)
   289  assert.lt(fltmin, 1.0)
   290  assert.lt(1.0, fltmax)
   291  assert.lt(fltmax, inf)
   292  
   293  # int/float comparisons
   294  assert.eq(0, 0.0)
   295  assert.eq(1, 1.0)
   296  assert.eq(-1, -1.0)
   297  assert.ne(-1, -1.0 + 1e-7)
   298  assert.lt(-2, -2 + 1e-15)
   299  
   300  # int conversion (rounds towards zero)
   301  assert.eq(int(100.1), 100)
   302  assert.eq(int(100.0), 100)
   303  assert.eq(int(99.9), 99)
   304  assert.eq(int(-99.9), -99)
   305  assert.eq(int(-100.0), -100)
   306  assert.eq(int(-100.1), -100)
   307  assert.eq(int(1e100), int("10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104"))
   308  assert.fails(lambda: int(inf), "cannot convert.*infinity")
   309  assert.fails(lambda: int(nan), "cannot convert.*NaN")
   310  
   311  # -- float() function --
   312  assert.eq(float(), 0.0)
   313  # float(bool)
   314  assert.eq(float(False), 0.0)
   315  assert.eq(float(True), 1.0)
   316  # float(int)
   317  assert.eq(float(0), 0.0)
   318  assert.eq(float(1), 1.0)
   319  assert.eq(float(123), 123.0)
   320  assert.eq(float(123 * 1000000 * 1000000 * 1000000 * 1000000 * 1000000), 1.23e+32)
   321  # float(float)
   322  assert.eq(float(1.1), 1.1)
   323  assert.fails(lambda: float(None), "want number or string")
   324  assert.ne(False, 0.0) # differs from Python
   325  assert.ne(True, 1.0)
   326  # float(string)
   327  assert.eq(float("1.1"), 1.1)
   328  assert.fails(lambda: float("1.1abc"), "invalid float literal")
   329  assert.fails(lambda: float("1e100.0"), "invalid float literal")
   330  assert.fails(lambda: float("1e1000"), "floating-point number too large")
   331  assert.eq(float("-1.1"), -1.1)
   332  assert.eq(float("+1.1"), +1.1)
   333  assert.eq(float("+Inf"), inf)
   334  assert.eq(float("-Inf"), neginf)
   335  assert.eq(float("NaN"), nan)
   336  assert.eq(float("NaN"), nan)
   337  assert.eq(float("+NAN"), nan)
   338  assert.eq(float("-nan"), nan)
   339  assert.eq(str(float("Inf")), "+inf")
   340  assert.eq(str(float("+INF")), "+inf")
   341  assert.eq(str(float("-inf")), "-inf")
   342  assert.eq(str(float("+InFiniTy")), "+inf")
   343  assert.eq(str(float("-iNFiniTy")), "-inf")
   344  assert.fails(lambda: float("one point two"), "invalid float literal: one point two")
   345  assert.fails(lambda: float("1.2.3"), "invalid float literal: 1.2.3")
   346  assert.fails(lambda: float(123 << 500 << 500 << 50), "int too large to convert to float")
   347  assert.fails(lambda: float(-123 << 500 << 500 << 50), "int too large to convert to float")
   348  assert.fails(lambda: float(str(-123 << 500 << 500 << 50)), "floating-point number too large")
   349  
   350  # -- implicit float(int) conversions --
   351  assert.fails(lambda: (1<<500<<500<<500) + 0.0, "int too large to convert to float")
   352  assert.fails(lambda: 0.0 + (1<<500<<500<<500), "int too large to convert to float")
   353  assert.fails(lambda: (1<<500<<500<<500) - 0.0, "int too large to convert to float")
   354  assert.fails(lambda: 0.0 - (1<<500<<500<<500), "int too large to convert to float")
   355  assert.fails(lambda: (1<<500<<500<<500) * 1.0, "int too large to convert to float")
   356  assert.fails(lambda: 1.0 * (1<<500<<500<<500), "int too large to convert to float")
   357  assert.fails(lambda: (1<<500<<500<<500) / 1.0, "int too large to convert to float")
   358  assert.fails(lambda: 1.0 / (1<<500<<500<<500), "int too large to convert to float")
   359  assert.fails(lambda: (1<<500<<500<<500) // 1.0, "int too large to convert to float")
   360  assert.fails(lambda: 1.0 // (1<<500<<500<<500), "int too large to convert to float")
   361  assert.fails(lambda: (1<<500<<500<<500) % 1.0, "int too large to convert to float")
   362  assert.fails(lambda: 1.0 % (1<<500<<500<<500), "int too large to convert to float")
   363  
   364  
   365  # -- int function --
   366  assert.eq(int(0.0), 0)
   367  assert.eq(int(1.0), 1)
   368  assert.eq(int(1.1), 1)
   369  assert.eq(int(0.9), 0)
   370  assert.eq(int(-1.1), -1.0)
   371  assert.eq(int(-1.0), -1.0)
   372  assert.eq(int(-0.9), 0.0)
   373  assert.eq(int(1.23e+32), 123000000000000004979083645550592)
   374  assert.eq(int(-1.23e-32), 0)
   375  assert.eq(int(1.23e-32), 0)
   376  assert.fails(lambda: int(float("+Inf")), "cannot convert float infinity to integer")
   377  assert.fails(lambda: int(float("-Inf")), "cannot convert float infinity to integer")
   378  assert.fails(lambda: int(float("NaN")), "cannot convert float NaN to integer")
   379  
   380  
   381  # hash
   382  # Check that equal float and int values have the same internal hash.
   383  def checkhash():
   384    for a in [1.23e100, 1.23e10, 1.23e1, 1.23,
   385              1, 4294967295, 8589934591, 9223372036854775807]:
   386      for b in [a, -a, 1/a, -1/a]:
   387        f = float(b)
   388        i = int(b)
   389        if f == i:
   390          fh = {f: None}
   391          ih = {i: None}
   392          if fh != ih:
   393            assert.true(False, "{%v: None} != {%v: None}: hashes vary" % fh, ih)
   394  checkhash()
   395  
   396  # string formatting
   397  
   398  # %d
   399  assert.eq("%d" % 0, "0")
   400  assert.eq("%d" % 0.0, "0")
   401  assert.eq("%d" % 123, "123")
   402  assert.eq("%d" % 123.0, "123")
   403  assert.eq("%d" % 1.23e45, "1229999999999999973814869011019624571608236032")
   404  # (see below for '%d' % NaN/Inf)
   405  assert.eq("%d" % negzero, "0")
   406  assert.fails(lambda: "%d" % float("NaN"), "cannot convert float NaN to integer")
   407  assert.fails(lambda: "%d" % float("+Inf"), "cannot convert float infinity to integer")
   408  assert.fails(lambda: "%d" % float("-Inf"), "cannot convert float infinity to integer")
   409  
   410  # %e
   411  assert.eq("%e" % 0, "0.000000e+00")
   412  assert.eq("%e" % 0.0, "0.000000e+00")
   413  assert.eq("%e" % 123, "1.230000e+02")
   414  assert.eq("%e" % 123.0, "1.230000e+02")
   415  assert.eq("%e" % 1.23e45, "1.230000e+45")
   416  assert.eq("%e" % -1.23e-45, "-1.230000e-45")
   417  assert.eq("%e" % nan, "nan")
   418  assert.eq("%e" % inf, "+inf")
   419  assert.eq("%e" % neginf, "-inf")
   420  assert.eq("%e" % negzero, "-0.000000e+00")
   421  assert.fails(lambda: "%e" % "123", "requires float, not str")
   422  # %f
   423  assert.eq("%f" % 0, "0.000000")
   424  assert.eq("%f" % 0.0, "0.000000")
   425  assert.eq("%f" % 123, "123.000000")
   426  assert.eq("%f" % 123.0, "123.000000")
   427  # Note: Starlark/Java emits 1230000000000000000000000000000000000000000000.000000. Why?
   428  assert.eq("%f" % 1.23e45, "1229999999999999973814869011019624571608236032.000000")
   429  assert.eq("%f" % -1.23e-45, "-0.000000")
   430  assert.eq("%f" % nan, "nan")
   431  assert.eq("%f" % inf, "+inf")
   432  assert.eq("%f" % neginf, "-inf")
   433  assert.eq("%f" % negzero, "-0.000000")
   434  assert.fails(lambda: "%f" % "123", "requires float, not str")
   435  # %g
   436  assert.eq("%g" % 0, "0.0")
   437  assert.eq("%g" % 0.0, "0.0")
   438  assert.eq("%g" % 123, "123.0")
   439  assert.eq("%g" % 123.0, "123.0")
   440  assert.eq("%g" % 1.110, "1.11")
   441  assert.eq("%g" % 1e5, "100000.0")
   442  assert.eq("%g" % 1e6, "1e+06") # Note: threshold of scientific notation is 1e17 in Starlark/Java
   443  assert.eq("%g" % 1.23e45, "1.23e+45")
   444  assert.eq("%g" % -1.23e-45, "-1.23e-45")
   445  assert.eq("%g" % nan, "nan")
   446  assert.eq("%g" % inf, "+inf")
   447  assert.eq("%g" % neginf, "-inf")
   448  assert.eq("%g" % negzero, "-0.0")
   449  # str uses %g
   450  assert.eq(str(0.0), "0.0")
   451  assert.eq(str(123.0), "123.0")
   452  assert.eq(str(1.23e45), "1.23e+45")
   453  assert.eq(str(-1.23e-45), "-1.23e-45")
   454  assert.eq(str(nan), "nan")
   455  assert.eq(str(inf), "+inf")
   456  assert.eq(str(neginf), "-inf")
   457  assert.eq(str(negzero), "-0.0")
   458  assert.fails(lambda: "%g" % "123", "requires float, not str")
   459  
   460  i0 = 1
   461  f0 = 1.0
   462  assert.eq(type(i0), "int")
   463  assert.eq(type(f0), "float")
   464  
   465  ops = {
   466      '+': lambda x, y: x + y,
   467      '-': lambda x, y: x - y,
   468      '*': lambda x, y: x * y,
   469      '/': lambda x, y: x / y,
   470      '//': lambda x, y: x // y,
   471      '%': lambda x, y: x % y,
   472  }
   473  
   474  # Check that if either argument is a float, so too is the result.
   475  def checktypes():
   476    want = set("""
   477  int + int = int
   478  int + float = float
   479  float + int = float
   480  float + float = float
   481  int - int = int
   482  int - float = float
   483  float - int = float
   484  float - float = float
   485  int * int = int
   486  int * float = float
   487  float * int = float
   488  float * float = float
   489  int / int = float
   490  int / float = float
   491  float / int = float
   492  float / float = float
   493  int // int = int
   494  int // float = float
   495  float // int = float
   496  float // float = float
   497  int % int = int
   498  int % float = float
   499  float % int = float
   500  float % float = float
   501  """[1:].splitlines())
   502    for opname in ("+", "-", "*", "/", "%"):
   503      for x in [i0, f0]:
   504        for y in [i0, f0]:
   505          op = ops[opname]
   506          got = "%s %s %s = %s" % (type(x), opname, type(y), type(op(x, y)))
   507          assert.contains(want, got)
   508  checktypes()