Generic integer math limitation

243 views
Skip to first unread message

Marcelo Cantos

unread,
Feb 5, 2022, 1:38:50 PM2/5/22
to golang-nuts
I am porting an int-set type to generics. It holds bits in a block structure with 512 bits per block. At some point, I need to divide by 512:

func block[T constraints.Integer](i T) T {
    return i / 512
}

Go 1.18 beta 2 complains: cannot convert 512 (untyped int constant) to T

The problem is that uint8 and int8 cannot represent the number 512. If I build a constraint similar to constraints.Integer that excludes ~uint8 and ~int8, it works fine. Explicit casting is no better, and there is no promotion (e.g., cast i to int and cast the result back to T) that's suitable for all integer types. I would like to shrink the block size for (u)int8, but there's no way to specialize the logic for specific types.

I figured out that I can use i >> 9 instead of i / 512 in this instance, though there will be other cases (divide by non-Po2) where there isn't a simple workaround Is there a general way around this limitation?

Ian Lance Taylor

unread,
Feb 5, 2022, 1:54:10 PM2/5/22
to Marcelo Cantos, golang-nuts
It's not clear to me what is supposed to happen for the int8/uint8
case. It sounds like your block type won't work for int8/uint8. In
that case it seems like the right approach is to use a constraint that
doesn't permit it, as you suggest. What other kind of workaround
would be appropriate?

Ian

Axel Wagner

unread,
Feb 5, 2022, 1:59:54 PM2/5/22
to Marcelo Cantos, golang-nuts
On Sat, Feb 5, 2022 at 7:38 PM Marcelo Cantos <marcelo...@gmail.com> wrote:
Explicit casting is no better, and there is no promotion (e.g., cast i to int and cast the result back to T) that's suitable for all integer types.

FWIW `uint64` and `int64` are large enough to represent any un/signed integer types respectively.
Depending on the case, as long as you can assume that your values fall in an appropriate range, you can use one of them.

I would like to shrink the block size for (u)int8, but there's no way to specialize the logic for specific types.

I figured out that I can use i >> 9 instead of i / 512 in this instance, though there will be other cases (divide by non-Po2) where there isn't a simple workaround Is there a general way around this limitation?

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/6a844487-0c22-443f-8e6e-c38860929515n%40googlegroups.com.

Henry

unread,
Feb 8, 2022, 3:10:03 AM2/8/22
to golang-nuts

I don't understand what your function is trying to accomplish, but you know you can break down 512 into smaller numbers, right? For instance, i / 512 is equivalent to (i / 64) / 8. 

Do remember that integer cannot hold fractions. In the case of uint8/int8, the result is always zero. If you use the above method where you perform several divisions, you may also lose precision due to rounding.  
Reply all
Reply to author
Forward
0 new messages