• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Tests for Lib/fractions.py."""
2
3from decimal import Decimal
4from test.test_support import run_unittest
5import math
6import numbers
7import operator
8import fractions
9import sys
10import unittest
11from copy import copy, deepcopy
12from cPickle import dumps, loads
13F = fractions.Fraction
14gcd = fractions.gcd
15
16# decorator for skipping tests on non-IEEE 754 platforms
17requires_IEEE_754 = unittest.skipUnless(
18    float.__getformat__("double").startswith("IEEE"),
19    "test requires IEEE 754 doubles")
20
21class DummyFloat(object):
22    """Dummy float class for testing comparisons with Fractions"""
23
24    def __init__(self, value):
25        if not isinstance(value, float):
26            raise TypeError("DummyFloat can only be initialized from float")
27        self.value = value
28
29    def _richcmp(self, other, op):
30        if isinstance(other, numbers.Rational):
31            return op(F.from_float(self.value), other)
32        elif isinstance(other, DummyFloat):
33            return op(self.value, other.value)
34        else:
35            return NotImplemented
36
37    def __eq__(self, other): return self._richcmp(other, operator.eq)
38    def __le__(self, other): return self._richcmp(other, operator.le)
39    def __lt__(self, other): return self._richcmp(other, operator.lt)
40    def __ge__(self, other): return self._richcmp(other, operator.ge)
41    def __gt__(self, other): return self._richcmp(other, operator.gt)
42
43    # shouldn't be calling __float__ at all when doing comparisons
44    def __float__(self):
45        assert False, "__float__ should not be invoked for comparisons"
46
47    # same goes for subtraction
48    def __sub__(self, other):
49        assert False, "__sub__ should not be invoked for comparisons"
50    __rsub__ = __sub__
51
52    # Silence Py3k warning
53    __hash__ = None
54
55
56class DummyRational(object):
57    """Test comparison of Fraction with a naive rational implementation."""
58
59    def __init__(self, num, den):
60        g = gcd(num, den)
61        self.num = num // g
62        self.den = den // g
63
64    def __eq__(self, other):
65        if isinstance(other, fractions.Fraction):
66            return (self.num == other._numerator and
67                    self.den == other._denominator)
68        else:
69            return NotImplemented
70
71    def __lt__(self, other):
72        return(self.num * other._denominator < self.den * other._numerator)
73
74    def __gt__(self, other):
75        return(self.num * other._denominator > self.den * other._numerator)
76
77    def __le__(self, other):
78        return(self.num * other._denominator <= self.den * other._numerator)
79
80    def __ge__(self, other):
81        return(self.num * other._denominator >= self.den * other._numerator)
82
83    # this class is for testing comparisons; conversion to float
84    # should never be used for a comparison, since it loses accuracy
85    def __float__(self):
86        assert False, "__float__ should not be invoked"
87
88    # Silence Py3k warning
89    __hash__ = None
90
91
92class DummyFraction(fractions.Fraction):
93    """Dummy Fraction subclass for copy and deepcopy testing."""
94
95class GcdTest(unittest.TestCase):
96
97    def testMisc(self):
98        self.assertEqual(0, gcd(0, 0))
99        self.assertEqual(1, gcd(1, 0))
100        self.assertEqual(-1, gcd(-1, 0))
101        self.assertEqual(1, gcd(0, 1))
102        self.assertEqual(-1, gcd(0, -1))
103        self.assertEqual(1, gcd(7, 1))
104        self.assertEqual(-1, gcd(7, -1))
105        self.assertEqual(1, gcd(-23, 15))
106        self.assertEqual(12, gcd(120, 84))
107        self.assertEqual(-12, gcd(84, -120))
108
109
110def _components(r):
111    return (r.numerator, r.denominator)
112
113
114class FractionTest(unittest.TestCase):
115
116    def assertTypedEquals(self, expected, actual):
117        """Asserts that both the types and values are the same."""
118        self.assertEqual(type(expected), type(actual))
119        self.assertEqual(expected, actual)
120
121    def assertRaisesMessage(self, exc_type, message,
122                            callable, *args, **kwargs):
123        """Asserts that callable(*args, **kwargs) raises exc_type(message)."""
124        try:
125            callable(*args, **kwargs)
126        except exc_type, e:
127            self.assertEqual(message, str(e))
128        else:
129            self.fail("%s not raised" % exc_type.__name__)
130
131    def testInit(self):
132        self.assertEqual((0, 1), _components(F()))
133        self.assertEqual((7, 1), _components(F(7)))
134        self.assertEqual((7, 3), _components(F(F(7, 3))))
135
136        self.assertEqual((-1, 1), _components(F(-1, 1)))
137        self.assertEqual((-1, 1), _components(F(1, -1)))
138        self.assertEqual((1, 1), _components(F(-2, -2)))
139        self.assertEqual((1, 2), _components(F(5, 10)))
140        self.assertEqual((7, 15), _components(F(7, 15)))
141        self.assertEqual((10**23, 1), _components(F(10**23)))
142
143        self.assertEqual((3, 77), _components(F(F(3, 7), 11)))
144        self.assertEqual((-9, 5), _components(F(2, F(-10, 9))))
145        self.assertEqual((2486, 2485), _components(F(F(22, 7), F(355, 113))))
146
147        self.assertRaisesMessage(ZeroDivisionError, "Fraction(12, 0)",
148                                 F, 12, 0)
149        self.assertRaises(TypeError, F, 1.5 + 3j)
150
151        self.assertRaises(TypeError, F, "3/2", 3)
152        self.assertRaises(TypeError, F, 3, 0j)
153        self.assertRaises(TypeError, F, 3, 1j)
154
155    @requires_IEEE_754
156    def testInitFromFloat(self):
157        self.assertEqual((5, 2), _components(F(2.5)))
158        self.assertEqual((0, 1), _components(F(-0.0)))
159        self.assertEqual((3602879701896397, 36028797018963968),
160                         _components(F(0.1)))
161        self.assertRaises(TypeError, F, float('nan'))
162        self.assertRaises(TypeError, F, float('inf'))
163        self.assertRaises(TypeError, F, float('-inf'))
164
165    def testInitFromDecimal(self):
166        self.assertEqual((11, 10),
167                         _components(F(Decimal('1.1'))))
168        self.assertEqual((7, 200),
169                         _components(F(Decimal('3.5e-2'))))
170        self.assertEqual((0, 1),
171                         _components(F(Decimal('.000e20'))))
172        self.assertRaises(TypeError, F, Decimal('nan'))
173        self.assertRaises(TypeError, F, Decimal('snan'))
174        self.assertRaises(TypeError, F, Decimal('inf'))
175        self.assertRaises(TypeError, F, Decimal('-inf'))
176
177    def testFromString(self):
178        self.assertEqual((5, 1), _components(F("5")))
179        self.assertEqual((3, 2), _components(F("3/2")))
180        self.assertEqual((3, 2), _components(F(" \n  +3/2")))
181        self.assertEqual((-3, 2), _components(F("-3/2  ")))
182        self.assertEqual((13, 2), _components(F("    013/02 \n  ")))
183        self.assertEqual((13, 2), _components(F(u"    013/02 \n  ")))
184
185        self.assertEqual((16, 5), _components(F(" 3.2 ")))
186        self.assertEqual((-16, 5), _components(F(u" -3.2 ")))
187        self.assertEqual((-3, 1), _components(F(u" -3. ")))
188        self.assertEqual((3, 5), _components(F(u" .6 ")))
189        self.assertEqual((1, 3125), _components(F("32.e-5")))
190        self.assertEqual((1000000, 1), _components(F("1E+06")))
191        self.assertEqual((-12300, 1), _components(F("-1.23e4")))
192        self.assertEqual((0, 1), _components(F(" .0e+0\t")))
193        self.assertEqual((0, 1), _components(F("-0.000e0")))
194
195
196        self.assertRaisesMessage(
197            ZeroDivisionError, "Fraction(3, 0)",
198            F, "3/0")
199        self.assertRaisesMessage(
200            ValueError, "Invalid literal for Fraction: '3/'",
201            F, "3/")
202        self.assertRaisesMessage(
203            ValueError, "Invalid literal for Fraction: '/2'",
204            F, "/2")
205        self.assertRaisesMessage(
206            ValueError, "Invalid literal for Fraction: '3 /2'",
207            F, "3 /2")
208        self.assertRaisesMessage(
209            # Denominators don't need a sign.
210            ValueError, "Invalid literal for Fraction: '3/+2'",
211            F, "3/+2")
212        self.assertRaisesMessage(
213            # Imitate float's parsing.
214            ValueError, "Invalid literal for Fraction: '+ 3/2'",
215            F, "+ 3/2")
216        self.assertRaisesMessage(
217            # Avoid treating '.' as a regex special character.
218            ValueError, "Invalid literal for Fraction: '3a2'",
219            F, "3a2")
220        self.assertRaisesMessage(
221            # Don't accept combinations of decimals and fractions.
222            ValueError, "Invalid literal for Fraction: '3/7.2'",
223            F, "3/7.2")
224        self.assertRaisesMessage(
225            # Don't accept combinations of decimals and fractions.
226            ValueError, "Invalid literal for Fraction: '3.2/7'",
227            F, "3.2/7")
228        self.assertRaisesMessage(
229            # Allow 3. and .3, but not .
230            ValueError, "Invalid literal for Fraction: '.'",
231            F, ".")
232
233    def testImmutable(self):
234        r = F(7, 3)
235        r.__init__(2, 15)
236        self.assertEqual((7, 3), _components(r))
237
238        self.assertRaises(AttributeError, setattr, r, 'numerator', 12)
239        self.assertRaises(AttributeError, setattr, r, 'denominator', 6)
240        self.assertEqual((7, 3), _components(r))
241
242        # But if you _really_ need to:
243        r._numerator = 4
244        r._denominator = 2
245        self.assertEqual((4, 2), _components(r))
246        # Which breaks some important operations:
247        self.assertNotEqual(F(4, 2), r)
248
249    def testFromFloat(self):
250        self.assertRaises(TypeError, F.from_float, 3+4j)
251        self.assertEqual((10, 1), _components(F.from_float(10)))
252        bigint = 1234567890123456789
253        self.assertEqual((bigint, 1), _components(F.from_float(bigint)))
254        self.assertEqual((0, 1), _components(F.from_float(-0.0)))
255        self.assertEqual((10, 1), _components(F.from_float(10.0)))
256        self.assertEqual((-5, 2), _components(F.from_float(-2.5)))
257        self.assertEqual((99999999999999991611392, 1),
258                         _components(F.from_float(1e23)))
259        self.assertEqual(float(10**23), float(F.from_float(1e23)))
260        self.assertEqual((3602879701896397, 1125899906842624),
261                         _components(F.from_float(3.2)))
262        self.assertEqual(3.2, float(F.from_float(3.2)))
263
264        inf = 1e1000
265        nan = inf - inf
266        self.assertRaisesMessage(
267            TypeError, "Cannot convert inf to Fraction.",
268            F.from_float, inf)
269        self.assertRaisesMessage(
270            TypeError, "Cannot convert -inf to Fraction.",
271            F.from_float, -inf)
272        self.assertRaisesMessage(
273            TypeError, "Cannot convert nan to Fraction.",
274            F.from_float, nan)
275
276    def testFromDecimal(self):
277        self.assertRaises(TypeError, F.from_decimal, 3+4j)
278        self.assertEqual(F(10, 1), F.from_decimal(10))
279        self.assertEqual(F(0), F.from_decimal(Decimal("-0")))
280        self.assertEqual(F(5, 10), F.from_decimal(Decimal("0.5")))
281        self.assertEqual(F(5, 1000), F.from_decimal(Decimal("5e-3")))
282        self.assertEqual(F(5000), F.from_decimal(Decimal("5e3")))
283        self.assertEqual(1 - F(1, 10**30),
284                         F.from_decimal(Decimal("0." + "9" * 30)))
285
286        self.assertRaisesMessage(
287            TypeError, "Cannot convert Infinity to Fraction.",
288            F.from_decimal, Decimal("inf"))
289        self.assertRaisesMessage(
290            TypeError, "Cannot convert -Infinity to Fraction.",
291            F.from_decimal, Decimal("-inf"))
292        self.assertRaisesMessage(
293            TypeError, "Cannot convert NaN to Fraction.",
294            F.from_decimal, Decimal("nan"))
295        self.assertRaisesMessage(
296            TypeError, "Cannot convert sNaN to Fraction.",
297            F.from_decimal, Decimal("snan"))
298
299    def testLimitDenominator(self):
300        rpi = F('3.1415926535897932')
301        self.assertEqual(rpi.limit_denominator(10000), F(355, 113))
302        self.assertEqual(-rpi.limit_denominator(10000), F(-355, 113))
303        self.assertEqual(rpi.limit_denominator(113), F(355, 113))
304        self.assertEqual(rpi.limit_denominator(112), F(333, 106))
305        self.assertEqual(F(201, 200).limit_denominator(100), F(1))
306        self.assertEqual(F(201, 200).limit_denominator(101), F(102, 101))
307        self.assertEqual(F(0).limit_denominator(10000), F(0))
308        for i in (0, -1):
309            self.assertRaisesMessage(
310                ValueError, "max_denominator should be at least 1",
311                F(1).limit_denominator, i)
312
313    def testConversions(self):
314        self.assertTypedEquals(-1, math.trunc(F(-11, 10)))
315        self.assertTypedEquals(-1, int(F(-11, 10)))
316        self.assertTypedEquals(1, math.trunc(F(11, 10)))
317        self.assertEqual(False, bool(F(0, 1)))
318        self.assertEqual(True, bool(F(3, 2)))
319        self.assertTypedEquals(0.1, float(F(1, 10)))
320
321        # Check that __float__ isn't implemented by converting the
322        # numerator and denominator to float before dividing.
323        self.assertRaises(OverflowError, float, long('2'*400+'7'))
324        self.assertAlmostEqual(2.0/3,
325                                float(F(long('2'*400+'7'), long('3'*400+'1'))))
326
327        self.assertTypedEquals(0.1+0j, complex(F(1,10)))
328
329
330    def testArithmetic(self):
331        self.assertEqual(F(1, 2), F(1, 10) + F(2, 5))
332        self.assertEqual(F(-3, 10), F(1, 10) - F(2, 5))
333        self.assertEqual(F(1, 25), F(1, 10) * F(2, 5))
334        self.assertEqual(F(1, 4), F(1, 10) / F(2, 5))
335        self.assertTypedEquals(2, F(9, 10) // F(2, 5))
336        self.assertTypedEquals(10**23, F(10**23, 1) // F(1))
337        self.assertEqual(F(2, 3), F(-7, 3) % F(3, 2))
338        self.assertEqual(F(8, 27), F(2, 3) ** F(3))
339        self.assertEqual(F(27, 8), F(2, 3) ** F(-3))
340        self.assertTypedEquals(2.0, F(4) ** F(1, 2))
341        self.assertEqual(F(1, 1), +F(1, 1))
342        # Will return 1j in 3.0:
343        self.assertRaises(ValueError, pow, F(-1), F(1, 2))
344
345    def testMixedArithmetic(self):
346        self.assertTypedEquals(F(11, 10), F(1, 10) + 1)
347        self.assertTypedEquals(1.1, F(1, 10) + 1.0)
348        self.assertTypedEquals(1.1 + 0j, F(1, 10) + (1.0 + 0j))
349        self.assertTypedEquals(F(11, 10), 1 + F(1, 10))
350        self.assertTypedEquals(1.1, 1.0 + F(1, 10))
351        self.assertTypedEquals(1.1 + 0j, (1.0 + 0j) + F(1, 10))
352
353        self.assertTypedEquals(F(-9, 10), F(1, 10) - 1)
354        self.assertTypedEquals(-0.9, F(1, 10) - 1.0)
355        self.assertTypedEquals(-0.9 + 0j, F(1, 10) - (1.0 + 0j))
356        self.assertTypedEquals(F(9, 10), 1 - F(1, 10))
357        self.assertTypedEquals(0.9, 1.0 - F(1, 10))
358        self.assertTypedEquals(0.9 + 0j, (1.0 + 0j) - F(1, 10))
359
360        self.assertTypedEquals(F(1, 10), F(1, 10) * 1)
361        self.assertTypedEquals(0.1, F(1, 10) * 1.0)
362        self.assertTypedEquals(0.1 + 0j, F(1, 10) * (1.0 + 0j))
363        self.assertTypedEquals(F(1, 10), 1 * F(1, 10))
364        self.assertTypedEquals(0.1, 1.0 * F(1, 10))
365        self.assertTypedEquals(0.1 + 0j, (1.0 + 0j) * F(1, 10))
366
367        self.assertTypedEquals(F(1, 10), F(1, 10) / 1)
368        self.assertTypedEquals(0.1, F(1, 10) / 1.0)
369        self.assertTypedEquals(0.1 + 0j, F(1, 10) / (1.0 + 0j))
370        self.assertTypedEquals(F(10, 1), 1 / F(1, 10))
371        self.assertTypedEquals(10.0, 1.0 / F(1, 10))
372        self.assertTypedEquals(10.0 + 0j, (1.0 + 0j) / F(1, 10))
373
374        self.assertTypedEquals(0, F(1, 10) // 1)
375        self.assertTypedEquals(0.0, F(1, 10) // 1.0)
376        self.assertTypedEquals(10, 1 // F(1, 10))
377        self.assertTypedEquals(10**23, 10**22 // F(1, 10))
378        self.assertTypedEquals(10.0, 1.0 // F(1, 10))
379
380        self.assertTypedEquals(F(1, 10), F(1, 10) % 1)
381        self.assertTypedEquals(0.1, F(1, 10) % 1.0)
382        self.assertTypedEquals(F(0, 1), 1 % F(1, 10))
383        self.assertTypedEquals(0.0, 1.0 % F(1, 10))
384
385        # No need for divmod since we don't override it.
386
387        # ** has more interesting conversion rules.
388        self.assertTypedEquals(F(100, 1), F(1, 10) ** -2)
389        self.assertTypedEquals(F(100, 1), F(10, 1) ** 2)
390        self.assertTypedEquals(0.1, F(1, 10) ** 1.0)
391        self.assertTypedEquals(0.1 + 0j, F(1, 10) ** (1.0 + 0j))
392        self.assertTypedEquals(4 , 2 ** F(2, 1))
393        # Will return 1j in 3.0:
394        self.assertRaises(ValueError, pow, (-1), F(1, 2))
395        self.assertTypedEquals(F(1, 4) , 2 ** F(-2, 1))
396        self.assertTypedEquals(2.0 , 4 ** F(1, 2))
397        self.assertTypedEquals(0.25, 2.0 ** F(-2, 1))
398        self.assertTypedEquals(1.0 + 0j, (1.0 + 0j) ** F(1, 10))
399
400    def testMixingWithDecimal(self):
401        # Decimal refuses mixed comparisons.
402        self.assertRaisesMessage(
403            TypeError,
404            "unsupported operand type(s) for +: 'Fraction' and 'Decimal'",
405            operator.add, F(3,11), Decimal('3.1415926'))
406        self.assertRaisesMessage(
407            TypeError,
408            "unsupported operand type(s) for +: 'Decimal' and 'Fraction'",
409            operator.add, Decimal('3.1415926'), F(3,11))
410        self.assertNotEqual(F(5, 2), Decimal('2.5'))
411
412    def testComparisons(self):
413        self.assertTrue(F(1, 2) < F(2, 3))
414        self.assertFalse(F(1, 2) < F(1, 2))
415        self.assertTrue(F(1, 2) <= F(2, 3))
416        self.assertTrue(F(1, 2) <= F(1, 2))
417        self.assertFalse(F(2, 3) <= F(1, 2))
418        self.assertTrue(F(1, 2) == F(1, 2))
419        self.assertFalse(F(1, 2) == F(1, 3))
420        self.assertFalse(F(1, 2) != F(1, 2))
421        self.assertTrue(F(1, 2) != F(1, 3))
422
423    def testComparisonsDummyRational(self):
424        self.assertTrue(F(1, 2) == DummyRational(1, 2))
425        self.assertTrue(DummyRational(1, 2) == F(1, 2))
426        self.assertFalse(F(1, 2) == DummyRational(3, 4))
427        self.assertFalse(DummyRational(3, 4) == F(1, 2))
428
429        self.assertTrue(F(1, 2) < DummyRational(3, 4))
430        self.assertFalse(F(1, 2) < DummyRational(1, 2))
431        self.assertFalse(F(1, 2) < DummyRational(1, 7))
432        self.assertFalse(F(1, 2) > DummyRational(3, 4))
433        self.assertFalse(F(1, 2) > DummyRational(1, 2))
434        self.assertTrue(F(1, 2) > DummyRational(1, 7))
435        self.assertTrue(F(1, 2) <= DummyRational(3, 4))
436        self.assertTrue(F(1, 2) <= DummyRational(1, 2))
437        self.assertFalse(F(1, 2) <= DummyRational(1, 7))
438        self.assertFalse(F(1, 2) >= DummyRational(3, 4))
439        self.assertTrue(F(1, 2) >= DummyRational(1, 2))
440        self.assertTrue(F(1, 2) >= DummyRational(1, 7))
441
442        self.assertTrue(DummyRational(1, 2) < F(3, 4))
443        self.assertFalse(DummyRational(1, 2) < F(1, 2))
444        self.assertFalse(DummyRational(1, 2) < F(1, 7))
445        self.assertFalse(DummyRational(1, 2) > F(3, 4))
446        self.assertFalse(DummyRational(1, 2) > F(1, 2))
447        self.assertTrue(DummyRational(1, 2) > F(1, 7))
448        self.assertTrue(DummyRational(1, 2) <= F(3, 4))
449        self.assertTrue(DummyRational(1, 2) <= F(1, 2))
450        self.assertFalse(DummyRational(1, 2) <= F(1, 7))
451        self.assertFalse(DummyRational(1, 2) >= F(3, 4))
452        self.assertTrue(DummyRational(1, 2) >= F(1, 2))
453        self.assertTrue(DummyRational(1, 2) >= F(1, 7))
454
455    def testComparisonsDummyFloat(self):
456        x = DummyFloat(1./3.)
457        y = F(1, 3)
458        self.assertTrue(x != y)
459        self.assertTrue(x < y or x > y)
460        self.assertFalse(x == y)
461        self.assertFalse(x <= y and x >= y)
462        self.assertTrue(y != x)
463        self.assertTrue(y < x or y > x)
464        self.assertFalse(y == x)
465        self.assertFalse(y <= x and y >= x)
466
467    def testMixedLess(self):
468        self.assertTrue(2 < F(5, 2))
469        self.assertFalse(2 < F(4, 2))
470        self.assertTrue(F(5, 2) < 3)
471        self.assertFalse(F(4, 2) < 2)
472
473        self.assertTrue(F(1, 2) < 0.6)
474        self.assertFalse(F(1, 2) < 0.4)
475        self.assertTrue(0.4 < F(1, 2))
476        self.assertFalse(0.5 < F(1, 2))
477
478        self.assertFalse(float('inf') < F(1, 2))
479        self.assertTrue(float('-inf') < F(0, 10))
480        self.assertFalse(float('nan') < F(-3, 7))
481        self.assertTrue(F(1, 2) < float('inf'))
482        self.assertFalse(F(17, 12) < float('-inf'))
483        self.assertFalse(F(144, -89) < float('nan'))
484
485    def testMixedLessEqual(self):
486        self.assertTrue(0.5 <= F(1, 2))
487        self.assertFalse(0.6 <= F(1, 2))
488        self.assertTrue(F(1, 2) <= 0.5)
489        self.assertFalse(F(1, 2) <= 0.4)
490        self.assertTrue(2 <= F(4, 2))
491        self.assertFalse(2 <= F(3, 2))
492        self.assertTrue(F(4, 2) <= 2)
493        self.assertFalse(F(5, 2) <= 2)
494
495        self.assertFalse(float('inf') <= F(1, 2))
496        self.assertTrue(float('-inf') <= F(0, 10))
497        self.assertFalse(float('nan') <= F(-3, 7))
498        self.assertTrue(F(1, 2) <= float('inf'))
499        self.assertFalse(F(17, 12) <= float('-inf'))
500        self.assertFalse(F(144, -89) <= float('nan'))
501
502    def testBigFloatComparisons(self):
503        # Because 10**23 can't be represented exactly as a float:
504        self.assertFalse(F(10**23) == float(10**23))
505        # The first test demonstrates why these are important.
506        self.assertFalse(1e23 < float(F(math.trunc(1e23) + 1)))
507        self.assertTrue(1e23 < F(math.trunc(1e23) + 1))
508        self.assertFalse(1e23 <= F(math.trunc(1e23) - 1))
509        self.assertTrue(1e23 > F(math.trunc(1e23) - 1))
510        self.assertFalse(1e23 >= F(math.trunc(1e23) + 1))
511
512    def testBigComplexComparisons(self):
513        self.assertFalse(F(10**23) == complex(10**23))
514        self.assertRaises(TypeError, operator.gt, F(10**23), complex(10**23))
515        self.assertRaises(TypeError, operator.le, F(10**23), complex(10**23))
516
517        x = F(3, 8)
518        z = complex(0.375, 0.0)
519        w = complex(0.375, 0.2)
520        self.assertTrue(x == z)
521        self.assertFalse(x != z)
522        self.assertFalse(x == w)
523        self.assertTrue(x != w)
524        for op in operator.lt, operator.le, operator.gt, operator.ge:
525            self.assertRaises(TypeError, op, x, z)
526            self.assertRaises(TypeError, op, z, x)
527            self.assertRaises(TypeError, op, x, w)
528            self.assertRaises(TypeError, op, w, x)
529
530    def testMixedEqual(self):
531        self.assertTrue(0.5 == F(1, 2))
532        self.assertFalse(0.6 == F(1, 2))
533        self.assertTrue(F(1, 2) == 0.5)
534        self.assertFalse(F(1, 2) == 0.4)
535        self.assertTrue(2 == F(4, 2))
536        self.assertFalse(2 == F(3, 2))
537        self.assertTrue(F(4, 2) == 2)
538        self.assertFalse(F(5, 2) == 2)
539        self.assertFalse(F(5, 2) == float('nan'))
540        self.assertFalse(float('nan') == F(3, 7))
541        self.assertFalse(F(5, 2) == float('inf'))
542        self.assertFalse(float('-inf') == F(2, 5))
543
544    def testStringification(self):
545        self.assertEqual("Fraction(7, 3)", repr(F(7, 3)))
546        self.assertEqual("Fraction(6283185307, 2000000000)",
547                         repr(F('3.1415926535')))
548        self.assertEqual("Fraction(-1, 100000000000000000000)",
549                         repr(F(1, -10**20)))
550        self.assertEqual("7/3", str(F(7, 3)))
551        self.assertEqual("7", str(F(7, 1)))
552
553    def testHash(self):
554        self.assertEqual(hash(2.5), hash(F(5, 2)))
555        self.assertEqual(hash(10**50), hash(F(10**50)))
556        self.assertNotEqual(hash(float(10**23)), hash(F(10**23)))
557
558    def testApproximatePi(self):
559        # Algorithm borrowed from
560        # http://docs.python.org/lib/decimal-recipes.html
561        three = F(3)
562        lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
563        while abs(s - lasts) > F(1, 10**9):
564            lasts = s
565            n, na = n+na, na+8
566            d, da = d+da, da+32
567            t = (t * n) / d
568            s += t
569        self.assertAlmostEqual(math.pi, s)
570
571    def testApproximateCos1(self):
572        # Algorithm borrowed from
573        # http://docs.python.org/lib/decimal-recipes.html
574        x = F(1)
575        i, lasts, s, fact, num, sign = 0, 0, F(1), 1, 1, 1
576        while abs(s - lasts) > F(1, 10**9):
577            lasts = s
578            i += 2
579            fact *= i * (i-1)
580            num *= x * x
581            sign *= -1
582            s += num / fact * sign
583        self.assertAlmostEqual(math.cos(1), s)
584
585    def test_copy_deepcopy_pickle(self):
586        r = F(13, 7)
587        dr = DummyFraction(13, 7)
588        self.assertEqual(r, loads(dumps(r)))
589        self.assertEqual(id(r), id(copy(r)))
590        self.assertEqual(id(r), id(deepcopy(r)))
591        self.assertNotEqual(id(dr), id(copy(dr)))
592        self.assertNotEqual(id(dr), id(deepcopy(dr)))
593        self.assertTypedEquals(dr, copy(dr))
594        self.assertTypedEquals(dr, deepcopy(dr))
595
596    def test_slots(self):
597        # Issue 4998
598        r = F(13, 7)
599        self.assertRaises(AttributeError, setattr, r, 'a', 10)
600
601def test_main():
602    run_unittest(FractionTest, GcdTest)
603
604if __name__ == '__main__':
605    test_main()
606