Quantcast
Channel: Tips for golfing in C - Code Golf Stack Exchange
Viewing all articles
Browse latest Browse all 67

Answer by Jonathan Frech for Tips for golfing in C

$
0
0

Calculating \$\lceil\log_{10}(n)\rceil\$

Especially in challenges where properties of decimal representations are of interest, one needs to find a number's decimal representation's length, or for \$n\in\mathbb{N}^+\$ equivalently, \$\lceil\log_{10}(n)\rceil\$.
In this post, several approaches are presented and discussed.

For a C source file containing approaches (a.1) to (b.3) together with a testing setup, see TIO.

I wrote this tip based on this answer of mine, searching for a smaller approach than (a.1).
If you know of any other approach possibly shorter in even a specific scenario, feel free to either add your own tip add to the list below.

(a.1) An expression in n, 20 bytes

snprintf(0,0,"%d",n)

Versatility is a great property of the above approach, when used to determine a number's decimal representation's length, the most direct approach might be the most byte-effective.

0 is given its correct decimal representation length of 1.

GCC only throws a warning for ignoring #include <stdio.h>, otherwise the inclusion would be very byte-heavy at potentially 19+20=39 bytes. If instead of sprintf(0, one uses sprintf(NULL, the byte count is increased to 23 bytes. If using both, the byte count could jump to 42 bytes.

(a.2) A function in n, 29 bytes

a(n){n=snprintf(0,0,"%d",n);}

By being a function, this approach's versatility is high; (a.1)'s compiler-specifics also apply, when properly returning, the byte count increases to 5+29=34 bytes.

0 is given its correct decimal representation length of 1.

(b.1) A function in n, requiring another variable, 32 bytes

b(n,k){for(k=0;n;k++)n/=10;n=k;}

Of all approaches presented, this one has the worst byte count. However, considering potential compiler restrictions discussed in (a.1), it could prove more byte-efficient, since the approach is nearer to the C core.

0 is given its incorrect decimal representation length of 0. One can make the case for defining \$\lceil-\infty\rceil:=0\$ which would make this approach closer to a logarithm implementation, when further defining \$\log(0):=-\infty\$.

Modification to calculate \$\lceil\log_b(n)\rceil\$ for a base \$b\in\mathbb{N}^+\$ is possible, changing the byte count by the bytes required to represent \$b\$ in C-source.

(b.2) A statement requiring existence of two variables, setting n=0, 20 bytes

for(k=0;n;k++)n/=10;

If another variable is already declared and n can be either discarded or needs to be cleared regardless and the use case is a whole block instead of a one-line expression, the above could be used. Since it is equivalent in byte count to (a.1), the behavioural differences have to be analyzed.

Minimally wrapped inside a function, it becomes (b.1), both being similar in features.

(b.3) A statement working additively on k, setting n=0, 17 (pot. 16) bytes

for(;n;k++)n/=10;

Another variation on (b.1), removing initialization of k. Furthermore, for(; leaves space for an expression, potentially allowing to save a semicolon's byte, effectively rendering this approach 16 bytes long.

(c.1) A statement in n, producing stdout-output, 14 bytes

printf("%d",n)

Courtesy of H.PWiz.

This approach's utter conciseness and simplicity may be alluring, its major drawback, however, is its stdout-output; tolerability being heavily challenge-dependent.

(c.2) A statement in n, producing stderr-output, 17 bytes

dprintf(2,"%d",n)

Courtesy of Jo King.

The above is equivalent to the five bytes longer fprintf(stderr,"%d",n) and a variant of (c.1), side-effecting not stdout but rather the much more clutterable stderr.
Ref. man dprintf.3


Viewing all articles
Browse latest Browse all 67

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>