Spaces:
Sleeping
Sleeping
File size: 5,797 Bytes
6a86ad5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
"""
test_pythonmpq.py
Test the PythonMPQ class for consistency with gmpy2's mpq type. If gmpy2 is
installed run the same tests for both.
"""
from fractions import Fraction
from decimal import Decimal
import pickle
from typing import Callable, List, Tuple, Type
from sympy.testing.pytest import raises
from sympy.external.pythonmpq import PythonMPQ
#
# If gmpy2 is installed then run the tests for both mpq and PythonMPQ.
# That should ensure consistency between the implementation here and mpq.
#
rational_types: List[Tuple[Callable, Type, Callable, Type]]
rational_types = [(PythonMPQ, PythonMPQ, int, int)]
try:
from gmpy2 import mpq, mpz
rational_types.append((mpq, type(mpq(1)), mpz, type(mpz(1))))
except ImportError:
pass
def test_PythonMPQ():
#
# Test PythonMPQ and also mpq if gmpy/gmpy2 is installed.
#
for Q, TQ, Z, TZ in rational_types:
def check_Q(q):
assert isinstance(q, TQ)
assert isinstance(q.numerator, TZ)
assert isinstance(q.denominator, TZ)
return q.numerator, q.denominator
# Check construction from different types
assert check_Q(Q(3)) == (3, 1)
assert check_Q(Q(3, 5)) == (3, 5)
assert check_Q(Q(Q(3, 5))) == (3, 5)
assert check_Q(Q(0.5)) == (1, 2)
assert check_Q(Q('0.5')) == (1, 2)
assert check_Q(Q(Fraction(3, 5))) == (3, 5)
# https://github.com/aleaxit/gmpy/issues/327
if Q is PythonMPQ:
assert check_Q(Q(Decimal('0.6'))) == (3, 5)
# Invalid types
raises(TypeError, lambda: Q([]))
raises(TypeError, lambda: Q([], []))
# Check normalisation of signs
assert check_Q(Q(2, 3)) == (2, 3)
assert check_Q(Q(-2, 3)) == (-2, 3)
assert check_Q(Q(2, -3)) == (-2, 3)
assert check_Q(Q(-2, -3)) == (2, 3)
# Check gcd calculation
assert check_Q(Q(12, 8)) == (3, 2)
# __int__/__float__
assert int(Q(5, 3)) == 1
assert int(Q(-5, 3)) == -1
assert float(Q(5, 2)) == 2.5
assert float(Q(-5, 2)) == -2.5
# __str__/__repr__
assert str(Q(2, 1)) == "2"
assert str(Q(1, 2)) == "1/2"
if Q is PythonMPQ:
assert repr(Q(2, 1)) == "MPQ(2,1)"
assert repr(Q(1, 2)) == "MPQ(1,2)"
else:
assert repr(Q(2, 1)) == "mpq(2,1)"
assert repr(Q(1, 2)) == "mpq(1,2)"
# __bool__
assert bool(Q(1, 2)) is True
assert bool(Q(0)) is False
# __eq__/__ne__
assert (Q(2, 3) == Q(2, 3)) is True
assert (Q(2, 3) == Q(2, 5)) is False
assert (Q(2, 3) != Q(2, 3)) is False
assert (Q(2, 3) != Q(2, 5)) is True
# __hash__
assert hash(Q(3, 5)) == hash(Fraction(3, 5))
# __reduce__
q = Q(2, 3)
assert pickle.loads(pickle.dumps(q)) == q
# __ge__/__gt__/__le__/__lt__
assert (Q(1, 3) < Q(2, 3)) is True
assert (Q(2, 3) < Q(2, 3)) is False
assert (Q(2, 3) < Q(1, 3)) is False
assert (Q(-2, 3) < Q(1, 3)) is True
assert (Q(1, 3) < Q(-2, 3)) is False
assert (Q(1, 3) <= Q(2, 3)) is True
assert (Q(2, 3) <= Q(2, 3)) is True
assert (Q(2, 3) <= Q(1, 3)) is False
assert (Q(-2, 3) <= Q(1, 3)) is True
assert (Q(1, 3) <= Q(-2, 3)) is False
assert (Q(1, 3) > Q(2, 3)) is False
assert (Q(2, 3) > Q(2, 3)) is False
assert (Q(2, 3) > Q(1, 3)) is True
assert (Q(-2, 3) > Q(1, 3)) is False
assert (Q(1, 3) > Q(-2, 3)) is True
assert (Q(1, 3) >= Q(2, 3)) is False
assert (Q(2, 3) >= Q(2, 3)) is True
assert (Q(2, 3) >= Q(1, 3)) is True
assert (Q(-2, 3) >= Q(1, 3)) is False
assert (Q(1, 3) >= Q(-2, 3)) is True
# __abs__/__pos__/__neg__
assert abs(Q(2, 3)) == abs(Q(-2, 3)) == Q(2, 3)
assert +Q(2, 3) == Q(2, 3)
assert -Q(2, 3) == Q(-2, 3)
# __add__/__radd__
assert Q(2, 3) + Q(5, 7) == Q(29, 21)
assert Q(2, 3) + 1 == Q(5, 3)
assert 1 + Q(2, 3) == Q(5, 3)
raises(TypeError, lambda: [] + Q(1))
raises(TypeError, lambda: Q(1) + [])
# __sub__/__rsub__
assert Q(2, 3) - Q(5, 7) == Q(-1, 21)
assert Q(2, 3) - 1 == Q(-1, 3)
assert 1 - Q(2, 3) == Q(1, 3)
raises(TypeError, lambda: [] - Q(1))
raises(TypeError, lambda: Q(1) - [])
# __mul__/__rmul__
assert Q(2, 3) * Q(5, 7) == Q(10, 21)
assert Q(2, 3) * 1 == Q(2, 3)
assert 1 * Q(2, 3) == Q(2, 3)
raises(TypeError, lambda: [] * Q(1))
raises(TypeError, lambda: Q(1) * [])
# __pow__/__rpow__
assert Q(2, 3) ** 2 == Q(4, 9)
assert Q(2, 3) ** 1 == Q(2, 3)
assert Q(-2, 3) ** 2 == Q(4, 9)
assert Q(-2, 3) ** -1 == Q(-3, 2)
if Q is PythonMPQ:
raises(TypeError, lambda: 1 ** Q(2, 3))
raises(TypeError, lambda: Q(1, 4) ** Q(1, 2))
raises(TypeError, lambda: [] ** Q(1))
raises(TypeError, lambda: Q(1) ** [])
# __div__/__rdiv__
assert Q(2, 3) / Q(5, 7) == Q(14, 15)
assert Q(2, 3) / 1 == Q(2, 3)
assert 1 / Q(2, 3) == Q(3, 2)
raises(TypeError, lambda: [] / Q(1))
raises(TypeError, lambda: Q(1) / [])
raises(ZeroDivisionError, lambda: Q(1, 2) / Q(0))
# __divmod__
if Q is PythonMPQ:
raises(TypeError, lambda: Q(2, 3) // Q(1, 3))
raises(TypeError, lambda: Q(2, 3) % Q(1, 3))
raises(TypeError, lambda: 1 // Q(1, 3))
raises(TypeError, lambda: 1 % Q(1, 3))
raises(TypeError, lambda: Q(2, 3) // 1)
raises(TypeError, lambda: Q(2, 3) % 1)
|