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