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
58# Regression test for https://github.com/google/starlark-go/issues/375.
59maxint64 = (1<<63)-1
60assert.eq(int(float(maxint64)), 9223372036854775808)
61
62assert.true(float(p53+1) != p53+1) # comparisons are exact
63assert.eq(float(p53+1) - (p53+1), 0) # arithmetic entails rounding
64
65assert.fails(lambda: {123.0: "f", 123: "i"}, "duplicate key: 123")
66
67# equal int/float values have same hash
68d = {123.0: "x"}
69d[123] = "y"
70assert.eq(len(d), 1)
71assert.eq(d[123.0], "y")
72
73# literals (mostly covered by scanner tests)
74assert.eq(str(0.), "0.0")
75assert.eq(str(.0), "0.0")
76assert.true(5.0 != 4.999999999999999)
77assert.eq(5.0, 4.9999999999999999) # both literals denote 5.0
78assert.eq(1.23e45, 1.23 * 1000000000000000000000000000000000000000000000)
79assert.eq(str(1.23e-45 - (1.23 / 1000000000000000000000000000000000000000000000)), "-1.5557538194652854e-61")
80
81nan = float("NaN")
82inf = float("+Inf")
83neginf = float("-Inf")
84negzero = (-1e-323 / 10)
85
86# -- arithmetic --
87
88# +float, -float
89assert.eq(+(123.0), 123.0)
90assert.eq(-(123.0), -123.0)
91assert.eq(-(-(123.0)), 123.0)
92assert.eq(+(inf), inf)
93assert.eq(-(inf), neginf)
94assert.eq(-(neginf), inf)
95assert.eq(str(-(nan)), "nan")
96# +
97assert.eq(1.2e3 + 5.6e7, 5.60012e+07)
98assert.eq(1.2e3 + 1, 1201)
99assert.eq(1 + 1.2e3, 1201)
100assert.eq(str(1.2e3 + nan), "nan")
101assert.eq(inf + 0, inf)
102assert.eq(inf + 1, inf)
103assert.eq(inf + inf, inf)
104assert.eq(str(inf + neginf), "nan")
105# -
106assert.eq(1.2e3 - 5.6e7, -5.59988e+07)
107assert.eq(1.2e3 - 1, 1199)
108assert.eq(1 - 1.2e3, -1199)
109assert.eq(str(1.2e3 - nan), "nan")
110assert.eq(inf - 0, inf)
111assert.eq(inf - 1, inf)
112assert.eq(str(inf - inf), "nan")
113assert.eq(inf - neginf, inf)
114# *
115assert.eq(1.5e6 * 2.2e3, 3.3e9)
116assert.eq(1.5e6 * 123, 1.845e+08)
117assert.eq(123 * 1.5e6, 1.845e+08)
118assert.eq(str(1.2e3 * nan), "nan")
119assert.eq(str(inf * 0), "nan")
120assert.eq(inf * 1, inf)
121assert.eq(inf * inf, inf)
122assert.eq(inf * neginf, neginf)
123# %
124assert.eq(100.0 % 7.0, 2)
125assert.eq(100.0 % -7.0, -5) # NB: different from Go / Java
126assert.eq(-100.0 % 7.0, 5) # NB: different from Go / Java
127assert.eq(-100.0 % -7.0, -2)
128assert.eq(-100.0 % 7, 5)
129assert.eq(100 % 7.0, 2)
130assert.eq(str(1.2e3 % nan), "nan")
131assert.eq(str(inf % 1), "nan")
132assert.eq(str(inf % inf), "nan")
133assert.eq(str(inf % neginf), "nan")
134# /
135assert.eq(str(100.0 / 7.0), "14.285714285714286")
136assert.eq(str(100 / 7.0), "14.285714285714286")
137assert.eq(str(100.0 / 7), "14.285714285714286")
138assert.eq(str(100.0 / nan), "nan")
139# //
140assert.eq(100.0 // 7.0, 14)
141assert.eq(100 // 7.0, 14)
142assert.eq(100.0 // 7, 14)
143assert.eq(100.0 // -7.0, -15)
144assert.eq(100 // -7.0, -15)
145assert.eq(100.0 // -7, -15)
146assert.eq(str(1 // neginf), "-0.0")
147assert.eq(str(100.0 // nan), "nan")
148
149# addition
150assert.eq(0.0 + 1.0, 1.0)
151assert.eq(1.0 + 1.0, 2.0)
152assert.eq(1.25 + 2.75, 4.0)
153assert.eq(5.0 + 7.0, 12.0)
154assert.eq(5.1 + 7, 12.1)  # float + int
155assert.eq(7 + 5.1, 12.1)  # int + float
156
157# subtraction
158assert.eq(5.0 - 7.0, -2.0)
159assert.eq(5.1 - 7.1, -2.0)
160assert.eq(5.5 - 7, -1.5)
161assert.eq(5 - 7.5, -2.5)
162assert.eq(0.0 - 1.0, -1.0)
163
164# multiplication
165assert.eq(5.0 * 7.0, 35.0)
166assert.eq(5.5 * 2.5, 13.75)
167assert.eq(5.5 * 7, 38.5)
168assert.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.
172assert.eq(100.0 / 8.0, 12.5)
173assert.eq(100.0 / -8.0, -12.5)
174assert.eq(-100.0 / 8.0, -12.5)
175assert.eq(-100.0 / -8.0, 12.5)
176assert.eq(98.0 / 8.0, 12.25)
177assert.eq(98.0 / -8.0, -12.25)
178assert.eq(-98.0 / 8.0, -12.25)
179assert.eq(-98.0 / -8.0, 12.25)
180assert.eq(2.5 / 2.0, 1.25)
181assert.eq(2.5 / 2, 1.25)
182assert.eq(5 / 4.0, 1.25)
183assert.eq(5 / 4, 1.25)
184assert.fails(lambda: 1.0 / 0, "floating-point division by zero")
185assert.fails(lambda: 1.0 / 0.0, "floating-point division by zero")
186assert.fails(lambda: 1 / 0.0, "floating-point division by zero")
187
188# floored division
189assert.eq(100.0 // 8.0, 12.0)
190assert.eq(100.0 // -8.0, -13.0)
191assert.eq(-100.0 // 8.0, -13.0)
192assert.eq(-100.0 // -8.0, 12.0)
193assert.eq(98.0 // 8.0, 12.0)
194assert.eq(98.0 // -8.0, -13.0)
195assert.eq(-98.0 // 8.0, -13.0)
196assert.eq(-98.0 // -8.0, 12.0)
197assert.eq(2.5 // 2.0, 1.0)
198assert.eq(2.5 // 2, 1.0)
199assert.eq(5 // 4.0, 1.0)
200assert.eq(5 // 4, 1)
201assert.eq(type(5 // 4), "int")
202assert.fails(lambda: 1.0 // 0, "floored division by zero")
203assert.fails(lambda: 1.0 // 0.0, "floored division by zero")
204assert.fails(lambda: 1 // 0.0, "floored division by zero")
205
206# remainder
207assert.eq(100.0 % 8.0, 4.0)
208assert.eq(100.0 % -8.0, -4.0)
209assert.eq(-100.0 % 8.0, 4.0)
210assert.eq(-100.0 % -8.0, -4.0)
211assert.eq(98.0 % 8.0, 2.0)
212assert.eq(98.0 % -8.0, -6.0)
213assert.eq(-98.0 % 8.0, 6.0)
214assert.eq(-98.0 % -8.0, -2.0)
215assert.eq(2.5 % 2.0, 0.5)
216assert.eq(2.5 % 2, 0.5)
217assert.eq(5 % 4.0, 1.0)
218assert.fails(lambda: 1.0 % 0, "floating-point modulo by zero")
219assert.fails(lambda: 1.0 % 0.0, "floating-point modulo by zero")
220assert.fails(lambda: 1 % 0.0, "floating-point modulo by zero")
221
222# floats cannot be used as indices, even if integral
223assert.fails(lambda: "abc"[1.0], "want int")
224assert.fails(lambda: ["A", "B", "C"].insert(1.0, "D"), "want int")
225assert.fails(lambda: range(3)[1.0], "got float, want int")
226
227# -- comparisons --
228# NaN
229assert.true(nan == nan) # \
230assert.true(nan >= nan) #  unlike Python
231assert.true(nan <= nan) # /
232assert.true(not (nan > nan))
233assert.true(not (nan < nan))
234assert.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.
237assert.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.
243assert.eq(str(sorted([7, 3, nan, 1, 9])), "[1, 3, 7, 9, nan]")
244assert.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.)
247nandict = {nan: 1}
248nandict[nan] = 2
249assert.eq(len(nandict), 1) # (same as Python)
250assert.eq(nandict[nan], 2) # (same as Python)
251assert.fails(lambda: {nan: 1, nan: 2}, "duplicate key: nan")
252
253nandict[float('nan')] = 3 # a distinct NaN object
254assert.eq(str(nandict), "{nan: 3}") # (Python: {nan: 2, nan: 3})
255
256assert.eq(str({inf: 1, neginf: 2}), "{+inf: 1, -inf: 2}")
257
258# zero
259assert.eq(0.0, negzero)
260
261# inf
262assert.eq(+inf / +inf, nan)
263assert.eq(+inf / -inf, nan)
264assert.eq(-inf / +inf, nan)
265assert.eq(0.0 / +inf, 0.0)
266assert.eq(0.0 / -inf, 0.0)
267assert.true(inf > -inf)
268assert.eq(inf, -neginf)
269# TODO(adonovan): assert inf > any finite number, etc.
270
271# negative zero
272negz = -0
273assert.eq(negz, 0)
274
275# min/max ordering with NaN (the greatest float value)
276assert.eq(max([1, nan, 3]), nan)
277assert.eq(max([nan, 2, 3]), nan)
278assert.eq(min([1, nan, 3]), 1)
279assert.eq(min([nan, 2, 3]), 2)
280
281# float/float comparisons
282fltmax = 1.7976931348623157e+308 # approx
283fltmin = 4.9406564584124654e-324 # approx
284assert.lt(-inf, -fltmax)
285assert.lt(-fltmax, -1.0)
286assert.lt(-1.0, -fltmin)
287assert.lt(-fltmin, 0.0)
288assert.lt(0, fltmin)
289assert.lt(fltmin, 1.0)
290assert.lt(1.0, fltmax)
291assert.lt(fltmax, inf)
292
293# int/float comparisons
294assert.eq(0, 0.0)
295assert.eq(1, 1.0)
296assert.eq(-1, -1.0)
297assert.ne(-1, -1.0 + 1e-7)
298assert.lt(-2, -2 + 1e-15)
299
300# int conversion (rounds towards zero)
301assert.eq(int(100.1), 100)
302assert.eq(int(100.0), 100)
303assert.eq(int(99.9), 99)
304assert.eq(int(-99.9), -99)
305assert.eq(int(-100.0), -100)
306assert.eq(int(-100.1), -100)
307assert.eq(int(1e100), int("10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104"))
308assert.fails(lambda: int(inf), "cannot convert.*infinity")
309assert.fails(lambda: int(nan), "cannot convert.*NaN")
310
311# -- float() function --
312assert.eq(float(), 0.0)
313# float(bool)
314assert.eq(float(False), 0.0)
315assert.eq(float(True), 1.0)
316# float(int)
317assert.eq(float(0), 0.0)
318assert.eq(float(1), 1.0)
319assert.eq(float(123), 123.0)
320assert.eq(float(123 * 1000000 * 1000000 * 1000000 * 1000000 * 1000000), 1.23e+32)
321# float(float)
322assert.eq(float(1.1), 1.1)
323assert.fails(lambda: float(None), "want number or string")
324assert.ne(False, 0.0) # differs from Python
325assert.ne(True, 1.0)
326# float(string)
327assert.eq(float("1.1"), 1.1)
328assert.fails(lambda: float("1.1abc"), "invalid float literal")
329assert.fails(lambda: float("1e100.0"), "invalid float literal")
330assert.fails(lambda: float("1e1000"), "floating-point number too large")
331assert.eq(float("-1.1"), -1.1)
332assert.eq(float("+1.1"), +1.1)
333assert.eq(float("+Inf"), inf)
334assert.eq(float("-Inf"), neginf)
335assert.eq(float("NaN"), nan)
336assert.eq(float("NaN"), nan)
337assert.eq(float("+NAN"), nan)
338assert.eq(float("-nan"), nan)
339assert.eq(str(float("Inf")), "+inf")
340assert.eq(str(float("+INF")), "+inf")
341assert.eq(str(float("-inf")), "-inf")
342assert.eq(str(float("+InFiniTy")), "+inf")
343assert.eq(str(float("-iNFiniTy")), "-inf")
344assert.fails(lambda: float("one point two"), "invalid float literal: one point two")
345assert.fails(lambda: float("1.2.3"), "invalid float literal: 1.2.3")
346assert.fails(lambda: float(123 << 500 << 500 << 50), "int too large to convert to float")
347assert.fails(lambda: float(-123 << 500 << 500 << 50), "int too large to convert to float")
348assert.fails(lambda: float(str(-123 << 500 << 500 << 50)), "floating-point number too large")
349
350# -- implicit float(int) conversions --
351assert.fails(lambda: (1<<500<<500<<500) + 0.0, "int too large to convert to float")
352assert.fails(lambda: 0.0 + (1<<500<<500<<500), "int too large to convert to float")
353assert.fails(lambda: (1<<500<<500<<500) - 0.0, "int too large to convert to float")
354assert.fails(lambda: 0.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")
359assert.fails(lambda: (1<<500<<500<<500) // 1.0, "int too large to convert to float")
360assert.fails(lambda: 1.0 // (1<<500<<500<<500), "int too large to convert to float")
361assert.fails(lambda: (1<<500<<500<<500) % 1.0, "int too large to convert to float")
362assert.fails(lambda: 1.0 % (1<<500<<500<<500), "int too large to convert to float")
363
364
365# -- int function --
366assert.eq(int(0.0), 0)
367assert.eq(int(1.0), 1)
368assert.eq(int(1.1), 1)
369assert.eq(int(0.9), 0)
370assert.eq(int(-1.1), -1.0)
371assert.eq(int(-1.0), -1.0)
372assert.eq(int(-0.9), 0.0)
373assert.eq(int(1.23e+32), 123000000000000004979083645550592)
374assert.eq(int(-1.23e-32), 0)
375assert.eq(int(1.23e-32), 0)
376assert.fails(lambda: int(float("+Inf")), "cannot convert float infinity to integer")
377assert.fails(lambda: int(float("-Inf")), "cannot convert float infinity to integer")
378assert.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.
383def 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)
394checkhash()
395
396# string formatting
397
398# %d
399assert.eq("%d" % 0, "0")
400assert.eq("%d" % 0.0, "0")
401assert.eq("%d" % 123, "123")
402assert.eq("%d" % 123.0, "123")
403assert.eq("%d" % 1.23e45, "1229999999999999973814869011019624571608236032")
404# (see below for '%d' % NaN/Inf)
405assert.eq("%d" % negzero, "0")
406assert.fails(lambda: "%d" % float("NaN"), "cannot convert float NaN to integer")
407assert.fails(lambda: "%d" % float("+Inf"), "cannot convert float infinity to integer")
408assert.fails(lambda: "%d" % float("-Inf"), "cannot convert float infinity to integer")
409
410# %e
411assert.eq("%e" % 0, "0.000000e+00")
412assert.eq("%e" % 0.0, "0.000000e+00")
413assert.eq("%e" % 123, "1.230000e+02")
414assert.eq("%e" % 123.0, "1.230000e+02")
415assert.eq("%e" % 1.23e45, "1.230000e+45")
416assert.eq("%e" % -1.23e-45, "-1.230000e-45")
417assert.eq("%e" % nan, "nan")
418assert.eq("%e" % inf, "+inf")
419assert.eq("%e" % neginf, "-inf")
420assert.eq("%e" % negzero, "-0.000000e+00")
421assert.fails(lambda: "%e" % "123", "requires float, not str")
422# %f
423assert.eq("%f" % 0, "0.000000")
424assert.eq("%f" % 0.0, "0.000000")
425assert.eq("%f" % 123, "123.000000")
426assert.eq("%f" % 123.0, "123.000000")
427# Note: Starlark/Java emits 1230000000000000000000000000000000000000000000.000000. Why?
428assert.eq("%f" % 1.23e45, "1229999999999999973814869011019624571608236032.000000")
429assert.eq("%f" % -1.23e-45, "-0.000000")
430assert.eq("%f" % nan, "nan")
431assert.eq("%f" % inf, "+inf")
432assert.eq("%f" % neginf, "-inf")
433assert.eq("%f" % negzero, "-0.000000")
434assert.fails(lambda: "%f" % "123", "requires float, not str")
435# %g
436assert.eq("%g" % 0, "0.0")
437assert.eq("%g" % 0.0, "0.0")
438assert.eq("%g" % 123, "123.0")
439assert.eq("%g" % 123.0, "123.0")
440assert.eq("%g" % 1.110, "1.11")
441assert.eq("%g" % 1e5, "100000.0")
442assert.eq("%g" % 1e6, "1e+06") # Note: threshold of scientific notation is 1e17 in Starlark/Java
443assert.eq("%g" % 1.23e45, "1.23e+45")
444assert.eq("%g" % -1.23e-45, "-1.23e-45")
445assert.eq("%g" % nan, "nan")
446assert.eq("%g" % inf, "+inf")
447assert.eq("%g" % neginf, "-inf")
448assert.eq("%g" % negzero, "-0.0")
449# str uses %g
450assert.eq(str(0.0), "0.0")
451assert.eq(str(123.0), "123.0")
452assert.eq(str(1.23e45), "1.23e+45")
453assert.eq(str(-1.23e-45), "-1.23e-45")
454assert.eq(str(nan), "nan")
455assert.eq(str(inf), "+inf")
456assert.eq(str(neginf), "-inf")
457assert.eq(str(negzero), "-0.0")
458assert.fails(lambda: "%g" % "123", "requires float, not str")
459
460i0 = 1
461f0 = 1.0
462assert.eq(type(i0), "int")
463assert.eq(type(f0), "float")
464
465ops = {
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.
475def checktypes():
476  want = set("""
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 = int
486int * float = float
487float * int = float
488float * float = float
489int / int = float
490int / float = float
491float / int = float
492float / float = float
493int // int = int
494int // float = float
495float // int = float
496float // float = float
497int % int = int
498int % float = float
499float % int = float
500float % 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)
508checktypes()
509