如何处理大数 - 第 1 部分
对大的正自然数和十进制数进行基本数学运算的简单方法
引言
随着计算能力的提高,大数的定义也发生了变化。 这导致了许多库的创建,这些库提供了处理大于标准数据类型最大值的数字的机制。 但是如果它们不存在呢? 本文尝试创建一个这样的库。
免责声明
提供的代码不是最佳的或可用于专业用途的。 这仅仅是为了展示一种可能的方法和处理大数所需的数学知识。 它只做四个基本的数学运算,并且没有进行负载测试。
背景
每个以 10 为底的数字都可以表示为 10 的幂的多项式。 看一下下面的例子
因此,数字 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:初始版本