-
-
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
Converting between integer types #22235
Conversation
base/math.jl
Outdated
@@ -41,9 +41,11 @@ end | |||
|
|||
""" | |||
clamp(x, lo, hi) | |||
clamp(x, T) |
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.
Typically in Base APIs, the type argument comes first. So this should be clamp(T, x)
.
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.
Documentation wasn't updated.
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.
I pushed a commit to fix that.
base/math.jl
Outdated
@@ -59,10 +61,13 @@ clamp(x::X, lo::L, hi::H) where {X,L,H} = | |||
convert(promote_type(X,L,H), lo), | |||
convert(promote_type(X,L,H), x))) | |||
|
|||
clamp( x, ::Type{T} ) where {T} = clamp( x, typemin(T), typemax(T) ) % T |
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.
No spaces around parens (here and elsewhere)
How does this differ from |
julia> trunc(Int8, 1000)
ERROR: InexactError()
Stacktrace:
[1] trunc(::Type{Int8}, ::Int64) at ./int.jl:407
julia> clamp(Int8, 1000)
127 |
base/math.jl
Outdated
@@ -72,6 +77,13 @@ function clamp!(x::AbstractArray, lo, hi) | |||
x | |||
end | |||
|
|||
function clamp!(x::AbstractArray, ::Type{T}) where {T} |
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.
not strictly related, but is the clamp!
function even necessary? Seems to me it could be written
A .= clamp.(lo, A, hi)
instead of
clamp!(A, lo, hi)
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.
I completely agree. It seemed strange that the vector version of clamp has been deprecated but the in place version hadn't.
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.
Isn't that the case with multiple in place functions right now, e.g:
fill!(A, x) -> A .= x
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.
fill!
is a little different IMO since it's intended to work on the array as a whole, whereas this clamp!
method is more like implicit vectorization.
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.
What does "intended to work on the array as a whole" mean?
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.
I guess I think of fill!
as more like an initialization operation for the array (even though it isn't exactly)
FWIW, since the type |
Personally I think it's more important to be consistent with APIs. |
I also prefer the symmetry with |
|
+1 to this functionality; not sure about the argument order although my first instinct is |
base/math.jl
Outdated
@@ -41,9 +41,11 @@ end | |||
|
|||
""" | |||
clamp(x, lo, hi) | |||
clamp(T, x) |
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.
I think that this would be more clear (i.e. more distinct) with two separate docstrings instead of trying to explain two things in the same docstring.
Something like:
"""
clamp(T, x)
Clamp `x` between `typemin(T)` and `typemax(T)` and convert the result to type `T`.
```jldoctest
julia> clamp(Int8, 200)
127
julia> clamp(Int8, -200)
-128
```
"""
base/math.jl
Outdated
@@ -59,6 +61,7 @@ clamp(x::X, lo::L, hi::H) where {X,L,H} = | |||
convert(promote_type(X,L,H), lo), | |||
convert(promote_type(X,L,H), x))) | |||
|
|||
clamp(::Type{T}, x) where {T} = clamp(x, typemin(T), typemax(T)) % T |
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.
Maybe where {T<:Integer}
?
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.
Yes. It doesn't make sense for floats - the %
operator isn't defined, and the problem doesn't exist because conversion to a narrower float clamps to typemin
and typemax
(+/-Inf) anyway.
base/math.jl
Outdated
clamp!(array::AbstractArray, lo, hi) | ||
clamp!(array::AbstractArray, T) |
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 line should be removed since you aren't defining this method
Sorry to insist for the order of parameters, but in my eyes |
Type first is a frequent convention when the return type (or element type) is part of what's asked for in an API, but not an absolutely universal one. I think If this had the same promotion behavior as |
Oh, I didn't notice the |
Not converting the result to |
For me, the conversion is important - I want to be able to define clamping-conversions for my own integer types - preferably using a standardized interface. How about: and implement & document both. |
|
Not sure about the three argument version:
This has overflowed rather than been clamped. I guess we could try to limit the type T1 to be 'bigger than or equal to' T2. The original use of '%' was to do a quick and safe (from overflow) conversion. It seems simpler just to have two variants of the two arg version: |
IMO having methods |
My entire motivation for this was to define a standard name for a clamping-conversion. The existing clamp does not convert, and the one I want to add does. I don't think we need a version where we supply two type names though. |
👍 to the |
This is #22235, but with the reversed argument order. ``` julia> clamp( 260, UInt8 ) 0xff ``` Co-authored-by: "arghhhh <[email protected]>"
This is #22235, but with the reversed argument order. ``` julia> clamp( 260, UInt8 ) 0xff ``` Co-authored-by: "arghhhh <[email protected]>"
Rebased with the reversed argument order in #34426. |
This is #22235, but with the reversed argument order. ``` julia> clamp( 260, UInt8 ) 0xff ``` Co-authored-by: "arghhhh <[email protected]>"
This is #22235, but with the reversed argument order. ``` julia> clamp( 260, UInt8 ) 0xff ``` Co-authored-by: "arghhhh <[email protected]>"
Julia currently has two ways of converting between integer types.
You can construct one integer type from another and this is range checked eg:
The other way is to use the modulo operator
%
:This never fails and just chops the MSBs to give you the answer modulo style - and this is very fast (a single LLVM instruction).
This pull request adds a third method - where you also want the conversion to always succeed, but you want the closest representable value. This is essentially the
clamp
function followed by the%
operator - so I've extended the functionality ofclamp
rather than make up a new name. eg:For completeness, I have also added the equivalent in-place function
clamp!
though it cannot change the type.