计算整数的小数长度的最快方法? (。网)
我有一些代码对 64 位整数进行大量比较,但是它必须考虑数字的长度,就好像它被格式化为字符串一样。 我无法更改调用代码,只能更改函数。
最简单的方法(除了 .ToString().Length 之外)是:
(int)Math.Truncate(Math.Log10(x)) + 1;
但是效果相当差。 由于我的应用程序仅发送正值,并且长度相当均匀地分布在 2 和 9 之间(有一些偏向 9),因此我预先计算了这些值并具有 if 语句:
static int getLen(long x) {
if (x < 1000000) {
if (x < 100) return 2;
if (x < 1000) return 3;
if (x < 10000) return 4;
if (x < 100000) return 5;
return 6;
} else {
if (x < 10000000) return 7;
if (x < 100000000) return 8;
if (x < 1000000000) return 9;
return (int)Math.Truncate(Math.Log10(x)) + 1; // Very uncommon
}
}
这样可以通过 4 次比较的平均值来计算长度。
那么,还有其他技巧可以使这个功能更快吗?
编辑:这将作为 32 位代码 (Silverlight) 运行。
更新:
我采纳了 Norman 的建议,并对 ifs 进行了一些更改,结果平均只有 3 次比较。 根据 Sean 的评论,我删除了 Math.Truncate。 合计而言,这使业绩增长了约 10%。 谢谢!
I have some code that does a lot of comparisons of 64-bit integers, however it must take into account the length of the number, as if it was formatted as a string. I can't change the calling code, only the function.
The easiest way (besides .ToString().Length) is:
(int)Math.Truncate(Math.Log10(x)) + 1;
However that performs rather poorly. Since my application only sends positive values, and the lengths are rather evenly distributed between 2 and 9 (with some bias towards 9), I precomputed the values and have if statements:
static int getLen(long x) {
if (x < 1000000) {
if (x < 100) return 2;
if (x < 1000) return 3;
if (x < 10000) return 4;
if (x < 100000) return 5;
return 6;
} else {
if (x < 10000000) return 7;
if (x < 100000000) return 8;
if (x < 1000000000) return 9;
return (int)Math.Truncate(Math.Log10(x)) + 1; // Very uncommon
}
}
This lets the length be computed with an average of 4 compares.
So, are there any other tricks I can use to make this function faster?
Edit: This will be running as 32-bit code (Silverlight).
Update:
I took Norman's suggestion and changed the ifs around a bit to result in an average of only 3 compares. As per Sean's comment, I removed the Math.Truncate. Together, this boosted things about 10%. Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
两个建议:
除非分布非常倾斜,否则这种组合可能不会给你带来太多好处。
Two suggestions:
This combination probably doesn't buy you much unless the distribution is very skew.
来自 Sean Anderson 的 Bit Twiddling Hacks:
查找以 10 为底的整数对数一个整数
至于计算 IntegerLogBase2,该页面上提供了几种替代方案。 对于各种高度优化的整数运算来说,它是一个很好的参考。
您的版本的一个变体也在那里,只不过它假设值(而不是值的对数基数 10)均匀分布,因此进行指数排序搜索:
查找整数的整数对数基数 10 是显而易见的方式
From Sean Anderson's Bit Twiddling Hacks:
Find integer log base 10 of an integer
As far as computing IntegerLogBase2, there are several alternatives presented on that page. It's a great reference for all sorts of highly optimized integer operations.
A variant of your version is also there, except it assumes the values (rather than the log base 10 of the values) are uniformly distributed, and therefore does an exponentially ordered search:
Find integer log base 10 of an integer the obvious way
这是我已经测试过的二进制搜索版本,它适用于 64 位整数,每次只使用五次比较。
我怀疑这会比你已经做的更快。 但这是可以预见的。
Here's a binary-search version, which I have tested, which works on 64-bit integers using exactly five comparisons each time.
I doubt this is going to be any faster than what you're already doing. But it's predictable.
我做了一些测试,这似乎比您现在的代码快 2-4 倍:
编辑:
这是一个使用更多 Int32 操作的版本,如果您没有 x64 应用程序,它应该可以更好地工作:
I did some testing, and this seems to be 2-4 times faster than the code that you have now:
Edit:
Here is a version that uses more Int32 operations, that should work better if you don't have an x64 application:
你在代码中评论说10位或更多是非常罕见的,所以你原来的解决方案还不错
You commented in code that 10 digits or more is very uncommon, so your original solution is not bad
我还没有对此进行测试,但基本定律的变化表明:
Log10(x) = Log2(x) / Log2(10)
如果实施正确,Log2 应该比 Log10 快一点。
I haven't tested this, but the change of base law says:
Log10(x) = Log2(x) / Log2(10)
Log2 should be a bit faster than Log10 if it's implemented right.
不确定这是否更快..但你总是可以数...
not sure if this is faster or not.. but you can always count...
你说的长度是什么意思? 零的数量还是全部? 这 的数字很重要,但您可以了解总体思路
What do you mean by length? Number of zeros or everything? This does significant figures, but you get the general idea
这是一个简单的方法。
如果 number 是 unsigned int 则不需要“Math.Abs(number)”。
我用所有数字类型制作了扩展方法。
那么你就用这个。
It's a simple way.
If number is unsigned int then "Math.Abs(number)" not necessary.
I made extension method with all numeric types.
then you use this.