Fix gcdx and lcm with mixed signed/unsigned arguments#59628
Fix gcdx and lcm with mixed signed/unsigned arguments#59628adienes merged 1 commit intoJuliaLang:masterfrom
Conversation
0569b5f to
c44a3f6
Compare
c44a3f6 to
6b1cf5c
Compare
|
nice! I ended up with something very similar (locally). I think it would be good if we had a clear policy about which inputs are allowed for all of
as it stands, this error may be thrown in several places throughout the |
|
Indeed! With this PR, the behaviour of julia> lcm(typemin(Int8), UInt16(256))
ERROR: InexactError: trunc(UInt16, -128)
Stacktrace:
[1] throw_inexacterror(func::Symbol, to::Type, val::Int8)
@ Core ./boot.jl:866
[2] check_sign_bit
@ ./boot.jl:872 [inlined]
[3] toUInt16
@ ./boot.jl:958 [inlined]
[4] UInt16
@ ./boot.jl:1011 [inlined]
[5] convert
@ ./number.jl:7 [inlined]
[6] _promote
@ ./promotion.jl:379 [inlined]
[7] promote
@ ./promotion.jl:404 [inlined]
[8] lcm(a::Int8, b::UInt16)
@ Main ./REPL[6]:1
[9] top-level scope
@ REPL[15]:1
julia> gcd(typemin(Int8), UInt16(256)) # untouched, current behaviour
ERROR: InexactError: trunc(UInt16, -128)
Stacktrace:
[1] throw_inexacterror(func::Symbol, to::Type, val::Int8)
@ Core ./boot.jl:866
[2] check_sign_bit
@ ./boot.jl:872 [inlined]
[3] toUInt16
@ ./boot.jl:958 [inlined]
[4] UInt16
@ ./boot.jl:1011 [inlined]
[5] convert
@ ./number.jl:7 [inlined]
[6] _promote
@ ./promotion.jl:379 [inlined]
[7] promote
@ ./promotion.jl:404 [inlined]
[8] gcd(a::Int8, b::UInt16)
@ Base ./intfuncs.jl:150
[9] top-level scope
@ REPL[16]:1
julia> gcdx(typemin(Int8), UInt16(256))
(0x0080, 0xffff, 0x0000)Adding support for the Irrespective of this PR, there is of course still the following discrepancy on non-mixed types: julia> gcdx(typemin(Int8), typemin(Int8)) # violate the condition "d is positive" from the documentation
(-128, 0, -1)
julia> gcdx(typemin(Int8), Int8(0)) # violate the condition "d is positive" from the documentation
(-128, -1, 0)
julia> gcd(typemin(Int8), typemin(Int8))
ERROR: OverflowError: gcd(-128, -128) overflows
Stacktrace:
[1] __throw_gcd_overflow(a::Int8, b::Int8)
@ Base .\intfuncs.jl:65
[2] gcd(a::Int8, b::Int8)
@ Base .\intfuncs.jl:58
[3] top-level scope
@ REPL[3]:1
julia> gcd(typemin(Int8), Int8(0))
ERROR: OverflowError: checked arithmetic: cannot compute |x| for x = -128::Int8
Stacktrace:
[1] checked_abs
@ .\checked.jl:128 [inlined]
[2] gcd(a::Int8, b::Int8)
@ Base .\intfuncs.jl:55
[3] top-level scope
@ REPL[5]:1but again, I'd rather keep it separate from the bugfix here. |
fair enough. I do believe this is a strict improvement; I can't find any test cases where erroring-ness changes from master, and everywhere the value changes it correctly matches |
Add `gcdx(a::Signed, b::Unsigned)` and `gcdx(a::Unsigned, b::Signed)` methods to fix #58025: ```julia julia> gcdx(UInt16(100), Int8(-101)) # pr (0x0001, 0xffff, 0xffff) julia> gcdx(UInt16(100), Int8(-101)) # master, incorrect result (0x0005, 0xf855, 0x0003) ``` Also add the equivalent methods for `lcm` to fix the systematic `InexactError` when one argument is a negative `Signed` and the other is any `Unsigned`: ```julia julia> lcm(UInt16(100), Int8(-101)) # pr 0x2774 julia> lcm(UInt16(100), Int8(-101)) # master, error ERROR: InexactError: trunc(UInt16, -101) Stacktrace: [1] throw_inexacterror(func::Symbol, to::Type, val::Int8) @ Core ./boot.jl:866 [2] check_sign_bit @ ./boot.jl:872 [inlined] [3] toUInt16 @ ./boot.jl:958 [inlined] [4] UInt16 @ ./boot.jl:1011 [inlined] [5] convert @ ./number.jl:7 [inlined] [6] _promote @ ./promotion.jl:379 [inlined] [7] promote @ ./promotion.jl:404 [inlined] [8] lcm(a::UInt16, b::Int8) @ Base ./intfuncs.jl:152 [9] top-level scope @ REPL[62]:1 ``` Inspired by #59487 (comment). The difference is that the solution proposed in this PR keeps the current correct result type for inputs such as `(::Int16, ::UInt8)`. (cherry picked from commit 4f1e471)
Add `gcdx(a::Signed, b::Unsigned)` and `gcdx(a::Unsigned, b::Signed)` methods to fix #58025: ```julia julia> gcdx(UInt16(100), Int8(-101)) # pr (0x0001, 0xffff, 0xffff) julia> gcdx(UInt16(100), Int8(-101)) # master, incorrect result (0x0005, 0xf855, 0x0003) ``` Also add the equivalent methods for `lcm` to fix the systematic `InexactError` when one argument is a negative `Signed` and the other is any `Unsigned`: ```julia julia> lcm(UInt16(100), Int8(-101)) # pr 0x2774 julia> lcm(UInt16(100), Int8(-101)) # master, error ERROR: InexactError: trunc(UInt16, -101) Stacktrace: [1] throw_inexacterror(func::Symbol, to::Type, val::Int8) @ Core ./boot.jl:866 [2] check_sign_bit @ ./boot.jl:872 [inlined] [3] toUInt16 @ ./boot.jl:958 [inlined] [4] UInt16 @ ./boot.jl:1011 [inlined] [5] convert @ ./number.jl:7 [inlined] [6] _promote @ ./promotion.jl:379 [inlined] [7] promote @ ./promotion.jl:404 [inlined] [8] lcm(a::UInt16, b::Int8) @ Base ./intfuncs.jl:152 [9] top-level scope @ REPL[62]:1 ``` Inspired by #59487 (comment). The difference is that the solution proposed in this PR keeps the current correct result type for inputs such as `(::Int16, ::UInt8)`. (cherry picked from commit 4f1e471)
Add `gcdx(a::Signed, b::Unsigned)` and `gcdx(a::Unsigned, b::Signed)` methods to fix #58025: ```julia julia> gcdx(UInt16(100), Int8(-101)) # pr (0x0001, 0xffff, 0xffff) julia> gcdx(UInt16(100), Int8(-101)) # master, incorrect result (0x0005, 0xf855, 0x0003) ``` Also add the equivalent methods for `lcm` to fix the systematic `InexactError` when one argument is a negative `Signed` and the other is any `Unsigned`: ```julia julia> lcm(UInt16(100), Int8(-101)) # pr 0x2774 julia> lcm(UInt16(100), Int8(-101)) # master, error ERROR: InexactError: trunc(UInt16, -101) Stacktrace: [1] throw_inexacterror(func::Symbol, to::Type, val::Int8) @ Core ./boot.jl:866 [2] check_sign_bit @ ./boot.jl:872 [inlined] [3] toUInt16 @ ./boot.jl:958 [inlined] [4] UInt16 @ ./boot.jl:1011 [inlined] [5] convert @ ./number.jl:7 [inlined] [6] _promote @ ./promotion.jl:379 [inlined] [7] promote @ ./promotion.jl:404 [inlined] [8] lcm(a::UInt16, b::Int8) @ Base ./intfuncs.jl:152 [9] top-level scope @ REPL[62]:1 ``` Inspired by #59487 (comment). The difference is that the solution proposed in this PR keeps the current correct result type for inputs such as `(::Int16, ::UInt8)`. (cherry picked from commit 4f1e471)
Add `gcdx(a::Signed, b::Unsigned)` and `gcdx(a::Unsigned, b::Signed)` methods to fix JuliaLang#58025: ```julia julia> gcdx(UInt16(100), Int8(-101)) # pr (0x0001, 0xffff, 0xffff) julia> gcdx(UInt16(100), Int8(-101)) # master, incorrect result (0x0005, 0xf855, 0x0003) ``` Also add the equivalent methods for `lcm` to fix the systematic `InexactError` when one argument is a negative `Signed` and the other is any `Unsigned`: ```julia julia> lcm(UInt16(100), Int8(-101)) # pr 0x2774 julia> lcm(UInt16(100), Int8(-101)) # master, error ERROR: InexactError: trunc(UInt16, -101) Stacktrace: [1] throw_inexacterror(func::Symbol, to::Type, val::Int8) @ Core ./boot.jl:866 [2] check_sign_bit @ ./boot.jl:872 [inlined] [3] toUInt16 @ ./boot.jl:958 [inlined] [4] UInt16 @ ./boot.jl:1011 [inlined] [5] convert @ ./number.jl:7 [inlined] [6] _promote @ ./promotion.jl:379 [inlined] [7] promote @ ./promotion.jl:404 [inlined] [8] lcm(a::UInt16, b::Int8) @ Base ./intfuncs.jl:152 [9] top-level scope @ REPL[62]:1 ``` Inspired by JuliaLang#59487 (comment). The difference is that the solution proposed in this PR keeps the current correct result type for inputs such as `(::Int16, ::UInt8)`.
Add `gcdx(a::Signed, b::Unsigned)` and `gcdx(a::Unsigned, b::Signed)` methods to fix #58025: ```julia julia> gcdx(UInt16(100), Int8(-101)) # pr (0x0001, 0xffff, 0xffff) julia> gcdx(UInt16(100), Int8(-101)) # master, incorrect result (0x0005, 0xf855, 0x0003) ``` Also add the equivalent methods for `lcm` to fix the systematic `InexactError` when one argument is a negative `Signed` and the other is any `Unsigned`: ```julia julia> lcm(UInt16(100), Int8(-101)) # pr 0x2774 julia> lcm(UInt16(100), Int8(-101)) # master, error ERROR: InexactError: trunc(UInt16, -101) Stacktrace: [1] throw_inexacterror(func::Symbol, to::Type, val::Int8) @ Core ./boot.jl:866 [2] check_sign_bit @ ./boot.jl:872 [inlined] [3] toUInt16 @ ./boot.jl:958 [inlined] [4] UInt16 @ ./boot.jl:1011 [inlined] [5] convert @ ./number.jl:7 [inlined] [6] _promote @ ./promotion.jl:379 [inlined] [7] promote @ ./promotion.jl:404 [inlined] [8] lcm(a::UInt16, b::Int8) @ Base ./intfuncs.jl:152 [9] top-level scope @ REPL[62]:1 ``` Inspired by #59487 (comment). The difference is that the solution proposed in this PR keeps the current correct result type for inputs such as `(::Int16, ::UInt8)`. (cherry picked from commit 4f1e471)
Add
gcdx(a::Signed, b::Unsigned)andgcdx(a::Unsigned, b::Signed)methods to fix #58025:Also add the equivalent methods for
lcmto fix the systematicInexactErrorwhen one argument is a negativeSignedand the other is anyUnsigned:Inspired by #59487 (comment). The difference is that the solution proposed in this PR keeps the current correct result type for inputs such as
(::Int16, ::UInt8).