Skip to content

Commit ea4b5cb

Browse files
committed
add more complete rational arithmetic
1 parent f1ffe2e commit ea4b5cb

File tree

3 files changed

+118
-4
lines changed

3 files changed

+118
-4
lines changed

src/rational.jl

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,18 @@ function operate!(::typeof(one), x::Rational)
2020
end
2121

2222
# +
23-
function promote_operation(::typeof(+), ::Type{Rational{S}}, ::Type{Rational{T}}) where {S,T}
23+
function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{Rational{S}}, ::Type{Rational{T}}) where {S,T}
2424
return Rational{promote_sum_mul(S, T)}
2525
end
26+
27+
function promote_operation(op::Union{typeof(+), typeof(-)}, ::Type{Rational{S}}, ::Type{I}) where {S,I<:Integer}
28+
return promote_operation(op, Rational{S}, Rational{I})
29+
end
30+
31+
function promote_operation(op::Union{typeof(+), typeof(-)}, ::Type{I}, ::Type{Rational{S}}) where {S,I<:Integer}
32+
return promote_operation(op, Rational{S}, Rational{I})
33+
end
34+
2635
function operate_to!(output::Rational, ::typeof(+), x::Rational, y::Rational)
2736
xd, yd = Base.divgcd(promote(x.den, y.den)...)
2837
# TODO Use `checked_mul` and `checked_add` like in Base
@@ -32,10 +41,26 @@ function operate_to!(output::Rational, ::typeof(+), x::Rational, y::Rational)
3241
return output
3342
end
3443

35-
# -
36-
function promote_operation(::typeof(-), ::Type{Rational{S}}, ::Type{Rational{T}}) where {S,T}
37-
return Rational{promote_sum_mul(S, T)}
44+
function operate_to!(output::Rational, ::typeof(+), x::Rational, y::Integer)
45+
# TODO Use `checked_mul` and `checked_add` like in Base
46+
operate_to!(output.num, *, x.den, y)
47+
operate!(+, output.num, x.num)
48+
operate_to!(output.den, *, x.den, oftype(x.den, 1))
49+
return output
50+
end
51+
52+
function operate_to!(output::Rational, ::typeof(+), y::Integer, x::Rational)
53+
return operate_to!(output, +, x, y)
3854
end
55+
56+
# unary -
57+
function operate_to!(output::Rational, ::typeof(-), x::Rational)
58+
operate_to!(output.num, -, x.num)
59+
operate_to!(output.den, copy, x.den)
60+
return output
61+
end
62+
63+
# binary -
3964
function operate_to!(output::Rational, ::typeof(-), x::Rational, y::Rational)
4065
xd, yd = Base.divgcd(promote(x.den, y.den)...)
4166
# TODO Use `checked_mul` and `checked_sub` like in Base
@@ -45,10 +70,35 @@ function operate_to!(output::Rational, ::typeof(-), x::Rational, y::Rational)
4570
return output
4671
end
4772

73+
function operate_to!(output::Rational, ::typeof(-), x::Rational, y::Integer)
74+
# TODO Use `checked_mul` and `checked_sub` like in Base
75+
operate_to!(output.num, *, x.den, y)
76+
operate!(-, output.num)
77+
operate!(+, output.num, x.num)
78+
operate_to!(output.den, copy, x.den)
79+
return output
80+
end
81+
82+
function operate_to!(output::Rational, ::typeof(-), y::Integer, x::Rational)
83+
# TODO Use `checked_mul` and `checked_sub` like in Base
84+
operate_to!(output, -, x, y)
85+
operate_to!(output, -, output)
86+
return output
87+
end
88+
4889
# *
4990
function promote_operation(::typeof(*), ::Type{Rational{S}}, ::Type{Rational{T}}) where {S,T}
5091
return Rational{promote_operation(*, S, T)}
5192
end
93+
94+
function promote_operation(::typeof(*), ::Type{Rational{S}}, ::Type{I}) where {S,I<:Integer}
95+
return promote_operation(*, Rational{S}, Rational{I})
96+
end
97+
98+
function promote_operation(::typeof(*), ::Type{I}, ::Type{Rational{S}}) where {S,I<:Integer}
99+
return promote_operation(*, Rational{S}, Rational{I})
100+
end
101+
52102
function operate_to!(output::Rational, ::typeof(*), x::Rational, y::Rational)
53103
xn, yd = Base.divgcd(promote(x.num, y.den)...)
54104
xd, yn = Base.divgcd(promote(x.den, y.num)...)
@@ -57,6 +107,48 @@ function operate_to!(output::Rational, ::typeof(*), x::Rational, y::Rational)
57107
return output
58108
end
59109

110+
function operate_to!(output::Rational, ::typeof(*), x::Rational, y::Integer)
111+
xn = x.num
112+
xd, yn = Base.divgcd(promote(x.den, y)...)
113+
operate_to!(output.num, *, xn, yn)
114+
operate_to!(output.den, copy, x.den)
115+
return output
116+
end
117+
118+
function operate_to!(output::Rational, ::typeof(*), y::Integer, x::Rational)
119+
return operate_to!(output, *, x, y)
120+
end
121+
122+
# //
123+
function operate_to!(output::Rational, op::Union{typeof(/), typeof(//)}, x::Rational, y::Rational)
124+
xn, yn = Base.divgcd(promote(x.num, y.num)...)
125+
xd, yd = Base.divgcd(promote(x.den, y.den)...)
126+
operate_to!(output.num, *, xn, yd)
127+
operate_to!(output.den, *, xd, yn)
128+
return output
129+
end
130+
131+
function operate_to!(output::Rational, op::Union{typeof(/), typeof(//)}, x::Rational, y::Integer)
132+
xn, yn = Base.divgcd(promote(x.num, y)...)
133+
operate_to!(output.num, copy, xn)
134+
operate_to!(output.den, *, x.den, yn)
135+
return output
136+
end
137+
138+
function operate_to!(output::Rational, op::Union{typeof(/), typeof(//)}, x::Integer, y::Rational)
139+
xn, yd = Base.divgcd(promote(x, y.den)...)
140+
operate_to!(output.num, *, xn, yd)
141+
operate_to!(output.den, copy, y.num)
142+
return output
143+
end
144+
145+
function operate_to!(output::Rational, op::Union{typeof(/), typeof(//)}, x::Integer, y::Integer)
146+
n, d = Base.divgcd(promote(x, y)...)
147+
operate_to!(output.num, copy, n)
148+
operate_to!(output.den, copy, d)
149+
return output
150+
end
151+
60152
# gcd
61153
function promote_operation(::Union{typeof(gcd),typeof(lcm)}, ::Type{Rational{S}}, ::Type{Rational{T}}) where {S,T}
62154
return Rational{promote_operation(gcd, S, T)}

test/rational.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
for op in (+, -, *, //)
2+
for (a,b) in (
3+
(2//3, 5), (2, 3//5), (2//3, 5//7),
4+
(big(2)//3, 5), (big(2), 3//5), (big(2)//3, 5//7),
5+
)
6+
@test MA.operate_to!!(MA.copy_if_mutable(op(a,b)), op, a, b) == op(a, b)
7+
@test MA.operate_to!!(MA.copy_if_mutable(op(b,a)), op, b, a) == op(b, a)
8+
end
9+
end
10+
11+
op = //
12+
for (a,b) in (
13+
(2,3), (big(2), 3), (2, big(3))
14+
)
15+
@test MA.operate_to!!(MA.copy_if_mutable(op(a,b)), op, a, b) == op(a,b)
16+
@test MA.operate_to!!(MA.copy_if_mutable(op(b,a)), op, b, a) == op(b,a)
17+
end

test/runtests.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ end
1414
@testset "BigInt" begin
1515
include("big.jl")
1616
end
17+
18+
@testset "Rational" begin
19+
include("rational.jl")
20+
end
21+
1722
@testset "Broadcast" begin
1823
include("broadcast.jl")
1924
end

0 commit comments

Comments
 (0)