如何计算数字中的总位数?

时间:2010-12-19 16:36:31

标签: c# math numbers

如何计算C#中数字的总位数?例如,数字887979789有9位数字。

17 个答案:

答案 0 :(得分:139)

如果不转换为字符串,您可以尝试:

Math.Ceiling(Math.Log10(n));

ysap评论后的更正:

Math.Floor(Math.Log10(n) + 1);

答案 1 :(得分:68)

试试这个:

myint.ToString().Length

这有用吗?

答案 2 :(得分:20)

这些扩展中的任何一个都可以胜任:

public static class Int32Extensions
{
    // THE MATHEMATICALLY FORMULATED ONE:
    public static int Digits1(this Int32 n) =>
        n == 0 ? 1 : 1 + (int) Math.Log10(Math.Abs(n));

    // TYPICAL PROGRAMMING APPROACH:
    public static int Digits2(this Int32 n)
    {
        int digits = 0;
        do { ++digits; n /= 10; } while (n != 0);
        return digits;
    }

    // THE UGLIEST POSSIBLE THING:
    public static int Digits3(this Int32 n)
    {
        n = Math.Abs(n);
        if (n < 10) return 1;
        if (n < 100) return 2;
        if (n < 1000) return 3;
        if (n < 10000) return 4;
        if (n < 100000) return 5;
        if (n < 1000000) return 6;
        if (n < 10000000) return 7;
        if (n < 100000000) return 8;
        if (n < 1000000000) return 9;
        return 10;
    }

    // THE LOCOMOTIVE PULLING CHARACTERS:
    public static int Digits4(this Int32 n) =>
        n >= 0 ? n.ToString().Length : n.ToString().Length - 1;
}

我在5种不同的情况下对这些性能进行了一些性能测试,这些情况是使用Stopwatch对for循环中的100.000.000次调用进行的。

胜利者是...

-1000000000.Digits1()  =>   1806 ms
-1000000000.Digits2()  =>   4114 ms
-1000000000.Digits3()  =>    664 ms <<<
-1000000000.Digits4()  =>  13600 ms

-1000.Digits1()  =>  1839 ms
-1000.Digits2()  =>  1163 ms
-1000.Digits3()  =>   429 ms <<<
-1000.Digits4()  =>  9959 ms

0.Digits1()  =>   166 ms <<<
0.Digits2()  =>   369 ms
0.Digits3()  =>   165 ms <<<
0.Digits4()  =>  7416 ms

1000.Digits1()  =>  1578 ms
1000.Digits2()  =>  1182 ms
1000.Digits3()  =>   328 ms <<<
1000.Digits4()  =>  9296 ms

1000000000.Digits1()  =>   1596 ms
1000000000.Digits2()  =>   4074 ms
1000000000.Digits3()  =>    581 ms <<<
1000000000.Digits4()  =>  13679 ms

最糟糕的事情!

答案 3 :(得分:12)

不直接使用C#,但公式为:n = floor(log10(x)+1)

答案 4 :(得分:7)

这里的答案适用于无符号整数,但我没有找到很好的解决方案来获取小数和双精度数字。

public static int Length(double number)
{
    number = Math.Abs(number);
    int length = 1;
    while ((number /= 10) >= 1)
        length++;
    return length;
}
//number of digits in 0 = 1,
//number of digits in 22.1 = 2,
//number of digits in -23 = 2

如果精度很重要,您可以将输入类型从double更改为decimal,但十进制也有限制。

答案 5 :(得分:5)

使用递归(有时会在面试时询问)

public int CountDigits(int number)
{
    // In case of negative numbers
    number = Math.Abs(number);

    if (number >= 10)
        return CountDigits(number / 10) + 1;
    return 1;
 }

答案 6 :(得分:5)

Steve is correct的答案,但它对小于1的整数不起作用。

这是一个适用于否定的更新版本:

int digits = n == 0 ? 1 : Math.Floor(Math.Log10(Math.Abs(n)) + 1)

答案 7 :(得分:4)

static void Main(string[] args)
{
    long blah = 20948230498204;
    Console.WriteLine(blah.ToString().Length);
}

答案 8 :(得分:1)

将数字除以10将得到最左边的数字,然后对数字进行模数10给出没有第一个数字的数字并重复该数字直到你拥有所有数字

答案 9 :(得分:1)

这是使用二进制搜索的实现。看起来是迄今为止int32上最快的。

将Int64实现留给读者练习(!)

我尝试使用Array.BinarySearch而不是对树进行硬编码,但这只是速度的一半。

编辑: 查找表比二进制搜索快得多,但代价是要使用更多的内存。实际上,我可能会在生产环境中使用二进制搜索,因此查找表的速度增加了很多复杂性,可能会被软件的其他部分所掩盖。

org.mockito.ArgumentMatchers.isNull

查找表版本:

Lookup-Table: 439 ms
Binary-Search: 1069 ms
If-Chain: 1409 ms
Log10: 1145 ms
While: 1768 ms
String: 5153 ms

二进制搜索版本

static byte[] _0000llll = new byte[0x10000];
static byte[] _FFFFllll = new byte[0x10001];
static sbyte[] _hhhhXXXXdigits = new sbyte[0x10000];

// Special cases where the high DWORD is not enough information to find out how
// many digits.
static ushort[] _lowordSplits = new ushort[12];
static sbyte[] _lowordSplitDigitsLT = new sbyte[12];
static sbyte[] _lowordSplitDigitsGE = new sbyte[12];

static Int32Extensions()
{
    // Simple lookup tables for number of digits where value is 
    //    0000xxxx (0 .. 65535)
    // or FFFFxxxx (-1 .. -65536)
    precomputePositiveLo16();
    precomputeNegativeLo16();

    // Hiword is a little more complex
    precomputeHiwordDigits();
}

private static void precomputeHiwordDigits()
{
    int b = 0;

    for(int hhhh = 0; hhhh <= 0xFFFF; hhhh++)
    {
        // For hiword hhhh, calculate integer value for loword of 0000 and FFFF.
        int hhhh0000 = (unchecked(hhhh * 0x10000));  // wrap around on negatives
        int hhhhFFFF = hhhh0000 + 0xFFFF;

        // How many decimal digits for each?
        int digits0000 = hhhh0000.Digits_IfChain();
        int digitsFFFF = hhhhFFFF.Digits_IfChain();

        // If same number of decimal digits, we know that when we see that hiword
        // we don't have to look at the loword to know the right answer.
        if(digits0000 == digitsFFFF)
        {
            _hhhhXXXXdigits[hhhh] = (sbyte)digits0000;
        }
        else
        {
            bool negative = hhhh >= 0x8000;

            // Calculate 10, 100, 1000, 10000 etc
            int tenToThePower = (int)Math.Pow(10, (negative ? digits0000 : digitsFFFF) - 1);

            // Calculate the loword of the 10^n value.
            ushort lowordSplit = unchecked((ushort)tenToThePower);
            if(negative)
                lowordSplit = unchecked((ushort)(2 + (ushort)~lowordSplit));

            // Store the split point and digits into these arrays
            _lowordSplits[b] = lowordSplit;
            _lowordSplitDigitsLT[b] = (sbyte)digits0000;
            _lowordSplitDigitsGE[b] = (sbyte)digitsFFFF;

            // Store the minus of the array index into the digits lookup. We look for
            // minus values and use these to trigger using the split points logic.
            _hhhhXXXXdigits[hhhh] = (sbyte)(-b);
            b++;
        }
    }
}

private static void precomputePositiveLo16()
{
    for(int i = 0; i <= 9; i++)
        _0000llll[i] = 1;

    for(int i = 10; i <= 99; i++)
        _0000llll[i] = 2;

    for(int i = 100; i <= 999; i++)
        _0000llll[i] = 3;

    for(int i = 1000; i <= 9999; i++)
        _0000llll[i] = 4;

    for(int i = 10000; i <= 65535; i++)
        _0000llll[i] = 5;
}

private static void precomputeNegativeLo16()
{
    for(int i = 0; i <= 9; i++)
        _FFFFllll[65536 - i] = 1;

    for(int i = 10; i <= 99; i++)
        _FFFFllll[65536 - i] = 2;

    for(int i = 100; i <= 999; i++)
        _FFFFllll[65536 - i] = 3;

    for(int i = 1000; i <= 9999; i++)
        _FFFFllll[65536 - i] = 4;

    for(int i = 10000; i <= 65535; i++)
        _FFFFllll[65536 - i] = 5;
}



public static int Digits_LookupTable(this int n)
{
    // Split input into low word and high word.
    ushort l = unchecked((ushort)n);
    ushort h = unchecked((ushort)(n >> 16));

    // If the hiword is 0000 or FFFF we have precomputed tables for these.
    if(h == 0x0000)
    {
        return _0000llll[l];
    }
    else if(h == 0xFFFF)
    {
        return _FFFFllll[l];
    }

    // In most cases the hiword will tell us the number of decimal digits.
    sbyte digits = _hhhhXXXXdigits[h];

    // We put a positive number in this lookup table when
    // hhhh0000 .. hhhhFFFF all have the same number of decimal digits.
    if(digits > 0)
        return digits;

    // Where the answer is different for hhhh0000 to hhhhFFFF, we need to
    // look up in a separate array to tell us at what loword the change occurs.
    var splitIndex = (sbyte)(-digits);

    ushort lowordSplit = _lowordSplits[splitIndex];

    // Pick the correct answer from the relevant array, depending whether
    // our loword is lower than the split point or greater/equal. Note that for
    // negative numbers, the loword is LOWER for MORE decimal digits.
    if(l < lowordSplit)
        return _lowordSplitDigitsLT[splitIndex];
    else
        return _lowordSplitDigitsGE[splitIndex];
}

答案 10 :(得分:0)

整数总位数:

      double input = Convert.ToDouble(Console.ReadLine());
      double b = Math.Floor(Math.Log10(input) + 1);          
      int c = Convert.ToInt32(b);

答案 11 :(得分:0)

创建一个返回所有数字的方法,另一个返回数字的方法:

public static int GetNumberOfDigits(this long value)
{
    return value.GetDigits().Count();
}

public static IEnumerable<int> GetDigits(this long value)
{
    do
    {
        yield return (int)(value % 10);
        value /= 10;
    } while (value != 0);
}

在解决此问题时,这感觉像是一种更直观的方法。由于其简单性,我首先尝试了Log10方法,但是它遇到了很多极端情况和精度问题。

我还发现另一个答案中提出的if链有点难看。

我知道这不是最有效的方法,但是它为您提供了另一个扩展名,也可以返回数字以用于其他用途(如果您不需要在外部使用它,则可以将其标记为private该课程)。

请记住,它不会将负号视为数字。

答案 12 :(得分:0)

int i = 855865264;
int NumLen = i.ToString().Length;

答案 13 :(得分:-1)

这取决于你想要用digiths做什么。您可以通过这种方式从最后一个数字开始迭代到第一个数字:

int tmp=number;
int lastDigith = 0;
do
{
    lastDigith = tmp/10;
    doSomethingWithDigith(lastDigith);
    tmp %= 10;
}while(tmp!=0);

答案 14 :(得分:-2)

转换为字符串然后你可以通过.length方法计算数字的数字。 像:

String numberString = "855865264".toString();
int NumLen = numberString .Length;

答案 15 :(得分:-3)

假设你的问题是指一个int,那么以下也适用于负/正和零:

Math.Floor((decimal) Math.Abs(n)).ToString().Length

答案 16 :(得分:-3)

如果它仅用于验证您可以执行:887979789 > 99999999