Skip to content

Commit cbdb321

Browse files
KlausCStefanKarpinski
authored andcommitted
BUGFIX avoid silent overflow in lcm least common multiple function (#33926)
1 parent 8a47793 commit cbdb321

File tree

3 files changed

+9
-5
lines changed

3 files changed

+9
-5
lines changed

base/intfuncs.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ function lcm(a::T, b::T) where T<:Integer
6868
if a == 0
6969
return a
7070
else
71-
return checked_abs(a * div(b, gcd(b,a)))
71+
return checked_abs(checked_mul(a, div(b, gcd(b,a))))
7272
end
7373
end
7474

base/twiceprecision.jl

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ function (:)(start::T, step::T, stop::T) where T<:Union{Float16,Float32,Float64}
393393
stop_n, stop_d = rat(stop)
394394
if start_d != 0 && stop_d != 0 &&
395395
T(start_n/start_d) == start && T(stop_n/stop_d) == stop
396-
den = lcm(start_d, step_d) # use same denominator for start and step
396+
den = lcm_unchecked(start_d, step_d) # use same denominator for start and step
397397
m = maxintfloat(T, Int)
398398
if den != 0 && abs(start*den) <= m && abs(step*den) <= m && # will round succeed?
399399
rem(den, start_d) == 0 && rem(den, step_d) == 0 # check lcm overflow
@@ -429,7 +429,7 @@ function _range(a::T, st::T, ::Nothing, len::Integer) where T<:Union{Float16,Flo
429429
step_n, step_d = rat(st)
430430
if start_d != 0 && step_d != 0 &&
431431
T(start_n/start_d) == a && T(step_n/step_d) == st
432-
den = lcm(start_d, step_d)
432+
den = lcm_unchecked(start_d, step_d)
433433
m = maxintfloat(T, Int)
434434
if abs(den*a) <= m && abs(den*st) <= m &&
435435
rem(den, start_d) == 0 && rem(den, step_d) == 0
@@ -513,7 +513,7 @@ function _convertSRL(::Type{StepRangeLen{T,R,S}}, r::AbstractRange{U}) where {T,
513513
step_n, step_d = rat(s)
514514
if start_d != 0 && step_d != 0 &&
515515
U(start_n/start_d) == f && U(step_n/step_d) == s
516-
den = lcm(start_d, step_d)
516+
den = lcm_unchecked(start_d, step_d)
517517
m = maxintfloat(T, Int)
518518
if den != 0 && abs(f*den) <= m && abs(s*den) <= m &&
519519
rem(den, start_d) == 0 && rem(den, step_d) == 0
@@ -582,7 +582,7 @@ function _range(start::T, ::Nothing, stop::T, len::Integer) where {T<:IEEEFloat}
582582
start_n, start_d = rat(start)
583583
stop_n, stop_d = rat(stop)
584584
if start_d != 0 && stop_d != 0
585-
den = lcm(start_d, stop_d)
585+
den = lcm_unchecked(start_d, stop_d)
586586
m = maxintfloat(T, Int)
587587
if den != 0 && abs(den*start) <= m && abs(den*stop) <= m
588588
start_n = round(Int, den*start)
@@ -691,6 +691,9 @@ function rat(x)
691691
return a, b
692692
end
693693

694+
# This version of lcm does not check for overflows
695+
lcm_unchecked(a::T, b::T) where T<:Integer = a * div(b, gcd(a, b))
696+
694697
narrow(::Type{T}) where {T<:AbstractFloat} = Float64
695698
narrow(::Type{Float64}) = Float32
696699
narrow(::Type{Float32}) = Float16

test/intfuncs.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ using Random
3535
@test lcm(-typemax(T), T(1)) === typemax(T)
3636
@test_throws OverflowError lcm(typemin(T), T(1))
3737
@test_throws OverflowError lcm(typemin(T), typemin(T))
38+
@test_throws OverflowError lcm(typemax(T), T(2))
3839
end
3940
end
4041
@testset "gcd/lcm for arrays" begin

0 commit comments

Comments
 (0)