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

Clarify that the unsigned type is promoted to, if the types differ only in signedness #48973

Merged
merged 5 commits into from
Mar 28, 2023

Conversation

robertfeldt
Copy link
Contributor

This choice was explained by Karpinski in

#9292 (comment)

but wasn't fully clear in the documentation. For example, it is hard to argue that an UInt64 is larger than an Int64, since they both are represented in 64 bits.

…ly in signedness. This choice was explained by Karpinski in JuliaLang#9292 (comment) but wasn't fully clear in the documentation.
@robertfeldt robertfeldt changed the title Clarify that the unsigned type is promoted to, if the types differ only in sightedness Clarify that the unsigned type is promoted to, if the types differ only in signedness Mar 11, 2023
@jakobnissen
Copy link
Contributor

Thanks for the PR. I just looked at the code in Base, and it looks like it doesn't follow the documented behaviour that it'll promote to machine native size if smaller. I.e. the docs lead me to believe that e.g. signed/unsigned UInt8 will promote to 64 bits on 64-bit systems but that seem not to be the case.
Am I right, and if so, could you perhaps amend the docs to be more accurate here?

@robertfeldt
Copy link
Contributor Author

Yes, you are right at least on my machine and on Julia 1.8.5 and Julia nightly (where I tested the below).

Here is the current text with sub-conditions named/numbered:

"Integer values are promoted to
(a) the larger of either the (a1) native machine word size or the (a2) largest integer argument type.
(b) If the types are the (b1) same size and (b2) differ in signedness, the unsigned type is chosen."

Now let's try some different cases and see what really happens:

# I'm on a 64 bit machine 
julia> versioninfo()
Julia Version 1.8.5
Commit 17cfb8e65ea (2023-01-08 06:45 UTC)
Platform Info:
  OS: macOS (arm64-apple-darwin21.5.0)
  CPU: 10 × Apple M1 Max
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, apple-m1)
  Threads: 8 on 8 virtual cores
Environment:
  JULIA_NUM_THREADS = 8

# Case 1: Int8 and UInt8 on 64 bit machine => UInt8 => not a1, but b1 (same size) and b2 (diffsign)
julia> max(Int8(1), UInt8(0)) |> typeof
UInt8

# Case 1b: Int16 and UInt16 follows same pattern as case 1
julia> max(Int16(1), UInt16(0)) |> typeof
UInt16

# Case 1c: Int32 and UInt32 follows same pattern as case 1
julia> max(Int32(1), UInt32(0)) |> typeof
UInt32

# Case 2: Int16 and UInt8 on 64 bit machine => Int16 => not a1, but a2 (larger)
julia> max(Int16(1), UInt8(0)) |> typeof
Int16

# Case 2b: Int32 and UInt16 on 64 bit machine follows same pattern as case 2
julia> max(Int32(1), UInt16(0)) |> typeof
Int32

# Case 2c: Int64 and UInt32 on 64 bit machine follows same pattern as case 2
julia> max(Int64(1), UInt32(0)) |> typeof
Int64

# Case 2d: Int128 and UInt64 on 64 bit machine follows same pattern as case 2
julia> max(Int128(1), UInt64(0)) |> typeof
Int128

# Case 3: Int8 and UInt8 on 64 bit machine => UInt8 => b1 (same size) and b2 (diffsign)
julia> max(Int8(1), UInt8(0)) |> typeof
UInt8

# Case 3b: Int16 and UInt16 on 64 bit machine follows same pattern as 3
julia> max(Int16(1), UInt16(0)) |> typeof
UInt16

# Case 3c: Int32 and UInt32 on 64 bit machine follows same pattern as 3
julia> max(Int32(1), UInt32(0)) |> typeof
UInt32

# Case 3d: Int64 and UInt64 on 64 bit machine follows same pattern as 3
julia> max(Int64(1), UInt64(0)) |> typeof
UInt64

# Case 3e: Int128 and UInt128 on 64 bit machine follows same pattern as 3
julia> max(Int128(1), UInt128(0)) |> typeof
UInt128

# Case 4: Int128 and BigInt on 64 bit machine => BigInt => a2 (larger)
julia> max(Int128(1), BigInt(0)) |> typeof
BigInt

# Case 4b: UInt128 and BigInt on 64 bit machine => BigInt => a2 (larger)
julia> max(UInt128(1), BigInt(0)) |> typeof
BigInt

So it seems to me that the text that captures this pattern is:

"Integer values are promoted to the largest integer argument type. If the types are the same size but differ in signedness, the unsigned type is chosen."

Unless there are more comments I'll go ahead and update the PR.

@inkydragon inkydragon added the docs This change adds or pertains to documentation label Mar 13, 2023
@robertfeldt
Copy link
Contributor Author

Text updated to reflect the actual behavior.

@robertfeldt
Copy link
Contributor Author

@jakobnissen if you need something more from me, just tell me...

@jakobnissen
Copy link
Contributor

I think this is good to go! Unfortunately I don't have permissions to merge PRs.

@jakobnissen jakobnissen added the merge me PR is reviewed. Merge when all tests are passing label Mar 15, 2023
promoted to the appropriate kind of complex value.
values are promoted to the largest of the integer argument types. If the types are the same size
but differ in signedness, the unsigned type is chosen. Mixtures of integers and floating-point
values are promoted to a floating-point type big enough to hold all the values. Integers mixed
Copy link
Member

@vtjnash vtjnash Mar 20, 2023

Choose a reason for hiding this comment

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

The (pre-existing) floating point comment doesn't seem particularly accurate: it is just promoted to the floating point type, whatever that is. For example:

julia> promote(Float16(1.0f0), typemax(Int))
(Float16(1.0), Inf16)

julia> promote(Float32(1), typemax(Int32))[2] |> Int 
2147483648

julia> typemax(Int32)
2147483647

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Correct @vtjnash. I can make the change to "Mixtures of integers and floating-point values are promoted to the floating-point type." if this is the wanted behavior and the current implementation is not the problem?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My point is that some people might find this quite unexpected:

julia> max(Float16(1), typemax(Int64))
Inf16

julia> versioninfo()
Julia Version 1.8.5
Commit 17cfb8e65ea (2023-01-08 06:45 UTC)
Platform Info:
  OS: macOS (arm64-apple-darwin21.5.0)
  CPU: 10 × Apple M1 Max
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, apple-m1)
  Threads: 8 on 8 virtual cores
Environment:
  JULIA_NUM_THREADS = 8

@DilumAluthge
Copy link
Member

Removing merge me pending Jameson's review.

@DilumAluthge DilumAluthge removed the merge me PR is reviewed. Merge when all tests are passing label Mar 28, 2023
@vtjnash vtjnash merged commit 045a392 into JuliaLang:master Mar 28, 2023
@vtjnash
Copy link
Member

vtjnash commented Mar 28, 2023

It is fine, since that text is actually pre-existing, though it contradicts the observed behavior.

Xnartharax pushed a commit to Xnartharax/julia that referenced this pull request Apr 19, 2023
Clarify that the unsigned type is promoted to, if the types differ only
in signedness. This choice was explained by Karpinski in
JuliaLang#9292 (comment)
but wasn't fully clear in the documentation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs This change adds or pertains to documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants