-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
fix hypot with multiple arguments #38158
Conversation
@@ -1150,12 +1150,7 @@ for func in (:sin,:cos,:tan,:asin,:acos,:atan,:sinh,:cosh,:tanh,:asinh,:acosh, | |||
end | |||
end | |||
|
|||
for func in (:atan,:hypot) | |||
@eval begin | |||
$func(a::Float16,b::Float16) = Float16($func(Float32(a),Float32(b))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we still use this for hypot
of `Float16?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could, though as the PR was written, it would have been the wrong function to overload (since we want to always give it once chance to call float
, then give it once chance to dispatch on the result, even if the type of the answer is the unchaged). It would be possible to define:
_hypot(a::Float16, b::Float16) = Float16(_hypot(Float32(a), Float32(b)))
_hypot(xs::Float16...) = Float16(_hypot(Float32.(xs)...))
But this also fall out of the generic definition _hypot
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This indeed seems to have broken things #38311 (comment)
@test (@inferred hypot(Furlong(1), Furlong(1), Furlong(1))) == Furlong(sqrt(3)) | ||
@test (@inferred hypot(Furlong(Inf), Furlong(NaN), Furlong(0))) == Furlong(Inf) | ||
@test (@inferred hypot(Furlong(Inf), Furlong(Inf), Furlong(Inf))) == Furlong(Inf) | ||
@test isnan(hypot(Furlong(NaN), Furlong(0), Furlong(1))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can there be a test hypot(Furlong(1), 1)
etc. to check that an error is thrown? I think this might fail currently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what it does currently (master and PR):
julia> hypot(Furlongs.Furlong(1), 1)
ERROR: promotion of types Main.Furlongs.Furlong{1, Int64} and Int64 failed to change any arguments
Stacktrace:
[1] error(::String, ::String, ::String)
@ Base ./error.jl:42
[2] sametype_error(input::Tuple{Main.Furlongs.Furlong{1, Int64}, Int64})
@ Base ./promotion.jl:316
[3] not_sametype(x::Tuple{Main.Furlongs.Furlong{1, Int64}, Int64}, y::Tuple{Main.Furlongs.Furlong{1, Int64}, Int64})
@ Base ./promotion.jl:310
[4] promote
@ ./promotion.jl:293 [inlined]
[5] hypot(::Main.Furlongs.Furlong{1, Int64}, ::Int64)
@ Base.Math ./math.jl:641
[6] top-level scope
@ REPL[5]:1
And I added a test for it also to make sure that continues to operate the same. Is that what you were intending?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding the test and for explaining that this PR doesn't change the error behavior of hypot(x, y)
for disparate dimensions. I think it would be better for a user if hypot
throws an error that has to do with a failure to compute on disparate dimensions instead of a promotion error, but that's not the point of this PR I suppose.
I still think it's the case that _hypot(Furlongs.Furlong(1), 1)
will produce a meaningless result instead of an error. Perhaps that should be documented, even though this function should be not used externally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like that also still fails, since we need to find the maximum value:
julia> Base.Math._hypot(Furlongs.Furlong(1), 1)
ERROR: MethodError: no method matching isless(::Main.Furlongs.Furlong{0, Float64}, ::Float64)
Closest candidates are:
isless(::Main.Furlongs.Furlong{p, T} where T<:Number, ::Main.Furlongs.Furlong{p, T} where T<:Number) where p at /Users/jameson/julia/test/testhelpers/Furlongs.jl:64
isless(::Any, ::Missing) at missing.jl:88
isless(::Missing, ::Any) at missing.jl:87
...
Stacktrace:
[1] <(x::Main.Furlongs.Furlong{0, Float64}, y::Float64)
@ Base ./operators.jl:279
[2] >(x::Float64, y::Main.Furlongs.Furlong{0, Float64})
@ Base ./operators.jl:305
[3] _hypot(x::Main.Furlongs.Furlong{1, Int64}, y::Int64)
@ Base.Math ./math.jl:657
[4] top-level scope
@ REPL[2]:1
I can require them to have the same type via the method signature, but I'm more inclined to let the user call Math._hypot
directly if they want to, and leave the error checking to the public hypot
function.
Fixes JuliaLang#27141: The previous code led to under/overflow.
Fixes #27141: The previous code led to under/overflow.
Rebase from #30301 (no permissions to update that directly).
Seems to remove the special cases for Number types added in #34817, but seems to still be passing the tests.