获取整数最高十进制数的最快方法是什么?

时间:2016-07-28 09:57:57

标签: algorithm integer bit-manipulation modulus integer-arithmetic

实施

的最快方式
template <typename T>
unsigned highest_decimal_digit(T x);

(例如,356431为3,71为9,9为9)?

我能想到的最好的是:

  • constexpr-计算&#34;中等大小&#34;适合T的10的力量。
  • 执行二进制搜索(超过10的幂,可能使用constexpr构造的查找表)来找到p,最高10的幂比x低。
  • 返回x除以p

......但也许还有另一种方法。

备注:

  • 我用C ++ 14ish术语表达了问题和方法,并且代码中的解决方案会很好,但是抽象解决方案(甚至是x86_64汇编中的解决方案)都可以。我确实想要一些适用于所有(无符号)整数类型的东西。
  • 您可以忽略已签名的整数类型。
  • 我没有说明&#34; fast&#34;是,但请注意硬件。

4 个答案:

答案 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。