github.com/lab47/exprcore@v0.0.0-20210525052339-fb7d6bd9331e/exprcore/testdata/float.star (about)

     1  # Tests of Starlark 'float'
     2  # option:float option:set
     3  
     4  load("assert.star", "assert")
     5  
     6  # TODO(adonovan): more tests:
     7  # - precision
     8  # - limits
     9  
    10  # literals
    11  assert.eq(type(1.234), "float")
    12  assert.eq(type(1e10), "float")
    13  assert.eq(type(1e+10), "float")
    14  assert.eq(type(1e-10), "float")
    15  assert.eq(type(1.234e10), "float")
    16  assert.eq(type(1.234e+10), "float")
    17  assert.eq(type(1.234e-10), "float")
    18  
    19  # truth
    20  assert.true(123.0)
    21  assert.true(-1.0)
    22  assert.true(not 0.0)
    23  
    24  # addition
    25  assert.eq(0.0 + 1.0, 1.0)
    26  assert.eq(1.0 + 1.0, 2.0)
    27  assert.eq(1.25 + 2.75, 4.0)
    28  assert.eq(5.0 + 7.0, 12.0)
    29  assert.eq(5.1 + 7, 12.1)  # float + int
    30  assert.eq(7 + 5.1, 12.1)  # int + float
    31  
    32  # subtraction
    33  assert.eq(5.0 - 7.0, -2.0)
    34  assert.eq(5.1 - 7.1, -2.0)
    35  assert.eq(5.5 - 7, -1.5)
    36  assert.eq(5 - 7.5, -2.5)
    37  assert.eq(0.0 - 1.0, -1.0)
    38  
    39  # multiplication
    40  assert.eq(5.0 * 7.0, 35.0)
    41  assert.eq(5.5 * 2.5, 13.75)
    42  assert.eq(5.5 * 7, 38.5)
    43  assert.eq(5 * 7.1, 35.5)
    44  
    45  # real division (like Python 3)
    46  # The / operator is available only when the 'fp' dialect option is enabled.
    47  assert.eq(100.0 / 8.0, 12.5)
    48  assert.eq(100.0 / -8.0, -12.5)
    49  assert.eq(-100.0 / 8.0, -12.5)
    50  assert.eq(-100.0 / -8.0, 12.5)
    51  assert.eq(98.0 / 8.0, 12.25)
    52  assert.eq(98.0 / -8.0, -12.25)
    53  assert.eq(-98.0 / 8.0, -12.25)
    54  assert.eq(-98.0 / -8.0, 12.25)
    55  assert.eq(2.5 / 2.0, 1.25)
    56  assert.eq(2.5 / 2, 1.25)
    57  assert.eq(5 / 4.0, 1.25)
    58  assert.eq(5 / 4, 1.25)
    59  assert.fails(=> 1.0 / 0, "real division by zero")
    60  assert.fails(=> 1.0 / 0.0, "real division by zero")
    61  assert.fails(=> 1 / 0.0, "real division by zero")
    62  
    63  # floored division
    64  assert.eq(100.0 // 8.0, 12.0)
    65  assert.eq(100.0 // -8.0, -13.0)
    66  assert.eq(-100.0 // 8.0, -13.0)
    67  assert.eq(-100.0 // -8.0, 12.0)
    68  assert.eq(98.0 // 8.0, 12.0)
    69  assert.eq(98.0 // -8.0, -13.0)
    70  assert.eq(-98.0 // 8.0, -13.0)
    71  assert.eq(-98.0 // -8.0, 12.0)
    72  assert.eq(2.5 // 2.0, 1.0)
    73  assert.eq(2.5 // 2, 1.0)
    74  assert.eq(5 // 4.0, 1.0)
    75  assert.eq(5 // 4, 1)
    76  assert.eq(type(5 // 4), "int")
    77  assert.fails(=> 1.0 // 0, "floored division by zero")
    78  assert.fails(=> 1.0 // 0.0, "floored division by zero")
    79  assert.fails(=> 1 // 0.0, "floored division by zero")
    80  
    81  # remainder
    82  assert.eq(100.0 % 8.0, 4.0)
    83  assert.eq(100.0 % -8.0, 4.0)
    84  assert.eq(-100.0 % 8.0, -4.0)
    85  assert.eq(-100.0 % -8.0, -4.0)
    86  assert.eq(98.0 % 8.0, 2.0)
    87  assert.eq(98.0 % -8.0, 2.0)
    88  assert.eq(-98.0 % 8.0, -2.0)
    89  assert.eq(-98.0 % -8.0, -2.0)
    90  assert.eq(2.5 % 2.0, 0.5)
    91  assert.eq(2.5 % 2, 0.5)
    92  assert.eq(5 % 4.0, 1.0)
    93  assert.fails(=> 1.0 % 0, "float modulo by zero")
    94  assert.fails(=> 1.0 % 0.0, "float modulo by zero")
    95  assert.fails(=> 1 % 0.0, "float modulo by zero")
    96  
    97  # floats cannot be used as indices, even if integral
    98  assert.fails(=> "abc"[1.0], "want int")
    99  assert.fails(=> ["A", "B", "C"].insert(1.0, "D"), "want int")
   100  
   101  # nan
   102  nan = float("NaN")
   103  def isnan(x) { return x != x }
   104  assert.true(nan != nan)
   105  assert.true(not (nan == nan))
   106  
   107  # ordered comparisons with NaN
   108  assert.true(not nan < nan)
   109  assert.true(not nan > nan)
   110  assert.true(not nan <= nan)
   111  assert.true(not nan >= nan)
   112  assert.true(not nan == nan) # use explicit operator, not assert.ne
   113  assert.true(nan != nan)
   114  assert.true(not nan < 0)
   115  assert.true(not nan > 0)
   116  assert.true(not [nan] < [nan])
   117  assert.true(not [nan] > [nan])
   118  
   119  # Even a value containing NaN is not equal to itself.
   120  nanlist = [nan]
   121  assert.true(not nanlist < nanlist)
   122  assert.true(not nanlist > nanlist)
   123  assert.ne(nanlist, nanlist)
   124  
   125  # Since NaN values never compare equal,
   126  # a dict may have any number of NaN keys.
   127  nandict = %{nan: 1, nan: 2, nan: 3}
   128  assert.eq(len(nandict), 3)
   129  assert.eq(str(nandict), "%{NaN: 1, NaN: 2, NaN: 3}")
   130  assert.true(nan not in nandict)
   131  assert.eq(nandict.get(nan, None), None)
   132  
   133  # inf
   134  inf = float("Inf")
   135  neginf = float("-Inf")
   136  assert.true(isnan(+inf / +inf))
   137  assert.true(isnan(+inf / -inf))
   138  assert.true(isnan(-inf / +inf))
   139  assert.eq(0.0 / +inf, 0.0)
   140  assert.eq(0.0 / -inf, 0.0)
   141  assert.true(inf > -inf)
   142  assert.eq(inf, -neginf)
   143  assert.eq(float(int("2" + "0" * 308)), inf) # 2e308 is too large to represent as a float
   144  assert.eq(float(int("-2" + "0" * 308)), -inf)
   145  # TODO(adonovan): assert inf > any finite number, etc.
   146  
   147  # negative zero
   148  negz = -0
   149  assert.eq(negz, 0)
   150  
   151  # float/float comparisons
   152  fltmax = 1.7976931348623157e+308 # approx
   153  fltmin = 4.9406564584124654e-324 # approx
   154  assert.lt(-inf, -fltmax)
   155  assert.lt(-fltmax, -1.0)
   156  assert.lt(-1.0, -fltmin)
   157  assert.lt(-fltmin, 0.0)
   158  assert.lt(0, fltmin)
   159  assert.lt(fltmin, 1.0)
   160  assert.lt(1.0, fltmax)
   161  assert.lt(fltmax, inf)
   162  
   163  # int/float comparisons
   164  assert.eq(0, 0.0)
   165  assert.eq(1, 1.0)
   166  assert.eq(-1, -1.0)
   167  assert.ne(-1, -1.0 + 1e-7)
   168  assert.lt(-2, -2 + 1e-15)
   169  
   170  # int conversion (rounds towards zero)
   171  assert.eq(int(100.1), 100)
   172  assert.eq(int(100.0), 100)
   173  assert.eq(int(99.9), 99)
   174  assert.eq(int(-99.9), -99)
   175  assert.eq(int(-100.0), -100)
   176  assert.eq(int(-100.1), -100)
   177  assert.eq(int(1e100), int("10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104"))
   178  assert.fails(=> int(inf), "cannot convert.*infinity")
   179  assert.fails(=> int(nan), "cannot convert.*NaN")
   180  
   181  # float conversion
   182  assert.eq(float(), 0.0)
   183  assert.eq(float(False), 0.0)
   184  assert.eq(float(True), 1.0)
   185  assert.eq(float(0), 0.0)
   186  assert.eq(float(1), 1.0)
   187  assert.eq(float(1.1), 1.1)
   188  assert.eq(float("1.1"), 1.1)
   189  assert.fails(=> float("1.1abc"), "invalid syntax")
   190  assert.fails(=> float("1e100.0"), "invalid syntax")
   191  assert.fails(=> float("1e1000"), "out of range")
   192  assert.fails(=> float(None), "want number or string")
   193  assert.eq(float("-1.1"), -1.1)
   194  assert.eq(float("+1.1"), +1.1)
   195  assert.eq(float("+Inf"), inf)
   196  assert.eq(float("-Inf"), neginf)
   197  assert.true(isnan(float("NaN")))
   198  assert.fails(=> float("+NaN"), "invalid syntax")
   199  assert.fails(=> float("-NaN"), "invalid syntax")
   200  
   201  # hash
   202  # Check that equal float and int values have the same internal hash.
   203  def checkhash() {
   204    for a in [1.23e100, 1.23e10, 1.23e1, 1.23,
   205              1, 4294967295, 8589934591, 9223372036854775807] {
   206      for b in [a, -a, 1/a, -1/a] {
   207        f = float(b)
   208        i = int(b)
   209        if f == i {
   210          fh = %{f: None}
   211          ih = %{i: None}
   212          if fh != ih {
   213            assert.true(False, "{%v: None} != {%v: None}: hashes vary" % fh, ih)
   214          }
   215        }
   216      }
   217    }
   218  }
   219  checkhash()
   220  
   221  # string formatting
   222  assert.eq("%s" % 123.45e67, "1.2345e+69")
   223  assert.eq("%r" % 123.45e67, "1.2345e+69")
   224  assert.eq("%e" % 123.45e67, "1.234500e+69")
   225  assert.eq("%f" % 123.45e67, "1234500000000000033987094856609369647752433474509923447907937257783296.000000")
   226  assert.eq("%g" % 123.45e67, "1.2345e+69")
   227  assert.eq("%e" % 123, "1.230000e+02")
   228  assert.eq("%f" % 123, "123.000000")
   229  assert.eq("%g" % 123, "123")
   230  assert.fails(=> "%e" % "123", "requires float, not str")
   231  assert.fails(=> "%f" % "123", "requires float, not str")
   232  assert.fails(=> "%g" % "123", "requires float, not str")
   233  
   234  i0 = 1
   235  f0 = 1.0
   236  assert.eq(type(i0), "int")
   237  assert.eq(type(f0), "float")
   238  
   239  ops = %{
   240      '+': (x, y) => x + y,
   241      '-': (x, y) => x - y,
   242      '*': (x, y) => x * y,
   243      '/': (x, y) => x / y,
   244      '//': (x, y) => x // y,
   245      '%': (x, y) => x % y,
   246  }
   247  
   248  # Check that if either argument is a float, so too is the result.
   249  def checktypes() {
   250    want = set("""
   251  int + int = int
   252  int + float = float
   253  float + int = float
   254  float + float = float
   255  int - int = int
   256  int - float = float
   257  float - int = float
   258  float - float = float
   259  int * int = int
   260  int * float = float
   261  float * int = float
   262  float * float = float
   263  int / int = float
   264  int / float = float
   265  float / int = float
   266  float / float = float
   267  int // int = int
   268  int // float = float
   269  float // int = float
   270  float // float = float
   271  int % int = int
   272  int % float = float
   273  float % int = float
   274  float % float = float
   275  """[1:].splitlines())
   276    for opname in ("+", "-", "*", "/", "%") {
   277      for x in [i0, f0] {
   278        for y in [i0, f0] {
   279          op = ops[opname]
   280          got = "%s %s %s = %s" % (type(x), opname, type(y), type(op(x, y)))
   281          assert.contains(want, got)
   282        }
   283      }
   284    }
   285  }
   286  checktypes()