65.9K
CodeProject 正在变化。 阅读更多。
Home

如何处理大数 - 第 1 部分

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2016年3月24日

CPOL

3分钟阅读

viewsIcon

17136

downloadIcon

116

对大的正自然数和十进制数进行基本数学运算的简单方法

引言

随着计算能力的提高,大数的定义也发生了变化。 这导致了许多库的创建,这些库提供了处理大于标准数据类型最大值的数字的机制。 但是如果它们不存在呢? 本文尝试创建一个这样的库。

免责声明

提供的代码不是最佳的或可用于专业用途的。 这仅仅是为了展示一种可能的方法和处理大数所需的数学知识。 它只做四个基本的数学运算,并且没有进行负载测试。

背景

每个以 10 为底的数字都可以表示为 10 的幂的多项式。 看一下下面的例子

123.456 = (1 * 102) + (2 * 101) + (3 * 100) + (4 * 10-1) + (5 * 10-2) + (6 * 10-3)

因此,数字 123.456 可以存储在一个数组中,其中索引表示与该数字相关的 10 的幂。 所以,这个数字可以表示为

int[] digitsBeforeSeparator = new int[3]{1,2,3};
int[] digitsAfterSeparator = new int[3]{4,5,6};

对于分隔符后的数字,索引实际上比与数字相关的实际幂大 1(索引 1 处的项表示 10-2)。 这将用于表示代码中的所有数字,并且将对这些数组执行数学运算。

Using the Code

为了简洁起见,我选择不包含代码段。

数字类

此类表示数字。 它支持创建表示正十进制和自然数的对象。 这些数字可以使用返回数字作为 string 的属性来访问。 只有一个可访问的构造函数接受 string 输入。 方法 ValidateInput 使用 Regex 确保输入有效。 PrepareArrays 方法将如上所示从数字创建数组。 到目前为止,仅支持句点 (.) 作为小数字符。 下面展示了如何将一个数字分解成数组

private void PrepareArrays()
        {
            int decimalLocation = -1;
            int numberLength = _value.Length;
            _isDecimal = (decimalLocation = _value.IndexOf('.')) != -1;

            if (_isDecimal)
            {
                _digitsBeforeDecimal = new int[decimalLocation];
                _digitsAfterDecimal = new int[numberLength - decimalLocation - 1];
            }
            else
            {
                _digitsBeforeDecimal = new int[numberLength];
                _digitsAfterDecimal = null;
            }

            for (int index = 0; index < _value.Length; index++)
            {
                if (index == decimalLocation)
                {
                    // Decimal separator
                    continue;
                }
                else if (_isDecimal && index > decimalLocation)
                {
                    _digitsAfterDecimal[index - decimalLocation - 1] = 
                       (int)Char.GetNumericValue(_value[index]);
                }
                else
                {
                    _digitsBeforeDecimal[index] = (int)Char.GetNumericValue(_value[index]);
                }
            }
        }

加法

这是最简单的数学运算。 相应数组中的每个元素将被加起来并存储在单独的数组中作为结果。 进位(如果存在)将被保留并添加到下一个元素集。

Number 类提供 static 方法 Add,允许添加两个数字。 它还重载了 operator +,因此可以像整数一样添加数字对象。 总和中的位数只能比两个数字中较大的一个多一位(假设显示小数点后的尾随零)。

public static Number Add(Number firstNumber, Number secondNumber)
public static Number operator +(Number firstNumber, Number secondNumber)

用法

Number first = new Number("12.34");
Number second = new Number("09.56");

 Number sum = first + second;
 // or
 sum = Number.Add(first, second);

减法

此操作的工作方式与加法相同。 数组中的每个元素将减去第二个数字中相应数组的元素。 此操作可以返回负数。

Number 类提供 static 方法 Subtract,允许减去两个数字。 它还重载了 operator -,因此可以像标准数据类型一样减去数字对象。

结果数字中的位数可以是两个数字之间的任何值。 在代码中,最初假设结果具有与较大数字相同的位数,然后从结果数组中删除不必要的元素。

public static Number Add(Number firstNumber, Number secondNumber)
public static Number operator -(Number firstNumber, Number secondNumber)

用法

Number first = new Number("12.34"); 
Number second = new Number("09.56"); 
Number difference = first - second; 
// or 
difference = Number.Subtract(first, second);

乘法

乘大数使用的思想与乘多项式类似。 这里的棘手之处在于预先确定结果中的位数。 让我们看看如何乘多项式

在这里,您可以看到小数点前可能的最大位数只能是较大数字的两倍。 同样适用于小数点后可能的最大位数。 在我们的例子中,小数点前我们可以有 4 位数字(来自 12.34),小数点后我们也只能有 4 位数字(来自两个数字)。

一旦数字相乘,我们需要确定它们出现在结果中的位置。 以下显示了用于获取此详细信息的机制

与其他操作类似,我们有如下方法和运算符

public static Number Multiply(Number firstNumber, Number secondNumber) 
public static Number operator *(Number firstNumber, Number secondNumber)

用法

Number first = new Number("12.34"); 
Number second = new Number("09.56"); 
Number product = first * second; 
// or 
product = Number.Multiply(first, second);

那除法呢?

除法需要实现一些复杂的算法。 我认为,它值得一篇专门的文章,即将推出。

历史

  • V 0.0:初始版本
© . All rights reserved.