C++ Logo

std-proposals

Advanced search

Re: [std-proposals] std::big_int

From: Jan Schultke <janschultke_at_[hidden]>
Date: Wed, 15 Apr 2026 06:30:47 +0200
>
> * It's pretty vague from the wording what the actual representation is.
> The reference implementation is sign-magnitude, but is that mandated?
> The only place I see where it's completely unambiguous is unary
> operator-().
>

Yes, it is mandated.


> Especially, the definition of "effective width" seems to imply two's
> complement. Is the effective width of "3" 2 bits, and of "-3" 3 bits?
> (And what about "0"?)
>

I thought the effective width definition actually implies that the sign bit
is separated because for two's complement would have different widths for
positive and negative numbers, and unsigned positive numbers need fewer
bits. The wording certainly may not be perfect yet.


> * Should width_mag() return `floor(log2(x))` or `floor(log2(x)) + 1`?
> It's defined (and implemented) as the former, but the name implies the
> latter. The way representation() is defined in terms of width_mag()
> definitely implies the latter. (Also, it's technically undefined for
> negative values right now.)
>

Hmm yeah, I guess there needs to be an abs() somewhere.


>
> * Regarding the from_range constructor, is determining the signedness of
> the encoded value based on the signedness of the range's value type the
> right API? I mean, it sort of makes sense, but I'm still on the fence.
> The individual digits themselves are technically not signed integers
> (their MSB is not a sign bit, except for the last), and are probably not
> stored as such.
>

I don't know if the design of that one is good. I think it makes a bit of
sense since it lets you construct from any other integer type, and
communicating whether it's signed or unsigned seems pretty natural. This is
useful when e.g. bit-casting a signed _BitInt(4096) to some limbs and
constructing big_int from that, although to be fair, that is already
provided directly via another constructor.


> Should there be a way to treat the range as big-endian (in term of the
> element order)? The range might not be reversible, but the big_int storage
> is.
>

That sounds like a general problem that applies to all from_range
constructors in the standard library. I don't really know how you would
find yourself in a situation where you can't reverse the range anyway. In
multiprecision, you basically always work with contiguous ranges, so it's
always possible to run one through std::views::reverse.


> In the "throws" section, you don't know ahead of time if the value
> requires an allocation or not, so you can't give that promise (plus, the
> iterator itself can throw).
>

I didn't think of the iterator throwing, but you don't need to know in
advance if the value will fit for unsigned integers at least. You can just
insert limbs into inplace storage as long as they fit, and if you run out
of space, start allocating. However, maybe that doesn't work for negative
integers passed via input range because you get an ever-increasing sequence
of 1-bits, and once you hit the sign bit, you may realize "OOPS, I only
need one limb to store this" because the number turns out to be minus one
or something.

Anyway, thanks for all the feedback, I'll see about fixing it :)

If you find anything else, it makes things a lot easier for us if you
create a GitHub issue in the repo; that allows us to immediately track the
problem.

Received on 2026-04-15 04:31:05