计算O(1)中数字的位数

时间:2012-05-23 15:34:57

标签: algorithm x86 numbers glibc

我需要计算一个数字中的小数位数(例如:100表示​​4)。我希望在O(1)时间复杂度下执行此操作,因为代码将在大量数字上进行迭代,从而显着节省了cpu时间。

我提出了两个解决方案:

  1. 循环除以10直到数字变为零。循环计数是 答案。但是,显然是O(n)时间。
  2. log_base_10(num) + 1
  3. 问题:log10是O(1)解决方案吗?我在x86机器上使用glibc运行代码。如何在引擎盖下实施?并且,有更好的解决方案吗?

6 个答案:

答案 0 :(得分:2)

这看起来像Bit Twiddling Hacks

的情况
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;

“当输入均匀分布在32位值上时,此方法效果很好,因为第一次比较捕获了76%的输入,第二次比较捕获了21%,第三次捕获占2%,等等(每次比较将剩余的数量减少90%)。因此,平均需要的操作少于2.6次。“

答案 1 :(得分:1)

假设无符号整数和Intel平台(BSR指令),您可以获得最高设置位。那你就知道了:

2^i <= num < 2^(i+1)

其中inum的最高设置位。如此简单的查找表(由i索引)将您限制为两个可能的十进制数字计数,只需单个if即可解决。

但是你真的使用如此庞大的数字吗?你需要这种不合格的优化吗?

答案 2 :(得分:0)

您需要做的就是:

1 + floor(log(N)/log(10))

(这不会对0有效。如果输入浮点数,它将返回小数点左边的位数,并且仅对浮点数> 0.1进行处理。)

几乎可以肯定有一条FPU指令,不是原来的x86,但肯定是你的CPU支持的扩展。您可以通过在循环中多次评估log(N)来测试这一点。

这假设您将数字存储为int或float。如果您使用某个库将数字存储为可变长度数组,那么如果库预先计算数组的长度(正确的事情),那么这是O(1)时间,否则为O(N)时间(错误的库) )。

与所有浮动操作一样,如果你真的接近转换99-100,999-1000等,准确性可能是一个问题。正如Steve Jessop在这个答案的评论中指出的,你可以确定是否过度/低估根据所需的语义是可以的。我甚至可能会说你有一点余地:如果这些转换数字失败了,你可以在N中添加/减去0.1之类的东西(没有那么多数字:你可以亲自手动测试它们,看看这是不是必要)。

答案 3 :(得分:0)

我不会使用log来解决这个问题,因为它涉及双重计算,并且可能会比循环慢一点,除以10.牺牲一些内存和一些时间进行预计算你可能会在几个整数指令中得到答案。例如,预先计算最多10 000的数字位数:

int num_digits[10000];
for (int i = 0; i < 10000; ++i) {
  if (i < 10) {
    num_digits[i] = 1;
  } else if (i < 100) {
    num_digits[i] = 2;
  } else if (i < 1000) {
    num_digits[i] = 3;
  }
}

现在,您可以在大约4个整数运算中获得数字的位数:

int get(int n) {
  int result = 0;
  while (n > 10000) {
    result += 4;
    n /= 10000;
  }
  return result + num_digits[n];
}

这当然牺牲了记忆的速度,但正如我们所知there is no free lunch

答案 4 :(得分:-1)

import java.util.*;
import java.lang.*;
class Main
{
  public static void main (String args[])
  {
    Scanner in = new Scanner (System.in);
    System.out.print ("Enter the number : ");
    int n = in.nextInt ();
    double ans = 1 + Math.floor (Math.log (n) / Math.log (10));
    int intANS = (int) (ans);
    System.out.println ("No. of digits in " + n + " = " + intANS);
  }
}

//由G.Varaprasad在JAVA中贡献

答案 5 :(得分:-1)

class NumberOfDigits{

    public static void main(String ar[]){
        int n=99;
        System.out.println(""+(1+Math.floor(Math.log10(n))));
    }
}