Bit-shift left

For…

a << b

…the documentation says " b must be comptime-known or have a type with log2 number of bits as a." This makes perfect sense. I have a b that is NOT comptime-known, and am having trouble. (Note: if I use a comptime-known value for b, all DOES work fine.) So, for example…

	var j: u32 = 7;
	j += 1;
	const z: u32 = 0b1 << j;

Complains with “LHS of shift must be a fixed-width integer type, or RHS must be comptime-known”. I assume this means that 0b1 is not a fixed-width integer (?), so I try:

	const z: u32 = @as(u32, 0b1) << j;

But this gives the more enigmatic “expected type ‘u5’, found ‘u32’” and “note: unsigned 5-bit int cannot represent all possible unsigned 32-bit values” … I’m not sure what type is considered only 5-bits wide, in this situation. I tried a few other things, but think I’ll leave it at this to see what help it might inspire.

Thank you,
<an aspiring new zig… uh… zigger?>

Maybe, @intCast instead of @as can help, something like this

var shift: u5 = @intCast((rank - 1) * 8); // <<<<<<
sym = @intCast((lst >> shift) & 0xFF);
const std = @import("std");

pub fn main() void {
    const shiftee: u32 = 1;
    var k: u5 = 0;
    while (k < 31) : (k += 1) {
        std.debug.print("{b}\n", .{shiftee << k});
    }
}

Works as expected, just use u5 (5 = log2(32)) , not u32 for shift value.

Except k overflow when upper limit is 32 (not 31).
To avoid this, use wider than u5 integer and explicit cast to u5:

const std = @import("std");

pub fn main() void {
    const shiftee: u32 = 1;
    var k: u8 = 0;

    while (k < 32) : (k += 1) {
        const shift: u5 = @intCast(k);
        std.debug.print("{d: >2} : {b:0>32}\n", .{k, shiftee << shift});
    }
    // last val is 1000_0000_0000_0000_0000_0000_0000_0000, ok
}


2 Likes

Language Reference - Primitive Types:

In addition to the integer types above, arbitrary bit-width integers can be referenced by using an identifier of i or u followed by digits. For example, the identifier i7 refers to a signed 7-bit integer.

I think I see the error in my ways.

“…have a type with log2 number of bits as a” - I didn’t read this carefully enough, or internalize its meaning. It makes perfect sense that the care that must be taken is in making sure that b is not more than log2 the size of a. I was thinking of the need to make a BIG enough (which, it wasn’t, anyway, as my b was a u32 – even IF I was only using a few of the lowest bits) – the key here is to make sure that b is SMALL enough - limited in bit-size so that shifting doesn’t overflow a. All very clear now. Thank you all again!

When I run into this for the very first time, I also did not understand at all what the compiler wants with me :slight_smile: Btw, see also this comment and the entire topic for the arbitrary width integers, it’s a really cool feature of Zig.

So, for completeness, here is a version that is closest to my OP version, with the least change necessary to accomplish the goal:

	var j: u4 = 7;
	j += 1;
	const z = @as(u32, 0b1) << j;

So, importantly, my j (I should have called it b!) needed to be a u4, as that’s the sufficient number of bits to hold my final value of 8 (u3 would have been enough for the original value of 7). AND my a needed to be cast to a u32 (it’s not enough for z to be defined as a u32). This latter bit is what the LHS part of the error message tries to make clear:

LHS of shift must be a fixed-width integer type, or RHS must be comptime-known

It might help to make that message say the same thing as the documentation: “b must be comptime-known or have a type with log2 number of bits as a.” and perhaps the documentation could also declare that a must be (cast to) a fixed-width integer, big enough to hold a 0b1 shifted b bits (or, big enough to hold the number 2^b). Just two cents of thought.

1 Like

Welcome, Ziguana.

Just wanted to mention another pattern, building off of what @dee0xeed shared. If you want to iterate over the entire range of an integer, you can write a loop like so:

const std = @import("std");

pub fn main() void {
    const shiftee: u32 = 1;
    var k: u5 = 0;
    while (true) {
        std.debug.print("{b}\n", .{shiftee << k});
        k +%= 1
        if (k == 0) break;
    }
}

May not be relevant for the problem you were trying to solve this time, but I find this comes in handy.

1 Like

Actually I had similar variant, just did not post it. Ok, here it is, top it off :slight_smile: :

const std = @import("std");

pub fn main() void {
    const shiftee: u32 = 1;
    var k: u5 = 0;

    while (true) {
        std.debug.print("{d: >2} : {b:0>32}\n", .{k, shiftee << k});
        if (31 == k) break;
        k += 1;
    }
}

And yeah, I had not thought about nifty +%= addition, since I have not got used to it yet.