c

The max number of digits in an int based on number of bits


So, I needed a constant value to represent the max number of digits in an int, and it needed to be calculated at compile time to pass into the size of a char array.

To add some more detail: The compiler/machine I'm working with has a very limited subset of the C language, so none of the std libraries work as they have unsupported features. As such I cannot use INT_MIN/MAX as I can neither include them, nor are they defined.

I need a compile time expression that calculates the size. The formula I came up with is:

((sizeof(int) / 2) * 3 + sizeof(int)) + 2

It is marginally successful with n byte integers based on hand calculating it.

sizeof(int)  INT_MAX               characters    formula
2           32767                       5            7
4           2147483647                  10           12
8           9223372036854775807         19           22

Solution

  • You're looking for a result related to a logarithm of the maximum value of the integer type in question (which logarithm depends on the radix of the representation whose digits you want to count). You cannot compute exact logarithms at compile time, but you can write macros that estimate them closely enough for your purposes, or that compute a close enough upper bound for your purposes. For example, see How to compute log with the preprocessor.

    It is useful also to know that you can convert between logarithms in different bases by multiplying by appropriate constants. In particular, if you know the base-a logarithm of a number and you want the base-b logarithm, you can compute it as

    logb(x) = loga(x) / loga(b)

    Your case is a bit easier than the general one, though. For the dimension of an array that is not a variable-length array, you need an "integer constant expression". Furthermore, your result does not need more than two digits of precision (three if you wanted the number of binary digits) for any built-in integer type you'll find in a C implementation, and it seems like you need only a close enough upper bound.

    Moreover, you get a head start from the sizeof operator, which can appear in integer constant expressions and which, when applied to an integer type, gives you an upper bound on the base-256 logarithm of values of that type (supposing that CHAR_BIT is 8). This estimate is very tight if every bit is a value bit, but signed integers have a sign bit, so this bound is a bit looser for them. It is a bit looser for integer representations that have padding bits as well.

    If you want a bound on the number of digits in a power-of-two radix then you can use sizeof pretty directly. Let's suppose, though, that you're looking for the number of decimal digits. Mathematically, the maximum number of digits in the decimal representation of an int is

    N = ceil(log10(MAX_INT))

    or

    N = floor(log10(MAX_INT)) + 1

    provided that MAX_INT is not a power of 10. Let's express that in terms of the base-256 logarithm:

    N = floor( log256(MAX_INT) / log256(10) ) + 1

    Now, log256(10) cannot be part of an integer constant expression, but it or its reciprocal can be pre-computed: 1 / log256(10) ≈ 2.40824. Now, let's use that to rewrite our expression:

    N <= floor( sizeof(int) * 2.40824 ) + 1

    That's not yet an integer constant expression, but it's close. This expression is an integer constant expression, and a good enough approximation to serve your purpose:

    N = 241 * sizeof(int) / 100 + 1

    Here are the results for various integer sizes:

    sizeof(int)          INT_MAX   True N  Computed N
        1                    127      3        3
        2                  32767      5        5
        4             2147483648     10       10
        8       ~9.223372037e+18     19       20
    

    (The values in the INT_MAX and True N columns suppose one of the allowed forms of signed representation, and no padding bits; the former and maybe both will be smaller if the representation contains padding bits.)

    I presume that in the unlikely event that you encounter a system with 8-byte ints, the extra one byte you provide for your digit array will not break you. The discrepancy arises from the difference between having (at most) 63 value bits in a signed 64-bit integer, and the formula accounting for 64 value bits in that case, with the result that sizeof(int) is a bit too much of an overestimation of the base-256 log of INT_MAX. The formula gives exact results for unsigned int up to at least size 8, provided there are no padding bits.

    As a macro, then:

    // Expands to an integer constant expression evaluating to a close upper bound
    // on the number of decimal digits in a value expressible in the
    // integer type given by the argument (if it an integer type name) or the
    // type of the argument (if it is an expression with integer type).
    #define DECIMAL_DIGITS_BOUND(t) (241 * sizeof(t) / 100 + 1)