@@ -10,23 +10,34 @@ struct Rational{T<:Integer} <: Real
10
10
num:: T
11
11
den:: T
12
12
13
- function Rational {T} (num:: Integer , den:: Integer ) where T<: Integer
14
- num == den == zero (T) && __throw_rational_argerror_zero (T)
15
- num2, den2 = divgcd (num, den)
16
- if T<: Signed && signbit (den2)
17
- den2 = - den2
18
- signbit (den2) && __throw_rational_argerror_typemin (T)
19
- num2 = - num2
20
- end
21
- return new (num2, den2)
13
+ # Unexported inner constructor of Rational that bypasses all checks
14
+ global unsafe_rational (:: Type{T} , num, den) where {T} = new {T} (num, den)
15
+ end
16
+
17
+ unsafe_rational (num:: T , den:: T ) where {T<: Integer } = unsafe_rational (T, num, den)
18
+ unsafe_rational (num:: Integer , den:: Integer ) = unsafe_rational (promote (num, den)... )
19
+
20
+ @noinline __throw_rational_argerror_typemin (T) = throw (ArgumentError (" invalid rational: denominator can't be typemin($T )" ))
21
+ function checked_den (num:: T , den:: T ) where T<: Integer
22
+ if signbit (den)
23
+ den = - den
24
+ signbit (den) && __throw_rational_argerror_typemin (T)
25
+ num = - num
22
26
end
27
+ return unsafe_rational (T, num, den)
23
28
end
29
+ checked_den (num:: Integer , den:: Integer ) = checked_den (promote (num, den)... )
30
+
24
31
@noinline __throw_rational_argerror_zero (T) = throw (ArgumentError (" invalid rational: zero($T )//zero($T )" ))
25
- @noinline __throw_rational_argerror_typemin (T) = throw (ArgumentError (" invalid rational: denominator can't be typemin($T )" ))
32
+ function Rational {T} (num:: Integer , den:: Integer ) where T<: Integer
33
+ iszero (den) && iszero (num) && __throw_rational_argerror_zero (T)
34
+ num, den = divgcd (num, den)
35
+ return checked_den (T (num), T (den))
36
+ end
26
37
27
- Rational (n:: T , d:: T ) where {T<: Integer } = Rational {T} (n,d)
28
- Rational (n:: Integer , d:: Integer ) = Rational (promote (n,d)... )
29
- Rational (n:: Integer ) = Rational (n,one (n))
38
+ Rational (n:: T , d:: T ) where {T<: Integer } = Rational {T} (n, d)
39
+ Rational (n:: Integer , d:: Integer ) = Rational (promote (n, d)... )
40
+ Rational (n:: Integer ) = unsafe_rational (n, one (n))
30
41
31
42
function divgcd (x:: Integer ,y:: Integer )
32
43
g = gcd (x,y)
@@ -50,20 +61,20 @@ julia> (3 // 5) // (2 // 1)
50
61
// (n:: Integer , d:: Integer ) = Rational (n,d)
51
62
52
63
function // (x:: Rational , y:: Integer )
53
- xn,yn = divgcd (x. num,y)
54
- xn // checked_mul (x. den,yn )
64
+ xn, yn = divgcd (x. num,y)
65
+ checked_den (xn, checked_mul (x. den, yn) )
55
66
end
56
67
function // (x:: Integer , y:: Rational )
57
- xn,yn = divgcd (x,y. num)
58
- checked_mul (xn,y. den)// yn
68
+ xn, yn = divgcd (x,y. num)
69
+ checked_den ( checked_mul (xn, y. den), yn)
59
70
end
60
71
function // (x:: Rational , y:: Rational )
61
72
xn,yn = divgcd (x. num,y. num)
62
73
xd,yd = divgcd (x. den,y. den)
63
- checked_mul (xn,yd)// checked_mul (xd,yn )
74
+ checked_den ( checked_mul (xn, yd), checked_mul (xd, yn) )
64
75
end
65
76
66
- // (x:: Complex , y:: Real ) = complex (real (x)// y,imag (x)// y)
77
+ // (x:: Complex , y:: Real ) = complex (real (x)// y, imag (x)// y)
67
78
// (x:: Number , y:: Complex ) = x* conj (y)// abs2 (y)
68
79
69
80
@@ -84,8 +95,12 @@ function write(s::IO, z::Rational)
84
95
write (s,numerator (z),denominator (z))
85
96
end
86
97
87
- Rational {T} (x:: Rational ) where {T<: Integer } = Rational {T} (convert (T,x. num), convert (T,x. den))
88
- Rational {T} (x:: Integer ) where {T<: Integer } = Rational {T} (convert (T,x), convert (T,1 ))
98
+ function Rational {T} (x:: Rational ) where T<: Integer
99
+ unsafe_rational (T, convert (T, x. num), convert (T, x. den))
100
+ end
101
+ function Rational {T} (x:: Integer ) where T<: Integer
102
+ unsafe_rational (T, convert (T, x), one (T))
103
+ end
89
104
90
105
Rational (x:: Rational ) = x
91
106
108
123
Rational (x:: Float64 ) = Rational {Int64} (x)
109
124
Rational (x:: Float32 ) = Rational {Int} (x)
110
125
111
- big (q:: Rational ) = big (numerator (q))// big (denominator (q))
126
+ big (q:: Rational ) = unsafe_rational ( big (numerator (q)), big (denominator (q) ))
112
127
113
128
big (z:: Complex{<:Rational{<:Integer}} ) = Complex {Rational{BigInt}} (z)
114
129
@@ -118,6 +133,8 @@ promote_rule(::Type{Rational{T}}, ::Type{S}) where {T<:Integer,S<:AbstractFloat}
118
133
119
134
widen (:: Type{Rational{T}} ) where {T} = Rational{widen (T)}
120
135
136
+ @noinline __throw_negate_unsigned () = throw (OverflowError (" cannot negate unsigned number" ))
137
+
121
138
"""
122
139
rationalize([T<:Integer=Int,] x; tol::Real=eps(x))
123
140
@@ -140,8 +157,9 @@ function rationalize(::Type{T}, x::AbstractFloat, tol::Real) where T<:Integer
140
157
if tol < 0
141
158
throw (ArgumentError (" negative tolerance $tol " ))
142
159
end
160
+ T<: Unsigned && x < 0 && __throw_negate_unsigned ()
143
161
isnan (x) && return T (x)// one (T)
144
- isinf (x) && return (x < 0 ? - one (T) : one (T)) // zero (T)
162
+ isinf (x) && return unsafe_rational (x < 0 ? - one (T) : one (T), zero (T) )
145
163
146
164
p, q = (x < 0 ? - one (T) : one (T)), zero (T)
147
165
pp, qq = zero (T), one (T)
@@ -234,59 +252,74 @@ denominator(x::Rational) = x.den
234
252
235
253
sign (x:: Rational ) = oftype (x, sign (x. num))
236
254
signbit (x:: Rational ) = signbit (x. num)
237
- copysign (x:: Rational , y:: Real ) = copysign (x. num,y) // x. den
238
- copysign (x:: Rational , y:: Rational ) = copysign (x. num,y. num) // x. den
255
+ copysign (x:: Rational , y:: Real ) = unsafe_rational ( copysign (x. num, y), x. den)
256
+ copysign (x:: Rational , y:: Rational ) = unsafe_rational ( copysign (x. num, y. num), x. den)
239
257
240
258
abs (x:: Rational ) = Rational (abs (x. num), x. den)
241
259
242
- typemin (:: Type{Rational{T}} ) where {T<: Integer } = - one (T)// zero (T)
243
- typemax (:: Type{Rational{T}} ) where {T<: Integer } = one (T)// zero (T)
260
+ typemin (:: Type{Rational{T}} ) where {T<: Signed } = unsafe_rational (T, - one (T), zero (T))
261
+ typemin (:: Type{Rational{T}} ) where {T<: Integer } = unsafe_rational (T, zero (T), one (T))
262
+ typemax (:: Type{Rational{T}} ) where {T<: Integer } = unsafe_rational (T, one (T), zero (T))
244
263
245
264
isinteger (x:: Rational ) = x. den == 1
246
265
247
- + (x:: Rational ) = (+ x. num) // x. den
248
- - (x:: Rational ) = (- x. num) // x. den
266
+ + (x:: Rational ) = unsafe_rational (+ x. num, x. den)
267
+ - (x:: Rational ) = unsafe_rational (- x. num, x. den)
249
268
250
269
function - (x:: Rational{T} ) where T<: BitSigned
251
- x. num == typemin (T) && throw ( OverflowError ( " rational numerator is typemin(T) " ) )
252
- (- x. num) // x. den
270
+ x. num == typemin (T) && __throw_rational_numerator_typemin (T )
271
+ unsafe_rational (- x. num, x. den)
253
272
end
273
+ @noinline __throw_rational_numerator_typemin (T) = throw (OverflowError (" rational numerator is typemin($T )" ))
274
+
254
275
function - (x:: Rational{T} ) where T<: Unsigned
255
- x. num != zero (T) && throw ( OverflowError ( " cannot negate unsigned number " ) )
276
+ x. num != zero (T) && __throw_negate_unsigned ( )
256
277
x
257
278
end
258
279
259
- for (op,chop) in ((:+ ,:checked_add ), (:- ,:checked_sub ),
260
- (:rem ,:rem ), (:mod ,:mod ))
280
+ for (op,chop) in ((:+ ,:checked_add ), (:- ,:checked_sub ), (:rem ,:rem ), (:mod ,:mod ))
261
281
@eval begin
262
282
function ($ op)(x:: Rational , y:: Rational )
263
283
xd, yd = divgcd (x. den, y. den)
264
284
Rational (($ chop)(checked_mul (x. num,yd), checked_mul (y. num,xd)), checked_mul (x. den,yd))
265
285
end
266
286
267
287
function ($ op)(x:: Rational , y:: Integer )
268
- Rational (($ chop)(x. num, checked_mul (x. den, y)), x. den)
288
+ unsafe_rational (($ chop)(x. num, checked_mul (x. den, y)), x. den)
269
289
end
270
-
290
+ end
291
+ end
292
+ for (op,chop) in ((:+ ,:checked_add ), (:- ,:checked_sub ))
293
+ @eval begin
294
+ function ($ op)(y:: Integer , x:: Rational )
295
+ unsafe_rational (($ chop)(checked_mul (x. den, y), x. num), x. den)
296
+ end
297
+ end
298
+ end
299
+ for (op,chop) in ((:rem ,:rem ), (:mod ,:mod ))
300
+ @eval begin
271
301
function ($ op)(y:: Integer , x:: Rational )
272
302
Rational (($ chop)(checked_mul (x. den, y), x. num), x. den)
273
303
end
274
304
end
275
305
end
276
306
277
307
function * (x:: Rational , y:: Rational )
278
- xn,yd = divgcd (x. num,y. den)
279
- xd,yn = divgcd (x. den,y. num)
280
- checked_mul (xn,yn) // checked_mul (xd,yd )
308
+ xn, yd = divgcd (x. num, y. den)
309
+ xd, yn = divgcd (x. den, y. num)
310
+ unsafe_rational ( checked_mul (xn, yn), checked_mul (xd, yd) )
281
311
end
282
312
function * (x:: Rational , y:: Integer )
283
313
xd, yn = divgcd (x. den, y)
284
- checked_mul (x. num, yn) // xd
314
+ unsafe_rational (checked_mul (x. num, yn), xd)
315
+ end
316
+ function * (y:: Integer , x:: Rational )
317
+ yn, xd = divgcd (y, x. den)
318
+ unsafe_rational (checked_mul (yn, x. num), xd)
285
319
end
286
- * (x:: Integer , y:: Rational ) = * (y, x)
287
- / (x:: Rational , y:: Rational ) = x// y
288
- / (x:: Rational , y:: Complex{<:Union{Integer,Rational}} ) = x// y
289
- inv (x:: Rational ) = Rational (x. den, x. num)
320
+ / (x:: Rational , y:: Union{Rational, Integer, Complex{<:Union{Integer,Rational}}} ) = x// y
321
+ / (x:: Union{Integer, Complex{<:Union{Integer,Rational}}} , y:: Rational ) = x// y
322
+ inv (x:: Rational{T} ) where {T} = checked_den (x. den, x. num)
290
323
291
324
fma (x:: Rational , y:: Rational , z:: Rational ) = x* y+ z
292
325
@@ -403,7 +436,7 @@ round(x::Rational, r::RoundingMode=RoundNearest) = round(typeof(x), x, r)
403
436
404
437
function round (:: Type{T} , x:: Rational{Tr} , r:: RoundingMode = RoundNearest) where {T,Tr}
405
438
if iszero (denominator (x)) && ! (T <: Integer )
406
- return convert (T, copysign (one (Tr)// zero (Tr), numerator (x)))
439
+ return convert (T, copysign (unsafe_rational ( one (Tr), zero (Tr) ), numerator (x)))
407
440
end
408
441
convert (T, div (numerator (x), denominator (x), r))
409
442
end
437
470
438
471
float (:: Type{Rational{T}} ) where {T<: Integer } = float (T)
439
472
440
- gcd (x:: Rational , y:: Rational ) = gcd (x. num, y. num) // lcm (x. den, y. den)
441
- lcm (x:: Rational , y:: Rational ) = lcm (x. num, y. num) // gcd (x. den, y. den)
473
+ gcd (x:: Rational , y:: Rational ) = unsafe_rational ( gcd (x. num, y. num), lcm (x. den, y. den) )
474
+ lcm (x:: Rational , y:: Rational ) = unsafe_rational ( lcm (x. num, y. num), gcd (x. den, y. den) )
442
475
function gcdx (x:: Rational , y:: Rational )
443
476
c = gcd (x, y)
444
477
if iszero (c. num)
0 commit comments