• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(5, 6), F(2, 3) * F(5, 4))
373        self.assertEqual(F(1, 4), F(1, 10) / F(2, 5))
374        self.assertEqual(F(-15, 8), F(3, 4) / F(-2, 5))
375        self.assertTypedEquals(2, F(9, 10) // F(2, 5))
376        self.assertTypedEquals(10**23, F(10**23, 1) // F(1))
377        self.assertEqual(F(5, 6), F(7, 3) % F(3, 2))
378        self.assertEqual(F(2, 3), F(-7, 3) % F(3, 2))
379        self.assertEqual((F(1), F(5, 6)), divmod(F(7, 3), F(3, 2)))
380        self.assertEqual((F(-2), F(2, 3)), divmod(F(-7, 3), F(3, 2)))
381        self.assertEqual(F(8, 27), F(2, 3) ** F(3))
382        self.assertEqual(F(27, 8), F(2, 3) ** F(-3))
383        self.assertTypedEquals(2.0, F(4) ** F(1, 2))
384        self.assertEqual(F(1, 1), +F(1, 1))
385        z = pow(F(-1), F(1, 2))
386        self.assertAlmostEqual(z.real, 0)
387        self.assertEqual(z.imag, 1)
388        # Regression test for #27539.
389        p = F(-1, 2) ** 0
390        self.assertEqual(p, F(1, 1))
391        self.assertEqual(p.numerator, 1)
392        self.assertEqual(p.denominator, 1)
393        p = F(-1, 2) ** -1
394        self.assertEqual(p, F(-2, 1))
395        self.assertEqual(p.numerator, -2)
396        self.assertEqual(p.denominator, 1)
397        p = F(-1, 2) ** -2
398        self.assertEqual(p, F(4, 1))
399        self.assertEqual(p.numerator, 4)
400        self.assertEqual(p.denominator, 1)
401
402    def testLargeArithmetic(self):
403        self.assertTypedEquals(
404            F(10101010100808080808080808101010101010000000000000000,
405              1010101010101010101010101011111111101010101010101010101010101),
406            F(10**35+1, 10**27+1) % F(10**27+1, 10**35-1)
407        )
408        self.assertTypedEquals(
409            F(7, 1901475900342344102245054808064),
410            F(-2**100, 3) % F(5, 2**100)
411        )
412        self.assertTypedTupleEquals(
413            (9999999999999999,
414             F(10101010100808080808080808101010101010000000000000000,
415               1010101010101010101010101011111111101010101010101010101010101)),
416            divmod(F(10**35+1, 10**27+1), F(10**27+1, 10**35-1))
417        )
418        self.assertTypedEquals(
419            -2 ** 200 // 15,
420            F(-2**100, 3) // F(5, 2**100)
421        )
422        self.assertTypedEquals(
423            1,
424            F(5, 2**100) // F(3, 2**100)
425        )
426        self.assertTypedEquals(
427            (1, F(2, 2**100)),
428            divmod(F(5, 2**100), F(3, 2**100))
429        )
430        self.assertTypedTupleEquals(
431            (-2 ** 200 // 15,
432             F(7, 1901475900342344102245054808064)),
433            divmod(F(-2**100, 3), F(5, 2**100))
434        )
435
436    def testMixedArithmetic(self):
437        self.assertTypedEquals(F(11, 10), F(1, 10) + 1)
438        self.assertTypedEquals(1.1, F(1, 10) + 1.0)
439        self.assertTypedEquals(1.1 + 0j, F(1, 10) + (1.0 + 0j))
440        self.assertTypedEquals(F(11, 10), 1 + F(1, 10))
441        self.assertTypedEquals(1.1, 1.0 + F(1, 10))
442        self.assertTypedEquals(1.1 + 0j, (1.0 + 0j) + F(1, 10))
443
444        self.assertTypedEquals(F(-9, 10), F(1, 10) - 1)
445        self.assertTypedEquals(-0.9, F(1, 10) - 1.0)
446        self.assertTypedEquals(-0.9 + 0j, F(1, 10) - (1.0 + 0j))
447        self.assertTypedEquals(F(9, 10), 1 - F(1, 10))
448        self.assertTypedEquals(0.9, 1.0 - F(1, 10))
449        self.assertTypedEquals(0.9 + 0j, (1.0 + 0j) - F(1, 10))
450
451        self.assertTypedEquals(F(1, 10), F(1, 10) * 1)
452        self.assertTypedEquals(0.1, F(1, 10) * 1.0)
453        self.assertTypedEquals(0.1 + 0j, F(1, 10) * (1.0 + 0j))
454        self.assertTypedEquals(F(1, 10), 1 * F(1, 10))
455        self.assertTypedEquals(0.1, 1.0 * F(1, 10))
456        self.assertTypedEquals(0.1 + 0j, (1.0 + 0j) * F(1, 10))
457
458        self.assertTypedEquals(F(1, 10), F(1, 10) / 1)
459        self.assertTypedEquals(0.1, F(1, 10) / 1.0)
460        self.assertTypedEquals(0.1 + 0j, F(1, 10) / (1.0 + 0j))
461        self.assertTypedEquals(F(10, 1), 1 / F(1, 10))
462        self.assertTypedEquals(10.0, 1.0 / F(1, 10))
463        self.assertTypedEquals(10.0 + 0j, (1.0 + 0j) / F(1, 10))
464
465        self.assertTypedEquals(0, F(1, 10) // 1)
466        self.assertTypedEquals(0.0, F(1, 10) // 1.0)
467        self.assertTypedEquals(10, 1 // F(1, 10))
468        self.assertTypedEquals(10**23, 10**22 // F(1, 10))
469        self.assertTypedEquals(1.0 // 0.1, 1.0 // F(1, 10))
470
471        self.assertTypedEquals(F(1, 10), F(1, 10) % 1)
472        self.assertTypedEquals(0.1, F(1, 10) % 1.0)
473        self.assertTypedEquals(F(0, 1), 1 % F(1, 10))
474        self.assertTypedEquals(1.0 % 0.1, 1.0 % F(1, 10))
475        self.assertTypedEquals(0.1, F(1, 10) % float('inf'))
476        self.assertTypedEquals(float('-inf'), F(1, 10) % float('-inf'))
477        self.assertTypedEquals(float('inf'), F(-1, 10) % float('inf'))
478        self.assertTypedEquals(-0.1, F(-1, 10) % float('-inf'))
479
480        self.assertTypedTupleEquals((0, F(1, 10)), divmod(F(1, 10), 1))
481        self.assertTypedTupleEquals(divmod(0.1, 1.0), divmod(F(1, 10), 1.0))
482        self.assertTypedTupleEquals((10, F(0)), divmod(1, F(1, 10)))
483        self.assertTypedTupleEquals(divmod(1.0, 0.1), divmod(1.0, F(1, 10)))
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        self.assertTypedTupleEquals(divmod(-0.1, float('inf')), divmod(F(-1, 10), float('inf')))
487        self.assertTypedTupleEquals(divmod(-0.1, float('-inf')), divmod(F(-1, 10), float('-inf')))
488
489        # ** has more interesting conversion rules.
490        self.assertTypedEquals(F(100, 1), F(1, 10) ** -2)
491        self.assertTypedEquals(F(100, 1), F(10, 1) ** 2)
492        self.assertTypedEquals(0.1, F(1, 10) ** 1.0)
493        self.assertTypedEquals(0.1 + 0j, F(1, 10) ** (1.0 + 0j))
494        self.assertTypedEquals(4 , 2 ** F(2, 1))
495        z = pow(-1, F(1, 2))
496        self.assertAlmostEqual(0, z.real)
497        self.assertEqual(1, z.imag)
498        self.assertTypedEquals(F(1, 4) , 2 ** F(-2, 1))
499        self.assertTypedEquals(2.0 , 4 ** F(1, 2))
500        self.assertTypedEquals(0.25, 2.0 ** F(-2, 1))
501        self.assertTypedEquals(1.0 + 0j, (1.0 + 0j) ** F(1, 10))
502        self.assertRaises(ZeroDivisionError, operator.pow,
503                          F(0, 1), -2)
504
505    def testMixingWithDecimal(self):
506        # Decimal refuses mixed arithmetic (but not mixed comparisons)
507        self.assertRaises(TypeError, operator.add,
508                          F(3,11), Decimal('3.1415926'))
509        self.assertRaises(TypeError, operator.add,
510                          Decimal('3.1415926'), F(3,11))
511
512    def testComparisons(self):
513        self.assertTrue(F(1, 2) < F(2, 3))
514        self.assertFalse(F(1, 2) < F(1, 2))
515        self.assertTrue(F(1, 2) <= F(2, 3))
516        self.assertTrue(F(1, 2) <= F(1, 2))
517        self.assertFalse(F(2, 3) <= F(1, 2))
518        self.assertTrue(F(1, 2) == F(1, 2))
519        self.assertFalse(F(1, 2) == F(1, 3))
520        self.assertFalse(F(1, 2) != F(1, 2))
521        self.assertTrue(F(1, 2) != F(1, 3))
522
523    def testComparisonsDummyRational(self):
524        self.assertTrue(F(1, 2) == DummyRational(1, 2))
525        self.assertTrue(DummyRational(1, 2) == F(1, 2))
526        self.assertFalse(F(1, 2) == DummyRational(3, 4))
527        self.assertFalse(DummyRational(3, 4) == F(1, 2))
528
529        self.assertTrue(F(1, 2) < DummyRational(3, 4))
530        self.assertFalse(F(1, 2) < DummyRational(1, 2))
531        self.assertFalse(F(1, 2) < DummyRational(1, 7))
532        self.assertFalse(F(1, 2) > DummyRational(3, 4))
533        self.assertFalse(F(1, 2) > DummyRational(1, 2))
534        self.assertTrue(F(1, 2) > DummyRational(1, 7))
535        self.assertTrue(F(1, 2) <= DummyRational(3, 4))
536        self.assertTrue(F(1, 2) <= DummyRational(1, 2))
537        self.assertFalse(F(1, 2) <= DummyRational(1, 7))
538        self.assertFalse(F(1, 2) >= DummyRational(3, 4))
539        self.assertTrue(F(1, 2) >= DummyRational(1, 2))
540        self.assertTrue(F(1, 2) >= DummyRational(1, 7))
541
542        self.assertTrue(DummyRational(1, 2) < F(3, 4))
543        self.assertFalse(DummyRational(1, 2) < F(1, 2))
544        self.assertFalse(DummyRational(1, 2) < F(1, 7))
545        self.assertFalse(DummyRational(1, 2) > F(3, 4))
546        self.assertFalse(DummyRational(1, 2) > F(1, 2))
547        self.assertTrue(DummyRational(1, 2) > F(1, 7))
548        self.assertTrue(DummyRational(1, 2) <= F(3, 4))
549        self.assertTrue(DummyRational(1, 2) <= F(1, 2))
550        self.assertFalse(DummyRational(1, 2) <= F(1, 7))
551        self.assertFalse(DummyRational(1, 2) >= F(3, 4))
552        self.assertTrue(DummyRational(1, 2) >= F(1, 2))
553        self.assertTrue(DummyRational(1, 2) >= F(1, 7))
554
555    def testComparisonsDummyFloat(self):
556        x = DummyFloat(1./3.)
557        y = F(1, 3)
558        self.assertTrue(x != y)
559        self.assertTrue(x < y or x > y)
560        self.assertFalse(x == y)
561        self.assertFalse(x <= y and x >= y)
562        self.assertTrue(y != x)
563        self.assertTrue(y < x or y > x)
564        self.assertFalse(y == x)
565        self.assertFalse(y <= x and y >= x)
566
567    def testMixedLess(self):
568        self.assertTrue(2 < F(5, 2))
569        self.assertFalse(2 < F(4, 2))
570        self.assertTrue(F(5, 2) < 3)
571        self.assertFalse(F(4, 2) < 2)
572
573        self.assertTrue(F(1, 2) < 0.6)
574        self.assertFalse(F(1, 2) < 0.4)
575        self.assertTrue(0.4 < F(1, 2))
576        self.assertFalse(0.5 < F(1, 2))
577
578        self.assertFalse(float('inf') < F(1, 2))
579        self.assertTrue(float('-inf') < F(0, 10))
580        self.assertFalse(float('nan') < F(-3, 7))
581        self.assertTrue(F(1, 2) < float('inf'))
582        self.assertFalse(F(17, 12) < float('-inf'))
583        self.assertFalse(F(144, -89) < float('nan'))
584
585    def testMixedLessEqual(self):
586        self.assertTrue(0.5 <= F(1, 2))
587        self.assertFalse(0.6 <= F(1, 2))
588        self.assertTrue(F(1, 2) <= 0.5)
589        self.assertFalse(F(1, 2) <= 0.4)
590        self.assertTrue(2 <= F(4, 2))
591        self.assertFalse(2 <= F(3, 2))
592        self.assertTrue(F(4, 2) <= 2)
593        self.assertFalse(F(5, 2) <= 2)
594
595        self.assertFalse(float('inf') <= F(1, 2))
596        self.assertTrue(float('-inf') <= F(0, 10))
597        self.assertFalse(float('nan') <= F(-3, 7))
598        self.assertTrue(F(1, 2) <= float('inf'))
599        self.assertFalse(F(17, 12) <= float('-inf'))
600        self.assertFalse(F(144, -89) <= float('nan'))
601
602    def testBigFloatComparisons(self):
603        # Because 10**23 can't be represented exactly as a float:
604        self.assertFalse(F(10**23) == float(10**23))
605        # The first test demonstrates why these are important.
606        self.assertFalse(1e23 < float(F(math.trunc(1e23) + 1)))
607        self.assertTrue(1e23 < F(math.trunc(1e23) + 1))
608        self.assertFalse(1e23 <= F(math.trunc(1e23) - 1))
609        self.assertTrue(1e23 > F(math.trunc(1e23) - 1))
610        self.assertFalse(1e23 >= F(math.trunc(1e23) + 1))
611
612    def testBigComplexComparisons(self):
613        self.assertFalse(F(10**23) == complex(10**23))
614        self.assertRaises(TypeError, operator.gt, F(10**23), complex(10**23))
615        self.assertRaises(TypeError, operator.le, F(10**23), complex(10**23))
616
617        x = F(3, 8)
618        z = complex(0.375, 0.0)
619        w = complex(0.375, 0.2)
620        self.assertTrue(x == z)
621        self.assertFalse(x != z)
622        self.assertFalse(x == w)
623        self.assertTrue(x != w)
624        for op in operator.lt, operator.le, operator.gt, operator.ge:
625            self.assertRaises(TypeError, op, x, z)
626            self.assertRaises(TypeError, op, z, x)
627            self.assertRaises(TypeError, op, x, w)
628            self.assertRaises(TypeError, op, w, x)
629
630    def testMixedEqual(self):
631        self.assertTrue(0.5 == F(1, 2))
632        self.assertFalse(0.6 == F(1, 2))
633        self.assertTrue(F(1, 2) == 0.5)
634        self.assertFalse(F(1, 2) == 0.4)
635        self.assertTrue(2 == F(4, 2))
636        self.assertFalse(2 == F(3, 2))
637        self.assertTrue(F(4, 2) == 2)
638        self.assertFalse(F(5, 2) == 2)
639        self.assertFalse(F(5, 2) == float('nan'))
640        self.assertFalse(float('nan') == F(3, 7))
641        self.assertFalse(F(5, 2) == float('inf'))
642        self.assertFalse(float('-inf') == F(2, 5))
643
644    def testStringification(self):
645        self.assertEqual("Fraction(7, 3)", repr(F(7, 3)))
646        self.assertEqual("Fraction(6283185307, 2000000000)",
647                         repr(F('3.1415926535')))
648        self.assertEqual("Fraction(-1, 100000000000000000000)",
649                         repr(F(1, -10**20)))
650        self.assertEqual("7/3", str(F(7, 3)))
651        self.assertEqual("7", str(F(7, 1)))
652
653    def testHash(self):
654        hmod = sys.hash_info.modulus
655        hinf = sys.hash_info.inf
656        self.assertEqual(hash(2.5), hash(F(5, 2)))
657        self.assertEqual(hash(10**50), hash(F(10**50)))
658        self.assertNotEqual(hash(float(10**23)), hash(F(10**23)))
659        self.assertEqual(hinf, hash(F(1, hmod)))
660        # Check that __hash__ produces the same value as hash(), for
661        # consistency with int and Decimal.  (See issue #10356.)
662        self.assertEqual(hash(F(-1)), F(-1).__hash__())
663
664    def testApproximatePi(self):
665        # Algorithm borrowed from
666        # http://docs.python.org/lib/decimal-recipes.html
667        three = F(3)
668        lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
669        while abs(s - lasts) > F(1, 10**9):
670            lasts = s
671            n, na = n+na, na+8
672            d, da = d+da, da+32
673            t = (t * n) / d
674            s += t
675        self.assertAlmostEqual(math.pi, s)
676
677    def testApproximateCos1(self):
678        # Algorithm borrowed from
679        # http://docs.python.org/lib/decimal-recipes.html
680        x = F(1)
681        i, lasts, s, fact, num, sign = 0, 0, F(1), 1, 1, 1
682        while abs(s - lasts) > F(1, 10**9):
683            lasts = s
684            i += 2
685            fact *= i * (i-1)
686            num *= x * x
687            sign *= -1
688            s += num / fact * sign
689        self.assertAlmostEqual(math.cos(1), s)
690
691    def test_copy_deepcopy_pickle(self):
692        r = F(13, 7)
693        dr = DummyFraction(13, 7)
694        self.assertEqual(r, loads(dumps(r)))
695        self.assertEqual(id(r), id(copy(r)))
696        self.assertEqual(id(r), id(deepcopy(r)))
697        self.assertNotEqual(id(dr), id(copy(dr)))
698        self.assertNotEqual(id(dr), id(deepcopy(dr)))
699        self.assertTypedEquals(dr, copy(dr))
700        self.assertTypedEquals(dr, deepcopy(dr))
701
702    def test_slots(self):
703        # Issue 4998
704        r = F(13, 7)
705        self.assertRaises(AttributeError, setattr, r, 'a', 10)
706
707    def test_int_subclass(self):
708        class myint(int):
709            def __mul__(self, other):
710                return type(self)(int(self) * int(other))
711            def __floordiv__(self, other):
712                return type(self)(int(self) // int(other))
713            def __mod__(self, other):
714                x = type(self)(int(self) % int(other))
715                return x
716            @property
717            def numerator(self):
718                return type(self)(int(self))
719            @property
720            def denominator(self):
721                return type(self)(1)
722
723        f = fractions.Fraction(myint(1 * 3), myint(2 * 3))
724        self.assertEqual(f.numerator, 1)
725        self.assertEqual(f.denominator, 2)
726        self.assertEqual(type(f.numerator), myint)
727        self.assertEqual(type(f.denominator), myint)
728
729
730if __name__ == '__main__':
731    unittest.main()
732