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()