Skip to content

Commit 6833e46

Browse files
committed
add more complete rational arithmetic
1 parent db3bc66 commit 6833e46

File tree

3 files changed

+131
-10
lines changed

3 files changed

+131
-10
lines changed

src/implementations/Rational.jl

Lines changed: 109 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,30 @@ function operate!(::typeof(one), x::Rational)
2828
end
2929

3030
# +
31-
3231
function promote_operation(
33-
::typeof(+),
32+
::Union{typeof(+),typeof(-)},
3433
::Type{Rational{S}},
35-
::Type{Rational{T}},
34+
::Type{Rational{T}}
3635
) where {S,T}
3736
return Rational{promote_sum_mul(S, T)}
3837
end
3938

39+
function promote_operation(
40+
op::Union{typeof(+),typeof(-)},
41+
::Type{Rational{S}},
42+
::Type{I}
43+
) where {S,I<:Integer}
44+
return promote_operation(op, Rational{S}, Rational{I})
45+
end
46+
47+
function promote_operation(
48+
op::Union{typeof(+),typeof(-)},
49+
::Type{I},
50+
::Type{Rational{S}}
51+
) where {S,I<:Integer}
52+
return promote_operation(op, Rational{S}, Rational{I})
53+
end
54+
4055
function operate_to!(output::Rational, ::typeof(+), x::Rational, y::Rational)
4156
xd, yd = Base.divgcd(promote(x.den, y.den)...)
4257
# TODO: Use `checked_mul` and `checked_add` like in Base
@@ -46,16 +61,26 @@ function operate_to!(output::Rational, ::typeof(+), x::Rational, y::Rational)
4661
return output
4762
end
4863

49-
# -
64+
function operate_to!(output::Rational, ::typeof(+), x::Rational, y::Integer)
65+
# TODO Use `checked_mul` and `checked_add` like in Base
66+
operate_to!(output.num, *, x.den, y)
67+
operate!(+, output.num, x.num)
68+
operate_to!(output.den, *, x.den, oftype(x.den, 1))
69+
return output
70+
end
5071

51-
function promote_operation(
52-
::typeof(-),
53-
::Type{Rational{S}},
54-
::Type{Rational{T}},
55-
) where {S,T}
56-
return Rational{promote_sum_mul(S, T)}
72+
function operate_to!(output::Rational, ::typeof(+), y::Integer, x::Rational)
73+
return operate_to!(output, +, x, y)
5774
end
5875

76+
# unary -
77+
function operate_to!(output::Rational, ::typeof(-), x::Rational)
78+
operate_to!(output.num, -, x.num)
79+
operate_to!(output.den, copy, x.den)
80+
return output
81+
end
82+
83+
# binary -
5984
function operate_to!(output::Rational, ::typeof(-), x::Rational, y::Rational)
6085
xd, yd = Base.divgcd(promote(x.den, y.den)...)
6186
# TODO: Use `checked_mul` and `checked_sub` like in Base
@@ -65,6 +90,22 @@ function operate_to!(output::Rational, ::typeof(-), x::Rational, y::Rational)
6590
return output
6691
end
6792

93+
function operate_to!(output::Rational, ::typeof(-), x::Rational, y::Integer)
94+
# TODO Use `checked_mul` and `checked_sub` like in Base
95+
operate_to!(output.num, *, x.den, y)
96+
operate!(-, output.num)
97+
operate!(+, output.num, x.num)
98+
operate_to!(output.den, copy, x.den)
99+
return output
100+
end
101+
102+
function operate_to!(output::Rational, ::typeof(-), y::Integer, x::Rational)
103+
# TODO Use `checked_mul` and `checked_sub` like in Base
104+
operate_to!(output, -, x, y)
105+
operate_to!(output, -, output)
106+
return output
107+
end
108+
68109
# *
69110

70111
function promote_operation(
@@ -75,6 +116,22 @@ function promote_operation(
75116
return Rational{promote_operation(*, S, T)}
76117
end
77118

119+
function promote_operation(
120+
::typeof(*),
121+
::Type{Rational{S}},
122+
::Type{I}
123+
) where {S,I<:Integer}
124+
return promote_operation(*, Rational{S}, Rational{I})
125+
end
126+
127+
function promote_operation(
128+
::typeof(*),
129+
::Type{I},
130+
::Type{Rational{S}}
131+
) where {S,I<:Integer}
132+
return promote_operation(*, Rational{S}, Rational{I})
133+
end
134+
78135
function operate_to!(output::Rational, ::typeof(*), x::Rational, y::Rational)
79136
xn, yd = Base.divgcd(promote(x.num, y.den)...)
80137
xd, yn = Base.divgcd(promote(x.den, y.num)...)
@@ -83,6 +140,48 @@ function operate_to!(output::Rational, ::typeof(*), x::Rational, y::Rational)
83140
return output
84141
end
85142

143+
function operate_to!(output::Rational, ::typeof(*), x::Rational, y::Integer)
144+
xn = x.num
145+
xd, yn = Base.divgcd(promote(x.den, y)...)
146+
operate_to!(output.num, *, xn, yn)
147+
operate_to!(output.den, copy, x.den)
148+
return output
149+
end
150+
151+
function operate_to!(output::Rational, ::typeof(*), y::Integer, x::Rational)
152+
return operate_to!(output, *, x, y)
153+
end
154+
155+
# //
156+
function operate_to!(output::Rational, op::Union{typeof(/), typeof(//)}, x::Rational, y::Rational)
157+
xn, yn = Base.divgcd(promote(x.num, y.num)...)
158+
xd, yd = Base.divgcd(promote(x.den, y.den)...)
159+
operate_to!(output.num, *, xn, yd)
160+
operate_to!(output.den, *, xd, yn)
161+
return output
162+
end
163+
164+
function operate_to!(output::Rational, op::Union{typeof(/), typeof(//)}, x::Rational, y::Integer)
165+
xn, yn = Base.divgcd(promote(x.num, y)...)
166+
operate_to!(output.num, copy, xn)
167+
operate_to!(output.den, *, x.den, yn)
168+
return output
169+
end
170+
171+
function operate_to!(output::Rational, op::Union{typeof(/), typeof(//)}, x::Integer, y::Rational)
172+
xn, yd = Base.divgcd(promote(x, y.den)...)
173+
operate_to!(output.num, *, xn, yd)
174+
operate_to!(output.den, copy, y.num)
175+
return output
176+
end
177+
178+
function operate_to!(output::Rational, op::Union{typeof(/), typeof(//)}, x::Integer, y::Integer)
179+
n, d = Base.divgcd(promote(x, y)...)
180+
operate_to!(output.num, copy, n)
181+
operate_to!(output.den, copy, d)
182+
return output
183+
end
184+
86185
# gcd
87186

88187
function promote_operation(

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)