# Is there a way to convert UInt to Int without overflow check?

Thanks to @kristoffer.carlsson I fixed the immediate problem and can make my PR better (more general); the possible “better compiler” part below still stands; Julia could have done this for the code as is.

In my PR for better factorial, Int64 case is good, but it’s worse for UInt64:

``````julia> @inline function factorial_lookup(n::Integer, table, lim)
if false # !(0 <= n <= 20)   # disabled for minimal example
return factorial_lookup_helper(n, table, lim)
else
@inbounds f = _shifted_fact_table64[oftype(Int64, n)+1]  # was _shifted_fact_table64[n+1]
return oftype(n, f)
end
end
factorial_lookup (generic function with 1 method)

@inline factorial_new(n::Union{Int64,UInt64}) = factorial_lookup(n, _fact_table64, 20)
``````

[The “between check” (now disabled) doesn’t help, but with a better compiler it should, as then no possibility of overflow.]

@code_native factorial_new(20) is at the bottom but for UInt I get more complex:

[this is for the line with oftype (better way to do this? reinterpret instead of oftype isn’t it. There’s the @checked macro, but I want basically the opposite @nocheck I’ve not found):

``````julia> @code_native factorial_new(UInt(20))
.text
; ┌ @ REPL[220]:1 within `factorial_new'
subq	\$56, %rsp
xorps	%xmm0, %xmm0
movaps	%xmm0, (%rsp)
movq	\$0, 16(%rsp)
movq	%fs:0, %rax
; │┌ @ REPL[248]:5 within `factorial_lookup'
movq	\$2, (%rsp)
movq	-15552(%rax), %rcx
movq	%rcx, 8(%rsp)
movq	%rsp, %rcx
movq	%rcx, -15552(%rax)
movabsq	\$jl_box_uint64, %rax
callq	*%rax
movq	%rax, 16(%rsp)
movabsq	\$jl_system_image_data, %rcx
movq	%rcx, 32(%rsp)
movabsq	\$139784872953840, %rcx  # imm = 0x7F2233B287F0
movq	%rcx, 40(%rsp)
movq	%rax, 48(%rsp)
movabsq	\$jl_invoke, %rax
movabsq	\$139784880894096, %rdi  # imm = 0x7F22342BB090
leaq	32(%rsp), %rsi
movl	\$3, %edx
callq	*%rax
ud2
nopw	%cs:(%rax,%rax)
; └└
``````

Without oftype worse:

``````julia> @code_native factorial_new(UInt(20))
.text
; ┌ @ REPL[220]:1 within `factorial_new'
; │┌ @ REPL[244]:5 within `factorial_lookup'
; ││┌ @ multidimensional.jl:458 within `getindex' @ REPL[220]:1
pushq	%rax
movabsq	\$139784873942800, %rax  # imm = 0x7F2233C19F10
movq	(%rax), %rax
movq	(%rax,%rdi,8), %rax
; │└└
; │┌ @ boot.jl:587 within `factorial_lookup'
testq	%rax, %rax
; │└
; │┌ @ REPL[244]:6 within `factorial_lookup'
; ││┌ @ essentials.jl:334 within `oftype'
; │││┌ @ number.jl:7 within `convert'
; ││││┌ @ boot.jl:738 within `Type'
; │││││┌ @ boot.jl:708 within `toUInt64'
; ││││││┌ @ boot.jl:597 within `check_top_bit'
js	L25
; │└└└└└└
popq	%rcx
retq
; │┌ @ REPL[244]:6 within `factorial_lookup'
; ││┌ @ essentials.jl:334 within `oftype'
; │││┌ @ number.jl:7 within `convert'
; ││││┌ @ boot.jl:738 within `Type'
; │││││┌ @ boot.jl:708 within `toUInt64'
; ││││││┌ @ boot.jl:597 within `check_top_bit'
L25:
movabsq	\$throw_inexacterror, %rcx
movabsq	\$139784870391424, %rdi  # imm = 0x7F22338B6E80
movabsq	\$139784872953840, %rsi  # imm = 0x7F2233B287F0
movq	%rax, %rdx
callq	*%rcx
ud2
nop
; └└└└└└└
``````

For Int64 ok (without oftype):

``````julia> @code_native factorial_new(20)
.text
; ┌ @ REPL[221]:1 within `factorial_new'
; │┌ @ REPL[244]:5 within `factorial_lookup'
; ││┌ @ REPL[221]:1 within `getindex'
movabsq	\$139784873942800, %rax  # imm = 0x7F2233C19F10
movq	(%rax), %rax
movq	(%rax,%rdi,8), %rax
; │└└
retq
nopw	%cs:(%rax,%rax)
; └
``````
1 Like

Is there a way to convert UInt to Int without overflow check?

``````julia> UInt(5) % Int
5

julia> typemax(UInt) % Int
-1

julia> @code_llvm UInt(5) % Int

; Function rem
; Location: int.jl:468
; Function Attrs: uwtable
define i64 @julia_rem_35211(i64, %jl_value_t addrspace(10)*) #0 {
top:
ret i64 %0
}
``````

Thanks, but doesn’t seem to work.

I’m maybe getting better code (at least shorter, back to e.g. with “\$throw_inexacterror” in asm; you have to scroll to see it), but unless I misunderstood you, and this isn’t the correct new line not fully what I wanted:

@inbounds f = _shifted_fact_table64[(n % Int)+1] # and not better with Int[64]: _shifted_fact_table64[Int64(n % Int)+1]

``````julia> @code_native factorial_new(UInt(20))
.text
; ┌ @ REPL[220]:1 within `factorial_new'
; │┌ @ REPL[262]:5 within `factorial_lookup'
; ││┌ @ REPL[220]:1 within `getindex'
pushq	%rax
movabsq	\$139784873942800, %rax  # imm = 0x7F2233C19F10
movq	(%rax), %rax
movq	(%rax,%rdi,8), %rax
; │└└
; │┌ @ boot.jl:587 within `factorial_lookup'
testq	%rax, %rax
; │└
; │┌ @ REPL[262]:6 within `factorial_lookup'
; ││┌ @ essentials.jl:334 within `oftype'
; │││┌ @ number.jl:7 within `convert'
; ││││┌ @ boot.jl:738 within `Type'
; │││││┌ @ boot.jl:708 within `toUInt64'
; ││││││┌ @ boot.jl:597 within `check_top_bit'
js	L25
; │└└└└└└
popq	%rcx
retq
; │┌ @ REPL[262]:6 within `factorial_lookup'
; ││┌ @ essentials.jl:334 within `oftype'
; │││┌ @ number.jl:7 within `convert'
; ││││┌ @ boot.jl:738 within `Type'
; │││││┌ @ boot.jl:708 within `toUInt64'
; ││││││┌ @ boot.jl:597 within `check_top_bit'
L25:
movabsq	\$throw_inexacterror, %rcx
movabsq	\$139784870391424, %rdi  # imm = 0x7F22338B6E80
movabsq	\$139784872953840, %rsi  # imm = 0x7F2233B287F0
movq	%rax, %rdx
callq	*%rcx
ud2
nop
; └└└└└└└
``````
``````julia> 5 % UInt
0x0000000000000005

julia> @code_llvm 5 % UInt

; Function rem
; Location: int.jl:468
define i64 @julia_rem_35399(i64, %jl_value_t addrspace(10)*) {
top:
ret i64 %0
}
``````

I’m confused. The question was how to convert UInt to Int without an overflow check which I showed (and showed that it worked). Apparently you are after something else?

Could you give a short description of what you want and what you have tried?

1 Like

Right, your code worked, thanks again, and I overlooked the next line:

``````@inbounds f = _shifted_fact_table64[n % Int)+1]
return oftype(n, f)  # needs the rather ugly: return typeof(n) <: UInt ? oftype(n, f % UInt) : oftype(n, f)
``````

This code isn’t used for BigInt, but if it where I would still need the oftype (I know a workaround for that; e.g. as is, overriding the function for BigInt).