DoxigAlpha

toString

Converts self to a string in the requested base. Asserts that base is in the range [2, 36]. string is a caller-provided slice of at least sizeInBaseUpperBound bytes, where the result is written to. Returns the length of the string. limbs_buffer is caller-provided memory for toString to use as a working area. It must have length of at least calcToStringLimbsBufferLen. In the case of power-of-two base, limbs_buffer is ignored. See also toStringAlloc, a higher level function than this.

Function parameters

Parameters

#
string:[]u8
base:u8
case:std.fmt.Case
limbs_buffer:[]Limb

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 toString(self: Const, string: []u8, base: u8, case: std.fmt.Case, limbs_buffer: []Limb) usize {
    assert(base >= 2);
    assert(base <= 36);

    if (self.eqlZero()) {
        string[0] = '0';
        return 1;
    }

    var digits_len: usize = 0;

    // Power of two: can do a single pass and use masks to extract digits.
    if (math.isPowerOfTwo(base)) {
        const base_shift = math.log2_int(Limb, base);

        outer: for (self.limbs[0..self.limbs.len]) |limb| {
            var shift: usize = 0;
            while (shift < limb_bits) : (shift += base_shift) {
                const r = @as(u8, @intCast((limb >> @as(Log2Limb, @intCast(shift))) & @as(Limb, base - 1)));
                const ch = std.fmt.digitToChar(r, case);
                string[digits_len] = ch;
                digits_len += 1;
                // If we hit the end, it must be all zeroes from here.
                if (digits_len == string.len) break :outer;
            }
        }

        // Always will have a non-zero digit somewhere.
        while (string[digits_len - 1] == '0') {
            digits_len -= 1;
        }
    } else {
        // Non power-of-two: batch divisions per word size.
        // We use a HalfLimb here so the division uses the faster lldiv0p5 over lldiv1 codepath.
        const digits_per_limb = math.log(HalfLimb, base, maxInt(HalfLimb));
        var limb_base: Limb = 1;
        var j: usize = 0;
        while (j < digits_per_limb) : (j += 1) {
            limb_base *= base;
        }
        const b: Const = .{ .limbs = &[_]Limb{limb_base}, .positive = true };

        var q: Mutable = .{
            .limbs = limbs_buffer[0 .. self.limbs.len + 2],
            .positive = true, // Make absolute by ignoring self.positive.
            .len = self.limbs.len,
        };
        @memcpy(q.limbs[0..self.limbs.len], self.limbs);

        var r: Mutable = .{
            .limbs = limbs_buffer[q.limbs.len..][0..self.limbs.len],
            .positive = true,
            .len = 1,
        };
        r.limbs[0] = 0;

        const rest_of_the_limbs_buf = limbs_buffer[q.limbs.len + r.limbs.len ..];

        while (q.len >= 2) {
            // Passing an allocator here would not be helpful since this division is destroying
            // information, not creating it. [TODO citation needed]
            q.divTrunc(&r, q.toConst(), b, rest_of_the_limbs_buf);

            var r_word = r.limbs[0];
            var i: usize = 0;
            while (i < digits_per_limb) : (i += 1) {
                const ch = std.fmt.digitToChar(@as(u8, @intCast(r_word % base)), case);
                r_word /= base;
                string[digits_len] = ch;
                digits_len += 1;
            }
        }

        {
            assert(q.len == 1);

            var r_word = q.limbs[0];
            while (r_word != 0) {
                const ch = std.fmt.digitToChar(@as(u8, @intCast(r_word % base)), case);
                r_word /= base;
                string[digits_len] = ch;
                digits_len += 1;
            }
        }
    }

    if (!self.positive) {
        string[digits_len] = '-';
        digits_len += 1;
    }

    const s = string[0..digits_len];
    mem.reverse(u8, s);
    return s.len;
}