Skip to content
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

Avoid silent overflow in /(x::Rational, y::Complex{Int}) #53453

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion base/complex.jl
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ muladd(z::Complex, w::Complex, x::Real) =
Complex(muladd(real(z), real(w), -muladd(imag(z), imag(w), -x)),
muladd(real(z), imag(w), imag(z) * real(w)))

/(a::R, z::S) where {R<:Real,S<:Complex} = (T = promote_type(R,S); a*inv(T(z)))
/(a::R, z::S) where {R<:Real, S<:Complex} = (T = promote_type(R,S); a*inv(T(z)))
/(z::Complex, x::Real) = Complex(real(z)/x, imag(z)/x)

function /(a::Complex{T}, b::Complex{T}) where T<:Real
Expand Down
18 changes: 15 additions & 3 deletions base/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -401,9 +401,21 @@ function *(y::Integer, x::Rational)
yn, xd = divgcd(promote(y, x.den)...)
unsafe_rational(checked_mul(yn, x.num), xd)
end
/(x::Rational, y::Union{Rational, Integer, Complex{<:Union{Integer,Rational}}}) = x//y
/(x::Union{Integer, Complex{<:Union{Integer,Rational}}}, y::Rational) = x//y
inv(x::Rational{T}) where {T} = checked_den(x.den, x.num)
/(x::Rational, y::Union{Rational, Integer}) = x//y
/(x::Integer, y::Rational) = x//y
# Avoid overflow for Rational math if result is zero.
# This method is needed because previously this method didn't check for overflows
# but would return the correct answer if `a` was zero even if 1//z was wrong.
function /(a::Rational, z::Complex{<:Integer})
z_r = complex(Rational(real(z)), Rational(imag(z)))
if iszero(a) && !iszero(z)
a/oneunit(z_r)
else
a/z_r
end
end

inv(x::Rational) = checked_den(x.den, x.num)
nhz2 marked this conversation as resolved.
Show resolved Hide resolved

fma(x::Rational, y::Rational, z::Rational) = x*y+z

Expand Down
16 changes: 16 additions & 0 deletions test/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,22 @@ end
end

@test Rational(rand_int, 3)/Complex(3, 2) == Complex(Rational(rand_int, 13), -Rational(rand_int*2, 39))
@test iszero(zero(Rational{Int8}) / complex(Int8(100), Int8(100)))
@test (true//true) / complex(false, true) === 0//1 - 1//1*im
@test (false//true) / complex(false, true) === 0//1 + 0//1*im
@test (false//true) / complex(true, false) === 0//1 + 0//1*im
@test (false//true) / complex(true, true) === 0//1 + 0//1*im
@test (true//true) / complex(true, true) === 1//2 - 1//2*im
@test (false//true) / complex(true//true, true//true) === 0//1 + 0//1*im
@test (true//true) / complex(true//true, true//true) === 1//2 - 1//2*im
@test (false//true) / complex(true//false, false//true) === 0//1 + 0//1*im
@test (true//true) / complex(true//true, true//false) === 0//1 + 0//1*im
@test_throws DivideError (0//1) / complex(0, 0)
@test_throws DivideError (1//1) / complex(0, 0)
Copy link
Contributor

@nsajko nsajko Oct 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong. The correct result is positive infinity, just like here:

julia> (1 // 1) / 0
1//0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With complex numbers, there are many possible infinities, I'm not sure what infinity is correct.

julia> 1.0/(0.0im)
NaN + NaN*im

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, sorry.

@test_throws DivideError (1//0) / complex(0, 0)

# 1//200 - 1//200*im cannot be represented as Complex{Rational{Int8}}
@test_throws OverflowError (Int8(1)//Int8(1)) / (Int8(100) + Int8(100)im)

@test Complex(rand_int, 0) == Rational(rand_int)
@test Rational(rand_int) == Complex(rand_int, 0)
Expand Down