# Split an Int128 to two Int64

**URL:** https://discourse.julialang.org/t/split-an-int128-to-two-int64/26625
**Category:** Performance
**Created:** [July 22, 2019, 12:19pm UTC](https://discourse.julialang.org/t/split-an-int128-to-two-int64/26625 "2019-07-22T12:19:50Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![hros](https://avatars.discourse-cdn.com/v4/letter/h/97f17d/32.png) [@hros](https://discourse.julialang.org/u/hros)
#### Post date: [July 22, 2019, 12:19pm UTC](https://discourse.julialang.org/t/split-an-int128-to-two-int64/26625/1 "2019-07-22T12:19:50Z")

</div>

Edit: this post started as a question and as a I found an answer turned into a suggestion to update the documentation

I have to multiply two Int64 values and split the result into the high and low 64 bit values.  
This is the functionality available by the [\_mulx\_u64](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mulx_&expand=4028) intrinsinc function.  
I could probably use the llvm code produced by a C program that calls the intrinsic and embed it in an llvmcall, but that seems excessive for this task.

If I look at the llvm code generated by the c program, I see a simple instruction to split the 128 bit integer:

```julia
%21 = trunc i128 %20 to i64

```

taking the high bits could be accomplished with `UInt64(v >> 64)`, but the generated llvm code contains excessive type checking code.  
taking the low bits could be done with `UInt64(v & 0xffffffffffffffff)`, but that too produces many type checking commands.

The answer turned up in a book: [Julia High Performance](https://www.packtpub.com/application-development/julia-10-high-performance), in a section labeled [unchecked conversions for unsigned integers](https://books.google.co.il/books?id=TODJDAAAQBAJ&pg=PA72&lpg=PA72&dq=julia+unchecked+integer+conversions&source=bl&ots=h0QT20jClb&sig=ACfU3U0yKx5csZ8jFfg1huytezES6mODvw&hl=iw&sa=X&ved=2ahUKEwi4jLGAucjjAhVFbFAKHUtmBrsQ6AEwA3oECAgQAQ#v=onepage&q=julia%20unchecked%20integer%20conversions&f=false).  
Instead of converting `T(v)` use `v % T` which doesn’t add any type checking  
`v_l, v_h = v % UInt64, (v >> 64) % UInt64`  
Testing the llvm, this indeed generated the optimized code, and **the run-times are reduced by almost 50%**

I searched the official docs and could not find this mentioned.  
I suggest the docs be updated to add this in the main section on integers and conversions.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [July 22, 2019, 12:25pm UTC](https://discourse.julialang.org/t/split-an-int128-to-two-int64/26625/2 "2019-07-22T12:25:55Z")

</div>

It is a nice trick, but I am not sure the manual is the best place for specific micro-optimizations.

Readers interested in these techniques should just buy the Julia High Performance book.

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [July 22, 2019, 12:31pm UTC](https://discourse.julialang.org/t/split-an-int128-to-two-int64/26625/3 "2019-07-22T12:31:46Z")

</div>

It is document, [Mathematics · The Julia Language](https://docs.julialang.org/en/v1/base/math/#Base.mod). What **is** missing is the mentioning of no-range-check and a cross link to convert and maybe constructor. For the online doc, a link from the rem doc in additional to the mod doc could also be useful.
