1"""Tests for Lib/fractions.py.""" 2 3from decimal import Decimal 4from test.support import requires_IEEE_754 5import math 6import numbers 7import operator 8import fractions 9import functools 10import sys 11import unittest 12from copy import copy, deepcopy 13from pickle import dumps, loads 14F = fractions.Fraction 15 16 17class DummyFloat(object): 18 """Dummy float class for testing comparisons with Fractions""" 19 20 def __init__(self, value): 21 if not isinstance(value, float): 22 raise TypeError("DummyFloat can only be initialized from float") 23 self.value = value 24 25 def _richcmp(self, other, op): 26 if isinstance(other, numbers.Rational): 27 return op(F.from_float(self.value), other) 28 elif isinstance(other, DummyFloat): 29 return op(self.value, other.value) 30 else: 31 return NotImplemented 32 33 def __eq__(self, other): return self._richcmp(other, operator.eq) 34 def __le__(self, other): return self._richcmp(other, operator.le) 35 def __lt__(self, other): return self._richcmp(other, operator.lt) 36 def __ge__(self, other): return self._richcmp(other, operator.ge) 37 def __gt__(self, other): return self._richcmp(other, operator.gt) 38 39 # shouldn't be calling __float__ at all when doing comparisons 40 def __float__(self): 41 assert False, "__float__ should not be invoked for comparisons" 42 43 # same goes for subtraction 44 def __sub__(self, other): 45 assert False, "__sub__ should not be invoked for comparisons" 46 __rsub__ = __sub__ 47 48 49class DummyRational(object): 50 """Test comparison of Fraction with a naive rational implementation.""" 51 52 def __init__(self, num, den): 53 g = math.gcd(num, den) 54 self.num = num // g 55 self.den = den // g 56 57 def __eq__(self, other): 58 if isinstance(other, fractions.Fraction): 59 return (self.num == other._numerator and 60 self.den == other._denominator) 61 else: 62 return NotImplemented 63 64 def __lt__(self, other): 65 return(self.num * other._denominator < self.den * other._numerator) 66 67 def __gt__(self, other): 68 return(self.num * other._denominator > self.den * other._numerator) 69 70 def __le__(self, other): 71 return(self.num * other._denominator <= self.den * other._numerator) 72 73 def __ge__(self, other): 74 return(self.num * other._denominator >= self.den * other._numerator) 75 76 # this class is for testing comparisons; conversion to float 77 # should never be used for a comparison, since it loses accuracy 78 def __float__(self): 79 assert False, "__float__ should not be invoked" 80 81class DummyFraction(fractions.Fraction): 82 """Dummy Fraction subclass for copy and deepcopy testing.""" 83 84 85def _components(r): 86 return (r.numerator, r.denominator) 87 88 89class FractionTest(unittest.TestCase): 90 91 def assertTypedEquals(self, expected, actual): 92 """Asserts that both the types and values are the same.""" 93 self.assertEqual(type(expected), type(actual)) 94 self.assertEqual(expected, actual) 95 96 def assertTypedTupleEquals(self, expected, actual): 97 """Asserts that both the types and values in the tuples are the same.""" 98 self.assertTupleEqual(expected, actual) 99 self.assertListEqual(list(map(type, expected)), list(map(type, actual))) 100 101 def assertRaisesMessage(self, exc_type, message, 102 callable, *args, **kwargs): 103 """Asserts that callable(*args, **kwargs) raises exc_type(message).""" 104 try: 105 callable(*args, **kwargs) 106 except exc_type as e: 107 self.assertEqual(message, str(e)) 108 else: 109 self.fail("%s not raised" % exc_type.__name__) 110 111 def testInit(self): 112 self.assertEqual((0, 1), _components(F())) 113 self.assertEqual((7, 1), _components(F(7))) 114 self.assertEqual((7, 3), _components(F(F(7, 3)))) 115 116 self.assertEqual((-1, 1), _components(F(-1, 1))) 117 self.assertEqual((-1, 1), _components(F(1, -1))) 118 self.assertEqual((1, 1), _components(F(-2, -2))) 119 self.assertEqual((1, 2), _components(F(5, 10))) 120 self.assertEqual((7, 15), _components(F(7, 15))) 121 self.assertEqual((10**23, 1), _components(F(10**23))) 122 123 self.assertEqual((3, 77), _components(F(F(3, 7), 11))) 124 self.assertEqual((-9, 5), _components(F(2, F(-10, 9)))) 125 self.assertEqual((2486, 2485), _components(F(F(22, 7), F(355, 113)))) 126 127 self.assertRaisesMessage(ZeroDivisionError, "Fraction(12, 0)", 128 F, 12, 0) 129 self.assertRaises(TypeError, F, 1.5 + 3j) 130 131 self.assertRaises(TypeError, F, "3/2", 3) 132 self.assertRaises(TypeError, F, 3, 0j) 133 self.assertRaises(TypeError, F, 3, 1j) 134 self.assertRaises(TypeError, F, 1, 2, 3) 135 136 @requires_IEEE_754 137 def testInitFromFloat(self): 138 self.assertEqual((5, 2), _components(F(2.5))) 139 self.assertEqual((0, 1), _components(F(-0.0))) 140 self.assertEqual((3602879701896397, 36028797018963968), 141 _components(F(0.1))) 142 # bug 16469: error types should be consistent with float -> int 143 self.assertRaises(ValueError, F, float('nan')) 144 self.assertRaises(OverflowError, F, float('inf')) 145 self.assertRaises(OverflowError, F, float('-inf')) 146 147 def testInitFromDecimal(self): 148 self.assertEqual((11, 10), 149 _components(F(Decimal('1.1')))) 150 self.assertEqual((7, 200), 151 _components(F(Decimal('3.5e-2')))) 152 self.assertEqual((0, 1), 153 _components(F(Decimal('.000e20')))) 154 # bug 16469: error types should be consistent with decimal -> int 155 self.assertRaises(ValueError, F, Decimal('nan')) 156 self.assertRaises(ValueError, F, Decimal('snan')) 157 self.assertRaises(OverflowError, F, Decimal('inf')) 158 self.assertRaises(OverflowError, F, Decimal('-inf')) 159 160 def testFromString(self): 161 self.assertEqual((5, 1), _components(F("5"))) 162 self.assertEqual((3, 2), _components(F("3/2"))) 163 self.assertEqual((3, 2), _components(F(" \n +3/2"))) 164 self.assertEqual((-3, 2), _components(F("-3/2 "))) 165 self.assertEqual((13, 2), _components(F(" 013/02 \n "))) 166 self.assertEqual((16, 5), _components(F(" 3.2 "))) 167 self.assertEqual((-16, 5), _components(F(" -3.2 "))) 168 self.assertEqual((-3, 1), _components(F(" -3. "))) 169 self.assertEqual((3, 5), _components(F(" .6 "))) 170 self.assertEqual((1, 3125), _components(F("32.e-5"))) 171 self.assertEqual((1000000, 1), _components(F("1E+06"))) 172 self.assertEqual((-12300, 1), _components(F("-1.23e4"))) 173 self.assertEqual((0, 1), _components(F(" .0e+0\t"))) 174 self.assertEqual((0, 1), _components(F("-0.000e0"))) 175 176 self.assertRaisesMessage( 177 ZeroDivisionError, "Fraction(3, 0)", 178 F, "3/0") 179 self.assertRaisesMessage( 180 ValueError, "Invalid literal for Fraction: '3/'", 181 F, "3/") 182 self.assertRaisesMessage( 183 ValueError, "Invalid literal for Fraction: '/2'", 184 F, "/2") 185 self.assertRaisesMessage( 186 ValueError, "Invalid literal for Fraction: '3 /2'", 187 F, "3 /2") 188 self.assertRaisesMessage( 189 # Denominators don't need a sign. 190 ValueError, "Invalid literal for Fraction: '3/+2'", 191 F, "3/+2") 192 self.assertRaisesMessage( 193 # Imitate float's parsing. 194 ValueError, "Invalid literal for Fraction: '+ 3/2'", 195 F, "+ 3/2") 196 self.assertRaisesMessage( 197 # Avoid treating '.' as a regex special character. 198 ValueError, "Invalid literal for Fraction: '3a2'", 199 F, "3a2") 200 self.assertRaisesMessage( 201 # Don't accept combinations of decimals and rationals. 202 ValueError, "Invalid literal for Fraction: '3/7.2'", 203 F, "3/7.2") 204 self.assertRaisesMessage( 205 # Don't accept combinations of decimals and rationals. 206 ValueError, "Invalid literal for Fraction: '3.2/7'", 207 F, "3.2/7") 208 self.assertRaisesMessage( 209 # Allow 3. and .3, but not . 210 ValueError, "Invalid literal for Fraction: '.'", 211 F, ".") 212 213 def testImmutable(self): 214 r = F(7, 3) 215 r.__init__(2, 15) 216 self.assertEqual((7, 3), _components(r)) 217 218 self.assertRaises(AttributeError, setattr, r, 'numerator', 12) 219 self.assertRaises(AttributeError, setattr, r, 'denominator', 6) 220 self.assertEqual((7, 3), _components(r)) 221 222 # But if you _really_ need to: 223 r._numerator = 4 224 r._denominator = 2 225 self.assertEqual((4, 2), _components(r)) 226 # Which breaks some important operations: 227 self.assertNotEqual(F(4, 2), r) 228 229 def testFromFloat(self): 230 self.assertRaises(TypeError, F.from_float, 3+4j) 231 self.assertEqual((10, 1), _components(F.from_float(10))) 232 bigint = 1234567890123456789 233 self.assertEqual((bigint, 1), _components(F.from_float(bigint))) 234 self.assertEqual((0, 1), _components(F.from_float(-0.0))) 235 self.assertEqual((10, 1), _components(F.from_float(10.0))) 236 self.assertEqual((-5, 2), _components(F.from_float(-2.5))) 237 self.assertEqual((99999999999999991611392, 1), 238 _components(F.from_float(1e23))) 239 self.assertEqual(float(10**23), float(F.from_float(1e23))) 240 self.assertEqual((3602879701896397, 1125899906842624), 241 _components(F.from_float(3.2))) 242 self.assertEqual(3.2, float(F.from_float(3.2))) 243 244 inf = 1e1000 245 nan = inf - inf 246 # bug 16469: error types should be consistent with float -> int 247 self.assertRaisesMessage( 248 OverflowError, "cannot convert Infinity to integer ratio", 249 F.from_float, inf) 250 self.assertRaisesMessage( 251 OverflowError, "cannot convert Infinity to integer ratio", 252 F.from_float, -inf) 253 self.assertRaisesMessage( 254 ValueError, "cannot convert NaN to integer ratio", 255 F.from_float, nan) 256 257 def testFromDecimal(self): 258 self.assertRaises(TypeError, F.from_decimal, 3+4j) 259 self.assertEqual(F(10, 1), F.from_decimal(10)) 260 self.assertEqual(F(0), F.from_decimal(Decimal("-0"))) 261 self.assertEqual(F(5, 10), F.from_decimal(Decimal("0.5"))) 262 self.assertEqual(F(5, 1000), F.from_decimal(Decimal("5e-3"))) 263 self.assertEqual(F(5000), F.from_decimal(Decimal("5e3"))) 264 self.assertEqual(1 - F(1, 10**30), 265 F.from_decimal(Decimal("0." + "9" * 30))) 266 267 # bug 16469: error types should be consistent with decimal -> int 268 self.assertRaisesMessage( 269 OverflowError, "cannot convert Infinity to integer ratio", 270 F.from_decimal, Decimal("inf")) 271 self.assertRaisesMessage( 272 OverflowError, "cannot convert Infinity to integer ratio", 273 F.from_decimal, Decimal("-inf")) 274 self.assertRaisesMessage( 275 ValueError, "cannot convert NaN to integer ratio", 276 F.from_decimal, Decimal("nan")) 277 self.assertRaisesMessage( 278 ValueError, "cannot convert NaN to integer ratio", 279 F.from_decimal, Decimal("snan")) 280 281 def test_as_integer_ratio(self): 282 self.assertEqual(F(4, 6).as_integer_ratio(), (2, 3)) 283 self.assertEqual(F(-4, 6).as_integer_ratio(), (-2, 3)) 284 self.assertEqual(F(4, -6).as_integer_ratio(), (-2, 3)) 285 self.assertEqual(F(0, 6).as_integer_ratio(), (0, 1)) 286 287 def testLimitDenominator(self): 288 rpi = F('3.1415926535897932') 289 self.assertEqual(rpi.limit_denominator(10000), F(355, 113)) 290 self.assertEqual(-rpi.limit_denominator(10000), F(-355, 113)) 291 self.assertEqual(rpi.limit_denominator(113), F(355, 113)) 292 self.assertEqual(rpi.limit_denominator(112), F(333, 106)) 293 self.assertEqual(F(201, 200).limit_denominator(100), F(1)) 294 self.assertEqual(F(201, 200).limit_denominator(101), F(102, 101)) 295 self.assertEqual(F(0).limit_denominator(10000), F(0)) 296 for i in (0, -1): 297 self.assertRaisesMessage( 298 ValueError, "max_denominator should be at least 1", 299 F(1).limit_denominator, i) 300 301 def testConversions(self): 302 self.assertTypedEquals(-1, math.trunc(F(-11, 10))) 303 self.assertTypedEquals(1, math.trunc(F(11, 10))) 304 self.assertTypedEquals(-2, math.floor(F(-11, 10))) 305 self.assertTypedEquals(-1, math.ceil(F(-11, 10))) 306 self.assertTypedEquals(-1, math.ceil(F(-10, 10))) 307 self.assertTypedEquals(-1, int(F(-11, 10))) 308 self.assertTypedEquals(0, round(F(-1, 10))) 309 self.assertTypedEquals(0, round(F(-5, 10))) 310 self.assertTypedEquals(-2, round(F(-15, 10))) 311 self.assertTypedEquals(-1, round(F(-7, 10))) 312 313 self.assertEqual(False, bool(F(0, 1))) 314 self.assertEqual(True, bool(F(3, 2))) 315 self.assertTypedEquals(0.1, float(F(1, 10))) 316 317 # Check that __float__ isn't implemented by converting the 318 # numerator and denominator to float before dividing. 319 self.assertRaises(OverflowError, float, int('2'*400+'7')) 320 self.assertAlmostEqual(2.0/3, 321 float(F(int('2'*400+'7'), int('3'*400+'1')))) 322 323 self.assertTypedEquals(0.1+0j, complex(F(1,10))) 324 325 def testBoolGuarateesBoolReturn(self): 326 # Ensure that __bool__ is used on numerator which guarantees a bool 327 # return. See also bpo-39274. 328 @functools.total_ordering 329 class CustomValue: 330 denominator = 1 331 332 def __init__(self, value): 333 self.value = value 334 335 def __bool__(self): 336 return bool(self.value) 337 338 @property 339 def numerator(self): 340 # required to preserve `self` during instantiation 341 return self 342 343 def __eq__(self, other): 344 raise AssertionError("Avoid comparisons in Fraction.__bool__") 345 346 __lt__ = __eq__ 347 348 # We did not implement all abstract methods, so register: 349 numbers.Rational.register(CustomValue) 350 351 numerator = CustomValue(1) 352 r = F(numerator) 353 # ensure the numerator was not lost during instantiation: 354 self.assertIs(r.numerator, numerator) 355 self.assertIs(bool(r), True) 356 357 numerator = CustomValue(0) 358 r = F(numerator) 359 self.assertIs(bool(r), False) 360 361 def testRound(self): 362 self.assertTypedEquals(F(-200), round(F(-150), -2)) 363 self.assertTypedEquals(F(-200), round(F(-250), -2)) 364 self.assertTypedEquals(F(30), round(F(26), -1)) 365 self.assertTypedEquals(F(-2, 10), round(F(-15, 100), 1)) 366 self.assertTypedEquals(F(-2, 10), round(F(-25, 100), 1)) 367 368 def testArithmetic(self): 369 self.assertEqual(F(1, 2), F(1, 10) + F(2, 5)) 370 self.assertEqual(F(-3, 10), F(1, 10) - F(2, 5)) 371 self.assertEqual(F(1, 25), F(1, 10) * F(2, 5)) 372 self.assertEqual(F(1, 4), F(1, 10) / F(2, 5)) 373 self.assertTypedEquals(2, F(9, 10) // F(2, 5)) 374 self.assertTypedEquals(10**23, F(10**23, 1) // F(1)) 375 self.assertEqual(F(5, 6), F(7, 3) % F(3, 2)) 376 self.assertEqual(F(2, 3), F(-7, 3) % F(3, 2)) 377 self.assertEqual((F(1), F(5, 6)), divmod(F(7, 3), F(3, 2))) 378 self.assertEqual((F(-2), F(2, 3)), divmod(F(-7, 3), F(3, 2))) 379 self.assertEqual(F(8, 27), F(2, 3) ** F(3)) 380 self.assertEqual(F(27, 8), F(2, 3) ** F(-3)) 381 self.assertTypedEquals(2.0, F(4) ** F(1, 2)) 382 self.assertEqual(F(1, 1), +F(1, 1)) 383 z = pow(F(-1), F(1, 2)) 384 self.assertAlmostEqual(z.real, 0) 385 self.assertEqual(z.imag, 1) 386 # Regression test for #27539. 387 p = F(-1, 2) ** 0 388 self.assertEqual(p, F(1, 1)) 389 self.assertEqual(p.numerator, 1) 390 self.assertEqual(p.denominator, 1) 391 p = F(-1, 2) ** -1 392 self.assertEqual(p, F(-2, 1)) 393 self.assertEqual(p.numerator, -2) 394 self.assertEqual(p.denominator, 1) 395 p = F(-1, 2) ** -2 396 self.assertEqual(p, F(4, 1)) 397 self.assertEqual(p.numerator, 4) 398 self.assertEqual(p.denominator, 1) 399 400 def testLargeArithmetic(self): 401 self.assertTypedEquals( 402 F(10101010100808080808080808101010101010000000000000000, 403 1010101010101010101010101011111111101010101010101010101010101), 404 F(10**35+1, 10**27+1) % F(10**27+1, 10**35-1) 405 ) 406 self.assertTypedEquals( 407 F(7, 1901475900342344102245054808064), 408 F(-2**100, 3) % F(5, 2**100) 409 ) 410 self.assertTypedTupleEquals( 411 (9999999999999999, 412 F(10101010100808080808080808101010101010000000000000000, 413 1010101010101010101010101011111111101010101010101010101010101)), 414 divmod(F(10**35+1, 10**27+1), F(10**27+1, 10**35-1)) 415 ) 416 self.assertTypedEquals( 417 -2 ** 200 // 15, 418 F(-2**100, 3) // F(5, 2**100) 419 ) 420 self.assertTypedEquals( 421 1, 422 F(5, 2**100) // F(3, 2**100) 423 ) 424 self.assertTypedEquals( 425 (1, F(2, 2**100)), 426 divmod(F(5, 2**100), F(3, 2**100)) 427 ) 428 self.assertTypedTupleEquals( 429 (-2 ** 200 // 15, 430 F(7, 1901475900342344102245054808064)), 431 divmod(F(-2**100, 3), F(5, 2**100)) 432 ) 433 434 def testMixedArithmetic(self): 435 self.assertTypedEquals(F(11, 10), F(1, 10) + 1) 436 self.assertTypedEquals(1.1, F(1, 10) + 1.0) 437 self.assertTypedEquals(1.1 + 0j, F(1, 10) + (1.0 + 0j)) 438 self.assertTypedEquals(F(11, 10), 1 + F(1, 10)) 439 self.assertTypedEquals(1.1, 1.0 + F(1, 10)) 440 self.assertTypedEquals(1.1 + 0j, (1.0 + 0j) + F(1, 10)) 441 442 self.assertTypedEquals(F(-9, 10), F(1, 10) - 1) 443 self.assertTypedEquals(-0.9, F(1, 10) - 1.0) 444 self.assertTypedEquals(-0.9 + 0j, F(1, 10) - (1.0 + 0j)) 445 self.assertTypedEquals(F(9, 10), 1 - F(1, 10)) 446 self.assertTypedEquals(0.9, 1.0 - F(1, 10)) 447 self.assertTypedEquals(0.9 + 0j, (1.0 + 0j) - F(1, 10)) 448 449 self.assertTypedEquals(F(1, 10), F(1, 10) * 1) 450 self.assertTypedEquals(0.1, F(1, 10) * 1.0) 451 self.assertTypedEquals(0.1 + 0j, F(1, 10) * (1.0 + 0j)) 452 self.assertTypedEquals(F(1, 10), 1 * F(1, 10)) 453 self.assertTypedEquals(0.1, 1.0 * F(1, 10)) 454 self.assertTypedEquals(0.1 + 0j, (1.0 + 0j) * F(1, 10)) 455 456 self.assertTypedEquals(F(1, 10), F(1, 10) / 1) 457 self.assertTypedEquals(0.1, F(1, 10) / 1.0) 458 self.assertTypedEquals(0.1 + 0j, F(1, 10) / (1.0 + 0j)) 459 self.assertTypedEquals(F(10, 1), 1 / F(1, 10)) 460 self.assertTypedEquals(10.0, 1.0 / F(1, 10)) 461 self.assertTypedEquals(10.0 + 0j, (1.0 + 0j) / F(1, 10)) 462 463 self.assertTypedEquals(0, F(1, 10) // 1) 464 self.assertTypedEquals(0.0, F(1, 10) // 1.0) 465 self.assertTypedEquals(10, 1 // F(1, 10)) 466 self.assertTypedEquals(10**23, 10**22 // F(1, 10)) 467 self.assertTypedEquals(1.0 // 0.1, 1.0 // F(1, 10)) 468 469 self.assertTypedEquals(F(1, 10), F(1, 10) % 1) 470 self.assertTypedEquals(0.1, F(1, 10) % 1.0) 471 self.assertTypedEquals(F(0, 1), 1 % F(1, 10)) 472 self.assertTypedEquals(1.0 % 0.1, 1.0 % F(1, 10)) 473 self.assertTypedEquals(0.1, F(1, 10) % float('inf')) 474 self.assertTypedEquals(float('-inf'), F(1, 10) % float('-inf')) 475 self.assertTypedEquals(float('inf'), F(-1, 10) % float('inf')) 476 self.assertTypedEquals(-0.1, F(-1, 10) % float('-inf')) 477 478 self.assertTypedTupleEquals((0, F(1, 10)), divmod(F(1, 10), 1)) 479 self.assertTypedTupleEquals(divmod(0.1, 1.0), divmod(F(1, 10), 1.0)) 480 self.assertTypedTupleEquals((10, F(0)), divmod(1, F(1, 10))) 481 self.assertTypedTupleEquals(divmod(1.0, 0.1), divmod(1.0, F(1, 10))) 482 self.assertTypedTupleEquals(divmod(0.1, float('inf')), divmod(F(1, 10), float('inf'))) 483 self.assertTypedTupleEquals(divmod(0.1, float('-inf')), divmod(F(1, 10), float('-inf'))) 484 self.assertTypedTupleEquals(divmod(-0.1, float('inf')), divmod(F(-1, 10), float('inf'))) 485 self.assertTypedTupleEquals(divmod(-0.1, float('-inf')), divmod(F(-1, 10), float('-inf'))) 486 487 # ** has more interesting conversion rules. 488 self.assertTypedEquals(F(100, 1), F(1, 10) ** -2) 489 self.assertTypedEquals(F(100, 1), F(10, 1) ** 2) 490 self.assertTypedEquals(0.1, F(1, 10) ** 1.0) 491 self.assertTypedEquals(0.1 + 0j, F(1, 10) ** (1.0 + 0j)) 492 self.assertTypedEquals(4 , 2 ** F(2, 1)) 493 z = pow(-1, F(1, 2)) 494 self.assertAlmostEqual(0, z.real) 495 self.assertEqual(1, z.imag) 496 self.assertTypedEquals(F(1, 4) , 2 ** F(-2, 1)) 497 self.assertTypedEquals(2.0 , 4 ** F(1, 2)) 498 self.assertTypedEquals(0.25, 2.0 ** F(-2, 1)) 499 self.assertTypedEquals(1.0 + 0j, (1.0 + 0j) ** F(1, 10)) 500 self.assertRaises(ZeroDivisionError, operator.pow, 501 F(0, 1), -2) 502 503 def testMixingWithDecimal(self): 504 # Decimal refuses mixed arithmetic (but not mixed comparisons) 505 self.assertRaises(TypeError, operator.add, 506 F(3,11), Decimal('3.1415926')) 507 self.assertRaises(TypeError, operator.add, 508 Decimal('3.1415926'), F(3,11)) 509 510 def testComparisons(self): 511 self.assertTrue(F(1, 2) < F(2, 3)) 512 self.assertFalse(F(1, 2) < F(1, 2)) 513 self.assertTrue(F(1, 2) <= F(2, 3)) 514 self.assertTrue(F(1, 2) <= F(1, 2)) 515 self.assertFalse(F(2, 3) <= F(1, 2)) 516 self.assertTrue(F(1, 2) == F(1, 2)) 517 self.assertFalse(F(1, 2) == F(1, 3)) 518 self.assertFalse(F(1, 2) != F(1, 2)) 519 self.assertTrue(F(1, 2) != F(1, 3)) 520 521 def testComparisonsDummyRational(self): 522 self.assertTrue(F(1, 2) == DummyRational(1, 2)) 523 self.assertTrue(DummyRational(1, 2) == F(1, 2)) 524 self.assertFalse(F(1, 2) == DummyRational(3, 4)) 525 self.assertFalse(DummyRational(3, 4) == F(1, 2)) 526 527 self.assertTrue(F(1, 2) < DummyRational(3, 4)) 528 self.assertFalse(F(1, 2) < DummyRational(1, 2)) 529 self.assertFalse(F(1, 2) < DummyRational(1, 7)) 530 self.assertFalse(F(1, 2) > DummyRational(3, 4)) 531 self.assertFalse(F(1, 2) > DummyRational(1, 2)) 532 self.assertTrue(F(1, 2) > DummyRational(1, 7)) 533 self.assertTrue(F(1, 2) <= DummyRational(3, 4)) 534 self.assertTrue(F(1, 2) <= DummyRational(1, 2)) 535 self.assertFalse(F(1, 2) <= DummyRational(1, 7)) 536 self.assertFalse(F(1, 2) >= DummyRational(3, 4)) 537 self.assertTrue(F(1, 2) >= DummyRational(1, 2)) 538 self.assertTrue(F(1, 2) >= DummyRational(1, 7)) 539 540 self.assertTrue(DummyRational(1, 2) < F(3, 4)) 541 self.assertFalse(DummyRational(1, 2) < F(1, 2)) 542 self.assertFalse(DummyRational(1, 2) < F(1, 7)) 543 self.assertFalse(DummyRational(1, 2) > F(3, 4)) 544 self.assertFalse(DummyRational(1, 2) > F(1, 2)) 545 self.assertTrue(DummyRational(1, 2) > F(1, 7)) 546 self.assertTrue(DummyRational(1, 2) <= F(3, 4)) 547 self.assertTrue(DummyRational(1, 2) <= F(1, 2)) 548 self.assertFalse(DummyRational(1, 2) <= F(1, 7)) 549 self.assertFalse(DummyRational(1, 2) >= F(3, 4)) 550 self.assertTrue(DummyRational(1, 2) >= F(1, 2)) 551 self.assertTrue(DummyRational(1, 2) >= F(1, 7)) 552 553 def testComparisonsDummyFloat(self): 554 x = DummyFloat(1./3.) 555 y = F(1, 3) 556 self.assertTrue(x != y) 557 self.assertTrue(x < y or x > y) 558 self.assertFalse(x == y) 559 self.assertFalse(x <= y and x >= y) 560 self.assertTrue(y != x) 561 self.assertTrue(y < x or y > x) 562 self.assertFalse(y == x) 563 self.assertFalse(y <= x and y >= x) 564 565 def testMixedLess(self): 566 self.assertTrue(2 < F(5, 2)) 567 self.assertFalse(2 < F(4, 2)) 568 self.assertTrue(F(5, 2) < 3) 569 self.assertFalse(F(4, 2) < 2) 570 571 self.assertTrue(F(1, 2) < 0.6) 572 self.assertFalse(F(1, 2) < 0.4) 573 self.assertTrue(0.4 < F(1, 2)) 574 self.assertFalse(0.5 < F(1, 2)) 575 576 self.assertFalse(float('inf') < F(1, 2)) 577 self.assertTrue(float('-inf') < F(0, 10)) 578 self.assertFalse(float('nan') < F(-3, 7)) 579 self.assertTrue(F(1, 2) < float('inf')) 580 self.assertFalse(F(17, 12) < float('-inf')) 581 self.assertFalse(F(144, -89) < float('nan')) 582 583 def testMixedLessEqual(self): 584 self.assertTrue(0.5 <= F(1, 2)) 585 self.assertFalse(0.6 <= F(1, 2)) 586 self.assertTrue(F(1, 2) <= 0.5) 587 self.assertFalse(F(1, 2) <= 0.4) 588 self.assertTrue(2 <= F(4, 2)) 589 self.assertFalse(2 <= F(3, 2)) 590 self.assertTrue(F(4, 2) <= 2) 591 self.assertFalse(F(5, 2) <= 2) 592 593 self.assertFalse(float('inf') <= F(1, 2)) 594 self.assertTrue(float('-inf') <= F(0, 10)) 595 self.assertFalse(float('nan') <= F(-3, 7)) 596 self.assertTrue(F(1, 2) <= float('inf')) 597 self.assertFalse(F(17, 12) <= float('-inf')) 598 self.assertFalse(F(144, -89) <= float('nan')) 599 600 def testBigFloatComparisons(self): 601 # Because 10**23 can't be represented exactly as a float: 602 self.assertFalse(F(10**23) == float(10**23)) 603 # The first test demonstrates why these are important. 604 self.assertFalse(1e23 < float(F(math.trunc(1e23) + 1))) 605 self.assertTrue(1e23 < F(math.trunc(1e23) + 1)) 606 self.assertFalse(1e23 <= F(math.trunc(1e23) - 1)) 607 self.assertTrue(1e23 > F(math.trunc(1e23) - 1)) 608 self.assertFalse(1e23 >= F(math.trunc(1e23) + 1)) 609 610 def testBigComplexComparisons(self): 611 self.assertFalse(F(10**23) == complex(10**23)) 612 self.assertRaises(TypeError, operator.gt, F(10**23), complex(10**23)) 613 self.assertRaises(TypeError, operator.le, F(10**23), complex(10**23)) 614 615 x = F(3, 8) 616 z = complex(0.375, 0.0) 617 w = complex(0.375, 0.2) 618 self.assertTrue(x == z) 619 self.assertFalse(x != z) 620 self.assertFalse(x == w) 621 self.assertTrue(x != w) 622 for op in operator.lt, operator.le, operator.gt, operator.ge: 623 self.assertRaises(TypeError, op, x, z) 624 self.assertRaises(TypeError, op, z, x) 625 self.assertRaises(TypeError, op, x, w) 626 self.assertRaises(TypeError, op, w, x) 627 628 def testMixedEqual(self): 629 self.assertTrue(0.5 == F(1, 2)) 630 self.assertFalse(0.6 == F(1, 2)) 631 self.assertTrue(F(1, 2) == 0.5) 632 self.assertFalse(F(1, 2) == 0.4) 633 self.assertTrue(2 == F(4, 2)) 634 self.assertFalse(2 == F(3, 2)) 635 self.assertTrue(F(4, 2) == 2) 636 self.assertFalse(F(5, 2) == 2) 637 self.assertFalse(F(5, 2) == float('nan')) 638 self.assertFalse(float('nan') == F(3, 7)) 639 self.assertFalse(F(5, 2) == float('inf')) 640 self.assertFalse(float('-inf') == F(2, 5)) 641 642 def testStringification(self): 643 self.assertEqual("Fraction(7, 3)", repr(F(7, 3))) 644 self.assertEqual("Fraction(6283185307, 2000000000)", 645 repr(F('3.1415926535'))) 646 self.assertEqual("Fraction(-1, 100000000000000000000)", 647 repr(F(1, -10**20))) 648 self.assertEqual("7/3", str(F(7, 3))) 649 self.assertEqual("7", str(F(7, 1))) 650 651 def testHash(self): 652 hmod = sys.hash_info.modulus 653 hinf = sys.hash_info.inf 654 self.assertEqual(hash(2.5), hash(F(5, 2))) 655 self.assertEqual(hash(10**50), hash(F(10**50))) 656 self.assertNotEqual(hash(float(10**23)), hash(F(10**23))) 657 self.assertEqual(hinf, hash(F(1, hmod))) 658 # Check that __hash__ produces the same value as hash(), for 659 # consistency with int and Decimal. (See issue #10356.) 660 self.assertEqual(hash(F(-1)), F(-1).__hash__()) 661 662 def testApproximatePi(self): 663 # Algorithm borrowed from 664 # http://docs.python.org/lib/decimal-recipes.html 665 three = F(3) 666 lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24 667 while abs(s - lasts) > F(1, 10**9): 668 lasts = s 669 n, na = n+na, na+8 670 d, da = d+da, da+32 671 t = (t * n) / d 672 s += t 673 self.assertAlmostEqual(math.pi, s) 674 675 def testApproximateCos1(self): 676 # Algorithm borrowed from 677 # http://docs.python.org/lib/decimal-recipes.html 678 x = F(1) 679 i, lasts, s, fact, num, sign = 0, 0, F(1), 1, 1, 1 680 while abs(s - lasts) > F(1, 10**9): 681 lasts = s 682 i += 2 683 fact *= i * (i-1) 684 num *= x * x 685 sign *= -1 686 s += num / fact * sign 687 self.assertAlmostEqual(math.cos(1), s) 688 689 def test_copy_deepcopy_pickle(self): 690 r = F(13, 7) 691 dr = DummyFraction(13, 7) 692 self.assertEqual(r, loads(dumps(r))) 693 self.assertEqual(id(r), id(copy(r))) 694 self.assertEqual(id(r), id(deepcopy(r))) 695 self.assertNotEqual(id(dr), id(copy(dr))) 696 self.assertNotEqual(id(dr), id(deepcopy(dr))) 697 self.assertTypedEquals(dr, copy(dr)) 698 self.assertTypedEquals(dr, deepcopy(dr)) 699 700 def test_slots(self): 701 # Issue 4998 702 r = F(13, 7) 703 self.assertRaises(AttributeError, setattr, r, 'a', 10) 704 705 def test_int_subclass(self): 706 class myint(int): 707 def __mul__(self, other): 708 return type(self)(int(self) * int(other)) 709 def __floordiv__(self, other): 710 return type(self)(int(self) // int(other)) 711 def __mod__(self, other): 712 x = type(self)(int(self) % int(other)) 713 return x 714 @property 715 def numerator(self): 716 return type(self)(int(self)) 717 @property 718 def denominator(self): 719 return type(self)(1) 720 721 f = fractions.Fraction(myint(1 * 3), myint(2 * 3)) 722 self.assertEqual(f.numerator, 1) 723 self.assertEqual(f.denominator, 2) 724 self.assertEqual(type(f.numerator), myint) 725 self.assertEqual(type(f.denominator), myint) 726 727 728if __name__ == '__main__': 729 unittest.main() 730