实施
的最快方式template <typename T>
unsigned highest_decimal_digit(T x);
(例如,356431为3,71为9,9为9)?
我能想到的最好的是:
......但也许还有另一种方法。
备注:
答案 0 :(得分:2)
最佳选择似乎是结合CLZ方法并除以预先计算的10的幂。所以,在伪代码中:
powers10=[1,1,1,1,10,10,10,10,100,100...]; // contains powers of 10 map to CLZ values
int firstDigit(unsigned INT_TYPE a) {
if (a<10) return a; // one digit, screw it
int j=typesize(a)-clz(a);
if (j==3) return 1; // 10-16 hit this, return 1
int k=a/powers10[j];
if (k>9) return 1; else return k;
}
typesize()
为long long
返回64,int
返回32,short int
返回16。
答案 1 :(得分:1)
较新的x86芯片支持lzcnt指令,该指令告诉您整数开头的清除位数。您可以使用内置编译器功能(如GCC):
访问它 unsigned short __builtin_ia32_lzcnt_16(unsigned short);
unsigned int __builtin_ia32_lzcnt_u32(unsigned int);
unsigned long long __builtin_ia32_lzcnt_u64 (unsigned long long);
您可以将其与640个值的查找表结合起来,这些值表示整数的下限和上限,从0-9开始的每个数字开始,以相应的清除位数开头。实际上,您可以通过右移lzcnt
值3个位置来节省空间;与第一个十进制数字的对应关系仍然是唯一的。
答案 2 :(得分:1)
使用lzcnt
指令,可以为每个前导零位数构造一个除数表。例如,对于无符号的64位数字:
lz | range | div
---+---------+----
64 | 0 | 1
63 | 1 | 1
62 | 2-3 | 1
61 | 4-7 | 1
60 | 8-15 | 1
59 | 16-31 | 10
58 | 32-63 | 10
57 | 64-127 | 10
56 | 128-255 | 100
...
0 | 9223372036854775808-18446744073709551615 | 1000000000000000000
然后计算变为:
leading_zero_bits = lzcnt(x);
leading_digit = x / divisor_table[leading_zero_bits];
if (leading_digit >= 10) leading_digit = 1;
除法的结果总是小于20,因此只需要对10到19之间的商进行简单的检查。也可以优化除以常数。
答案 3 :(得分:0)
我发生的选项;
蛮力:保持整数除以10,直到你得到零;它会告诉你你正在查看的号码顺序(例如860需要3个班次(86,8,0)所以它是10 ^ 3)然后返回n /(10 ^ order)
二进制搜索:如您所说,搜索超过10的权限,但它需要额外的变量和分配,并且需要关注的是,额外的跟踪信息是否会为您自己的数字类型付费关心?例如,如果你的大部分数字都很小,那么蛮力可能会更快。
Bitshift优化:计算您需要做多少次x >> 1
直到达到零;这会设置搜索范围。例如,94
需要7个班次来清除这个数字。因此,&lt;&lt; s&lt;因此,在10 ^ 3开始蛮力搜索。您需要查找bits =&gt; order。