作者:OH-MQNZ_259 | 来源:互联网 | 2023-07-15 11:24
Ihavesomecodethatdoesalotofcomparisonsof64-bitintegers,howeveritmusttakeintoaccoun
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.
我有一些代码可以对64位整数进行大量的比较,但是它必须考虑数字的长度,就像它被格式化为字符串一样。我无法更改调用代码,只能更改函数。
The easiest way (besides .ToString().Length) is:
最简单的方法(除了.ToString()。Length)是:
(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:
然而,这表现得相当糟糕。由于我的应用程序只发送正值,并且长度相当均匀地分布在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
}
}
This lets the length be computed with an average of 4 compares.
这使得长度可以用平均4个比较来计算。
So, are there any other tricks I can use to make this function faster?
那么,我有什么其他技巧可以让这个功能更快吗?
Edit: This will be running as 32-bit code (Silverlight).
编辑:这将作为32位代码(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!
我采用了Norman的建议并稍微改变了ifs,结果平均只有3个比较。根据肖恩的评论,我删除了Math.Truncate。总之,这促进了大约10%的事情。谢谢!
10 个解决方案
5
From Sean Anderson's Bit Twiddling Hacks:
来自Sean Anderson的Bit Twiddling Hacks:
Find integer log base 10 of an integer
查找整数的整数对数10
unsigned int v; // non-zero 32-bit integer value to compute the log base 10 of
int r; // result goes here
int t; // temporary
static unsigned int const PowersOf10[] =
{1, 10, 100, 1000, 10000, 100000,
1000000, 10000000, 100000000, 1000000000};
t = (IntegerLogBase2(v) + 1) * 1233 >> 12; // (use a lg2 method from above)
r = t - (v
The integer log base 10 is computed by first using one of the techniques above for finding the log base 2. By the relationship log10(v) = log2(v) / log2(10), we need to multiply it by 1/log2(10), which is approximately 1233/4096, or 1233 followed by a right shift of 12. Adding one is needed because the IntegerLogBase2 rounds down. Finally, since the value t is only an approximation that may be off by one, the exact value is found by subtracting the result of v
通过首先使用上述技术之一来查找日志库2来计算整数对数库10.通过关系log10(v)= log2(v)/ log2(10),我们需要将其乘以1 / log2( 10),大约是1233/4096,或1233,然后右移12.需要添加一个,因为IntegerLogBase2向下舍入。最后,由于值t只是一个可能偏离1的近似值,因此通过减去v
This method takes 6 more operations than IntegerLogBase2. It may be sped up (on machines with fast memory access) by modifying the log base 2 table-lookup method above so that the entries hold what is computed for t (that is, pre-add, -mulitply, and -shift). Doing so would require a total of only 9 operations to find the log base 10, assuming 4 tables were used (one for each byte of v).
此方法比IntegerLogBase2多运行6次。通过修改上面的log base 2 table-lookup方法,可以加速(在具有快速内存访问的机器上),以便条目保存为t计算的内容(即pre-add,-mulitply和-shift)。这样做将需要总共仅9个操作来找到日志库10,假设使用了4个表(对于v的每个字节一个表)。
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.
就计算IntegerLogBase2而言,该页面上提供了几种替代方案。它是各种高度优化的整数运算的绝佳参考。
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:
您的版本的变体也存在,除了它假设值(而不是值的日志基数10)是均匀分布的,因此执行指数排序的搜索:
Find integer log base 10 of an integer the obvious way
以明显的方式查找整数的整数对数10
unsigned int v; // non-zero 32-bit integer value to compute the log base 10 of
int r; // result goes here
r = (v >= 1000000000) ? 9 : (v >= 100000000) ? 8 : (v >= 10000000) ? 7 :
(v >= 1000000) ? 6 : (v >= 100000) ? 5 : (v >= 10000) ? 4 :
(v >= 1000) ? 3 : (v >= 100) ? 2 : (v >= 10) ? 1 : 0;
This method works well when the input is uniformly distributed over 32-bit values because 76% of the inputs are caught by the first compare, 21% are caught by the second compare, 2% are caught by the third, and so on (chopping the remaining down by 90% with each comparision). As a result, less than 2.6 operations are needed on average.
当输入均匀分布在32位值时,此方法很有效,因为76%的输入被第一次比较捕获,21%被第二次比较捕获,2%被第三次比较捕获,依此类推(斩波)每次比较后剩下的90%)。因此,平均需要不到2.6次操作。