我看到一篇解释如何将 int 转换为字符串的帖子。在解释中有一行代码用于获取字符串中的字符数:
(int)((ceil(log10(num))+1)*sizeof(char))
Run Code Online (Sandbox Code Playgroud)
我想知道为什么使用 log base 10?
ike*_*ami 10
ceil(log10(num))+1被错误地使用而不是floor(log10(num))+2.
该代码试图确定将正整数的十进制表示存储num为字符串所需的内存量。
除了数字是 10 的精确幂之外,上面给出的两个公式是相等的,在这种情况下,前一个版本返回的数字比所需数字少 1。
例如,10,000 需要 6 个字节,但ceil(log10(10000))+1返回5. floor(log10(10000))+2正确返回 6。
是如何floor(log10(num))+2获得的?
4567等4位数字会在1000(含)和10000(不含)之间,所以会在10 3(含)和10 4(不含)之间,所以log 10(4567)会在3(含)之间) 和 4(独占)。
因此,floor(log10(num))+1将返回num以十进制表示正值所需的位数。
因此,floor(log10(num))+2将返回将正整数的十进制表示存储num为字符串所需的内存量。(额外的字符用于终止字符串的 NUL。)
\n\n\n我\xe2\x80\x99m想知道为什么使用以10为底的对数?
\n
我也在想同样的事情。它使用运行时发生的非常复杂的计算来节省几个字节的临时存储。但它却做错了。
\n\n原则上,通过取以 10 为底的对数和取整并加 1 ,可以得到以 10 为底的位数。它准确地来自以下事实:
\n\nlog10(1) = log10(10\xe2\x81\xb0) = 0\nlog10(10) = log10(10\xc2\xb9) = 1\nlog10(100) = log10(10\xc2\xb2) = 2\nRun Code Online (Sandbox Code Playgroud)\n\n10 到 100 之间的所有数字的对数都在 1 到 2 之间,因此,如果将任意两位数的对数取底,您将得到 1...加 1,即可得到位数。
\n\n但您不需要在运行时执行此操作。以 10 为基数的 32 位 int 所需的最大字节数为 10 位数字、负号和 12 个字符的空终止符。通过运行时计算,您最多可以节省 10 个字节的 RAM,但它通常是临时的,因此不值得。如果它是堆栈内存,那么对 等的调用log10可能ceil需要更多。
事实上,我们知道表示一个整数所需的最大位数sizeof (int) * CHAR_BIT: 。这大于或等于的log2MAX_INT + 1。我们知道log10(x)=~ ,所以我们只需除以3 就3.32192809489 * log2(x)可以得到一个很好的(可能是下底的)近似值。然后添加,因为我们应该在下底对数上加 1 以获得位数,然后得到可能的符号,并且对于空终止符,我们得到log10(MAX_INT)sizeof (int) * CHAR_BIT111
sizeof (int) * CHAR_BIT / 3 + 3\nRun Code Online (Sandbox Code Playgroud)\n\n与您的问题不同,这是一个整数常量表达式,即编译器可以在编译时轻松折叠它,并且它可用于设置静态类型数组的大小,对于 32 位,它给出13这仅比实际需要的 12 位多 1,对于 16 位,它给出8,这又只比所需的最大值 7 多 1,对于 8 位,它给出5,这是确切的最大值。
\n