简体   繁体   English

如何计算一个数字的总位数?

[英]How can I get a count of the total number of digits in a number?

How can I get a count of the total number of digits of a number in C#?如何计算 C# 中某个数字的总位数? For example, the number 887979789 has 9 digits.例如,数字 887979789 有 9 位数字。

无需转换为字符串,您可以尝试

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

Try This:试试这个:

myint.ToString().Length

Does that work ?那样有用吗 ?

The Solution解决方案

Any of the following extension methods will do the job.以下任何扩展方法都可以完成这项工作。 All of them consider the minus sign as a digit, and work correctly for all possible input values.它们都将减号视为数字,并且对所有可能的输入值都能正常工作。 They also work for .NET Framework and for .NET Core.它们也适用于 .NET Framework 和 .NET Core。 There are however relevant performance differences (discussed below), depending on your choice of Platform / Framework.然而,存在相关的性能差异(如下所述),具体取决于您选择的平台/框架。

Int32 version: Int32 版本:

public static class Int32Extensions
{
    // IF-CHAIN:
    public static int Digits_IfChain(this int n)
    {
        if (n >= 0)
        {
            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;
        }
        else
        {
            if (n > -10) return 2;
            if (n > -100) return 3;
            if (n > -1000) return 4;
            if (n > -10000) return 5;
            if (n > -100000) return 6;
            if (n > -1000000) return 7;
            if (n > -10000000) return 8;
            if (n > -100000000) return 9;
            if (n > -1000000000) return 10;
            return 11;
        }
    }

    // USING LOG10:
    public static int Digits_Log10(this int n) =>
        n == 0 ? 1 : (n > 0 ? 1 : 2) + (int)Math.Log10(Math.Abs((double)n));

    // WHILE LOOP:
    public static int Digits_While(this int n)
    {
        int digits = n < 0 ? 2 : 1;
        while ((n /= 10) != 0) ++digits;
        return digits;
    }

    // STRING CONVERSION:
    public static int Digits_String(this int n) =>
        n.ToString().Length;
}

Int64 version: Int64 版本:

public static class Int64Extensions
{
    // IF-CHAIN:
    public static int Digits_IfChain(this long n)
    {
        if (n >= 0)
        {
            if (n < 10L) return 1;
            if (n < 100L) return 2;
            if (n < 1000L) return 3;
            if (n < 10000L) return 4;
            if (n < 100000L) return 5;
            if (n < 1000000L) return 6;
            if (n < 10000000L) return 7;
            if (n < 100000000L) return 8;
            if (n < 1000000000L) return 9;
            if (n < 10000000000L) return 10;
            if (n < 100000000000L) return 11;
            if (n < 1000000000000L) return 12;
            if (n < 10000000000000L) return 13;
            if (n < 100000000000000L) return 14;
            if (n < 1000000000000000L) return 15;
            if (n < 10000000000000000L) return 16;
            if (n < 100000000000000000L) return 17;
            if (n < 1000000000000000000L) return 18;
            return 19;
        }
        else
        {
            if (n > -10L) return 2;
            if (n > -100L) return 3;
            if (n > -1000L) return 4;
            if (n > -10000L) return 5;
            if (n > -100000L) return 6;
            if (n > -1000000L) return 7;
            if (n > -10000000L) return 8;
            if (n > -100000000L) return 9;
            if (n > -1000000000L) return 10;
            if (n > -10000000000L) return 11;
            if (n > -100000000000L) return 12;
            if (n > -1000000000000L) return 13;
            if (n > -10000000000000L) return 14;
            if (n > -100000000000000L) return 15;
            if (n > -1000000000000000L) return 16;
            if (n > -10000000000000000L) return 17;
            if (n > -100000000000000000L) return 18;
            if (n > -1000000000000000000L) return 19;
            return 20;
        }
    }

    // USING LOG10:
    public static int Digits_Log10(this long n) =>
        n == 0L ? 1 : (n > 0L ? 1 : 2) + (int)Math.Log10(Math.Abs((double)n));

    // WHILE LOOP:
    public static int Digits_While(this long n)
    {
        int digits = n < 0 ? 2 : 1;
        while ((n /= 10L) != 0L) ++digits;
        return digits;
    }

    // STRING CONVERSION:
    public static int Digits_String(this long n) =>
        n.ToString().Length;
}

Discussion讨论

This answer includes tests performed for both Int32 and Int64 types, using an array of 100.000.000 randomly sampled int / long numbers.这个答案包括对Int32Int64类型执行的测试,使用100.000.000随机采样的int / long数字的数组。 The random dataset is pre-processed into an array before executing the tests.在执行测试之前,随机数据集被预处理成一个数组。

Consistency tests among the 4 different methods were also executed, for MinValue , negative border cases, -1 , 0 , 1 , positive border cases, MaxValue , and also for the whole random dataset.还执行了 4 种不同方法之间的一致性测试,对于MinValue 、负边界情况、 -101 、正边界情况、 MaxValue以及整个随机数据集。 No consistency tests fail for the above provided methods, EXCEPT for the LOG10 method (this is discussed later).上面提供的方法没有一致性测试失败,除了 LOG10 方法(稍后讨论)。

The tests were executed on .NET Framework 4.7.2 and .NET Core 2.2 ;测试在.NET Framework 4.7.2.NET Core 2.2 for x86 and x64 platforms, on a 64-bit Intel Processor machine, with Windows 10 , and with VS2017 v.15.9.17 .对于x86x64平台,在 64 位英特尔处理器机器上,使用Windows 10VS2017 v.15.9.17 The following 4 cases have the same effect on performance results:以下4种情况对性能结果有相同的影响:

.NET Framework (x86) .NET 框架 (x86)

  • Platform = x86

  • Platform = AnyCPU , Prefer 32-bit is checked in project settings Platform = AnyCPU ,在项目设置中选中Prefer 32-bit

.NET Framework (x64) .NET 框架 (x64)

  • Platform = x64

  • Platform = AnyCPU , Prefer 32-bit is unchecked in project settings Platform = AnyCPU ,在项目设置中取消选中Prefer 32-bit

.NET Core (x86) .NET 核心 (x86)

  • "C:\\Program Files (x86)\\dotnet\\dotnet.exe" bin\\Release\\netcoreapp2.2\\ConsoleApp.dll

  • "C:\\Program Files (x86)\\dotnet\\dotnet.exe" bin\\x86\\Release\\netcoreapp2.2\\ConsoleApp.dll

.NET Core (x64) .NET 核心 (x64)

  • "C:\\Program Files\\dotnet\\dotnet.exe" bin\\Release\\netcoreapp2.2\\ConsoleApp.dll

  • "C:\\Program Files\\dotnet\\dotnet.exe" bin\\x64\\Release\\netcoreapp2.2\\ConsoleApp.dll

Results结果

The performance tests below produce a uniform distribution of values among the wide range of values an integer could assume.下面的性能测试在整数可以假设的广泛值中产生均匀分布的值。 This means there is a much higher chance of testing values with a big count of digits.这意味着测试具有大量数字的值的可能性要高得多。 In real life scenarios, most values may be small, so the IF-CHAIN should perform even better.在现实生活场景中,大多数值可能很小,因此 IF-CHAIN 应该表现得更好。 Furthermore, the processor will cache and optimize the IF-CHAIN decisions according to your dataset.此外,处理器将根据您的数据集缓存和优化 IF-CHAIN 决策。

As @AlanSingfield pointed out in the comment section, the LOG10 method had to be fixed with a casting to double inside Math.Abs() for the case when the input value is int.MinValue or long.MinValue .如在@AlanSingfield注释部分指出的那样,LOG10方法必须固定有浇铸到doubleMath.Abs()用于当输入值是这样int.MinValuelong.MinValue

Regarding the early performance tests I've implemented before editing this question (it had to be edited a million times already), there was a specific case pointed out by @GyörgyKőszeg , in which the IF-CHAIN method performs slower than the LOG10 method.关于我在编辑这个问题之前实施的早期性能测试(它已经被编辑了一百万次), @GyörgyKőszeg指出了一个具体案例,其中 IF-CHAIN 方法的执行速度比 LOG10 方法慢。

This still happens, although the magnitude of the difference became much lower after the fix for the issue pointed out by @AlanSingfield .这种情况仍然会发生,尽管在解决@AlanSingfield指出的问题后差异的幅度变得小得多 This fix (adding a cast to double ) causes a computation error when the input value is exactly -999999999999999999 : the LOG10 method returns 20 instead of 19 .当输入值正好是-999999999999999999时,此修复(向double添加强制转换)会导致计算错误:LOG10 方法返回20而不是19 The LOG10 method also must have a if guard for the case when the input value is zero.对于输入值为零的情况,LOG10 方法还必须具有if保护。

The LOG10 method is quite tricky to get working for all values, which means you should avoid it. LOG10 方法很难适用于所有值,这意味着您应该避免使用它。 If someone finds a way to make it work correctly for all the consistency tests below, please post a comment!如果有人找到一种方法使其在下面的所有一致性测试中都能正常工作,请发表评论!

The WHILE method also got a recent refactored version which is faster, but it is still slow for Platform = x86 (I could not find the reason why, until now). WHILE 方法也有一个最近的重构版本,它更快,但对于Platform = x86仍然很慢(直到现在我找不到原因)。

The STRING method is consistently slow: it greedily allocates too much memory for nothing. STRING 方法一直很慢:它贪婪地分配了太多的内存。 Interestingly, in .NET Core, string allocation seems to be much faster than in .NET Framework.有趣的是,在 .NET Core 中,字符串分配似乎比在 .NET Framework 中快得多。 Good to know.很高兴知道。

The IF-CHAIN method should outperform all other methods in 99.99% of the cases; IF-CHAIN 方法应该在 99.99% 的情况下优于所有其他方法; and, in my personal opinion, is your best choice (considering all the adjusts necessary to make the LOG10 method work correctly, and the bad performance of the other two methods).并且,在我个人看来,这是您的最佳选择(考虑到使 LOG10 方法正确工作所需的所有调整,以及其他两种方法的不良性能)。

Finally, the results are:最后,结果是:

在此处输入图片说明

Since these results are hardware-dependent, I recommend anyway running the performance tests below on your own computer if you really need to be 100% sure in your specific case.由于这些结果取决于硬件,如果您确实需要在特定情况下 100% 确定,我建议无论如何在您自己的计算机上运行以下性能测试。

Test Code测试代码

Below is the code for the performance test, and the consistency test too.下面是性能测试和一致性测试的代码。 The same code is used for both .NET Framework and .NET Core. .NET Framework 和 .NET Core 使用相同的代码。

using System;
using System.Diagnostics;

namespace NumberOfDigits
{
    // Performance Tests:
    class Program
    {
        private static void Main(string[] args)
        {
            Console.WriteLine("\r\n.NET Core");

            RunTests_Int32();
            RunTests_Int64();
        }

        // Int32 Performance Tests:
        private static void RunTests_Int32()
        {
            Console.WriteLine("\r\nInt32");

            const int size = 100000000;
            int[] samples = new int[size];
            Random random = new Random((int)DateTime.Now.Ticks);
            for (int i = 0; i < size; ++i)
                samples[i] = random.Next(int.MinValue, int.MaxValue);

            Stopwatch sw1 = new Stopwatch();
            sw1.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_IfChain();
            sw1.Stop();
            Console.WriteLine($"IfChain: {sw1.ElapsedMilliseconds} ms");

            Stopwatch sw2 = new Stopwatch();
            sw2.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_Log10();
            sw2.Stop();
            Console.WriteLine($"Log10: {sw2.ElapsedMilliseconds} ms");

            Stopwatch sw3 = new Stopwatch();
            sw3.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_While();
            sw3.Stop();
            Console.WriteLine($"While: {sw3.ElapsedMilliseconds} ms");

            Stopwatch sw4 = new Stopwatch();
            sw4.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_String();
            sw4.Stop();
            Console.WriteLine($"String: {sw4.ElapsedMilliseconds} ms");


            // Start of consistency tests:
            Console.WriteLine("Running consistency tests...");
            bool isConsistent = true;

            // Consistency test on random set:
            for (int i = 0; i < samples.Length; ++i)
            {
                int s = samples[i];
                int a = s.Digits_IfChain();
                int b = s.Digits_Log10();
                int c = s.Digits_While();
                int d = s.Digits_String();
                if (a != b || c != d || a != c)
                {
                    Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
                    isConsistent = false;
                    break;
                }
            }

            // Consistency test of special values:
            samples = new int[]
            {
                0,
                int.MinValue, -1000000000, -999999999, -100000000, -99999999, -10000000, -9999999, -1000000, -999999, -100000, -99999, -10000, -9999, -1000, -999, -100, -99, -10, -9, - 1,
                int.MaxValue, 1000000000, 999999999, 100000000, 99999999, 10000000, 9999999, 1000000, 999999, 100000, 99999, 10000, 9999, 1000, 999, 100, 99, 10, 9,  1,
            };
            for (int i = 0; i < samples.Length; ++i)
            {
                int s = samples[i];
                int a = s.Digits_IfChain();
                int b = s.Digits_Log10();
                int c = s.Digits_While();
                int d = s.Digits_String();
                if (a != b || c != d || a != c)
                {
                    Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
                    isConsistent = false;
                    break;
                }
            }

            // Consistency test result:
            if (isConsistent)
                Console.WriteLine("Consistency tests are OK");
        }

        // Int64 Performance Tests:
        private static void RunTests_Int64()
        {
            Console.WriteLine("\r\nInt64");

            const int size = 100000000;
            long[] samples = new long[size];
            Random random = new Random((int)DateTime.Now.Ticks);
            for (int i = 0; i < size; ++i)
                samples[i] = Math.Sign(random.Next(-1, 1)) * (long)(random.NextDouble() * long.MaxValue);

            Stopwatch sw1 = new Stopwatch();
            sw1.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_IfChain();
            sw1.Stop();
            Console.WriteLine($"IfChain: {sw1.ElapsedMilliseconds} ms");

            Stopwatch sw2 = new Stopwatch();
            sw2.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_Log10();
            sw2.Stop();
            Console.WriteLine($"Log10: {sw2.ElapsedMilliseconds} ms");

            Stopwatch sw3 = new Stopwatch();
            sw3.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_While();
            sw3.Stop();
            Console.WriteLine($"While: {sw3.ElapsedMilliseconds} ms");

            Stopwatch sw4 = new Stopwatch();
            sw4.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_String();
            sw4.Stop();
            Console.WriteLine($"String: {sw4.ElapsedMilliseconds} ms");

            // Start of consistency tests:
            Console.WriteLine("Running consistency tests...");
            bool isConsistent = true;

            // Consistency test on random set:
            for (int i = 0; i < samples.Length; ++i)
            {
                long s = samples[i];
                int a = s.Digits_IfChain();
                int b = s.Digits_Log10();
                int c = s.Digits_While();
                int d = s.Digits_String();
                if (a != b || c != d || a != c)
                {
                    Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
                    isConsistent = false;
                    break;
                }
            }

            // Consistency test of special values:
            samples = new long[] 
            {
                0,
                long.MinValue, -1000000000000000000, -999999999999999999, -100000000000000000, -99999999999999999, -10000000000000000, -9999999999999999, -1000000000000000, -999999999999999, -100000000000000, -99999999999999, -10000000000000, -9999999999999, -1000000000000, -999999999999, -100000000000, -99999999999, -10000000000, -9999999999, -1000000000, -999999999, -100000000, -99999999, -10000000, -9999999, -1000000, -999999, -100000, -99999, -10000, -9999, -1000, -999, -100, -99, -10, -9, - 1,
                long.MaxValue, 1000000000000000000, 999999999999999999, 100000000000000000, 99999999999999999, 10000000000000000, 9999999999999999, 1000000000000000, 999999999999999, 100000000000000, 99999999999999, 10000000000000, 9999999999999, 1000000000000, 999999999999, 100000000000, 99999999999, 10000000000, 9999999999, 1000000000, 999999999, 100000000, 99999999, 10000000, 9999999, 1000000, 999999, 100000, 99999, 10000, 9999, 1000, 999, 100, 99, 10, 9,  1,
            };
            for (int i = 0; i < samples.Length; ++i)
            {
                long s = samples[i];
                int a = s.Digits_IfChain();
                int b = s.Digits_Log10();
                int c = s.Digits_While();
                int d = s.Digits_String();
                if (a != b || c != d || a != c)
                {
                    Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
                    isConsistent = false;
                    break;
                }
            }

            // Consistency test result:
            if (isConsistent)
                Console.WriteLine("Consistency tests are OK");
        }
    }
}

不是直接C#,而是公式: n = floor(log10(x)+1)

Answers already here work for unsigned integers, but I have not found good solutions for getting number of digits from decimals and doubles.这里的答案已经适用于无符号整数,但我还没有找到从小数和双精度数中获取位数的好解决方案。

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

You may change input type from double to decimal if precision matters, but decimal has a limit too.如果精度很重要,您可以将输入类型从double精度更改为decimal ,但十进制也有限制。

The answer of Steve is correct , but it doesn't work for integers less than 1.史蒂夫的答案是正确的,但它不适用于小于 1 的整数。

Here an updated version that does work for negatives:这是一个适用于底片的更新版本:

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

Using recursion (sometimes asked on interviews)使用递归(有时在面试中被问到)

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

    if (number >= 10)
        return CountDigits(number / 10) + 1;
    return 1;
 }
static void Main(string[] args)
{
    long blah = 20948230498204;
    Console.WriteLine(blah.ToString().Length);
}

将一个数字除以 10 会给你最左边的数字,然后在数字上做一个 mod 10 给出没有第一个数字的数字,然后重复这个直到你有所有的数字

Here's an implementation using a binary search.这是使用二进制搜索的实现。 Looks to be the fastest so far on int32.看起来是迄今为止最快的 int32。

Int64 implementation is left as an exercise for the reader(!) Int64 实现留给读者作为练习(!)

I tried using Array.BinarySearch rather than hard-coding the tree, but that was about half the speed.我尝试使用 Array.BinarySearch 而不是对树进行硬编码,但这大约是速度的一半。

EDIT: A lookup table is much faster than the binary search, at the expense of using more memory.编辑:查找表比二分查找快得多,代价是使用更多内存。 Realistically I'd probably use the binary search one in production, the lookup table is a lot of complexity for a speed gain that's likely to be overshadowed by other parts of the software.实际上,我可能会在生产中使用二进制搜索,查找表对于速度增益来说非常复杂,这可能会被软件的其他部分所掩盖。

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

Lookup table version:查找表版本:

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];
}

Binary search version二进制搜索版本

        public static int Digits_BinarySearch(this int n)
        {
            if(n >= 0)
            {
                if(n <= 9999) // 0 .. 9999
                {
                    if(n <= 99) // 0 .. 99
                    {
                        return (n <= 9) ? 1 : 2;
                    }
                    else // 100 .. 9999
                    {
                        return (n <= 999) ? 3 : 4;
                    }
                }
                else // 10000 .. int.MaxValue
                {
                    if(n <= 9_999_999) // 10000 .. 9,999,999
                    {
                        if(n <= 99_999)
                            return 5;
                        else if(n <= 999_999)
                            return 6;
                        else
                            return 7;
                    }
                    else // 10,000,000 .. int.MaxValue
                    {
                        if(n <= 99_999_999)
                            return 8;
                        else if(n <= 999_999_999)
                            return 9;
                        else
                            return 10;
                    }
                }
            }
            else
            {
                if(n >= -9999) // -9999 .. -1
                {
                    if(n >= -99) // -99 .. -1
                    {
                        return (n >= -9) ? 1 : 2;
                    }
                    else // -9999 .. -100
                    {
                        return (n >= -999) ? 3 : 4;
                    }
                }
                else // int.MinValue .. -10000
                {
                    if(n >= -9_999_999) // -9,999,999 .. -10000
                    {
                        if(n >= -99_999)
                            return 5;
                        else if(n >= -999_999)
                            return 6;
                        else
                            return 7;
                    }
                    else // int.MinValue .. -10,000,000 
                    {
                        if(n >= -99_999_999)
                            return 8;
                        else if(n >= -999_999_999)
                            return 9;
                        else
                            return 10;
                    }
                }
            }
        }

        Stopwatch sw0 = new Stopwatch();
        sw0.Start();
        for(int i = 0; i < size; ++i) samples[i].Digits_BinarySearch();
        sw0.Stop();
        Console.WriteLine($"Binary-Search: {sw0.ElapsedMilliseconds} ms");
int i = 855865264;
int NumLen = i.ToString().Length;

Total digits of integer:整数的总位数:

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

Not able to comment, but this is in relation to sɐunıɔןɐqɐp's excellent comment.无法发表评论,但这与 sɐunıɔןɐqɐp 的精彩评论有关。
This function works with doubles.这个 function 与双打一起工作。 I also believe there was an error with the negative comparisons.我也认为负面比较存在错误。

    /// <summary>
    /// counts the digits of the integral part of a number. <br></br>
    ///  4 -> 1; 4.3 -> 1; -4 -> 1; -0.4 -> 0, 1e53 -> 53
    /// </summary>
    /// <param name="n"></param>
    /// <returns>number 1+</returns>
    public static int IntegralDigitLength( double n )
    {
        //this if-chain is allegedly the best way
        //https://stackoverflow.com/questions/4483886/how-can-i-get-a-count-of-the-total-number-of-digits-in-a-number
        if(n< 1 && n > -1 )
        {
            return 0;
        }
        if( n >= 0 )
        {
            if( n < 10L ) return 1;
            if( n < 100L ) return 2;
            if( n < 1000L ) return 3;
            if( n < 10000L ) return 4;
            if( n < 100000L ) return 5;
            if( n < 1000000L ) return 6;
            if( n < 10000000L ) return 7;
            if( n < 100000000L ) return 8;
            if( n < 1000000000L ) return 9;
            if( n < 10000000000L ) return 10;
            if( n < 100000000000L ) return 11;
            if( n < 1000000000000L ) return 12;
            if( n < 10000000000000L ) return 13;
            if( n < 100000000000000L ) return 14;
            if( n < 1000000000000000L ) return 15;
            if( n < 10000000000000000L ) return 16;
            if( n < 100000000000000000L ) return 17;
            if( n < 1000000000000000000L ) return 18;

            n = Math.Floor( n );
            var numOfDigits = 19;
            while( true )
            {

                double comparison = Math.Pow( 10, numOfDigits );
                if( n <= comparison )
                {
                    return numOfDigits;
                }
                numOfDigits++;
            }
        }
        else
        {
            if( n > -10L ) return 1;
            if( n > -100L ) return 2;
            if( n > -1000L ) return 3;
            if( n > -10000L ) return 4;
            if( n > -100000L ) return 5;
            if( n > -1000000L ) return 6;
            if( n > -10000000L ) return 7;
            if( n > -100000000L ) return 8;
            if( n > -1000000000L ) return 9;
            if( n > -10000000000L ) return 10;
            if( n > -100000000000L ) return 11;
            if( n > -1000000000000L ) return 12;
            if( n > -10000000000000L ) return 13;
            if( n > -100000000000000L ) return 14;
            if( n > -1000000000000000L ) return 15;
            if( n > -10000000000000000L ) return 16;
            if( n > -100000000000000000L ) return 17;
            if( n > -1000000000000000000L ) return 18;
            n = Math.Floor( n );
            var numOfDigits = 19;
            while( true )
            {
                if( n <= Math.Pow( -10, numOfDigits ) )
                {
                    return numOfDigits;
                }
                numOfDigits++;
            }
        }
    }

It passes the following unit tests:它通过了以下单元测试:

    [Test]
public void IntegralDigitLength()
{

    Assert.AreEqual( 1, Logic.IntegralDigitLength( 1 ) );
    Assert.AreEqual( 1, Logic.IntegralDigitLength( 2 ) );
    Assert.AreEqual( 1, Logic.IntegralDigitLength( -3 ) );
    Assert.AreEqual( 1, Logic.IntegralDigitLength( -3.4 ) );
    Assert.AreEqual( 1, Logic.IntegralDigitLength( 3.4 ) );
    Assert.AreEqual( 1, Logic.IntegralDigitLength( 9.9 ) );
    Assert.AreEqual( 2, Logic.IntegralDigitLength( 10 ) );
    Assert.AreEqual( 2, Logic.IntegralDigitLength( 19 ) );
    Assert.AreEqual( 2, Logic.IntegralDigitLength( 19.9 ) );
    Assert.AreEqual( 2, Logic.IntegralDigitLength( -19.9 ) );
    Assert.AreEqual( 5, Logic.IntegralDigitLength( 12345 ) );
    Assert.AreEqual( 5, Logic.IntegralDigitLength( 92345 ) );
    Assert.AreEqual( 4, Logic.IntegralDigitLength( 02345 ) );
    Assert.AreEqual( 1, Logic.IntegralDigitLength( 00005 ) );
    Assert.AreEqual( 8, Logic.IntegralDigitLength( 47616294 ) );
    Assert.AreEqual( 8, Logic.IntegralDigitLength( -47616294 ) );
    Assert.AreEqual( 25, Logic.IntegralDigitLength( 1111111111111111111111111f ) );
    Assert.AreEqual( 25, Logic.IntegralDigitLength( 4444444444444444444444444f ) );
    Assert.AreEqual( 25, Logic.IntegralDigitLength( 9999999999999999999999999f ) );
    Assert.AreEqual( 25, Logic.IntegralDigitLength( 1e25 ) );
    Assert.AreEqual( 305, Logic.IntegralDigitLength( 1e305 ) );
    Assert.AreEqual( 0, Logic.IntegralDigitLength( 1e-3 ) );
}

NB: the last one returns zero, I want it to return 0 for values less than one but greater than -1.注意:最后一个返回零,我希望它为小于一但大于 -1 的值返回 0。

It depends what exactly you want to do with the digits.这取决于您究竟想对数字做什么。 You can iterate through the digits starting from the last to the first one like this:您可以像这样遍历从最后一个到第一个的数字:

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

Create a method that returns all digits, and another that counts them:创建一个返回所有数字的方法,以及另一个计算数字的方法:

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);
}

This felt like the more intuitive approach to me when tackling this problem.在解决这个问题时,这对我来说是一种更直观的方法。 I tried the Log10 method first due to its apparent simplicity, but it has an insane amount of corner cases and precision problems.由于其明显的简单性,我首先尝试了Log10方法,但它有大量的极端情况和精度问题。

I also found the if -chain proposed in the other answer to a bit ugly to look at.我还发现在另一个答案中提出的if -chain 有点难看。

I know this is not the most efficient method, but it gives you the other extension to return the digits as well for other uses (you can just mark it private if you don't need to use it outside the class).我知道这不是最有效的方法,但它为您提供了另一个扩展来返回数字以及用于其他用途(如果您不需要在课堂外使用它,您可以将其标记为private )。

Keep in mind that it does not consider the negative sign as a digit.请记住,它不会将负号视为数字。

convert into string and then you can count tatal no of digit by .length method.转换为字符串,然后您可以通过 .length 方法计算数字的总数。 Like:像:

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

如果它只是为了验证你可以这样做: 887979789 > 99999999

假设您的问题指的是 int,以下内容也适用于负/正和零:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用C#获取Excel中图表中系列总数的计数? - How can I get a count of the total number of series in a chart in excel using c#? 如何将小数点后的值四舍五入到一个精度,以使总位数不超过15? - How can I round a Decimal value upto a precision so that the total number of digits doesnot cross 15? 如何获取设备总数和发送到azure IoT hub的消息总数c# - How can I get total number of devices and total number of messages send to azure IoT hub c# 如何获取列表以正确计算 Unity 中的 int 总数 - How to get a list to correctly count the total number of int in Unity 如何在WPF中获取数字以在屏幕上向前计数? - How can I get a number to count forward on the screen in WPF? 我可以获得正则表达式信用卡号的最后 4 位数字吗? - Can I get the last 4 digits of a regex credit card number? 如何在没有循环的情况下计算数字的位数? - How to count digits of number without loop? 我需要通过解析Json后获得的循环来计算值的总数,但无法使其与Console Application一起使用) - I need to count a total number of the values through the loop which I get after parsing Json but can't make it working with Console Application) 如何获得双精度数中包含的位数? - How can you get the number of digits contained in a double? 在C#中,如何仅显示一定数量的数字? - In C#, how can I display only a certain number of digits?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM