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

非常大整数的加法、乘法

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.50/5 (6投票s)

2010 年 9 月 3 日

CPOL

5分钟阅读

viewsIcon

59079

downloadIcon

942

使用 C# 实现非常大整数的加法、乘法

引言

我很久没写文章了。在我阅读一个 C++ 程序时,我遇到了一个展示非常大整数用法的程序。它非常好,给我留下了深刻的印象,让我用 C# 重新实现它。

概述

本文的目的是构建一个类,该类允许任何 C# 程序员使用非常大整数相关的加法和乘法等功能。我通过运算符重载来实现它。在阅读 C++ 程序并分析其来用 C# 编写时,我得出的结论是,使用运算符重载可以使性能更便捷,并且在某些情况下代码和功能更容易理解。

什么是运算符重载?(来自维基百科的定义)

在计算机编程中,运算符重载(有时也称为运算符特设多态)是多态性的一种特殊情况,其中某些或所有运算符,如 +、= 或 ==,根据其参数的类型具有不同的实现。有时重载由语言定义;有时程序员可以为新类型实现支持。运算符重载被认为是有用的,因为它允许开发人员使用“更接近目标域”的语法进行编程,并为用户定义类型提供与语言内置类型相似的语法支持。它可以通过函数调用轻松模拟;例如,考虑整数 a、b、c

a + b * c

在支持运算符重载的语言中,并且假设“*”运算符的优先级高于“+”,这实际上是编写以下内容的更简洁的方式

add (a, multiply (b,c))

C# 中的运算符重载是什么?

所有一元和二元运算符都有预定义的实现,这些实现在任何表达式中都可用。除了这些预定义的实现外,还可以在 C# 中引入用户定义的实现。为用户定义的数据类型(如类或结构)赋予标准 C# 运算符特殊含义的机制称为运算符重载。请记住,并非所有运算符都可以重载。下表显示了 C# 中的运算符及其重载能力。

运算符重载能力

  • +, -, *, /, %, &, |, <<, >> 所有 C# 二元运算符都可以重载。
  • +, -, !, ~, ++, –, true, false 所有 C# 一元运算符都可以重载。
  • ==, !=, <, >, <= , >= 所有关系运算符都可以重载,但只能成对重载。
  • &&, || 它们不能重载。
  • () (转换运算符) 它们不能重载。
  • +=, -=, *=, /=, %= 这些复合赋值运算符可以重载。但在 C# 中,当相应的二元运算符被重载时,这些运算符会自动重载。
  • =, . , ?:, ->, new, is, as, size of 这些运算符不能重载。

在 C# 中,使用一个名为运算符函数的特殊函数来进行重载。这些特殊函数或方法必须是publicstatic。它们只能接受值参数。refout参数不允许作为运算符函数的参数。运算符函数的一般形式如下

public static return_type operator op (argument list)

其中op是要重载的运算符,operator是必需的关键字。重载一元运算符时,只有一个参数;重载二元运算符时,有两个参数。请记住,至少有一个参数必须是用户定义类型,例如classstruct类型。

重载一元运算符 - 一元运算符的运算符函数的一般形式如下

public static return_type operator op (Type t){// Statements}

其中Type必须是classstruct。对于 +,~, ! 和 . (.) 运算符,返回类型可以是除void以外的任何类型。但是,对于 ++ 和 -- 运算符,返回类型必须是“Type”类型。请记住,true 和 false 运算符只能成对重载。如果一个类声明了其中一个运算符而没有声明另一个,则会发生编译错误。

为什么需要运算符重载?

运算符重载允许我们将不同的变量类型传递给同一个函数并产生不同的结果。在本文中,我详细介绍了 C# 中的运算符重载。运算符重载在许多高效的 C# 程序员中很常见。它允许您使用相同的函数名,但具有不同的功能。

在本文中,我准确地展示了运算符重载是什么,以及如何在 C# 中使用它。

幕后

1. 加法

首先,非常大的数字以string形式输入。然后,将string中的每个字符转换为整数。在执行操作之前,将string反转。

+()运算符方法将两个非常大的对象相加,并将结果保存在第三个非常大的对象中。它通过逐位考虑数字来完成此操作。它相加两个数字的各位,必要时存储进位。然后,它相加第一位的数字,必要时加上进位。它一直进行到加完两个数字中较大者中的所有数字。如果数字长度不同,则在短数字中不存在的数字被设置为 0,然后再进行相加。

加法的示意图表示

VeryLongInteger2/pic1.jpg

加法代码

// Adds two very long numbers.
public static VeryLongInteger operator +(VeryLongInteger veryLongInteger1, 
	VeryLongInteger veryLongInteger2)
    {
        char[] outputChars = new char[MAXLENGTH];
        string veryLongString1 = Reverse(veryLongInteger1.ToString());
        string veryLongString2 = Reverse(veryLongInteger2.ToString());
        int length1 = veryLongString1.Length;
        int length2 = veryLongString2.Length;
        int maxLength = length1 > length2 ? length1 : length2;
        int carry = 0;
        int j = 0;
        for (j = 0; j < maxLength; j++)
        {
            int digit1 = (j > length1 - 1) ? 0 : 
		Convert.ToInt32(veryLongString1[j].ToString());
            int digit2 = (j > length2 - 1) ? 0 : 
		Convert.ToInt32(veryLongString2[j].ToString());
            int digitsum = digit1 + digit2 + carry;
            if (digitsum >= 10)
            {
                digitsum -= 10;
                carry = 1;
            }
            else
                carry = 0;
            outputChars[j] = Convert.ToChar(Convert.ToString(digitsum));
        }
        if (carry == 1)
            outputChars[j++] = '1';
        return new VeryLongInteger(Reverse(new string(outputChars)));
    }

2. 乘法

这里的逻辑也一样。乘法使用*()运算符方法。该方法通过将乘数与乘数中的每个单独数字相乘来执行乘法。它为此调用MultiplyDigit()方法。然后,使用Mulitply10()方法将结果乘以10的适当次数,以使结果与数字的位置匹配。然后使用+()运算符方法将这些单独计算的结果相加。

乘法代码

// Multiplies two very long numbers.
public static VeryLongInteger operator *(VeryLongInteger veryLongInteger1, 
	VeryLongInteger veryLongInteger2)
    {
        char[] outputChars = new char[MAXLENGTH];
        string veryLongString = Reverse(veryLongInteger2.ToString());
        VeryLongInteger powerproduct = null;
        VeryLongInteger outputVeryLongInteger = new VeryLongInteger("0");
        int j = 0;
        for (j = 0; j < veryLongString.Length; j++)
        {
            int digit = Convert.ToInt32(veryLongString[j].ToString());
            powerproduct = MultiplyDigit(veryLongInteger1, digit);
            for (int k = 0; k < j; k++)
            {
                powerproduct = Multiply10(powerproduct);
            }
            outputVeryLongInteger = outputVeryLongInteger + powerproduct;
        }
        return outputVeryLongInteger;
    }

3. 阶乘

在这里,我们通过递归调用乘法来实现阶乘。我们可以找到高达 250 的数字的阶乘(!太棒了)。

阶乘代码

VeryLongInteger v1 = new VeryLongInteger("1");
int num = 100;
for (int i = num; i > 0; i--)
{
    VeryLongInteger v2 = new VeryLongInteger(i.ToString());
    v1 = v1 * v2;
}

示例输出

VeryLongInteger2/screenshot2.jpg

关注点

是的,当然 .NET 4.0 有一个BigInteger类,它效率更高。但是,我认为这个VeryLongInteger类可以用于之前的版本。当然,我们可以理解这些类型功能的内部工作原理。

结论

感谢您阅读本文。我期待您的反馈。您将从我这里期待更多。

© . All rights reserved.