@@ -330,6 +330,8 @@ cdef object _FLOAT_FORMAT_SPECIFICATION_MATCHER = re.compile(r"""
330
330
$
331
331
""" , re.DOTALL | re.VERBOSE).match
332
332
333
+ cdef object NOINIT = object ()
334
+
333
335
334
336
cdef class Fraction:
335
337
""" A Rational number.
@@ -367,9 +369,12 @@ cdef class Fraction:
367
369
cdef _denominator
368
370
cdef Py_hash_t _hash
369
371
370
- def __cinit__ (self , numerator = 0 , denominator = None , *, bint _normalize = True ):
371
- cdef Fraction value
372
+ def __cinit__ (self , numerator = 0 , denominator = None ):
372
373
self ._hash = - 1
374
+ if numerator is NOINIT:
375
+ return # fast-path for external initialisation
376
+
377
+ cdef bint _normalize = True
373
378
if denominator is None :
374
379
if type (numerator) is int or type (numerator) is long :
375
380
self ._numerator = numerator
@@ -500,14 +505,19 @@ cdef class Fraction:
500
505
raise OverflowError (f" Cannot convert {dec} to {cls.__name__}." )
501
506
if dec.is_nan():
502
507
raise ValueError (f" Cannot convert {dec} to {cls.__name__}." )
508
+
509
+ if _decimal_supports_integer_ratio:
510
+ num, denom = dec.as_integer_ratio()
511
+ return _fraction_from_coprime_ints(num, denom, cls )
512
+
503
513
sign, digits, exp = dec.as_tuple()
504
514
digits = int (' ' .join(map (str , digits)))
505
515
if sign:
506
516
digits = - digits
507
517
if exp >= 0 :
508
- return cls (digits * pow10(exp))
518
+ return _fraction_from_coprime_ints (digits * pow10(exp), None , cls )
509
519
else :
510
- return cls (digits, pow10(- exp))
520
+ return _fraction_from_coprime_ints (digits, pow10(- exp), cls )
511
521
512
522
def is_integer (self ):
513
523
""" Return True if the Fraction is an integer."""
@@ -574,9 +584,9 @@ cdef class Fraction:
574
584
# the distance from p1/q1 to self is d/(q1*self._denominator). So we
575
585
# need to compare 2*(q0+k*q1) with self._denominator/d.
576
586
if 2 * d* (q0+ k* q1) <= self ._denominator:
577
- return Fraction (p1, q1, _normalize = False )
587
+ return _fraction_from_coprime_ints (p1, q1)
578
588
else :
579
- return Fraction (p0+ k* p1, q0+ k* q1, _normalize = False )
589
+ return _fraction_from_coprime_ints (p0+ k* p1, q0+ k* q1)
580
590
581
591
@property
582
592
def numerator (self ):
@@ -839,15 +849,15 @@ cdef class Fraction:
839
849
""" +a: Coerces a subclass instance to Fraction"""
840
850
if type (a) is Fraction:
841
851
return a
842
- return Fraction (a._numerator, a._denominator, _normalize = False )
852
+ return _fraction_from_coprime_ints (a._numerator, a._denominator)
843
853
844
854
def __neg__ (a ):
845
855
""" -a"""
846
- return Fraction (- a._numerator, a._denominator, _normalize = False )
856
+ return _fraction_from_coprime_ints (- a._numerator, a._denominator)
847
857
848
858
def __abs__ (a ):
849
859
""" abs(a)"""
850
- return Fraction (abs (a._numerator), a._denominator, _normalize = False )
860
+ return _fraction_from_coprime_ints (abs (a._numerator), a._denominator)
851
861
852
862
def __int__ (a ):
853
863
""" int(a)"""
@@ -1113,20 +1123,39 @@ cdef class Fraction:
1113
1123
Rational.register(Fraction)
1114
1124
1115
1125
1126
+ cdef _fraction_from_coprime_ints(numerator, denominator, cls = None ):
1127
+ """ Convert a pair of ints to a rational number, for internal use.
1128
+
1129
+ The ratio of integers should be in lowest terms and the denominator
1130
+ should be positive.
1131
+ """
1132
+ cdef Fraction obj
1133
+ if cls is None or cls is Fraction:
1134
+ obj = Fraction.__new__ (Fraction, NOINIT, NOINIT)
1135
+ else :
1136
+ obj = super (Fraction, cls ).__new__(cls )
1137
+ obj._numerator = numerator
1138
+ obj._denominator = denominator
1139
+ return obj
1140
+
1141
+
1116
1142
cdef _pow(an, ad, bn, bd):
1117
1143
if bd == 1 :
1144
+ # power = bn
1118
1145
if bn >= 0 :
1119
- return Fraction(an ** bn,
1120
- ad ** bn,
1121
- _normalize = False )
1122
- elif an >= 0 :
1123
- return Fraction(ad ** - bn,
1124
- an ** - bn,
1125
- _normalize = False )
1146
+ return _fraction_from_coprime_ints(
1147
+ an ** bn,
1148
+ ad ** bn)
1149
+ elif an > 0 :
1150
+ return _fraction_from_coprime_ints(
1151
+ ad ** - bn,
1152
+ an ** - bn)
1153
+ elif an == 0 :
1154
+ raise ZeroDivisionError (f' Fraction({ad ** -bn}, 0)' )
1126
1155
else :
1127
- return Fraction(( - ad) ** - bn,
1128
- ( - an ) ** - bn,
1129
- _normalize = False )
1156
+ return _fraction_from_coprime_ints(
1157
+ ( - ad ) ** - bn,
1158
+ ( - an) ** - bn )
1130
1159
else :
1131
1160
# A fractional power will generally produce an
1132
1161
# irrational number.
@@ -1210,26 +1239,26 @@ cdef _add(na, da, nb, db):
1210
1239
# return Fraction(na * db + nb * da, da * db)
1211
1240
g = _gcd(da, db)
1212
1241
if g == 1 :
1213
- return Fraction (na * db + da * nb, da * db, _normalize = False )
1242
+ return _fraction_from_coprime_ints (na * db + da * nb, da * db)
1214
1243
s = da // g
1215
1244
t = na * (db // g) + nb * s
1216
1245
g2 = _gcd(t, g)
1217
1246
if g2 == 1 :
1218
- return Fraction (t, s * db, _normalize = False )
1219
- return Fraction (t // g2, s * (db // g2), _normalize = False )
1247
+ return _fraction_from_coprime_ints (t, s * db)
1248
+ return _fraction_from_coprime_ints (t // g2, s * (db // g2))
1220
1249
1221
1250
cdef _sub(na, da, nb, db):
1222
1251
""" a - b"""
1223
1252
# return Fraction(na * db - nb * da, da * db)
1224
1253
g = _gcd(da, db)
1225
1254
if g == 1 :
1226
- return Fraction (na * db - da * nb, da * db, _normalize = False )
1255
+ return _fraction_from_coprime_ints (na * db - da * nb, da * db)
1227
1256
s = da // g
1228
1257
t = na * (db // g) - nb * s
1229
1258
g2 = _gcd(t, g)
1230
1259
if g2 == 1 :
1231
- return Fraction (t, s * db, _normalize = False )
1232
- return Fraction (t // g2, s * (db // g2), _normalize = False )
1260
+ return _fraction_from_coprime_ints (t, s * db)
1261
+ return _fraction_from_coprime_ints (t // g2, s * (db // g2))
1233
1262
1234
1263
cdef _mul(na, da, nb, db):
1235
1264
""" a * b"""
@@ -1242,12 +1271,14 @@ cdef _mul(na, da, nb, db):
1242
1271
if g2 > 1 :
1243
1272
nb //= g2
1244
1273
da //= g2
1245
- return Fraction (na * nb, db * da, _normalize = False )
1274
+ return _fraction_from_coprime_ints (na * nb, db * da)
1246
1275
1247
1276
cdef _div(na, da, nb, db):
1248
1277
""" a / b"""
1249
1278
# return Fraction(na * db, da * nb)
1250
1279
# Same as _mul(), with inversed b.
1280
+ if nb == 0 :
1281
+ raise ZeroDivisionError (f' Fraction({db}, 0)' )
1251
1282
g1 = _gcd(na, nb)
1252
1283
if g1 > 1 :
1253
1284
na //= g1
@@ -1259,7 +1290,7 @@ cdef _div(na, da, nb, db):
1259
1290
n, d = na * db, nb * da
1260
1291
if d < 0 :
1261
1292
n, d = - n, - d
1262
- return Fraction (n, d, _normalize = False )
1293
+ return _fraction_from_coprime_ints (n, d)
1263
1294
1264
1295
cdef _floordiv(an, ad, bn, bd):
1265
1296
""" a // b -> int"""
0 commit comments