Skip to content

Commit 80b95af

Browse files
authored
Simplify rationals on addition and substraction (#168)
* Simplify rationals on addition and substraction * Fix * Fix * Fix format * aqua-lint fix
1 parent 731f211 commit 80b95af

File tree

6 files changed

+86
-13
lines changed

6 files changed

+86
-13
lines changed

src/implementations/BigFloat.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ operate!(::typeof(one), x::BigFloat) = _set_si!(x, 1)
4444

4545
# +
4646

47-
promote_operation(::typeof(+), ::Vararg{Type{BigFloat},N}) where {N} = BigFloat
47+
function promote_operation(::typeof(+), ::Type{BigFloat}, ::Type{BigFloat})
48+
return BigFloat
49+
end
4850

4951
function operate_to!(output::BigFloat, ::typeof(+), a::BigFloat, b::BigFloat)
5052
ccall(
@@ -78,7 +80,7 @@ end
7880

7981
# *
8082

81-
promote_operation(::typeof(*), ::Vararg{Type{BigFloat},N}) where {N} = BigFloat
83+
promote_operation(::typeof(*), ::Type{BigFloat}, ::Type{BigFloat}) = BigFloat
8284

8385
function operate_to!(output::BigFloat, ::typeof(*), a::BigFloat, b::BigFloat)
8486
ccall(

src/implementations/BigInt.jl

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ operate!(::typeof(one), x::BigInt) = Base.GMP.MPZ.set_si!(x, 1)
2727

2828
# +
2929

30-
promote_operation(::typeof(+), ::Vararg{Type{BigInt},N}) where {N} = BigInt
30+
promote_operation(::typeof(+), ::Type{BigInt}, ::Type{BigInt}) = BigInt
3131

3232
function operate_to!(output::BigInt, ::typeof(+), a::BigInt, b::BigInt)
3333
return Base.GMP.MPZ.add!(output, a, b)
@@ -43,18 +43,25 @@ end
4343

4444
# *
4545

46-
promote_operation(::typeof(*), ::Vararg{Type{BigInt},N}) where {N} = BigInt
46+
promote_operation(::typeof(*), ::Type{BigInt}, ::Type{BigInt}) = BigInt
4747

4848
function operate_to!(output::BigInt, ::typeof(*), a::BigInt, b::BigInt)
4949
return Base.GMP.MPZ.mul!(output, a, b)
5050
end
5151

52+
promote_operation(::typeof(div), ::Type{BigInt}, ::Type{BigInt}) = BigInt
53+
54+
function operate_to!(output::BigInt, ::typeof(div), a::BigInt, b::BigInt)
55+
return Base.GMP.MPZ.tdiv_q!(output, a, b)
56+
end
57+
5258
# gcd
5359

5460
function promote_operation(
5561
::Union{typeof(gcd),typeof(lcm)},
56-
::Vararg{Type{BigInt},N},
57-
) where {N}
62+
::Type{BigInt},
63+
::Type{BigInt},
64+
)
5865
return BigInt
5966
end
6067

src/implementations/Rational.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,22 @@ function promote_operation(
4343
return Rational{promote_sum_mul(S, T)}
4444
end
4545

46+
function _buffered_simplify(buffer, x::Rational)
47+
operate_to!(buffer, gcd, x.num, x.den)
48+
if !isone(buffer)
49+
operate!(div, x.num, buffer)
50+
operate!(div, x.den, buffer)
51+
end
52+
end
53+
4654
function operate_to!(output::Rational, ::typeof(+), x::Rational, y::Rational)
4755
xd, yd = Base.divgcd(promote(x.den, y.den)...)
4856
# TODO: Use `checked_mul` and `checked_add` like in Base
4957
operate_to!(output.num, *, x.num, yd)
5058
operate!(add_mul, output.num, y.num, xd)
5159
operate_to!(output.den, *, x.den, yd)
60+
# Reuse `xd` as it is a local copy created by this method
61+
_buffered_simplify(xd, output)
5262
return output
5363
end
5464

@@ -68,6 +78,8 @@ function operate_to!(output::Rational, ::typeof(-), x::Rational, y::Rational)
6878
operate_to!(output.num, *, x.num, yd)
6979
operate!(sub_mul, output.num, y.num, xd)
7080
operate_to!(output.den, *, x.den, yd)
81+
# Reuse `xd` as it is a local copy created by this method
82+
_buffered_simplify(xd, output)
7183
return output
7284
end
7385

src/interface.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ end
6161
promote_operation_fallback(::typeof(*), ::Type{T}) where {T} = T
6262

6363
function promote_operation_fallback(
64-
::typeof(*),
64+
op::Union{typeof(*),typeof(+),typeof(gcd),typeof(lcm)},
6565
::Type{S},
6666
::Type{T},
6767
::Type{U},
6868
args::Vararg{Type,N},
6969
) where {S,T,U,N}
70-
return promote_operation(*, promote_operation(*, S, T), U, args...)
70+
return promote_operation(op, promote_operation(op, S, T), U, args...)
7171
end
7272

7373
# `Vararg` gives extra allocations on Julia v1.3, see

src/shortcuts.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,22 @@ Shortcut for `operate(*, a, b, ...)`, see [`operate`](@ref).
5757
"""
5858
mul(args::Vararg{Any,N}) where {N} = operate(*, args...)
5959

60+
"""
61+
div_to!!(output, a, b)
62+
63+
Return `div(a, b)` possibly modifying `output`.
64+
"""
65+
function div_to!!(output, a, b)
66+
return operate_to!!(output, div, a, b)
67+
end
68+
69+
"""
70+
div!!(a, b)
71+
72+
Return `div(a, b)` possibly modifying `a`.
73+
"""
74+
div!!(a, b) = operate!!(div, a, b)
75+
6076
"""
6177
gcd_to!!(a, b, c, ...)
6278

test/big.jl

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,22 @@
44
# v.2.0. If a copy of the MPL was not distributed with this file, You can obtain
55
# one at http://mozilla.org/MPL/2.0/.
66

7-
function allocation_test(op, T, short, short_to, n)
8-
a = T(2)
9-
b = T(3)
10-
c = T(4)
7+
function allocation_test(
8+
op,
9+
T,
10+
short,
11+
short_to,
12+
n;
13+
a = T(2),
14+
b = T(3),
15+
c = T(4),
16+
)
1117
@test MA.promote_operation(op, T, T) == T
12-
@test MA.promote_operation(op, T, T, T) == T
18+
alloc_test(() -> MA.promote_operation(op, T, T), 0)
19+
if op != div && op != -
20+
@test MA.promote_operation(op, T, T, T) == T
21+
alloc_test(() -> MA.promote_operation(op, T, T, T), 0)
22+
end
1323
g = op(a, b)
1424
@test c === short_to(c, a, b)
1525
@test g == c
@@ -23,9 +33,35 @@ end
2333
MA.Test.int_test(T)
2434
@testset "Allocation" begin
2535
allocation_test(+, T, MA.add!!, MA.add_to!!, T <: Rational ? 168 : 0)
36+
allocation_test(-, T, MA.sub!!, MA.sub_to!!, T <: Rational ? 168 : 0)
2637
allocation_test(*, T, MA.mul!!, MA.mul_to!!, T <: Rational ? 240 : 0)
38+
if T <: Rational # https://github.com/jump-dev/MutableArithmetics.jl/issues/167
39+
allocation_test(
40+
+,
41+
T,
42+
MA.add!!,
43+
MA.add_to!!,
44+
168,
45+
a = T(1 // 2),
46+
b = T(3 // 2),
47+
c = T(5 // 2),
48+
)
49+
allocation_test(
50+
-,
51+
T,
52+
MA.sub!!,
53+
MA.sub_to!!,
54+
168,
55+
a = T(1 // 2),
56+
b = T(3 // 2),
57+
c = T(5 // 2),
58+
)
59+
end
2760
# Requires https://github.com/JuliaLang/julia/commit/3f92832df042198b2daefc1f7ca609db38cb8173
2861
# for `gcd` to be defined on `Rational`.
62+
if T == BigInt
63+
allocation_test(div, T, MA.div!!, MA.div_to!!, 0)
64+
end
2965
if T == BigInt || T == Rational{BigInt}
3066
allocation_test(gcd, T, MA.gcd!!, MA.gcd_to!!, 0)
3167
allocation_test(lcm, T, MA.lcm!!, MA.lcm_to!!, 0)

0 commit comments

Comments
 (0)