DoxigAlpha

setTwosCompIntLimit

Set self to either bound of a 2s-complement integer. Note: The result is still sign-magnitude, not twos complement! In order to convert the result to twos complement, it is sufficient to take the absolute value.

Asserts the result fits in r. An upper bound on the number of limbs needed by r is calcTwosCompLimbCount(bit_count).

Function parameters

Parameters

#
r:*Mutable
bit_count:usize

Used to indicate either limit of a 2s-complement integer.

Types

#
TwosCompIntLimit
Used to indicate either limit of a 2s-complement integer.
Mutable
A arbitrary-precision big integer, with a fixed set of mutable limbs.
Const
A arbitrary-precision big integer, with a fixed set of immutable limbs.
Managed
An arbitrary-precision big integer along with an allocator which manages the memory.

Returns the number of limbs needed to store `scalar`, which must be a

Functions

#
calcLimbLen
Returns the number of limbs needed to store `scalar`, which must be a
calcSetStringLimbCount
Assumes `string_len` doesn't account for minus signs if the number is negative.
calcNonZeroTwosCompLimbCount
Compute the number of limbs required to store a 2s-complement number of `bit_count` bits.
calcTwosCompLimbCount
Compute the number of limbs required to store a 2s-complement number of `bit_count` bits.
addMulLimbWithCarry
a + b * c + *carry, sets carry to the overflow bits
llcmp
Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively for limbs.

Source

Implementation

#
pub fn setTwosCompIntLimit(
    r: *Mutable,
    limit: TwosCompIntLimit,
    signedness: Signedness,
    bit_count: usize,
) void {
    // Handle zero-bit types.
    if (bit_count == 0) {
        r.set(0);
        return;
    }

    const req_limbs = calcTwosCompLimbCount(bit_count);
    const bit: Log2Limb = @truncate(bit_count - 1);
    const signmask = @as(Limb, 1) << bit; // 0b0..010..0 where 1 is the sign bit.
    const mask = (signmask << 1) -% 1; // 0b0..011..1 where the leftmost 1 is the sign bit.

    r.positive = true;

    switch (signedness) {
        .signed => switch (limit) {
            .min => {
                // Negative bound, signed = -0x80.
                r.len = req_limbs;
                @memset(r.limbs[0 .. r.len - 1], 0);
                r.limbs[r.len - 1] = signmask;
                r.positive = false;
            },
            .max => {
                // Positive bound, signed = 0x7F
                // Note, in this branch we need to normalize because the first bit is
                // supposed to be 0.

                // Special case for 1-bit integers.
                if (bit_count == 1) {
                    r.set(0);
                } else {
                    const new_req_limbs = calcTwosCompLimbCount(bit_count - 1);
                    const msb = @as(Log2Limb, @truncate(bit_count - 2));
                    const new_signmask = @as(Limb, 1) << msb; // 0b0..010..0 where 1 is the sign bit.
                    const new_mask = (new_signmask << 1) -% 1; // 0b0..001..1 where the rightmost 0 is the sign bit.

                    r.len = new_req_limbs;
                    @memset(r.limbs[0 .. r.len - 1], maxInt(Limb));
                    r.limbs[r.len - 1] = new_mask;
                }
            },
        },
        .unsigned => switch (limit) {
            .min => {
                // Min bound, unsigned = 0x00
                r.set(0);
            },
            .max => {
                // Max bound, unsigned = 0xFF
                r.len = req_limbs;
                @memset(r.limbs[0 .. r.len - 1], maxInt(Limb));
                r.limbs[r.len - 1] = mask;
            },
        },
    }
}