简体   繁体   English

如何比较大字符串整数值

[英]How to compare large string integer values

Currently I am working on a program that processes extremely large integer numbers . 目前,我正在开发一个处理极大integer的程序。

To prevent hitting the intiger.maxvalue a script that processes strings as numbers, and splits them up into a List<int> as following 为了防止触及intiger.maxvalue以下脚本,该脚本将字符串处理为数字,然后将其拆分为List<int> ,如下所示

0 is the highest currently known value 0是当前已知的最高值

  • list entry 0: 123 (hundred twenty three million) 列表条目0:123(一亿二千三百万)
  • list entry 1: 321 (three hundred twenty one thousand) 列表条目1:321(三十二万一千)
  • list entry 2: 777 (seven hundred seventy seven) 清单2:777(七百七十七)

Now my question is: How would one check if the incoming string value is sub tractable from these values? 现在我的问题是:如何检查传入的字符串值是否可以从这些值中减去?

The start for subtraction I currently made is as following, but I am getting stuck on the subtracting part. 我目前进行的减法开始如下,但是我陷入了减法部分。

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

EDIT Current target for the highest achievable number in this program is a Googolplex And are limited to .net3.5 MONO 编辑此程序中可实现的最高数字的当前目标是Googolplex,并且仅限于.net3.5 MONO

You should do some testing on this because I haven't run extensive tests but it has worked on the cases I've put it through. 您应该对此进行一些测试,因为我还没有进行广泛的测试,但是它可以解决我遇到的问题。 Also, it might be worth ensuring that each character in the string is truly a valid integer as this procedure would bomb given a non-integer character. 同样,可能值得确保字符串中的每个字符都是真正的有效整数,因为此过程将给定非整数字符而引起轰炸。 Finally, it expects positive numbers for both subtrahend and minuend. 最后,它期望次交易和次交易都为正数。

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

[BigInteger] ( https://msdn.microsoft.com/en-us/library/system.numerics.biginteger.aspx ) is of aribtary size. [BigInteger]https://msdn.microsoft.com/zh-cn/library/system.numerics.biginteger.aspx )大小。

Run this code if you don't believe me 如果您不相信我,请运行此代码

        var foo = new BigInteger(2);


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

Things get crazy. 事情变得疯狂。 My debugger (VS2013) becomes unable to represent the number before it's done. 我的调试器(VS2013)在完成之前无法表示该数字。 ran it for a short time and got a number with 1.2 million digits in base 10 from ToString. 运行了很短的时间,并从ToString得到一个以120为基数的数字。 It is big enough. 它足够大。 There is a 2GB limit on object, which can be overriden in .NET 4.5 with the setting gcAllowVeryLargeObjects 对象上有2GB的限制,可以在.NET 4.5中使用设置gcAllowVeryLargeObjects覆盖它

Now what to do if you are using .NET 3.5? 现在,如果您使用的是.NET 3.5,该怎么办? You basically need to reimplement BigInteger (obviously only taking what you need, there is a lot in there). 基本上,您需要重新实现BigInteger(很明显,仅接受您需要的东西,那里有很多东西)。

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

.... ....

You also need to perform maths on these arrays. 您还需要在这些数组上执行数学运算。 here is the Equals method from BigInteger: 这是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;
    }

It basically does cheap length and sign comparisons of the byte arrays, then, if that doesn't produce a difference hands off to GetDiffLength. 它基本上可以进行字节数组的长度和符号比较便宜,然后,如果这样不会产生差异,请移交给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;
    }

Which does the expensive check of looping through the arrays looking for a difference. 进行循环遍历数组以寻找差异的昂贵检查。

All you math will have to follow this pattern and can largely be ripped of from the .Net source code . 您所有的数学运算都必须遵循这种模式,并且可以从.Net源代码中大致删除。

Googleplex and 2GB: Googleplex和2GB:

Here the 2GB limit becomes a problem, because you will be needing an object size of 3.867×10^90 gigabyte . 在这里2GB的限制成为一个问题,因为您将需要3.867×10 ^ 90 GB的对象大小。 This the the point where you give up, or get clever and store objects as powers at the cost of not being able to represent a lot of them. 在这一点上,您放弃或变得聪明,并以无法代表很多物体为代价而将物体存储为力量。 *2 * 2

if you moderate your expectations, it doesn't actually change the maths of BigInteger to split _bits into multiple jagged arrays *1. 如果您期望适中,则实际上不会改变BigInteger的数学将_bits拆分为多个锯齿状数组* 1。 You change the cheap checks a bit. 您可以稍微更改廉价支票。 Rather than checking the size of the array, you check the number of subarrays and then the size of the last one. 而不是检查数组的大小,而是检查子数组的数量,然后检查最后一个的大小。 Then the loop needs to be a bit more (but not much) more complex in that it does elementwise array comparison for each sub array. 然后,循环需要稍微复杂一些(但不要太多),因为它会对每个子数组进行逐元素数组比较。 There are other changes as well, but it's by no means impossible and gets you out of the 2GB limit. 还有其他更改,但这绝不是不可能的,它使您脱离了2GB的限制。

*1 Note use jagged arrays[][], not multidimensional arrays [,] which are still subject to the same limit. * 1请注意,使用锯齿状数组[] [],而不要使用多维数组[,],它们仍然受到相同的限制。

*2 Ie give up on precision and store the mantissa and exponent. * 2即放弃精度并存储尾数和指数。 If you look how floating point numbers are implemented they can't represent all numbers between their max and min (as the number of real numbers in a range is 'bigger' than infinite). 如果您看一下浮点数是如何实现的,它们就不能代表其最大值和最小值之间的所有数字(因为范围内的实数比无限大)。 They make a complex trade off between precision and range. 它们在精度和范围之间进行了复杂的权衡。 If you are wanting to do this, looking at float implementations will be a lot more useful than taking about integer representations like Biginteger. 如果您想这样做,那么与考虑像Biginteger这样的整数表示形式相比,查看float实现会有用得多。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM