- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 5.7k
Fix gcdx and lcm with mixed signed/unsigned arguments #59628
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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).