# Sum of rationals

I wrote the following function to calculate the sum of a vector of rational numbers:

``````function rationalsum(numbers::Vector{T} where T<:Rational)
den = lcm([x.den for x in numbers])
nums = (x.num * div(den, x.den) for x in numbers)
return sum(nums)//den
end
``````

In my benchmarks it is 4-8 times faster than `sum()` (depending on the rational numbers). My first assumption was that this is because the `sum()` method looks for the common denominator at every step. But the performance ratio between the two appears to be close to constant, so this is likely not the explanation. Is my implementation bad or missing something?

Your function doesn’t check for overflow, where most/all(?) operations on `Rational`s are checked:

``````julia> rats = [(typemax(Int64)-1)//typemax(Int64), (typemax(Int64)-2)//typemax(Int64), (typemax(Int64)-1)//typemax(Int64)]
3-element Vector{Rational{Int64}}:
9223372036854775806//9223372036854775807
9223372036854775805//9223372036854775807
9223372036854775806//9223372036854775807

julia> sum(rats)
ERROR: OverflowError: 9223372036854775806 + 9223372036854775805 overflowed for type Int64
Stacktrace:
 throw_overflowerr_binaryop(op::Symbol, x::Int64, y::Int64)
@ Base.Checked ./checked.jl:155
@ ./checked.jl:167 [inlined]
 +
@ ./rational.jl:290 [inlined]
@ ./reduce.jl:27 [inlined]
 _mapreduce(f::typeof(identity), op::typeof(Base.add_sum), #unused#::IndexLinear,
...
 sum(a::Vector{Rational{Int64}})
@ Base ./reducedim.jl:994
 top-level scope
@ REPL:1

julia> function rationalsum(numbers::Vector{T} where T<:Rational)
den = lcm([x.den for x in numbers])
nums = (x.num * div(den, x.den) for x in numbers)
return sum(nums)//den
end
rationalsum (generic function with 1 method)

julia> rationalsum(rats)
9223372036854775801//9223372036854775807
``````
4 Likes