基于非函数运算符的单线程,用于int的大小

时间:2010-10-08 16:58:06

标签: language-agnostic

我想知道是否有办法在不使用函数调用且仅使用运算符(无控制结构)的情况下获得整数的大小。

如果我在这里使用的术语幅度不正确,我的意思是基本上占用了多少位数。例如。 2468的幅度为4。

否则,最有效的方法是什么? 我能想到的最好的是while ( num /= 10 ) mag++;,但我只是想知道那里是否有某种黑魔法我不知道。

首选C风格语言的解决方案(C,C ++,Java,C#等)

2 个答案:

答案 0 :(得分:1)

数学上你想要⌊log 10 (| x |)⌋+ 1.除非x是0。

您给出的运算符和函数之间的区别是相当随意的。总是可以使用⌊log 10 (| x |)⌋+ 1运算符创建一种语言!

仍然为了它的乐趣,我们可以从创建一个整数日志 10 (x)方法开始,这很容易通过简单比较完成:

//assumes 32-bit int in max value. Add cases accordingly
return (x >= 1000000000) ? 9 : (x >= 100000000) ? 8 : (x >= 10000000) ? 7 : 
  (x >= 1000000) ? 6 : (x >= 100000) ? 5 : (x >= 10000) ? 4 : 
  (x >= 1000) ? 3 : (x >= 100) ? 2 : (x >= 10) ? 1 : 0;

我们将为我们获得的任何结果添加1,因此我们甚至不需要添加,我们只是更改结果:

return (x >= 1000000000) ? 10 : (x >= 100000000) ? 9 : (x >= 10000000) ? 8 : 
  (x >= 1000000) ? 7 : (x >= 100000) ? 6 : (x >= 10000) ? 5 : 
  (x >= 1000) ? 4 : (x >= 100) ? 3 : (x >= 10) ? 2 : 1;

奖金是这也正确处理x == 0的情况。

现在我们只需要吸收它。

x = x > 0 ? x : -x;
return (x >= 1000000000) ? 10 : (x >= 100000000) ? 9 : (x >= 10000000) ? 8 : 
  (x >= 1000000) ? 7 : (x >= 100000) ? 6 : (x >= 10000) ? 5 : 
  (x >= 1000) ? 4 : (x >= 100) ? 3 : (x >= 10) ? 2 : 1;

对于单行而言:

return ((x > 0 ? x : -x) >= 1000000000) ? 10 : ((x > 0 ? x : -x) >= 100000000) ? 9 : ((x > 0 ? x : -x) >= 10000000) ? 8 :  ((x > 0 ? x : -x) >= 1000000) ? 7 : ((x > 0 ? x : -x) >= 100000) ? 6 : ((x > 0 ? x : -x) >= 10000) ? 5 : ((x > 0 ? x : -x) >= 1000) ? 4 : ((x > 0 ? x : -x) >= 100) ? 3 : ((x > 0 ? x : -x) >= 10) ? 2 : 1;

问题在于您是否考虑?:控制结构。它一个运算符,但它确实是分支的(并且比使用控制结构更具实际影响,但仍然是微观的选择)。

至少应该可以在多线程中进行非分支,让我们看看。

非分支abs很容易:

 (x ^ (x >> 31)) - (x >> 31); // assuming 32-bit int, adjust shift accordingly

现在以对数为例,我作弊并查看一些我记不起来的尖锐的黑客行为。我只是打算干这个端口(因为我已经做了C#到目前为止,并且可以坚持使用它),我可以在http://graphics.stanford.edu/~seander/bithacks.html阅读,并留下测试并修复我的任何错误作为练习介绍:

我们首先找到log 2 (x);

int[] MultiplyDeBruijnBitPosition = new int[]
{
  0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
  8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
};

int l = x >> 1; // first round down to one less than a power of 2 
l |= l >> 2;
l |= l >> 4;
l |= l >> 8;
l |= l >> 16;

l = MultiplyDeBruijnBitPosition[(uint)(l * 0x07C4ACDDU) >> 27];

现在我们可以用它来找到基数为10的对数:

int[] PowersOf10 = new int[]
    {1, 10, 100, 1000, 10000, 100000,
     1000000, 10000000, 100000000, 1000000000};

int t = (l + 1) * 1233 >> 12;
return t - (x < PowersOf10[t]);

答案 1 :(得分:0)

对于计算相关值存在恒定时间“位攻击”,例如the highest bit that is set in a number.这是类似的,因为您想要找到非零的最高位。

但是,由于您对base-10值感兴趣,并且这些方法使用二进制算法,我不确定它们是否可以调整。不过,看看它们的工作原理可能会给你一些想法。