确定整数位数的有效方法

Set*_*eth 138 c++ integer digits

什么是一个非常有效的确定多少位有在C++中的整数的方法吗?

Vit*_*ali 103

那么,假设你知道整数的大小,最有效的方法就是查找.应该比基于对数的方法更短.如果您不关心计算' - ',请删除+ 1.

// generic solution
template <class T>
int numDigits(T number)
{
    int digits = 0;
    if (number < 0) digits = 1; // remove this line if '-' counts as a digit
    while (number) {
        number /= 10;
        digits++;
    }
    return digits;
}

// partial specialization optimization for 32-bit numbers
template<>
int numDigits(int32_t x)
{
    if (x == MIN_INT) return 10 + 1;
    if (x < 0) return numDigits(-x) + 1;

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

// partial-specialization optimization for 8-bit numbers
template <>
int numDigits(char n)
{
    // if you have the time, replace this with a static initialization to avoid
    // the initial overhead & unnecessary branch
    static char x[256] = {0};
    if (x[0] == 0) {
        for (char c = 1; c != 0; c++)
            x[c] = numDigits((int32_t)c);
        x[0] = 1;
    }
    return x[n];
}
Run Code Online (Sandbox Code Playgroud)

  • 或者可能重新排序并嵌套if语句,以进行二分搜索而不是线性搜索. (27认同)
  • 可能比我的答案快,干得好.为了提高效率,如果你知道你的输入数字大多是小的(我猜小于100,000),那么反转测试:if(x <10)返回1; if(x <100)返回2; 等等,这样功能可以减少测试次数并退出更快. (5认同)
  • 关于256或128位整数,我不会太担心.除非你需要计算宇宙中的电子数量(上次我做了10 ^ 78),否则64位会很好.32位机器持续了~~ 15年.我猜64位机器会持续更长时间.对于更大的数字,多精度算术会很好,我怀疑计算数字计数的效率是否重要. (5认同)
  • 假设数字的均匀分布,反向线性搜索(从最大数字开始到1)可能比二进制搜索更快,因为有更多数字的N位数比N-1位数http://graphics.stanford埃杜/〜seander/bithacks.html#IntegerLog10Obvious (3认同)

Ski*_*izz 70

最简单的方法是:

unsigned GetNumberOfDigits (unsigned i)
{
    return i > 0 ? (int) log10 ((double) i) + 1 : 1;
}
Run Code Online (Sandbox Code Playgroud)

log10在<cmath>或中定义<math.h>.您需要对此进行分析,以确定它是否比此处发布的其他任何内容更快.我不确定这对于浮点精度有多强大.此外,参数是无符号的负值,而日志实际上并没有混合.

  • 对于32位整数和56位浮点数,这可能有效.如果输入是长(64位),则56位双精度日志可能会导致在接近大值10 ^ n的值的情况下产生错误答案.预计2 ^ 50以上的麻烦. (5认同)

Bra*_*rad 53

也许我误解了这个问题,但这不是吗?

int NumDigits(int x)  
{  
    x = abs(x);  
    return (x < 10 ? 1 :   
        (x < 100 ? 2 :   
        (x < 1000 ? 3 :   
        (x < 10000 ? 4 :   
        (x < 100000 ? 5 :   
        (x < 1000000 ? 6 :   
        (x < 10000000 ? 7 :  
        (x < 100000000 ? 8 :  
        (x < 1000000000 ? 9 :  
        10)))))))));  
}  
Run Code Online (Sandbox Code Playgroud)

  • 如果这个解决方案最快,我也不会感到惊讶. (25认同)

squ*_*art 33

int digits = 0; while (number != 0) { number /= 10; digits++; }
Run Code Online (Sandbox Code Playgroud)

注意:"0"将有0位数!如果您需要0来显示1位数,请使用:

int digits = 0; do { number /= 10; digits++; } while (number != 0);
Run Code Online (Sandbox Code Playgroud)

(谢谢Kevin Fegan)

最后,使用分析器知道您的机器上的所有答案中的哪一个会更快...

  • 这可能会或者可能不会比我采用的展开循环方法更快 - 您需要分析差异(从长远来看应该可以忽略不计). (3认同)

小智 11

恶作剧:这是最有效的方式(中位数在编译时计算):

template <unsigned long long N, size_t base=10>
struct numberlength
{
    enum { value = 1 + numberlength<N/base, base>::value };
};

template <size_t base>
struct numberlength<0, base>
{
    enum { value = 0 };
};
Run Code Online (Sandbox Code Playgroud)

可能有助于确定格式化,输入元素等中数字字段所需的宽度.

  • 首先,您的解决方案不适用于0.其次,您的解决方案不适用于变量的一般情况.第三,如果你使用常量文字,你已经知道它有多少位数. (3认同)
  • 我认为它确实没有.它在'0'上失败并且在基础`1` :)上失败并且如果基数被给定为0则给出除零错误.它可以修复.无论如何,我正在挑剔一个非常古老的帖子,很抱歉,这只是我认为这不一定是一个笑话,实际上可能是有用的. (2认同)

Jos*_*man 9

请参阅Bit Twiddling Hacks获取您接受的答案的更短版本.如果您的输入是正态分布,它还可以通过首先检查大常量来更快地找到答案. (v >= 1000000000)捕获76%的值,因此首先检查平均值会更快.


小智 8

转换为字符串,然后使用内置函数

unsigned int i;
cout<< to_string(i).length()<<endl;
Run Code Online (Sandbox Code Playgroud)

  • 地狱慢:D (5认同)

Ira*_*ter 6

之前的海报提出了一个循环除以10.由于现代机器上的乘法速度要快得多,我建议使用以下代码:

 int digits = 1, pten=10; while ( pten <= number ) { digits++; pten*=10; }
Run Code Online (Sandbox Code Playgroud)

  • 如果您担心这种情况,可以添加一个额外的IF来处理非常大的值. (2认同)
  • 我应该观察到在x86机器上,在这种情况下乘以常数10实际上可以由编译器实现为LEA R2,[8*R1 + R1],ADD R1,R2,因此最多需要2个时钟.变量乘以数十个时钟,并且分频更差. (2认同)
  • 我对乘法方法(使用晶圆厂消除符号问题)与除法方法进行了基准测试。在我的机器上,除法方法比乘法方法慢 2 倍。这是否是过早优化实际上取决于调用的位置和方式。 (2认同)

小智 5

ppc架构有一个位计数指令.这样,您可以在单个指令中确定正整数的对数基数2.例如,32位将是:

#define log_2_32_ppc(x) (31-__cntlzw(x))
Run Code Online (Sandbox Code Playgroud)

如果您可以在较大的值上处理一小部分错误,您可以使用另外几条指令将其转换为log 10:

#define log_10_estimate_32_ppc(x) (9-(((__cntlzw(x)*1233)+1545)>>12))
Run Code Online (Sandbox Code Playgroud)

这是特定于平台的并且稍微不准确,但也不涉及分支,划分或转换为浮点.一切都取决于你需要什么.

我只知道ppc指令,但其他架构应该有类似的指令.


bem*_*aru 5

int x = 1000;
int numberOfDigits = x ? static_cast<int>(log10(abs(x))) + 1 : 1;
Run Code Online (Sandbox Code Playgroud)

  • 尽管就LOC而言这是有效的,但如公认的答案所述,使用log可能不会提供最佳性能。 (3认同)