11"""Tests for Lib/fractions.py."""
22
3+ import cmath
34from decimal import Decimal
45from test .support import requires_IEEE_754
56import math
@@ -91,6 +92,170 @@ class DummyFraction(fractions.Fraction):
9192def _components (r ):
9293 return (r .numerator , r .denominator )
9394
95+ def is_eq (a , b ):
96+ return type (a ) == type (b ) and (a == b or math .isclose (a , b ))
97+
98+ class One :
99+ def __mul__ (self , other ):
100+ if isinstance (other , F ):
101+ return NotImplemented
102+ return other
103+ def __rmul__ (self , other ):
104+ return other
105+ def __truediv__ (self , other ):
106+ if isinstance (other , F ):
107+ return NotImplemented
108+ return 1 / other
109+ def __rtruediv__ (self , other ):
110+ return other
111+ def __mod__ (self , other ):
112+ if isinstance (other , F ):
113+ return NotImplemented
114+ return 1 % other
115+ def __rmod__ (self , other ):
116+ return other % 1
117+ def __pow__ (self , other ):
118+ if isinstance (other , F ):
119+ return NotImplemented
120+ return self
121+ def __rpow__ (self , other ):
122+ return other
123+ One = One ()
124+
125+ class Rat :
126+ def __init__ (self , n , d ):
127+ self .numerator = n
128+ self .denominator = d
129+ def __mul__ (self , other ):
130+ if isinstance (other , F ):
131+ return NotImplemented
132+ return self .__class__ (self .numerator * other .numerator ,
133+ self .denominator * other .denominator )
134+ def __rmul__ (self , other ):
135+ return self .__class__ (other .numerator * self .numerator ,
136+ other .denominator * self .denominator )
137+ def __truediv__ (self , other ):
138+ if isinstance (other , F ):
139+ return NotImplemented
140+ return self .__class__ (self .numerator * other .denominator ,
141+ self .denominator * other .numerator )
142+ def __rtruediv__ (self , other ):
143+ return self .__class__ (other .numerator * self .denominator ,
144+ other .denominator * self .numerator )
145+ def __mod__ (self , other ):
146+ if isinstance (other , F ):
147+ return NotImplemented
148+ d = self .denominator * other .numerator
149+ return self .__class__ (self .numerator * other .denominator % d , d )
150+ def __rmod__ (self , other ):
151+ d = other .denominator * self .numerator
152+ return self .__class__ (other .numerator * self .denominator % d , d )
153+
154+ return self .__class__ (other .numerator / self .numerator ,
155+ other .denominator / self .denominator )
156+ def __pow__ (self , other ):
157+ if isinstance (other , F ):
158+ return NotImplemented
159+ return self .__class__ (self .numerator ** other ,
160+ self .denominator ** other )
161+ def __float__ (self ):
162+ return self .numerator / self .denominator
163+ def __eq__ (self , other ):
164+ if self .__class__ != other .__class__ :
165+ return NotImplemented
166+ return (is_eq (self .numerator , other .numerator ) and
167+ is_eq (self .denominator , other .denominator ))
168+ def __repr__ (self ):
169+ return f'{ self .__class__ .__name__ } ({ self .numerator !r} , { self .denominator !r} )'
170+ numbers .Rational .register (Rat )
171+
172+ class Root :
173+ def __init__ (self , v , n = F (2 )):
174+ self .base = v
175+ self .degree = n
176+ def __mul__ (self , other ):
177+ if isinstance (other , F ):
178+ return NotImplemented
179+ return self .__class__ (self .base * other ** self .degree , self .degree )
180+ def __rmul__ (self , other ):
181+ return self .__class__ (other ** self .degree * self .base , self .degree )
182+ def __truediv__ (self , other ):
183+ if isinstance (other , F ):
184+ return NotImplemented
185+ return self .__class__ (self .base / other ** self .degree , self .degree )
186+ def __rtruediv__ (self , other ):
187+ return self .__class__ (other ** self .degree / self .base , self .degree )
188+ def __pow__ (self , other ):
189+ if isinstance (other , F ):
190+ return NotImplemented
191+ return self .__class__ (self .base , self .degree / other )
192+ def __float__ (self ):
193+ return float (self .base ) ** (1 / float (self .degree ))
194+ def __eq__ (self , other ):
195+ if self .__class__ != other .__class__ :
196+ return NotImplemented
197+ return is_eq (self .base , other .base ) and is_eq (self .degree , other .degree )
198+ def __repr__ (self ):
199+ return f'{ self .__class__ .__name__ } ({ self .base !r} , { self .degree !r} )'
200+ numbers .Real .register (Root )
201+
202+ class Polar :
203+ def __init__ (self , r , phi ):
204+ self .r = r
205+ self .phi = phi
206+ def __mul__ (self , other ):
207+ if isinstance (other , F ):
208+ return NotImplemented
209+ return self .__class__ (self .r * other , self .phi )
210+ def __rmul__ (self , other ):
211+ return self .__class__ (other * self .r , self .phi )
212+ def __truediv__ (self , other ):
213+ if isinstance (other , F ):
214+ return NotImplemented
215+ return self .__class__ (self .r / other , self .phi )
216+ def __rtruediv__ (self , other ):
217+ return self .__class__ (other / self .r , - self .phi )
218+ def __pow__ (self , other ):
219+ if isinstance (other , F ):
220+ return NotImplemented
221+ return self .__class__ (self .r ** other , self .phi * other )
222+ def __eq__ (self , other ):
223+ if self .__class__ != other .__class__ :
224+ return NotImplemented
225+ return is_eq (self .r , other .r ) and is_eq (self .phi , other .phi )
226+ def __repr__ (self ):
227+ return f'{ self .__class__ .__name__ } ({ self .r !r} , { self .phi !r} )'
228+ numbers .Complex .register (Polar )
229+
230+ class Rect :
231+ def __init__ (self , x , y ):
232+ self .x = x
233+ self .y = y
234+ def __mul__ (self , other ):
235+ if isinstance (other , F ):
236+ return NotImplemented
237+ return self .__class__ (self .x * other , self .y * other )
238+ def __rmul__ (self , other ):
239+ return self .__class__ (other * self .x , other * self .y )
240+ def __truediv__ (self , other ):
241+ if isinstance (other , F ):
242+ return NotImplemented
243+ return self .__class__ (self .x / other , self .y / other )
244+ def __rtruediv__ (self , other ):
245+ r = self .x * self .x + self .y * self .y
246+ return self .__class__ (other * (self .x / r ), other * (self .y / r ))
247+ def __rpow__ (self , other ):
248+ return Polar (other ** self .x , math .log (other ) * self .y )
249+ def __complex__ (self ):
250+ return complex (self .x , self .y )
251+ def __eq__ (self , other ):
252+ if self .__class__ != other .__class__ :
253+ return NotImplemented
254+ return is_eq (self .x , other .x ) and is_eq (self .y , other .y )
255+ def __repr__ (self ):
256+ return f'{ self .__class__ .__name__ } ({ self .x !r} , { self .y !r} )'
257+ numbers .Complex .register (Rect )
258+
94259
95260class FractionTest (unittest .TestCase ):
96261
@@ -593,20 +758,57 @@ def testMixedArithmetic(self):
593758 self .assertTypedEquals (0.9 , 1.0 - F (1 , 10 ))
594759 self .assertTypedEquals (0.9 + 0j , (1.0 + 0j ) - F (1 , 10 ))
595760
761+ def testMixedMultiplication (self ):
596762 self .assertTypedEquals (F (1 , 10 ), F (1 , 10 ) * 1 )
597763 self .assertTypedEquals (0.1 , F (1 , 10 ) * 1.0 )
598764 self .assertTypedEquals (0.1 + 0j , F (1 , 10 ) * (1.0 + 0j ))
599765 self .assertTypedEquals (F (1 , 10 ), 1 * F (1 , 10 ))
600766 self .assertTypedEquals (0.1 , 1.0 * F (1 , 10 ))
601767 self .assertTypedEquals (0.1 + 0j , (1.0 + 0j ) * F (1 , 10 ))
602768
769+ self .assertTypedEquals (F (3 , 2 ) * DummyFraction (5 , 3 ), F (5 , 2 ))
770+ self .assertTypedEquals (DummyFraction (5 , 3 ) * F (3 , 2 ), F (5 , 2 ))
771+ self .assertTypedEquals (F (3 , 2 ) * Rat (5 , 3 ), Rat (15 , 6 ))
772+ self .assertTypedEquals (Rat (5 , 3 ) * F (3 , 2 ), F (5 , 2 ))
773+
774+ self .assertTypedEquals (F (3 , 2 ) * Root (4 ), Root (F (9 , 1 )))
775+ self .assertTypedEquals (Root (4 ) * F (3 , 2 ), 3.0 )
776+
777+ self .assertTypedEquals (F (3 , 2 ) * Polar (4 , 2 ), Polar (F (6 , 1 ), 2 ))
778+ self .assertTypedEquals (F (3 , 2 ) * Polar (4.0 , 2 ), Polar (6.0 , 2 ))
779+ self .assertTypedEquals (F (3 , 2 ) * Rect (4 , 3 ), Rect (F (6 , 1 ), F (9 , 2 )))
780+ self .assertRaises (TypeError , operator .mul , Polar (4 , 2 ), F (3 , 2 ))
781+ self .assertTypedEquals (Rect (4 , 3 ) * F (3 , 2 ), 6.0 + 4.5j )
782+
783+ self .assertTypedEquals (F (3 , 2 ) * One , F (3 , 2 ))
784+ self .assertRaises (TypeError , operator .mul , One , F (3 , 2 ))
785+
786+ def testMixedDivision (self ):
603787 self .assertTypedEquals (F (1 , 10 ), F (1 , 10 ) / 1 )
604788 self .assertTypedEquals (0.1 , F (1 , 10 ) / 1.0 )
605789 self .assertTypedEquals (0.1 + 0j , F (1 , 10 ) / (1.0 + 0j ))
606790 self .assertTypedEquals (F (10 , 1 ), 1 / F (1 , 10 ))
607791 self .assertTypedEquals (10.0 , 1.0 / F (1 , 10 ))
608792 self .assertTypedEquals (10.0 + 0j , (1.0 + 0j ) / F (1 , 10 ))
609793
794+ self .assertTypedEquals (F (3 , 2 ) / DummyFraction (3 , 5 ), F (5 , 2 ))
795+ self .assertTypedEquals (DummyFraction (5 , 3 ) / F (2 , 3 ), F (5 , 2 ))
796+ self .assertTypedEquals (F (3 , 2 ) / Rat (3 , 5 ), Rat (15 , 6 ))
797+ self .assertTypedEquals (Rat (5 , 3 ) / F (2 , 3 ), F (5 , 2 ))
798+
799+ self .assertTypedEquals (F (2 , 3 ) / Root (4 ), Root (F (1 , 9 )))
800+ self .assertTypedEquals (Root (4 ) / F (2 , 3 ), 3.0 )
801+
802+ self .assertTypedEquals (F (3 , 2 ) / Polar (4 , 2 ), Polar (F (3 , 8 ), - 2 ))
803+ self .assertTypedEquals (F (3 , 2 ) / Polar (4.0 , 2 ), Polar (0.375 , - 2 ))
804+ self .assertTypedEquals (F (3 , 2 ) / Rect (4 , 3 ), Rect (0.24 , 0.18 ))
805+ self .assertRaises (TypeError , operator .truediv , Polar (4 , 2 ), F (2 , 3 ))
806+ self .assertTypedEquals (Rect (4 , 3 ) / F (2 , 3 ), 6.0 + 4.5j )
807+
808+ self .assertTypedEquals (F (3 , 2 ) / One , F (3 , 2 ))
809+ self .assertRaises (TypeError , operator .truediv , One , F (2 , 3 ))
810+
811+ def testMixedIntegerDivision (self ):
610812 self .assertTypedEquals (0 , F (1 , 10 ) // 1 )
611813 self .assertTypedEquals (0.0 , F (1 , 10 ) // 1.0 )
612814 self .assertTypedEquals (10 , 1 // F (1 , 10 ))
@@ -631,6 +833,21 @@ def testMixedArithmetic(self):
631833 self .assertTypedTupleEquals (divmod (- 0.1 , float ('inf' )), divmod (F (- 1 , 10 ), float ('inf' )))
632834 self .assertTypedTupleEquals (divmod (- 0.1 , float ('-inf' )), divmod (F (- 1 , 10 ), float ('-inf' )))
633835
836+ self .assertTypedEquals (F (3 , 2 ) % DummyFraction (3 , 5 ), F (3 , 10 ))
837+ self .assertTypedEquals (DummyFraction (5 , 3 ) % F (2 , 3 ), F (1 , 3 ))
838+ self .assertTypedEquals (F (3 , 2 ) % Rat (3 , 5 ), Rat (3 , 6 ))
839+ self .assertTypedEquals (Rat (5 , 3 ) % F (2 , 3 ), F (1 , 3 ))
840+
841+ self .assertRaises (TypeError , operator .mod , F (2 , 3 ), Root (4 ))
842+ self .assertTypedEquals (Root (4 ) % F (3 , 2 ), 0.5 )
843+
844+ self .assertRaises (TypeError , operator .mod , F (3 , 2 ), Polar (4 , 2 ))
845+ self .assertRaises (TypeError , operator .mod , Rect (4 , 3 ), F (2 , 3 ))
846+
847+ self .assertTypedEquals (F (3 , 2 ) % One , F (1 , 2 ))
848+ self .assertRaises (TypeError , operator .mod , One , F (2 , 3 ))
849+
850+ def testMixedPower (self ):
634851 # ** has more interesting conversion rules.
635852 self .assertTypedEquals (F (100 , 1 ), F (1 , 10 ) ** - 2 )
636853 self .assertTypedEquals (F (100 , 1 ), F (10 , 1 ) ** 2 )
@@ -647,6 +864,35 @@ def testMixedArithmetic(self):
647864 self .assertRaises (ZeroDivisionError , operator .pow ,
648865 F (0 , 1 ), - 2 )
649866
867+ self .assertTypedEquals (F (3 , 2 ) ** Rat (3 , 1 ), F (27 , 8 ))
868+ self .assertTypedEquals (F (3 , 2 ) ** Rat (- 3 , 1 ), F (8 , 27 ))
869+ self .assertTypedEquals (F (- 3 , 2 ) ** Rat (- 3 , 1 ), F (- 8 , 27 ))
870+ self .assertTypedEquals (F (9 , 4 ) ** Rat (3 , 2 ), 3.375 )
871+ self .assertIsInstance (F (4 , 9 ) ** Rat (- 3 , 2 ), float )
872+ self .assertAlmostEqual (F (4 , 9 ) ** Rat (- 3 , 2 ), 3.375 )
873+ self .assertAlmostEqual (F (- 4 , 9 ) ** Rat (- 3 , 2 ), 3.375j )
874+
875+ self .assertTypedEquals (Rat (9 , 4 ) ** F (3 , 2 ), 3.375 )
876+ self .assertTypedEquals (Rat (3 , 2 ) ** F (3 , 1 ), Rat (27 , 8 ))
877+ self .assertTypedEquals (Rat (3 , 2 ) ** F (- 3 , 1 ), F (8 , 27 ))
878+ self .assertIsInstance (Rat (4 , 9 ) ** F (- 3 , 2 ), float )
879+ self .assertAlmostEqual (Rat (4 , 9 ) ** F (- 3 , 2 ), 3.375 )
880+
881+ self .assertTypedEquals (Root (4 ) ** F (2 , 3 ), Root (4 , 3.0 ))
882+ self .assertTypedEquals (Root (4 ) ** F (2 , 1 ), Root (4 , F (1 )))
883+ self .assertTypedEquals (Root (4 ) ** F (- 2 , 1 ), Root (4 , - F (1 )))
884+ self .assertTypedEquals (Root (4 ) ** F (- 2 , 3 ), Root (4 , - 3.0 ))
885+
886+ self .assertTypedEquals (F (3 , 2 ) ** Rect (2 , 0 ), Polar (2.25 , 0.0 ))
887+ self .assertTypedEquals (F (1 , 1 ) ** Rect (2 , 3 ), Polar (1.0 , 0.0 ))
888+ self .assertTypedEquals (Polar (4 , 2 ) ** F (3 , 2 ), Polar (8.0 , 3.0 ))
889+ self .assertTypedEquals (Polar (4 , 2 ) ** F (3 , 1 ), Polar (64 , 6 ))
890+ self .assertTypedEquals (Polar (4 , 2 ) ** F (- 3 , 1 ), Polar (0.015625 , - 6 ))
891+ self .assertTypedEquals (Polar (4 , 2 ) ** F (- 3 , 2 ), Polar (0.125 , - 3.0 ))
892+
893+ self .assertTypedEquals (F (3 , 2 ) ** One , 1.5 )
894+ self .assertTypedEquals (One ** F (3 , 2 ), One )
895+
650896 def testMixingWithDecimal (self ):
651897 # Decimal refuses mixed arithmetic (but not mixed comparisons)
652898 self .assertRaises (TypeError , operator .add ,
0 commit comments