当前位置: 首页 > 知识库问答 >
问题:

我能在C#中找到一个大整数的位数吗?

尚声
2023-03-14

我正在解决这个问题,其中他们要求第一个1000位斐波那契数的索引,我的第一个想法类似于:

BigInteger x = 1;
BigInteger y = 1;
BigInteger tmp = 0;

int currentIndex = 2;
while (x.NoOfDigits < 1000)
{
    tmp = x + y;
    y = x;
    x = tmp;
    currentIndex++;
}
return currentIndex;

然而,据我所知,没有计算BigInteger的位数的方法。这是真的吗?绕开它的一种方法是使用。ToString()。一个BigInteger的长度方法,但我听说字符串处理很慢。

大整数也有一个。ToByteArray(),我曾想过将BigInteger转换为字节数组,并检查该数组的长度,但我认为这并不能唯一地确定BigInteger中的位数。

值得一提的是,我实现了另一种解决方法,即手动将斐波那契数存储在数组中,数组满后立即停止,我将其与基于. ToString的方法进行了比较,后者大约慢2.5倍,但第一种方法需要0.1秒,这似乎也需要很长时间。

编辑:我已经测试了下面答案中的两个建议(一个是biginger.Log,另一个是MaxLimitMethod)。我得到以下运行时间:

  • 原始方法:00:00:00.0961957
  • 字符串方法:00:00:00.1535350
  • BigIntgerLogMethod:00:00:00.0387479
  • MaxLimitMethod:00:00:00.0019509

程序

using System;
using System.Collections.Generic;
using System.Numerics;
using System.Diagnostics;

class Program
{
    static void Main(string[] args)
    {
        Stopwatch clock = new Stopwatch();
        clock.Start();
        int index1 = Algorithms.IndexOfNDigits(1000);
        clock.Stop();
        var elapsedTime1 = clock.Elapsed;
        Console.WriteLine(index1);
        Console.WriteLine("Original method: {0}",elapsedTime1);
        Console.ReadKey();

        clock.Reset();
        clock.Start();
        int index2 = Algorithms.StringMethod(1000);
        clock.Stop();
        var elapsedTime2 = clock.Elapsed;
        Console.WriteLine(index2);
        Console.WriteLine("StringMethod: {0}", elapsedTime2);
        Console.ReadKey();

        clock.Reset();
        clock.Start();
        int index3 = Algorithms.BigIntegerLogMethod(1000);
        clock.Stop();
        var elapsedTime3 = clock.Elapsed;
        Console.WriteLine(index3);
        Console.WriteLine("BigIntegerLogMethod: {0}", elapsedTime3);
        Console.ReadKey();

        clock.Reset();
        clock.Start();
        int index4 = Algorithms.MaxLimitMethod(1000);
        clock.Stop();
        var elapsedTime4 = clock.Elapsed;
        Console.WriteLine(index4);
        Console.WriteLine("MaxLimitMethod: {0}", elapsedTime4);
        Console.ReadKey();


    }
}

static class Algorithms
{
    //Find the index of the first Fibonacci number of n digits
    public static int IndexOfNDigits(int n)
    {
        if (n == 1) return 1;
        int[] firstNumber = new int[n];
        int[] secondNumber = new int[n];

        firstNumber[0] = 1;
        secondNumber[0] = 1;
        int currentIndex = 2;

        while (firstNumber[n-1] == 0)
        {
            int carry = 0, singleSum = 0;
            int[] tmp = new int[n]; //Placeholder for the sum
            for (int i = 0; i<n; i++)
            {
                singleSum = firstNumber[i] + secondNumber[i];
                if (singleSum >= 10) carry = 1;
                else carry = 0;

                tmp[i] += singleSum % 10;
                if (tmp[i] >= 10)
                {
                    tmp[i] = 0;
                    carry = 1;
                }
                int countCarries = 0;
                while (carry == 1)
                {
                    countCarries++;
                    if (tmp[i + countCarries] == 9)
                    {
                        tmp[i + countCarries] = 0;
                        tmp[i + countCarries + 1] += 1;
                        carry = 1;
                    }
                    else
                    {
                        tmp[i + countCarries] += 1;
                        carry = 0;
                    }
                }
            }

            for (int i = 0; i < n; i++ )
            {
                secondNumber[i] = firstNumber[i];
                firstNumber[i] = tmp[i];
            }
            currentIndex++;
        }
        return currentIndex;
    }

    public static int StringMethod(int n)
    {
        BigInteger x = 1;
        BigInteger y = 1;
        BigInteger tmp = 0;
        int currentIndex = 2;

        while (x.ToString().Length < n)
        {
            tmp = x + y;
            y = x;
            x = tmp;
            currentIndex++;
        }
        return currentIndex;
    }

    public static int BigIntegerLogMethod(int n)
    {
        BigInteger x = 1;
        BigInteger y = 1;
        BigInteger tmp = 0;
        int currentIndex = 2;

        while (Math.Floor(BigInteger.Log10(x) + 1) < n)
        {
            tmp = x + y;
            y = x;
            x = tmp;
            currentIndex++;
        }
        return currentIndex;
    }

    public static int MaxLimitMethod(int n)
    {
        BigInteger maxLimit = BigInteger.Pow(10, n - 1);
        BigInteger x = 1;
        BigInteger y = 1;
        BigInteger tmp = 0;
        int currentIndex = 2;

        while (x.CompareTo(maxLimit) < 0)
        {
            tmp = x + y;
            y = x;
            x = tmp;
            currentIndex++;
        }
        return currentIndex;
    }
}

共有3个答案

穆宏胜
2023-03-14

更新:

这是一个更快的方法。NET 5(因为需要GetBitLength()):

private static readonly double exponentConvert = Math.Log10(2);
private static readonly BigInteger _ten = 10;

public static int CountDigits(BigInteger value)
{
    if (value.IsZero)
        return 1;

    value = BigInteger.Abs(value);

    if (value.IsOne)
        return 1;

    long numBits = value.GetBitLength();

    int base10Digits = (int)(numBits * exponentConvert).Dump();
    var reference = BigInteger.Pow(_ten, base10Digits);

    if (value >= reference)
        base10Digits++;

    return base10Digits;
}

对于大值,该算法最慢的部分是BigInteger。Pow()操作。我在Singulink中优化了CountDigits()方法。数字。BigIntegerExtensions的缓存容量为10次方,所以如果您对最快的实现感兴趣,请查看。默认情况下,它缓存的指数高达1023,但如果您想在更大的值上用内存使用换取更快的性能,可以通过调用BigIntegerPowCache来增加最大缓存指数。GetCache(10,maxSize)其中maxSize=maxExponent 1

在i7-3770 CPU上,当数字计数时,该库需要350毫秒才能获得1000万BigInteger值(单线程)的数字计数

原始答案:

如评论所示,接受的答案是不可靠的。此方法适用于所有数字:

private static int CountDigits(BigInteger value)
{    
    if (value.IsZero)
        return 1;
        
    value = BigInteger.Abs(value);
    
    if (value.IsOne)
        return 1;
    
    int exp = (int)Math.Ceiling(BigInteger.Log10(value));
    var test = BigInteger.Pow(10, exp);
    
    return value >= test ? exp + 1 : exp;
}
叶鸿煊
2023-03-14

扩展我的评论——不是基于位数的测试,而是基于超过问题上限的常量的测试:

public static int MaxLimitMethod(int n)
    {
        BigInteger maxLimit = BigInteger.Pow(10, n);
        BigInteger x = 1;
        BigInteger y = 1;
        BigInteger tmp = 0;
        int currentIndex = 2;

        while (x.CompareTo(maxLimit) < 0)
        {
            tmp = x + y;
            y = x;
            x = tmp;
            currentIndex++;
        }
        return currentIndex;
    }

这将显著提高性能。

邵骏喆
2023-03-14

如果x

int digits = (int)Math.Floor(BigInteger.Log10(x) + 1);

将获得位数。

出于好奇,我测试了

int digits = x.ToString().Length; 

方法对于100000次迭代,它比Log10解决方案慢3倍。

 类似资料:
  • 问题内容: 我有一个。如果用户第二次输入相同的数字,我想向用户显示。为此,我需要找到它。 我希望我能说清楚。 问题答案: 如果要检查是否在中存储了某些值,则可以使用该方法,如果对象在列表中,则将返回该方法,否则。

  • 本文向大家介绍找出C ++中整数数组中位数的程序,包括了找出C ++中整数数组中位数的程序的使用技巧和注意事项,需要的朋友参考一下 假设我们必须实现一个名为MedianClass的类,其中包含以下方法- add(value) 这会为数据结构添加一个值。 median() 查找数据结构中当前存在的所有数字的中位数。 因此,如果我们加上5、3、8并找到中位数,则输出将为5.0,然后如果我们加上9并找到

  • 问题内容: 最近有人要求我为一份工作编写3个测试程序。它们将仅使用核心Java API和我选择的任何测试框架来编写。应在适当的地方实施单元测试。 尽管我根本没有收到任何反馈,但我想他们不喜欢我的解决方案(否则我会收到他们的来信),所以我决定在这里展示我的程序,并询问这种实现是否可以认为是好的,并且,如果没有,那为什么呢? 为避免混淆,我现在只问第一个。 实现一个函数,以在另一个更大的数组中查找一个

  • 我需要找到所输入的数字的和和乘积。我有求和部分,但它唯一的问题是,当我第一次输入一个数字时,它会给我正确的答案,但当我输入另一个数字时,它只是将第一个数字的和与第二个数字的和相加,然后检查这两个和的和是否是奇数(对不起,如果它的混淆)。对于代码的产品部分,我似乎不知道该怎么做。 最后,如果和和积都是奇数,我需要它来说明输入的数字是一个极奇数。 这个Java应用程序检查区间[101,100001]中

  • 我有一个数组,我需要三个数中最大的一个数和各自的索引值。我有一个这样的数组: 如何找到最大的数字及其索引值?

  • 本文向大家介绍在C ++中找到偶数和奇数位数的数字总和,包括了在C ++中找到偶数和奇数位数的数字总和的使用技巧和注意事项,需要的朋友参考一下 假设我们有一个整数N,我们必须找到奇数位和偶数位的和。因此,如果数字是153654,则odd_sum = 9,even_sum = 15。 为了解决这个问题,我们可以从最后一位提取所有数字,如果原始数字的位数是奇数,则最后一位必须是奇数位,否则将是偶数位。