| 1 | import unittest
|
|---|
| 2 | from test import test_support
|
|---|
| 3 |
|
|---|
| 4 | import random
|
|---|
| 5 |
|
|---|
| 6 | # Used for lazy formatting of failure messages
|
|---|
| 7 | class Frm(object):
|
|---|
| 8 | def __init__(self, format, *args):
|
|---|
| 9 | self.format = format
|
|---|
| 10 | self.args = args
|
|---|
| 11 |
|
|---|
| 12 | def __str__(self):
|
|---|
| 13 | return self.format % self.args
|
|---|
| 14 |
|
|---|
| 15 | # SHIFT should match the value in longintrepr.h for best testing.
|
|---|
| 16 | SHIFT = 15
|
|---|
| 17 | BASE = 2 ** SHIFT
|
|---|
| 18 | MASK = BASE - 1
|
|---|
| 19 | KARATSUBA_CUTOFF = 70 # from longobject.c
|
|---|
| 20 |
|
|---|
| 21 | # Max number of base BASE digits to use in test cases. Doubling
|
|---|
| 22 | # this will more than double the runtime.
|
|---|
| 23 | MAXDIGITS = 15
|
|---|
| 24 |
|
|---|
| 25 | # build some special values
|
|---|
| 26 | special = map(long, [0, 1, 2, BASE, BASE >> 1])
|
|---|
| 27 | special.append(0x5555555555555555L)
|
|---|
| 28 | special.append(0xaaaaaaaaaaaaaaaaL)
|
|---|
| 29 | # some solid strings of one bits
|
|---|
| 30 | p2 = 4L # 0 and 1 already added
|
|---|
| 31 | for i in range(2*SHIFT):
|
|---|
| 32 | special.append(p2 - 1)
|
|---|
| 33 | p2 = p2 << 1
|
|---|
| 34 | del p2
|
|---|
| 35 | # add complements & negations
|
|---|
| 36 | special = special + map(lambda x: ~x, special) + \
|
|---|
| 37 | map(lambda x: -x, special)
|
|---|
| 38 |
|
|---|
| 39 |
|
|---|
| 40 | class LongTest(unittest.TestCase):
|
|---|
| 41 |
|
|---|
| 42 | # Get quasi-random long consisting of ndigits digits (in base BASE).
|
|---|
| 43 | # quasi == the most-significant digit will not be 0, and the number
|
|---|
| 44 | # is constructed to contain long strings of 0 and 1 bits. These are
|
|---|
| 45 | # more likely than random bits to provoke digit-boundary errors.
|
|---|
| 46 | # The sign of the number is also random.
|
|---|
| 47 |
|
|---|
| 48 | def getran(self, ndigits):
|
|---|
| 49 | self.assert_(ndigits > 0)
|
|---|
| 50 | nbits_hi = ndigits * SHIFT
|
|---|
| 51 | nbits_lo = nbits_hi - SHIFT + 1
|
|---|
| 52 | answer = 0L
|
|---|
| 53 | nbits = 0
|
|---|
| 54 | r = int(random.random() * (SHIFT * 2)) | 1 # force 1 bits to start
|
|---|
| 55 | while nbits < nbits_lo:
|
|---|
| 56 | bits = (r >> 1) + 1
|
|---|
| 57 | bits = min(bits, nbits_hi - nbits)
|
|---|
| 58 | self.assert_(1 <= bits <= SHIFT)
|
|---|
| 59 | nbits = nbits + bits
|
|---|
| 60 | answer = answer << bits
|
|---|
| 61 | if r & 1:
|
|---|
| 62 | answer = answer | ((1 << bits) - 1)
|
|---|
| 63 | r = int(random.random() * (SHIFT * 2))
|
|---|
| 64 | self.assert_(nbits_lo <= nbits <= nbits_hi)
|
|---|
| 65 | if random.random() < 0.5:
|
|---|
| 66 | answer = -answer
|
|---|
| 67 | return answer
|
|---|
| 68 |
|
|---|
| 69 | # Get random long consisting of ndigits random digits (relative to base
|
|---|
| 70 | # BASE). The sign bit is also random.
|
|---|
| 71 |
|
|---|
| 72 | def getran2(ndigits):
|
|---|
| 73 | answer = 0L
|
|---|
| 74 | for i in xrange(ndigits):
|
|---|
| 75 | answer = (answer << SHIFT) | random.randint(0, MASK)
|
|---|
| 76 | if random.random() < 0.5:
|
|---|
| 77 | answer = -answer
|
|---|
| 78 | return answer
|
|---|
| 79 |
|
|---|
| 80 | def check_division(self, x, y):
|
|---|
| 81 | eq = self.assertEqual
|
|---|
| 82 | q, r = divmod(x, y)
|
|---|
| 83 | q2, r2 = x//y, x%y
|
|---|
| 84 | pab, pba = x*y, y*x
|
|---|
| 85 | eq(pab, pba, Frm("multiplication does not commute for %r and %r", x, y))
|
|---|
| 86 | eq(q, q2, Frm("divmod returns different quotient than / for %r and %r", x, y))
|
|---|
| 87 | eq(r, r2, Frm("divmod returns different mod than %% for %r and %r", x, y))
|
|---|
| 88 | eq(x, q*y + r, Frm("x != q*y + r after divmod on x=%r, y=%r", x, y))
|
|---|
| 89 | if y > 0:
|
|---|
| 90 | self.assert_(0 <= r < y, Frm("bad mod from divmod on %r and %r", x, y))
|
|---|
| 91 | else:
|
|---|
| 92 | self.assert_(y < r <= 0, Frm("bad mod from divmod on %r and %r", x, y))
|
|---|
| 93 |
|
|---|
| 94 | def test_division(self):
|
|---|
| 95 | digits = range(1, MAXDIGITS+1) + range(KARATSUBA_CUTOFF,
|
|---|
| 96 | KARATSUBA_CUTOFF + 14)
|
|---|
| 97 | digits.append(KARATSUBA_CUTOFF * 3)
|
|---|
| 98 | for lenx in digits:
|
|---|
| 99 | x = self.getran(lenx)
|
|---|
| 100 | for leny in digits:
|
|---|
| 101 | y = self.getran(leny) or 1L
|
|---|
| 102 | self.check_division(x, y)
|
|---|
| 103 |
|
|---|
| 104 | def test_karatsuba(self):
|
|---|
| 105 | digits = range(1, 5) + range(KARATSUBA_CUTOFF, KARATSUBA_CUTOFF + 10)
|
|---|
| 106 | digits.extend([KARATSUBA_CUTOFF * 10, KARATSUBA_CUTOFF * 100])
|
|---|
| 107 |
|
|---|
| 108 | bits = [digit * SHIFT for digit in digits]
|
|---|
| 109 |
|
|---|
| 110 | # Test products of long strings of 1 bits -- (2**x-1)*(2**y-1) ==
|
|---|
| 111 | # 2**(x+y) - 2**x - 2**y + 1, so the proper result is easy to check.
|
|---|
| 112 | for abits in bits:
|
|---|
| 113 | a = (1L << abits) - 1
|
|---|
| 114 | for bbits in bits:
|
|---|
| 115 | if bbits < abits:
|
|---|
| 116 | continue
|
|---|
| 117 | b = (1L << bbits) - 1
|
|---|
| 118 | x = a * b
|
|---|
| 119 | y = ((1L << (abits + bbits)) -
|
|---|
| 120 | (1L << abits) -
|
|---|
| 121 | (1L << bbits) +
|
|---|
| 122 | 1)
|
|---|
| 123 | self.assertEqual(x, y,
|
|---|
| 124 | Frm("bad result for a*b: a=%r, b=%r, x=%r, y=%r", a, b, x, y))
|
|---|
| 125 |
|
|---|
| 126 | def check_bitop_identities_1(self, x):
|
|---|
| 127 | eq = self.assertEqual
|
|---|
| 128 | eq(x & 0, 0, Frm("x & 0 != 0 for x=%r", x))
|
|---|
| 129 | eq(x | 0, x, Frm("x | 0 != x for x=%r", x))
|
|---|
| 130 | eq(x ^ 0, x, Frm("x ^ 0 != x for x=%r", x))
|
|---|
| 131 | eq(x & -1, x, Frm("x & -1 != x for x=%r", x))
|
|---|
| 132 | eq(x | -1, -1, Frm("x | -1 != -1 for x=%r", x))
|
|---|
| 133 | eq(x ^ -1, ~x, Frm("x ^ -1 != ~x for x=%r", x))
|
|---|
| 134 | eq(x, ~~x, Frm("x != ~~x for x=%r", x))
|
|---|
| 135 | eq(x & x, x, Frm("x & x != x for x=%r", x))
|
|---|
| 136 | eq(x | x, x, Frm("x | x != x for x=%r", x))
|
|---|
| 137 | eq(x ^ x, 0, Frm("x ^ x != 0 for x=%r", x))
|
|---|
| 138 | eq(x & ~x, 0, Frm("x & ~x != 0 for x=%r", x))
|
|---|
| 139 | eq(x | ~x, -1, Frm("x | ~x != -1 for x=%r", x))
|
|---|
| 140 | eq(x ^ ~x, -1, Frm("x ^ ~x != -1 for x=%r", x))
|
|---|
| 141 | eq(-x, 1 + ~x, Frm("not -x == 1 + ~x for x=%r", x))
|
|---|
| 142 | eq(-x, ~(x-1), Frm("not -x == ~(x-1) forx =%r", x))
|
|---|
| 143 | for n in xrange(2*SHIFT):
|
|---|
| 144 | p2 = 2L ** n
|
|---|
| 145 | eq(x << n >> n, x,
|
|---|
| 146 | Frm("x << n >> n != x for x=%r, n=%r", (x, n)))
|
|---|
| 147 | eq(x // p2, x >> n,
|
|---|
| 148 | Frm("x // p2 != x >> n for x=%r n=%r p2=%r", (x, n, p2)))
|
|---|
| 149 | eq(x * p2, x << n,
|
|---|
| 150 | Frm("x * p2 != x << n for x=%r n=%r p2=%r", (x, n, p2)))
|
|---|
| 151 | eq(x & -p2, x >> n << n,
|
|---|
| 152 | Frm("not x & -p2 == x >> n << n for x=%r n=%r p2=%r", (x, n, p2)))
|
|---|
| 153 | eq(x & -p2, x & ~(p2 - 1),
|
|---|
| 154 | Frm("not x & -p2 == x & ~(p2 - 1) for x=%r n=%r p2=%r", (x, n, p2)))
|
|---|
| 155 |
|
|---|
| 156 | def check_bitop_identities_2(self, x, y):
|
|---|
| 157 | eq = self.assertEqual
|
|---|
| 158 | eq(x & y, y & x, Frm("x & y != y & x for x=%r, y=%r", (x, y)))
|
|---|
| 159 | eq(x | y, y | x, Frm("x | y != y | x for x=%r, y=%r", (x, y)))
|
|---|
| 160 | eq(x ^ y, y ^ x, Frm("x ^ y != y ^ x for x=%r, y=%r", (x, y)))
|
|---|
| 161 | eq(x ^ y ^ x, y, Frm("x ^ y ^ x != y for x=%r, y=%r", (x, y)))
|
|---|
| 162 | eq(x & y, ~(~x | ~y), Frm("x & y != ~(~x | ~y) for x=%r, y=%r", (x, y)))
|
|---|
| 163 | eq(x | y, ~(~x & ~y), Frm("x | y != ~(~x & ~y) for x=%r, y=%r", (x, y)))
|
|---|
| 164 | eq(x ^ y, (x | y) & ~(x & y),
|
|---|
| 165 | Frm("x ^ y != (x | y) & ~(x & y) for x=%r, y=%r", (x, y)))
|
|---|
| 166 | eq(x ^ y, (x & ~y) | (~x & y),
|
|---|
| 167 | Frm("x ^ y == (x & ~y) | (~x & y) for x=%r, y=%r", (x, y)))
|
|---|
| 168 | eq(x ^ y, (x | y) & (~x | ~y),
|
|---|
| 169 | Frm("x ^ y == (x | y) & (~x | ~y) for x=%r, y=%r", (x, y)))
|
|---|
| 170 |
|
|---|
| 171 | def check_bitop_identities_3(self, x, y, z):
|
|---|
| 172 | eq = self.assertEqual
|
|---|
| 173 | eq((x & y) & z, x & (y & z),
|
|---|
| 174 | Frm("(x & y) & z != x & (y & z) for x=%r, y=%r, z=%r", (x, y, z)))
|
|---|
| 175 | eq((x | y) | z, x | (y | z),
|
|---|
| 176 | Frm("(x | y) | z != x | (y | z) for x=%r, y=%r, z=%r", (x, y, z)))
|
|---|
| 177 | eq((x ^ y) ^ z, x ^ (y ^ z),
|
|---|
| 178 | Frm("(x ^ y) ^ z != x ^ (y ^ z) for x=%r, y=%r, z=%r", (x, y, z)))
|
|---|
| 179 | eq(x & (y | z), (x & y) | (x & z),
|
|---|
| 180 | Frm("x & (y | z) != (x & y) | (x & z) for x=%r, y=%r, z=%r", (x, y, z)))
|
|---|
| 181 | eq(x | (y & z), (x | y) & (x | z),
|
|---|
| 182 | Frm("x | (y & z) != (x | y) & (x | z) for x=%r, y=%r, z=%r", (x, y, z)))
|
|---|
| 183 |
|
|---|
| 184 | def test_bitop_identities(self):
|
|---|
| 185 | for x in special:
|
|---|
| 186 | self.check_bitop_identities_1(x)
|
|---|
| 187 | digits = xrange(1, MAXDIGITS+1)
|
|---|
| 188 | for lenx in digits:
|
|---|
| 189 | x = self.getran(lenx)
|
|---|
| 190 | self.check_bitop_identities_1(x)
|
|---|
| 191 | for leny in digits:
|
|---|
| 192 | y = self.getran(leny)
|
|---|
| 193 | self.check_bitop_identities_2(x, y)
|
|---|
| 194 | self.check_bitop_identities_3(x, y, self.getran((lenx + leny)//2))
|
|---|
| 195 |
|
|---|
| 196 | def slow_format(self, x, base):
|
|---|
| 197 | if (x, base) == (0, 8):
|
|---|
| 198 | # this is an oddball!
|
|---|
| 199 | return "0L"
|
|---|
| 200 | digits = []
|
|---|
| 201 | sign = 0
|
|---|
| 202 | if x < 0:
|
|---|
| 203 | sign, x = 1, -x
|
|---|
| 204 | while x:
|
|---|
| 205 | x, r = divmod(x, base)
|
|---|
| 206 | digits.append(int(r))
|
|---|
| 207 | digits.reverse()
|
|---|
| 208 | digits = digits or [0]
|
|---|
| 209 | return '-'[:sign] + \
|
|---|
| 210 | {8: '0', 10: '', 16: '0x'}[base] + \
|
|---|
| 211 | "".join(map(lambda i: "0123456789abcdef"[i], digits)) + "L"
|
|---|
| 212 |
|
|---|
| 213 | def check_format_1(self, x):
|
|---|
| 214 | for base, mapper in (8, oct), (10, repr), (16, hex):
|
|---|
| 215 | got = mapper(x)
|
|---|
| 216 | expected = self.slow_format(x, base)
|
|---|
| 217 | msg = Frm("%s returned %r but expected %r for %r",
|
|---|
| 218 | mapper.__name__, got, expected, x)
|
|---|
| 219 | self.assertEqual(got, expected, msg)
|
|---|
| 220 | self.assertEqual(long(got, 0), x, Frm('long("%s", 0) != %r', got, x))
|
|---|
| 221 | # str() has to be checked a little differently since there's no
|
|---|
| 222 | # trailing "L"
|
|---|
| 223 | got = str(x)
|
|---|
| 224 | expected = self.slow_format(x, 10)[:-1]
|
|---|
| 225 | msg = Frm("%s returned %r but expected %r for %r",
|
|---|
| 226 | mapper.__name__, got, expected, x)
|
|---|
| 227 | self.assertEqual(got, expected, msg)
|
|---|
| 228 |
|
|---|
| 229 | def test_format(self):
|
|---|
| 230 | for x in special:
|
|---|
| 231 | self.check_format_1(x)
|
|---|
| 232 | for i in xrange(10):
|
|---|
| 233 | for lenx in xrange(1, MAXDIGITS+1):
|
|---|
| 234 | x = self.getran(lenx)
|
|---|
| 235 | self.check_format_1(x)
|
|---|
| 236 |
|
|---|
| 237 | def test_misc(self):
|
|---|
| 238 | import sys
|
|---|
| 239 |
|
|---|
| 240 | # check the extremes in int<->long conversion
|
|---|
| 241 | hugepos = sys.maxint
|
|---|
| 242 | hugeneg = -hugepos - 1
|
|---|
| 243 | hugepos_aslong = long(hugepos)
|
|---|
| 244 | hugeneg_aslong = long(hugeneg)
|
|---|
| 245 | self.assertEqual(hugepos, hugepos_aslong, "long(sys.maxint) != sys.maxint")
|
|---|
| 246 | self.assertEqual(hugeneg, hugeneg_aslong,
|
|---|
| 247 | "long(-sys.maxint-1) != -sys.maxint-1")
|
|---|
| 248 |
|
|---|
| 249 | # long -> int should not fail for hugepos_aslong or hugeneg_aslong
|
|---|
| 250 | try:
|
|---|
| 251 | self.assertEqual(int(hugepos_aslong), hugepos,
|
|---|
| 252 | "converting sys.maxint to long and back to int fails")
|
|---|
| 253 | except OverflowError:
|
|---|
| 254 | self.fail("int(long(sys.maxint)) overflowed!")
|
|---|
| 255 | try:
|
|---|
| 256 | self.assertEqual(int(hugeneg_aslong), hugeneg,
|
|---|
| 257 | "converting -sys.maxint-1 to long and back to int fails")
|
|---|
| 258 | except OverflowError:
|
|---|
| 259 | self.fail("int(long(-sys.maxint-1)) overflowed!")
|
|---|
| 260 |
|
|---|
| 261 | # but long -> int should overflow for hugepos+1 and hugeneg-1
|
|---|
| 262 | x = hugepos_aslong + 1
|
|---|
| 263 | try:
|
|---|
| 264 | y = int(x)
|
|---|
| 265 | except OverflowError:
|
|---|
| 266 | self.fail("int(long(sys.maxint) + 1) mustn't overflow")
|
|---|
| 267 | self.assert_(isinstance(y, long),
|
|---|
| 268 | "int(long(sys.maxint) + 1) should have returned long")
|
|---|
| 269 |
|
|---|
| 270 | x = hugeneg_aslong - 1
|
|---|
| 271 | try:
|
|---|
| 272 | y = int(x)
|
|---|
| 273 | except OverflowError:
|
|---|
| 274 | self.fail("int(long(-sys.maxint-1) - 1) mustn't overflow")
|
|---|
| 275 | self.assert_(isinstance(y, long),
|
|---|
| 276 | "int(long(-sys.maxint-1) - 1) should have returned long")
|
|---|
| 277 |
|
|---|
| 278 | class long2(long):
|
|---|
| 279 | pass
|
|---|
| 280 | x = long2(1L<<100)
|
|---|
| 281 | y = int(x)
|
|---|
| 282 | self.assert_(type(y) is long,
|
|---|
| 283 | "overflowing int conversion must return long not long subtype")
|
|---|
| 284 |
|
|---|
| 285 | # ----------------------------------- tests of auto int->long conversion
|
|---|
| 286 |
|
|---|
| 287 | def test_auto_overflow(self):
|
|---|
| 288 | import math, sys
|
|---|
| 289 |
|
|---|
| 290 | special = [0, 1, 2, 3, sys.maxint-1, sys.maxint, sys.maxint+1]
|
|---|
| 291 | sqrt = int(math.sqrt(sys.maxint))
|
|---|
| 292 | special.extend([sqrt-1, sqrt, sqrt+1])
|
|---|
| 293 | special.extend([-i for i in special])
|
|---|
| 294 |
|
|---|
| 295 | def checkit(*args):
|
|---|
| 296 | # Heavy use of nested scopes here!
|
|---|
| 297 | self.assertEqual(got, expected,
|
|---|
| 298 | Frm("for %r expected %r got %r", args, expected, got))
|
|---|
| 299 |
|
|---|
| 300 | for x in special:
|
|---|
| 301 | longx = long(x)
|
|---|
| 302 |
|
|---|
| 303 | expected = -longx
|
|---|
| 304 | got = -x
|
|---|
| 305 | checkit('-', x)
|
|---|
| 306 |
|
|---|
| 307 | for y in special:
|
|---|
| 308 | longy = long(y)
|
|---|
| 309 |
|
|---|
| 310 | expected = longx + longy
|
|---|
| 311 | got = x + y
|
|---|
| 312 | checkit(x, '+', y)
|
|---|
| 313 |
|
|---|
| 314 | expected = longx - longy
|
|---|
| 315 | got = x - y
|
|---|
| 316 | checkit(x, '-', y)
|
|---|
| 317 |
|
|---|
| 318 | expected = longx * longy
|
|---|
| 319 | got = x * y
|
|---|
| 320 | checkit(x, '*', y)
|
|---|
| 321 |
|
|---|
| 322 | if y:
|
|---|
| 323 | expected = longx / longy
|
|---|
| 324 | got = x / y
|
|---|
| 325 | checkit(x, '/', y)
|
|---|
| 326 |
|
|---|
| 327 | expected = longx // longy
|
|---|
| 328 | got = x // y
|
|---|
| 329 | checkit(x, '//', y)
|
|---|
| 330 |
|
|---|
| 331 | expected = divmod(longx, longy)
|
|---|
| 332 | got = divmod(longx, longy)
|
|---|
| 333 | checkit(x, 'divmod', y)
|
|---|
| 334 |
|
|---|
| 335 | if abs(y) < 5 and not (x == 0 and y < 0):
|
|---|
| 336 | expected = longx ** longy
|
|---|
| 337 | got = x ** y
|
|---|
| 338 | checkit(x, '**', y)
|
|---|
| 339 |
|
|---|
| 340 | for z in special:
|
|---|
| 341 | if z != 0 :
|
|---|
| 342 | if y >= 0:
|
|---|
| 343 | expected = pow(longx, longy, long(z))
|
|---|
| 344 | got = pow(x, y, z)
|
|---|
| 345 | checkit('pow', x, y, '%', z)
|
|---|
| 346 | else:
|
|---|
| 347 | self.assertRaises(TypeError, pow,longx, longy, long(z))
|
|---|
| 348 |
|
|---|
| 349 | def test_float_overflow(self):
|
|---|
| 350 | import math
|
|---|
| 351 |
|
|---|
| 352 | for x in -2.0, -1.0, 0.0, 1.0, 2.0:
|
|---|
| 353 | self.assertEqual(float(long(x)), x)
|
|---|
| 354 |
|
|---|
| 355 | shuge = '12345' * 120
|
|---|
| 356 | huge = 1L << 30000
|
|---|
| 357 | mhuge = -huge
|
|---|
| 358 | namespace = {'huge': huge, 'mhuge': mhuge, 'shuge': shuge, 'math': math}
|
|---|
| 359 | for test in ["float(huge)", "float(mhuge)",
|
|---|
| 360 | "complex(huge)", "complex(mhuge)",
|
|---|
| 361 | "complex(huge, 1)", "complex(mhuge, 1)",
|
|---|
| 362 | "complex(1, huge)", "complex(1, mhuge)",
|
|---|
| 363 | "1. + huge", "huge + 1.", "1. + mhuge", "mhuge + 1.",
|
|---|
| 364 | "1. - huge", "huge - 1.", "1. - mhuge", "mhuge - 1.",
|
|---|
| 365 | "1. * huge", "huge * 1.", "1. * mhuge", "mhuge * 1.",
|
|---|
| 366 | "1. // huge", "huge // 1.", "1. // mhuge", "mhuge // 1.",
|
|---|
| 367 | "1. / huge", "huge / 1.", "1. / mhuge", "mhuge / 1.",
|
|---|
| 368 | "1. ** huge", "huge ** 1.", "1. ** mhuge", "mhuge ** 1.",
|
|---|
| 369 | "math.sin(huge)", "math.sin(mhuge)",
|
|---|
| 370 | "math.sqrt(huge)", "math.sqrt(mhuge)", # should do better
|
|---|
| 371 | "math.floor(huge)", "math.floor(mhuge)"]:
|
|---|
| 372 |
|
|---|
| 373 | self.assertRaises(OverflowError, eval, test, namespace)
|
|---|
| 374 |
|
|---|
| 375 | # XXX Perhaps float(shuge) can raise OverflowError on some box?
|
|---|
| 376 | # The comparison should not.
|
|---|
| 377 | self.assertNotEqual(float(shuge), int(shuge),
|
|---|
| 378 | "float(shuge) should not equal int(shuge)")
|
|---|
| 379 |
|
|---|
| 380 | def test_logs(self):
|
|---|
| 381 | import math
|
|---|
| 382 |
|
|---|
| 383 | LOG10E = math.log10(math.e)
|
|---|
| 384 |
|
|---|
| 385 | for exp in range(10) + [100, 1000, 10000]:
|
|---|
| 386 | value = 10 ** exp
|
|---|
| 387 | log10 = math.log10(value)
|
|---|
| 388 | self.assertAlmostEqual(log10, exp)
|
|---|
| 389 |
|
|---|
| 390 | # log10(value) == exp, so log(value) == log10(value)/log10(e) ==
|
|---|
| 391 | # exp/LOG10E
|
|---|
| 392 | expected = exp / LOG10E
|
|---|
| 393 | log = math.log(value)
|
|---|
| 394 | self.assertAlmostEqual(log, expected)
|
|---|
| 395 |
|
|---|
| 396 | for bad in -(1L << 10000), -2L, 0L:
|
|---|
| 397 | self.assertRaises(ValueError, math.log, bad)
|
|---|
| 398 | self.assertRaises(ValueError, math.log10, bad)
|
|---|
| 399 |
|
|---|
| 400 | def test_mixed_compares(self):
|
|---|
| 401 | eq = self.assertEqual
|
|---|
| 402 | import math
|
|---|
| 403 | import sys
|
|---|
| 404 |
|
|---|
| 405 | # We're mostly concerned with that mixing floats and longs does the
|
|---|
| 406 | # right stuff, even when longs are too large to fit in a float.
|
|---|
| 407 | # The safest way to check the results is to use an entirely different
|
|---|
| 408 | # method, which we do here via a skeletal rational class (which
|
|---|
| 409 | # represents all Python ints, longs and floats exactly).
|
|---|
| 410 | class Rat:
|
|---|
| 411 | def __init__(self, value):
|
|---|
| 412 | if isinstance(value, (int, long)):
|
|---|
| 413 | self.n = value
|
|---|
| 414 | self.d = 1
|
|---|
| 415 | elif isinstance(value, float):
|
|---|
| 416 | # Convert to exact rational equivalent.
|
|---|
| 417 | f, e = math.frexp(abs(value))
|
|---|
| 418 | assert f == 0 or 0.5 <= f < 1.0
|
|---|
| 419 | # |value| = f * 2**e exactly
|
|---|
| 420 |
|
|---|
| 421 | # Suck up CHUNK bits at a time; 28 is enough so that we suck
|
|---|
| 422 | # up all bits in 2 iterations for all known binary double-
|
|---|
| 423 | # precision formats, and small enough to fit in an int.
|
|---|
| 424 | CHUNK = 28
|
|---|
| 425 | top = 0
|
|---|
| 426 | # invariant: |value| = (top + f) * 2**e exactly
|
|---|
| 427 | while f:
|
|---|
| 428 | f = math.ldexp(f, CHUNK)
|
|---|
| 429 | digit = int(f)
|
|---|
| 430 | assert digit >> CHUNK == 0
|
|---|
| 431 | top = (top << CHUNK) | digit
|
|---|
| 432 | f -= digit
|
|---|
| 433 | assert 0.0 <= f < 1.0
|
|---|
| 434 | e -= CHUNK
|
|---|
| 435 |
|
|---|
| 436 | # Now |value| = top * 2**e exactly.
|
|---|
| 437 | if e >= 0:
|
|---|
| 438 | n = top << e
|
|---|
| 439 | d = 1
|
|---|
| 440 | else:
|
|---|
| 441 | n = top
|
|---|
| 442 | d = 1 << -e
|
|---|
| 443 | if value < 0:
|
|---|
| 444 | n = -n
|
|---|
| 445 | self.n = n
|
|---|
| 446 | self.d = d
|
|---|
| 447 | assert float(n) / float(d) == value
|
|---|
| 448 | else:
|
|---|
| 449 | raise TypeError("can't deal with %r" % val)
|
|---|
| 450 |
|
|---|
| 451 | def __cmp__(self, other):
|
|---|
| 452 | if not isinstance(other, Rat):
|
|---|
| 453 | other = Rat(other)
|
|---|
| 454 | return cmp(self.n * other.d, self.d * other.n)
|
|---|
| 455 |
|
|---|
| 456 | cases = [0, 0.001, 0.99, 1.0, 1.5, 1e20, 1e200]
|
|---|
| 457 | # 2**48 is an important boundary in the internals. 2**53 is an
|
|---|
| 458 | # important boundary for IEEE double precision.
|
|---|
| 459 | for t in 2.0**48, 2.0**50, 2.0**53:
|
|---|
| 460 | cases.extend([t - 1.0, t - 0.3, t, t + 0.3, t + 1.0,
|
|---|
| 461 | long(t-1), long(t), long(t+1)])
|
|---|
| 462 | cases.extend([0, 1, 2, sys.maxint, float(sys.maxint)])
|
|---|
| 463 | # 1L<<20000 should exceed all double formats. long(1e200) is to
|
|---|
| 464 | # check that we get equality with 1e200 above.
|
|---|
| 465 | t = long(1e200)
|
|---|
| 466 | cases.extend([0L, 1L, 2L, 1L << 20000, t-1, t, t+1])
|
|---|
| 467 | cases.extend([-x for x in cases])
|
|---|
| 468 | for x in cases:
|
|---|
| 469 | Rx = Rat(x)
|
|---|
| 470 | for y in cases:
|
|---|
| 471 | Ry = Rat(y)
|
|---|
| 472 | Rcmp = cmp(Rx, Ry)
|
|---|
| 473 | xycmp = cmp(x, y)
|
|---|
| 474 | eq(Rcmp, xycmp, Frm("%r %r %d %d", x, y, Rcmp, xycmp))
|
|---|
| 475 | eq(x == y, Rcmp == 0, Frm("%r == %r %d", x, y, Rcmp))
|
|---|
| 476 | eq(x != y, Rcmp != 0, Frm("%r != %r %d", x, y, Rcmp))
|
|---|
| 477 | eq(x < y, Rcmp < 0, Frm("%r < %r %d", x, y, Rcmp))
|
|---|
| 478 | eq(x <= y, Rcmp <= 0, Frm("%r <= %r %d", x, y, Rcmp))
|
|---|
| 479 | eq(x > y, Rcmp > 0, Frm("%r > %r %d", x, y, Rcmp))
|
|---|
| 480 | eq(x >= y, Rcmp >= 0, Frm("%r >= %r %d", x, y, Rcmp))
|
|---|
| 481 |
|
|---|
| 482 | def test_main():
|
|---|
| 483 | test_support.run_unittest(LongTest)
|
|---|
| 484 |
|
|---|
| 485 | if __name__ == "__main__":
|
|---|
| 486 | test_main()
|
|---|