【问题标题】:How to compare large string integer values如何比较大字符串整数值
【发布时间】:2015-09-06 14:13:30
【问题描述】:

目前我正在开发一个处理超大 integernumbers 的程序。

为了防止碰到intiger.maxvalue,脚本将字符串处理为数字,并将它们拆分为List<int>,如下所示

0 是当前已知的最高值

  • 列表条目 0:123(1.23 亿)
  • 列表条目 1:321(三十二万一千)
  • 列表条目 2:777(七百七十七)

现在我的问题是:如何检查传入的字符串值是否可以从这些值中减去?

我目前做的减法开始如下,但我卡在减法部分。

public bool Subtract(string value)
{
    string cleanedNumeric = NumericAndSpaces(value);
    List<string> input = new List<string>(cleanedNumeric.Split(' '));

    // In case 1) the amount is bigger 2) biggest value exceeded by a 10 fold 
    // 3)  biggest value exceeds the value
    if (input.Count > values.Count ||
        input[input.Count - 1].Length > values[0].ToString().Length ||
        FastParseInt(input[input.Count -1]) > values[0])
        return false;

    // Flip the array for ease of comparison
    input.Reverse();

    return true;
}

编辑 该程序中可实现的最高数字的当前目标是 Googolplex 并且仅限于 .net3.5 MONO

【问题讨论】:

  • 我不确定你想达到什么目标,但你是否已经考虑过使用System.Numerics.BigInteger
  • 为什么不用long,应该够大了吧?
  • @elgonzo 是的,但如果我相信的话,我相信这也是一个限制值,最高可达 2^(2^33)。
  • @MXD,没有。它没有上限和下限 - 限制只是由可用内存给出。阅读documentation。尤其是备注部分...(阅读备注部分应该始终是验证自己假设的第一步;-))
  • @MXD 据我所知,除了内存没有限制……它的描述是表示一个任意大的有符号整数。

标签: c# string int


【解决方案1】:

您应该对此进行一些测试,因为我没有进行过广泛的测试,但它已经在我已经完成的案例中发挥了作用。此外,可能值得确保字符串中的每个字符都是真正有效的整数,因为此过程会在给定非整数字符的情况下爆炸。最后,它期望减数和被减数都为正数。

    static void Main(string[] args)
    {
        // In subtraction, a subtrahend is subtracted from a minuend to find a difference.
        string minuend = "900000";
        string subtrahend = "900001";

        var isSubtractable = IsSubtractable(subtrahend, minuend);
    }

    public static bool IsSubtractable(string subtrahend, string minuend)
    {
        minuend = minuend.Trim();
        subtrahend = subtrahend.Trim();

        // maybe loop through characters and ensure all are valid integers

        // check if the original number is longer - clearly subtractable
        if (minuend.Length > subtrahend.Length) return true;
        // check if original number is shorter - not subtractable
        if (minuend.Length < subtrahend.Length) return false;

        // at this point we know the strings are the same length, so we'll
        // loop through the characters, one by one, from the start, to determine
        // if the minued has a higher value character in a column of the number.
        int numberIndex = 0;

        while (numberIndex < minuend.Length )
        {
            Int16 minuendCharValue = Convert.ToInt16(minuend[numberIndex]);
            Int16 subtrahendCharValue = Convert.ToInt16(subtrahend[numberIndex]);

            if (minuendCharValue > subtrahendCharValue) return true;
            if (minuendCharValue < subtrahendCharValue) return false;

            numberIndex++;
        }

        // number are the same
        return true;
    }

【讨论】:

  • 已经在检查一个有效的整数,但感谢您的注意;)。但是考虑到上述情况,我们会遇到极其庞大的数字。 Convert.ToInt16 不会越界吗?因此,我拆分数字并将它们以 3 为单位存储在列表中的原因。
  • @MXD 实际上,在我们确定数字的长度相同之后,我们会一个一个地循环遍历每个字符,检查在某一列中被减数是否比被减数高。例如,在minued = 50030000subtrahend = 50020000 中,一旦我们检查了第 4 个数字列,我们就会发现被减去的值更大,因此两者是“可减的”。所以我们永远不会在Int16 中存储大于 9 的数字。
  • @MXD 运气好吗?
  • 是的,我肯定有。到目前为止,它进展顺利,每隔一段时间它就会返回,因为它可以减去而不能减去,一旦我弄清楚这是从哪里来的,我愿意接受这个答案;)
  • @MXD 如果你给我一个失败的例子,我可以调整程序
【解决方案2】:

[BigInteger](https://msdn.microsoft.com/en-us/library/system.numerics.biginteger.aspx) 是任意大小。

如果您不相信我,请运行此代码

        var foo = new BigInteger(2);


        while (true)
        {
            foo = foo * foo;
        }

事情变得疯狂。我的调试器(VS2013)在完成之前无法表示数字。运行了很短的时间,从 ToString 得到一个以 10 为底的 120 万位数字。它足够大。对象有 2GB 的限制,可以在 .NET 4.5 中通过设置 gcAllowVeryLargeObjects 覆盖该限制

如果您使用的是 .NET 3.5,现在该怎么办?您基本上需要重新实现 BigInteger(显然只取您需要的,里面有很多)。

public class MyBigInteger
{
     uint[] _bits; // you need somewhere to store the value to an arbitrary length.

....

您还需要对这些数组进行数学运算。这是 BigInteger 的 Equals 方法:

 public bool Equals(BigInteger other)
    {
        AssertValid();
        other.AssertValid();

        if (_sign != other._sign)
            return false;
        if (_bits == other._bits) 
            // _sign == other._sign && _bits == null && other._bits == null
            return true;

        if (_bits == null || other._bits == null)
            return false;
        int cu = Length(_bits);
        if (cu != Length(other._bits))
            return false;
        int cuDiff = GetDiffLength(_bits, other._bits, cu);
        return cuDiff == 0;
    }

它基本上对字节数组进行廉价的长度和符号比较,然后,如果这不会产生差异,则交给 GetDiffLength。

    internal static int GetDiffLength(uint[] rgu1, uint[] rgu2, int cu)
    {
        for (int iv = cu; --iv >= 0; )
        {
            if (rgu1[iv] != rgu2[iv])
                return iv + 1;
        }
        return 0;
    }

在寻找差异的数组中循环进行昂贵的检查。

你所有的数学都必须遵循这个模式,并且很大程度上可以从 .Net source code 中删除。

Googleplex 和 2GB:

这里 2GB 的限制成为一个问题,因为您需要 3.867×10^90 gigabyte 的对象大小。这是您放弃或变得聪明并将对象存储为权力的地方,但代价是无法代表其中的很多。 *2

如果您调整您的期望,它实际上并不会改变 BigInteger 的数学运算来将 _bits 拆分为多个锯齿状数组 *1。你稍微改变一下廉价支票。不是检查数组的大小,而是检查子数组的数量,然后检查最后一个的大小。然后循环需要更复杂一些(但不多),因为它对每个子数组进行元素数组比较。还有其他一些变化,但这绝不是不可能的,并且可以让您摆脱 2GB 的限制。

*1 注意使用交错数组[][],而不是多维数组[,],仍然受到同样的限制。

*2 即放弃精度并存储尾数和指数。如果你看看浮点数是如何实现的,它们不能代表它们的最大值和最小值之间的所有数字(因为一个范围内的实数比无限大)。他们在精度和范围之间做出了复杂的权衡。如果您想这样做,查看浮点实现将比使用 Biginteger 等整数表示更有用。

【讨论】:

  • 我一定要试试这个,谢谢分配;)
猜你喜欢
  • 1970-01-01
  • 2013-09-03
  • 2015-10-27
  • 1970-01-01
  • 1970-01-01
  • 2011-06-21
  • 2012-02-09
  • 2013-05-30
  • 1970-01-01
相关资源
最近更新 更多