为什么在这段代码中使用 log base 10 将 int 转换为 string?

Why is log base 10 used in this code to convert int to string?

我看到 post 解释了如何将 int 转换为字符串。在解释中有一行代码可以获取字符串中的字符数:

(int)((ceil(log10(num))+1)*sizeof(char))

我想知道为什么使用 log base 10?

这是因为它分配的 space 足以让数字适合字符串。

例如,如果您的号码是 1034,log10(1034) = 3.0145...ceil(3.0145)是4,也就是数字的位数。 + 1 用于空终止符。

但这并不完美:以 1000 为例。尽管有四位数字,log(1000) = 3ceil(3) = 3,所以这将为太少的数字分配 space。另外,正如@phuclv 在下面提到的,log() 函数为此目的非常耗时,尤其是因为数字的长度有一个(相对较低的)上限。

它以 10 为底的对数的原因是,大概是因为此函数表示十进制形式的数字。例如,如果它是十六进制的,将使用以 16 为底的日志。

ceil(log10(num))+1 被错误地使用而不是 floor(log10(num))+2.

代码正在尝试确定将正整数 num 的十进制表示形式存储为字符串所需的内存量。

上面给出的两个公式除了数字是 10 的精确幂之外是相等的,在这种情况下,前一个版本 return 比所需数字小一。

例如,10,000 需要 6 个字节,但 ceil(log10(10000))+1 returns 5floor(log10(10000))+2 正确 returns 6.


floor(log10(num))+2是怎么得到的?

4位数字如4567会在1000(含)到10000(不含)之间,所以它会在103(含)到10[=之间40=]4(不含),所以log10(4567)会在3(含)和4(不含)之间。

因此,floor(log10(num))+1 将 return 表示十进制正值 num 所需的位数。

因此,floor(log10(num))+2 将 return 将正整数 num 的十进制表示形式存储为字符串所需的内存量。 (额外的字符用于终止字符串的 NUL。)

ceil(log10(num)) + 1 旨在提供输出字符串所需的字符数。

例如,如果 num=101,则表达式的值为 4,即“101”的正确长度加上空终止符。

但如果 num=100,则值为 3。此行为是不正确的。

数字 N 有 n 个十进制数字当且仅当 10^(n-1) <= N < 10^n 等于 n-1 <= log(N) < nn = floor(log(N)) + 1.

由于 double 表示的精度有限 floor(log(N)) 对于某些值可能会偏离 1,因此允许额外的数字更安全,即分配 floor(log(N)) + 2 个字符,并且然后是 nul 终止符的另一个字符,总共 floor(log(N)) + 3.

原题ceil(log(N)) + 1中的表达式似乎没有计算nul终止符,也没有考虑到舍入误差的可能性,所以一般会短一个,10的幂则短两个。

I’m wondering why log base 10 is used?

我也在想同样的事情。它使用在运行时发生的 非常 复杂的计算,以节省几个字节的 临时 存储。而且它做错了。


原则上,您可以通过取以 10 为底的对数和 flooring 并加 1 来获得以 10 为底的位数。它正是来自

log10(1) = log10(10⁰) = 0
log10(10) = log10(10¹) = 1
log10(100) = log10(10²) = 2

10 到 100 之间的所有数字的对数都在 1 到 2 之间,所以如果你对任何两位数的对数求底,你会得到 1...加 1 就得到位数。

但您不需要在运行时执行此操作。以 10 为基数的 32 位 int 所需的最大字节数是 10 个数字、负号和 12 个字符的空终止符。通过运行时计算最多可以节省 10 字节 RAM,但这通常是临时的,因此不值得。如果它是堆栈内存,那么对 log10ceil 等的调用可能需要更多。


事实上,我们知道表示一个整数所需的最大数:sizeof (int) * CHAR_BIT。这大于或等于 MAX_INT + 1log2。我们知道 log10(x) =~ 3.32192809489 * log2(x),所以我们通过将 sizeof (int) * CHAR_BIT 除以 3 得到了 log10(MAX_INT) 的一个很好的(可能是最低限度的)近似值。然后加上 1 对于 我们应该在底对数上加 1 以获得位数 ,然后 1 表示可能的符号, 1 表示空终止符和我们得到

sizeof (int) * CHAR_BIT / 3 + 3

与你的问题不同,这是一个整数常量表达式,即编译器可以很容易地在编译时折叠它,它可以用来设置大小一个静态类型的数组,对于 32 位它给出 13 这只比实际需要的 12 多 1,对于 16 位它给出 8 这又只比所需的最大值多 7,对于 8 位,它给出 5 这是确切的最大值。