# Can I have a UInt12?

**URL:** https://discourse.julialang.org/t/can-i-have-a-uint12/60935
**Category:** General Usage
**Tags:** question
**Created:** [May 11, 2021, 7:42am UTC](https://discourse.julialang.org/t/can-i-have-a-uint12/60935 "2021-05-11T07:42:15Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)
#### Post date: [May 11, 2021, 7:42am UTC](https://discourse.julialang.org/t/can-i-have-a-uint12/60935/1 "2021-05-11T07:42:15Z")

</div>

I need to use a number that has 2^12 discrete levels, i.e. a `UInt12`. Is there a package that does this (I tried `BitIntegers` but no joy)?

---

<div class="post-metadata">

### Author: ![mschauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mschauer/32/13946_2.png) [@mschauer](https://discourse.julialang.org/u/mschauer)
#### Post date: [May 11, 2021, 8:02am UTC](https://discourse.julialang.org/t/can-i-have-a-uint12/60935/2 "2021-05-11T08:02:51Z")

</div>

Can it be 2^12 discrete levels between [0, 1] instead? Then you can use [GitHub - JuliaMath/FixedPointNumbers.jl: fixed point types for julia](https://github.com/JuliaMath/FixedPointNumbers.jl) Else I would look through @JeffreySarnoff 's packages 😉

---

<div class="post-metadata">

### Author: ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)
#### Post date: [May 11, 2021, 1:27pm UTC](https://discourse.julialang.org/t/can-i-have-a-uint12/60935/3 "2021-05-11T13:27:03Z")

</div>

Julia’s primitive types are multiples of 8bits, so there is no native 12 bit UInt available.  
@mschauer suggests [FixedPointNumbers.jl](https://github.com/JuliaMath/FixedPointNumbers.jl) and that is a strong, well-used package.  
If you must have a UInt12 work-alike, it would be implemented using UInt16s, with the necessary testing and masking. What operations would you require? What is the purpose?

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [May 11, 2021, 1:30pm UTC](https://discourse.julialang.org/t/can-i-have-a-uint12/60935/4 "2021-05-11T13:30:19Z")

</div>

Do you want a single `UInt12` or do you want packed array storage for a whole slew of them? The latter is possible with a custom array type, but likely to be significantly slower than just using `UInt16`s even with the 25% space savings.

---

<div class="post-metadata">

### Author: ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)
#### Post date: [May 11, 2021, 2:28pm UTC](https://discourse.julialang.org/t/can-i-have-a-uint12/60935/5 "2021-05-11T14:28:46Z")

</div>

I see. This is just for the sake of messages to an external servo motor, so not worth too much trouble. I though though that since there are cameras that encode pixels in UInt12 (I think?) there would be something established already. But that’s fine, thanks for the awesome info!

---

<div class="post-metadata">

### Author: ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)
#### Post date: [May 11, 2021, 2:43pm UTC](https://discourse.julialang.org/t/can-i-have-a-uint12/60935/6 "2021-05-11T14:43:55Z")

</div>

In that case, it’s FixedPointNumbers that you want. Mapping to the interval [0, 1] has the advantage that each color will correspond to the same value(s), regardless of the number of bits used to store it. (And the same for servomotor angles, of course.)

---

<div class="post-metadata">

### Author: ![bjarthur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bjarthur/32/9638_2.png) [@bjarthur](https://discourse.julialang.org/u/bjarthur)
#### Post date: [May 12, 2021, 12:46am UTC](https://discourse.julialang.org/t/can-i-have-a-uint12/60935/7 "2021-05-12T00:46:10Z")

</div>

@mkitti is working on a UInt12Array with functionality similar to BitArrays

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [May 12, 2021, 7:39am UTC](https://discourse.julialang.org/t/can-i-have-a-uint12/60935/8 "2021-05-12T07:39:40Z")

</div>

Yes, @bjarthur is correct. I have been working on a package to do this. I’m working with a 12-bit camera. Essentially you have a UInt12Array that can be backed by a UInt24 Vector (via BitIntegers) or an UInt16 Vector. I’ve also developed SIMD based code to unpack 12-bit integer data into 16-bit integers.

Would that be helpful for you @yakir12 ?

---

<div class="post-metadata">

### Author: ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)
#### Post date: [May 12, 2021, 7:55am UTC](https://discourse.julialang.org/t/can-i-have-a-uint12/60935/9 "2021-05-12T07:55:06Z")

</div>

That sounds cool. The need and use of 12-bits in cameras is what I thought would fuel this, so that makes total sense. I’ll gladly try and bench things for my needs once you’re done.

Thanks a lot!

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [May 12, 2021, 8:02am UTC](https://discourse.julialang.org/t/can-i-have-a-uint12/60935/10 "2021-05-12T08:02:40Z")

</div>

Do you need to deal with arrays of UInt12s or an individual UInt12? I did some work on both cases, but mostly focused on arrays.

The main thing that was holding me back from pushing it to Github was feature creep. I think the package as-is might do too many things, so I was planning to break it up.

---

<div class="post-metadata">

### Author: ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)
#### Post date: [May 12, 2021, 8:10am UTC](https://discourse.julialang.org/t/can-i-have-a-uint12/60935/11 "2021-05-12T08:10:00Z")

</div>

The messages I would deal with are vectors and/or arrays.

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [May 13, 2021, 11:59am UTC](https://discourse.julialang.org/t/can-i-have-a-uint12/60935/12 "2021-05-13T11:59:11Z")

</div>

Here’s the real solution, an actual package:  
[https://github.com/JaneliaSciComp/UInt12Arrays.jl](https://github.com/JaneliaSciComp/UInt12Arrays.jl)

Let’s talk about the underlying data first and the packing. I’ve seen many ways to pack 12-bit integers together, but the most natural and common way is to pack them consecutively. Let’s say we have six bytes of data or 48 bits. This represents four 12-bit integers. In the six bytes below, I’ve numbered the the first six nibbles (4-bits each) using `1` through `6` and the last six nibbles using `a` through `f`. If we reinterpret them as 24-bit integers via BitIntegers.jl we can see the order holds.

```julia
julia> data = UInt8[0x21, 0x43, 0x65, 0xba, 0xdc, 0xfe]
6-element Array{UInt8,1}:
 0x21
 0x43
 0x65
 0xba
 0xdc
 0xfe

```

```julia
julia> using UInt12Arrays

julia> A24 = reinterpret(UInt24,data)
2-element reinterpret(UInt24, ::Array{UInt8,1}):
 0x654321
 0xfedcba

```

We want 12-bit integers though and not 24-bit integers. It is currently not possible to make non-byte sized bitstypes in Julia, so we cannot just use `reinterpret` as we did for 24-bit integers.

```julia
julia> using BitIntegers

julia> BitIntegers.@define_integers 12
ERROR: invalid number of bits in primitive type Int12
Stacktrace:
 [1] top-level scope
   @ ~\.julia\packages\BitIntegers\fcpdN\src\BitIntegers.jl:60

julia> reinterpret(UInt12,data)
ERROR: ArgumentError: cannot reinterpret `UInt8` `UInt12`, type `UInt12` is not a bits type
Stacktrace:
 [1] (::Base.var"#throwbits#220")(::Type{UInt8}, ::Type{UInt12}, ::Type{UInt12}) at .\reinterpretarray.jl:16
 [2] reinterpret(::Type{UInt12}, ::Array{UInt8,1}) at .\reinterpretarray.jl:33
 [3] top-level scope at REPL[155]:1

```

What we essentially want to do is just break the 24-bit integer into 12-bit integer halfs:

```julia
julia> A24[1]
0x654321

julia> first(A24[1])
0x0321

julia> last(A24[1])
0x0654

julia> first(A24[2])
0x0cba

julia> last(A24[2])
0x0fed

```

This is what `UInt12Array` and `UInt12Vector` do. The default form uses `UInt16` as an element type. However, you can also `UInt12` as an element type.

```julia
julia> A16 = UInt12Vector(data)
4-element UInt12Array{UInt16,Array{UInt8,1},1}:
 0x0321
 0x0654
 0x0cba
 0x0fed

julia> A12 = UInt12Vector{UInt12}(data)
4-element UInt12Array{UInt12,Array{UInt8,1},1}:
 0x321
 0x654
 0xcba
 0xfed

```

`UInt12` is actually just a boxed `UInt16` in the current implementation, so you might as well just use `UInt16` directly in most cases. The main advantage of using `UInt12` is handling overflow correctly as well as display:

```julia
julia> A16[1] + 0xd00
0x1021

julia> A12[1] + 0xd00
0x021

```

However, even with 16-bit element types, assignment into the `UInt12Array` will properly discard the highest nibble:

```julia
julia> A16[1]
0x0321

julia> A16[1] += 0xd00; A16[1]
0x0021

```

Note that `UInt12Array` is basically just a 12-bit unsigned integer view of the original bytes. By changing the first 12-bit integer, we removed the `3` nibble from all the other views of the same underlying data:

```julia
julia> A24
2-element reinterpret(UInt24, ::Array{UInt8,1}):
 0x654021
 0xfedcba

julia> A12
4-element UInt12Array{UInt12,Array{UInt8,1},1}:
 0x021
 0x654
 0xcba
 0xfed

julia> A16
4-element UInt12Array{UInt16,Array{UInt8,1},1}:
 0x0021
 0x0654
 0x0cba
 0x0fed

julia> A16[1]
0x0021

julia> data[2] = 0x43
0x43

julia> A12
4-element UInt12Array{UInt12,Array{UInt8,1},1}:
 0x321
 0x654
 0xcba
 0xfed

```

Because `UInt12Array` is a view on the underlying data it is pretty inexpensive to create, but it may take a while to convert the entire array to a true `UInt16` array that may be faster to work with for other applications:

```julia
julia> data = rand(UInt8, 1024*1024*1024*2+1)
2147483649-element Array{UInt8,1}:
 0x84
 0x7d
 0xde
 0x63
 0x99
 0x39
 0xcb
    ⋮
 0x8a
 0x42
 0x88
 0x30
 0x88
 0x57

julia> @time A16 = UInt12Vector(data)
  0.000013 seconds (6 allocations: 336 bytes)
1431655766-element UInt12Array{UInt16,Array{UInt8,1},1}:
 0x0d84
 0x0de7
 0x0963
 0x0399
 0x01cb
 0x0c2d
 0x0795
      ⋮
 0x0d52
 0x0605
 0x028a
 0x0884
 0x0830
 0x0578

julia> @time copy(A16)
  5.329485 seconds (2 allocations: 2.667 GiB, 3.17% gc time)
1431655766-element Array{UInt16,1}:
 0x0d84
 0x0de7
 0x0963
 0x0399
 0x01cb
 0x0c2d
 0x0795
 0x0e67
 0x0dd7
 0x05f4
 0x0f4b
 0x006b
 0x0386
 0x09f1
 0x07bc
 0x0b50
      ⋮
 0x0538
 0x02a2
 0x0d40
 0x092e
 0x00ad
 0x0412
 0x0dbf
 0x0496
 0x079b
 0x0d52
 0x0605
 0x028a
 0x0884
 0x0830
 0x0578

```

For converting the entire array to a native `UInt16` array, I overrode `Base.convert` and used SIMD.jl to accelerate conversion:

```julia
julia> @time convert(Array{UInt16}, A16)
  1.029260 seconds (6 allocations: 2.667 GiB, 8.86% gc time)
1431655766-element Array{UInt16,1}:
 0x0d84
 0x0de7
 0x0963
 0x0399

```

Let me know if this works for you. One possible complication that I can see is if your 12-bit integers are packed differently.
