如何从十进制到整个字节数组携带数字

ABP*_*son 7 c# math binary

注意:这比特定的C#问题更像是逻辑/数学问题.

我有自己的类调用Number- 它只包含两个单独的字节数组,称为WholeDecimal.这些字节数组每个都代表一个无限大的整数,但是,当它们放在一起时,它的想法是它们创建一个带小数部分的整数.

字节以小端格式存储,表示数字.我正在创建一个方法AddNumbers,它将把这些中Number的两个加在一起.

此方法依赖于另一个调用的方法PerformAdd,它只将两个数组相加.它只需要一个指向最终字节数组的指针,一个指向要添加的数组的指针,以及一个指向要添加的第二个数组的指针 - 以及每个数组的长度.这两个数组只是命名为"更大"和"更小".以下是此方法的代码:

    private static unsafe void PerformAdd(byte* finalPointer, byte* largerPointer, byte* smallerPointer, int largerLength, int smallerLength)
    {
        int carry = 0;

        // Go through all the items that can be added, and work them out.
        for (int i = 0; i < smallerLength; i++)
        {
            var add = *largerPointer-- + *smallerPointer-- + carry;

            // Stick the result of this addition in the "final" array.
            *finalPointer-- = (byte)(add & 0xFF);

            // Now, set a carry from this.
            carry = add >> 8;
        }

        // Now, go through all the remaining items (which don't need to be added), and add them to the "final" - still working with the carry.
        for (int i = smallerLength; i < largerLength; i++)
        {
            var wcarry = *largerPointer-- + carry;

            // Stick the result of this addition in the "final" array.
            *finalPointer-- = (byte)(wcarry & 0xFF);

            // Now, set a carry from this.
            carry = wcarry >> 8;
        }

        // Now, if we have anything still left to carry, carry it into a new byte.
        if (carry > 0)
            *finalPointer-- = (byte)carry;
    }
Run Code Online (Sandbox Code Playgroud)

这个方法不是问题所在 - 问题在于我如何使用它.这AddNumbers是使用它的方法.它的工作方式很好 - 它将两个独立的字节数组织成"更大"(更大的含义,具有更高的字节长度)和"更小".然后,它会创建的指针,它这两个WholeDecimal分开.问题在于小数部分.

假设我们将数字12512185在一起,在这种情况下你会得到3436- 这样就完美了!

再举一个例子:你有数字4.6并添加1.2- 再次,这工作正常,你得到5.8.问题出在下一个例子中.

然而,我们有,15.673并且1.783,你会想到17.456,实际上,这会返回:16.1456,原因是因为它没有带"1".

所以,这是我的问题:我如何实现一种知道何时以及如何做到这一点的方法?这是我的AddNumbers方法的代码:

    public static unsafe Number AddNumbers(Number num1, Number num2)
    {
        // Store the final result.
        Number final = new Number(new byte[num1.Whole.Length + num2.Whole.Length], new byte[num1.Decimal.Length + num2.Decimal.Length]);

        // We're going to figure out which number (num1 or num2) has more bytes, and then we'll create pointers to smallest and largest.
        fixed (byte* num1FixedWholePointer = num1.Whole, num1FixedDecPointer = num1.Decimal, num2FixedWholePointer = num2.Whole, num2FixedDecPointer = num2.Decimal,
            finalFixedWholePointer = final.Whole, finalFixedDecimalPointer = final.Decimal)
        {
            // Create a pointer and figure out which whole number has the most bytes.
            var finalWholePointer = finalFixedWholePointer + (final.Whole.Length - 1);
            var num1WholeLarger = num1.Whole.Length > num2.Whole.Length ? true : false;

            // Store the larger/smaller whole number lengths.
            var largerLength = num1WholeLarger ? num1.Whole.Length : num2.Whole.Length;
            var smallerLength = num1WholeLarger ? num2.Whole.Length : num1.Whole.Length;

            // Create pointers to the whole numbers (the largest amount of bytes and smallest amount of bytes).
            var largerWholePointer = num1WholeLarger ? num1FixedWholePointer + (num1.Whole.Length - 1) : num2FixedWholePointer + (num2.Whole.Length - 1);
            var smallerWholePointer = num1WholeLarger ? num2FixedWholePointer + (num2.Whole.Length - 1) : num1FixedWholePointer + (num1.Whole.Length - 1);

            // Handle decimal numbers.
            if (num1.Decimal.Length > 0 || num2.Decimal.Length > 0)
            {
                // Create a pointer and figure out which decimal has the most bytes.
                var finalDecPointer = finalFixedDecimalPointer + (final.Decimal.Length - 1);
                var num1DecLarger = num1.Decimal.Length > num2.Decimal.Length ? true : false;

                // Store the larger/smaller whole number lengths.
                var largerDecLength = num1DecLarger ? num1.Decimal.Length : num2.Decimal.Length;
                var smallerDecLength = num1DecLarger ? num2.Whole.Length : num1.Decimal.Length;

                // Store pointers for decimals as well.
                var largerDecPointer = num1DecLarger ? num1FixedDecPointer + (num1.Decimal.Length - 1) : num2FixedDecPointer + (num2.Decimal.Length - 1);
                var smallerDecPointer = num1DecLarger ? num2FixedDecPointer + (num2.Decimal.Length - 1) : num1FixedDecPointer + (num1.Decimal.Length - 1);

                // Add the decimals first.
                PerformAdd(finalDecPointer, largerDecPointer, smallerDecPointer, largerDecLength, smallerDecLength);
            }

            // Add the whole number now.
            PerformAdd(finalWholePointer, largerWholePointer, smallerWholePointer, largerLength, smallerLength);
        }

        return final;
    }
Run Code Online (Sandbox Code Playgroud)

aio*_*sov 2

如果您只需要BigDecimalC#,我建议您找到并使用现有的实现。例如https://gist.github.com/nberardi/2667136(我不是作者,但看起来不错)。

如果您出于任何原因(学校等)必须实施它,那么我只会诉诸于使用BigInteger.

如果您必须使用字节数组来实现它......您仍然可以从使用比例的想法中受益。显然,您必须在执行“PerformAdd”等操作后取出任何额外的数字,然后将它们转入主号码。

然而问题还不止于此。当您开始实现乘法时,您将遇到更多问题,并且您将不得不开始不可避免地混合小数和整数部分。

8.73*0.11 -> 0.9603 0.12*0.026 -> 0.00312

正如您所看到的,整数和小数部分混合在一起,然后小数部分增长为更长的序列

但是,如果您将它们表示为:

873|2 * 11|2 -> 873*11|4 -> 9603|4 -> 0.9603 12|2 & 26|3 -> 12*26|5 -> 312|5 -> 0.00312

这些问题就会消失。