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

多语言复数库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (38投票s)

2015年3月5日

CPOL

19分钟阅读

viewsIcon

93603

downloadIcon

1418

本文对复数进行了基本概述,并介绍了如何创建复数及其函数,特别是算术函数的运算符重载。目前涉及的编程语言包括 Java、C++、C# 和 VB.NET。

目录

本文包含以下章节及其子章节列表。

  1. 引言
  2. 现实中的复数
  3. 复数的编程实现
    1. 创建类
    2. 复数的成员
  4. 复数的函数
    1. 从笛卡尔坐标形式转换为极坐标形式的复数
    2. 将极坐标形式转换为笛卡尔坐标形式的复数
    3. 获取复数的对数值
    4. 复数的共轭
      1. 笛卡尔坐标形式的共轭
      2. 极坐标形式的共轭
    5. 复数的倒数
    6. 基于对象的函数
  5. 算术运算
    1. 二元运算符
      1. 笛卡尔坐标形式复数的运算
        1. 加法
        2. 减法
      2. 极坐标和笛卡尔坐标形式复数的运算
        1. 乘法
          1. 笛卡尔坐标形式的复数
          2. 极坐标形式的复数
        2. 除法
          1. 笛卡尔坐标形式的复数
          2. 极坐标形式的复数
        3. 相等性检查
    2. 一元运算符
      1. 取反
  6. 关注点
  7. 历史

引言

本文是关于如何编程一个使用复数及其属性的应用程序。本文将概述复数,以及如何在多种不同的编程语言(从 C++、C#、Java 到 VB.NET)中创建一个可以处理复数的对象。

本文还将分享复数上执行的函数、它们的底层过程等。本文将概述复数的所有函数、它们从一种形式到另一种形式的转换等等。本文还会略微涉及数学中用于复数的运算符,例如 +、- 等。

在某些语言中,提供了重载运算符的功能,但在某些语言(如 Java)中,则不提供此功能,我们必须创建一个函数来执行这些任务,例如 C++ 或 C# 中的 a + b 在 Java 中可以写成 a.add(b)。随着我们阅读本文,我们将了解如何做到这些。

如果您阅读本文只是为了学习如何在一种语言中实现这些,那么您无需阅读其他语言的代码。只需阅读特定于您的框架(或语言)的代码即可。

现实中的复数

复数是包含虚数部分的数。例如,可以表示为 x + iy 形式的数,其中 i 是一个虚数单位。这些数被称为复数。在这个等式中,x 和 y 都是实数,只有 i 是虚数单位。

虚数单位在某种意义上并不存在,例如 √(-1),一个负数的平方根没有这样的可能答案。

所以,根据定义,“i”(发音为 iota)是一个虚数单位,它的值是负一的平方根。这里也需要提到,一个没有实数部分(例如 x 和/或 y 的值为零)的复数被称为纯虚数,因为它并不存在。iota 的值是负一的平方根,它不存在。没有哪个数自乘的结果是负一。iota 的平方可以计算为负一。

正如评论中提到的,-1 的平方根会得到 -ii。所以,最好说 iota 的平方值为负一。

维基百科关于复数的文章概述部分有一个很好的例子,说明了这些数在实际生活中的巨大用途,如物理、化学、生物学等。

复数的编程实现

现在让我们来谈谈我们的编程语言,以及如何创建这样的对象,它们实际上可以作为复数来处理,表现得像复数,并具有它们在现实生活中的属性。在编程语言中,我们可以创建类对象,这些对象可以表现为对象的数据类型,可以有成员,并且可以对它们调用不同的函数。这些函数、成员和类型在我们的编程语言中被用来创建不同的现实生活对象。

我们将定义一个类似的类来描述我们的复数,以及它的一些属性和函数。让我们先看看它会是什么样子,

在上图中,复数对象有两个子类别,极坐标类型或笛卡尔坐标类型。在这两种类型中,有相当不同的成员;属性,我们还需要定义它们。

对于一个极坐标形式的复数:

  1. 一个角(Angle):也称为复数的辐角。
  2. 一个半径(Radius):也称为复数的模。

用这种表示法表示的复数,是通过使用三角函数(例如 cos 和 sin)来表示的。

对于一个笛卡尔坐标(有时称为直角坐标)形式的复数:

  1. 一个实部。
  2. 一个虚部。

在上图中,i 是虚数单位,而其他(x 和 y)是实数;a 表示复数。到此,我们现在无需更多关于复数的细节了。

注意:在我们开始之前,我需要说明一下,C++ 代码被替换为标题 C,但代码仍然是 C++ 而不是 C。我知道这没有太大的区别,但代码仍然是 C++。我无法使用 C++,因为如果我将标题设置为 C++,标签页会损坏,从而破坏文章的界面。还有一件事是,我使用 NetBeans IDE 进行 Java 开发,Eclipse 对于包(com.example.app 命名空间和打包设置)有不同的文件系统,所以请确保你已经正确设置。

创建类

为了在我们的语言中实现上述对象,我们可以在项目中创建一个类,为此我使用了一个头文件(在 C++ 中,在其他语言中你可以创建一个类文件,例如 C# 中的 .cs 文件和 Java 中的 .java 文件等),将类的所有逻辑存储在一个单独的头文件(在 Java 中是包,在 C# 中是命名空间)中,而不是在主文件中。此刻类中的代码反映了构造函数;以及 C++ 中的析构函数。

class ComplexNumber 
{
    public ComplexNumber()
    {
        // Default
        Real = 0;
        Imaginary = 0;
    }

    public ComplexNumber(double firstVal, double secondVal)
    {
        Real = firstVal;
        Imaginary = secondVal;
    }
}
class ComplexNumber {
    // Constructors
    public ComplexNumber() {
        Real = 0;
        Imaginary = 0;
    }
    
    public ComplexNumber(double firstVal, double secondVal) {
        this.Real = firstVal;
        this.Imaginary = secondVal;
    }
}
Class ComplexNumber
    ' Constructors
    Public Sub New()
        ' Default
        Real = 0
        Imaginary = 0
    End Sub

    Public Sub New(firstVal As Double, secondVal As Double)
        Real = firstVal
        Imaginary = secondVal
    End Sub
End Class
class ComplexNumber {
// Constructors and Destructors of the objects
public:
	// Simple constructor
	ComplexNumber() {
		real = 0;
		imaginary = 0;
	};

	// Constructor with a few values
	ComplexNumber(int firstVal, int secondVal){
		real = firstVal;
		imaginary = secondVal;
	};

	// A destructor for the ComplexNumber class object. 
	~ComplexNumber() {
		
	};
};

一个复数包含两个值,一个实部和一个虚部。我们应该存储这两个变量,然后根据需要,如果想得到极坐标形式的复数,我们可以计算出该复数的角和/或半径。

复数的成员

正如我所说,我们可以创建函数来提取复数类的值,请看下面的代码。

注意,只有 VB.NET 要求你为 getter 和 setter 创建私有成员。在其他语言中,将变量设置为 public 就足以让开发者使用类的成员。

// Members of the class
public double Real { get; set; }
public double Imaginary { get; set; }

public double Radius()
{
    return Math.Sqrt(Real * Real + Imaginary * Imaginary);
}

public double Angle()
{
    return Math.Atan2(Imaginary, Real);
}
// Members
private double real;
private double imaginary;
    
// Members
double getRadius() {
    return Math.sqrt((real * real) + (imaginary * imaginary));
}
    
double getAngle() {
    return Math.atan2(imaginary, real);
}
    
double getReal() {
    return real;
}
    
void setReal(double r) {
    real = r;
}
    
double getImaginary() {
    return imaginary;
}
    
void setImaginary(double i) {
    imaginary = i;
}
' Hidden private members for the Getters and Setters
Private m_Imaginary As Double
Private m_Real As Double

' Members of the class
Public Property Real() As Double
    Get
        Return m_Real
    End Get
    Set(value As Double)
        m_Real = value
    End Set
End Property 
Public Property Imaginary() As Double
    Get
        Return m_Imaginary
    End Get
    Set(value As Double)
       m_Imaginary = value
    End Set
 End Property

' For the radius and angle
Public Function Radius() As Double
    Return (Real * Real + Imaginary * Imaginary)
End Function

Public Function Angle() As Double
    ' Check for a DivideByZeroException
    If Real <> 0 Then
         ' If the real part is not zero
         Return Math.Atan(Imaginary / Real)
    Else
         Return 0.0
    End If
End Function
private:
	// For complex number
	double real;
	double imaginary;

double getAngle() const {
	return atan2(this->imaginary, this->real);
}

double getRadius() const {
	// Get square root of the value
	return sqrt((real * real) + (imaginary * imaginary));
}

// Member accessing
double getReal() const {
	return real;
}

void setReal(double r) {
	real = r;
}

double getImaginary() const {
	return imaginary;
}

void setImaginary(double i) {
	imaginary = i;
}

评论中提出了一个很好的观点,即在做任何操作之前先检查实部,也就是检查数的实部是否为零。如果实部为零,就有可能出现 DivideByZeroException;异常的标题取决于你使用的语言或框架。因此,在将值传递给反正切函数之前,需要进行条件判断。

由于我们的类中有公共成员,因此我们不需要为这些成员创建 setter 或 getter 方法,可以直接获取公共属性。只是在 VB.NET 中,我们需要创建私有成员,并在 getter 或 setter 中返回它们的值。

复数的函数

这就结束了关于复数属性的讨论。接下来是可以在复数上执行以实现不同目的的函数。与复数的函数相比,属性要少得多。正如我已经说过的,一个复数可以是极坐标形式也可以是直角坐标形式的,所以在执行任何其他函数之前,首先要看这个数是极坐标形式还是直角坐标形式;你将在运算符部分找到原因。

注意:代码需要数学库来支持像求一个角的正弦这样的函数。在 C++ 中,你需要显式地包含库,如 #include <math.h>,而在其他语言(Java、C#、VB.NET)中,你可以在 System(C# 或 VB.NET)命名空间和 java.lang.Math 包中找到它,这样你就可以调用这些函数了。

从笛卡尔坐标形式转换为极坐标形式的复数

将笛卡尔坐标形式的复数转换为极坐标形式的复数的过程如下。

  1. 极坐标复数的半径可以通过以下关系找到:

    然后在两边取平方根,得到半径。这有时也称为复数的模(长度和/或范数)。
  2. 极坐标复数的角可以通过以下关系找到:

毕竟,极坐标形式的复数也是复数.

将极坐标形式转换为笛卡尔坐标形式的复数

与上面的函数类似,极坐标形式的数可以转换为笛卡尔坐标形式的复数,它有一个实部和一个虚部。其逻辑是:

  1. 复数的实部可以通过半径乘以角的余弦值得到。
  2. 复数的虚部可以通过半径乘以角的正弦值得到。

获取复数的对数值

对数也可以应用于复数,但其答案(底层逻辑)相当不同,返回的也是一个笛卡尔坐标形式的复数;它包含一个虚数单位(iota)。

对于一个复数进行对数运算,并没有定义或要求它必须是极坐标或笛卡尔坐标形式。你可以使用其中任何一种形式,但公式必须保持相同:

将上述规则转换成函数形式大概是这样的:

ComplexNumber Logarithm()
{
    return new ComplexNumber()
    {
         Real = Math.Log(this.Radius()),
         Imaginary = this.Angle()
    };
}
ComplexNumber getLogarithm() {
    return new ComplexNumber() {{
        this.setReal(Math.log(getRadius()));
        this.setImaginary(getAngle());
    }};
}
Private Function Logarithm() As ComplexNumber
    Dim number As New ComplexNumber()
    number.Real = Math.Log(Me.Radius())
    number.Imaginary = Me.Angle()
    Return number
End Function
// Formula for logarithm ln(z) = ln(|z|) + i(arctan"theta")
ComplexNumber getLogarithm() const {

	return ComplexNumber::ComplexNumber(
		log(this->getRadius()),
		this->getAngle()
	);
}

复数的共轭

复数的共轭是一个非常有趣的话题,值得注意的是,极坐标形式笛卡尔坐标形式的共轭是不同的。

1. 笛卡尔坐标形式的共轭

对于笛卡尔坐标形式的复数,其共轭非常简单。你只需将虚部乘以负一;或者只是改变虚部的符号。

2. 极坐标形式的共轭

对于极坐标形式的数,同样地,唯一的变化是复数的角。可以看作是:

抱歉:我无法找到一个完美的解决方案来表示 exp^(-itheta),而 MS Powerpoint 不允许我以任何其他格式书写,所以我只能照原样写。这里需要注意的是,负号是与 iota 和 theta 在一起的。

因此,根据以上结论,要将上述逻辑转换为函数,我们将使用以下函数:

 

ComplexNumber Conjugate()
{
    return new ComplexNumber(this.Real, -this.Imaginary);
}
ComplexNumber getConjugate() {
    return new ComplexNumber() {{
        this.setReal(this.getReal());
        this.setImaginary(-this.getImaginary());
    }};
}
Private Function Conjugate() As ComplexNumber
    Return New ComplexNumber(Me.Real, -Me.Imaginary)
End Function
ComplexNumber getConjugate() const {
	// Get the conjugate to this ComplexNumber
	return ComplexNumber::ComplexNumber(
		// Change the sign
		this->real,
		-this->imaginary
	);
}

在此之后,我们可以使用它们的函数将数字转换为极坐标表示法,以获取角度或半径。

复数的倒数

一个复数绝不能出现在分母中,这就是为什么我们对复数进行有理化,以从分母中移除 iota;一旦完成,分母就可以写在实部和虚部的下面,使其成为一个新的复数

经过有理化过程后,新的复数看起来像下面这样。

所以,实现这个的代码就像下面的代码一样简单:

ComplexNumber Reciprocal()
{
    return new ComplexNumber() { 
        Real = (this.Real) / (this.Real * this.Real + this.Imaginary * this.Imaginary),
        Imaginary = -(this.Imaginary) / (this.Real * this.Real + this.Imaginary * this.Imaginary)
    };
}
ComplexNumber getReciprocal() {
    return new ComplexNumber() {{
        this.setReal(this.getReal() / 
            (this.getReal() * this.getReal()) + 
                 (this.getImaginary() * this.getImaginary()));
        this.setImaginary(-this.getImaginary() / 
            (this.getReal() * this.getReal()) + 
                 (this.getImaginary() * this.getImaginary()));
    }};
}
Private Function Reciprocal() As ComplexNumber
    Dim number As New ComplexNumber()

    number.Real = (Me.Real) / (Me.Real * Me.Real + Me.Imaginary * Me.Imaginary)
    ' Minus sign shows that there is a conjugate of the complex number.
    number.Imaginary = -(Me.Imaginary) / (Me.Real * Me.Real + Me.Imaginary * Me.Imaginary)
    Return number
End Function
ComplexNumber getReciprocal() const {
	// Create a new object
	return ComplexNumber::ComplexNumber(
		// Run the logic
		(this->real) / (this->real * this->real + this->imaginary * this->imaginary),
		// Minus sign shows that there is a conjugate of the complex number.
		-(this->imaginary) / (this->real * this->real + this->imaginary * this->imaginary)
	);
}

上面的代码执行的操作与上面方程中的表达式相同。然后它返回这个数。

基于对象的函数;不是复数函数

我创建的另一个函数是,对象应该以它所属的形式来表示,极坐标形式的必须用三角函数表示,而笛卡尔坐标形式的必须用实部和虚部表示。让我们创建一个 toString 函数;大家都知道这个函数的作用。我们将传递一个标志 asPolar,来决定是将数字表示为笛卡尔坐标形式的复数还是极坐标形式的复数。

基于语言的说明:在 Java 中,你需要重写该函数,因为每个函数都被标记为 virtual,并且在 java.lang.Object 中存在一个 toString 公共函数,所以你可以重写它。在其他语言中,你可以也可以不这样做。在 C++ 中,你可以创建一个函数将对象转换为其字符串表示。在 C++ 中,使用 StringStream 创建一个字符流,然后调用 .str() 函数将其转换为字符串是一个很好的方法。

public string ToString(bool asPolar)
{
     string str = "";

     if (asPolar)
     {
         // Polar
         if (this.Angle() > 0)
         {
              // Positive angle
              str = this.Radius() + "(cos" + this.Angle() + " + isin" + this.Angle() + ")";
         }
         else
         {
              str = this.Radius() + "(cos" + this.Angle() + " - isin" + -this.Angle() + ")";
         }
     }
     else
     {
         // Rect
         if (this.Imaginary > 0)
         {
             // Positive Imaginary
             str = this.Real + " + i" + this.Imaginary;
         }
         else
         {
             str = this.Real + " - i" + -this.Imaginary;
         }
     }
     return str;
}
public String toString(boolean asPolar) {
        String str;
        
        if(asPolar) {
            // Polar notation
            if(this.getAngle() > 0) {
                str = this.getRadius() + "(cos" + this.getAngle() + 
                        " + isin" + this.getAngle() + ")";
            } else {
                str = this.getRadius() + "(cos" + this.getAngle() + 
                        " - isin" + -this.getAngle() + ")";
            }
        } else {
            // Cartesian notation
            if(this.imaginary > 0) {
                str = this.real + " + i" + this.imaginary;
            } else {
                str = this.real + " + -" + -this.imaginary;
            }
        }
        return str;
    }
Public Function ToString(asPolar As Boolean) As String
    Dim str As String = ""

    If asPolar Then
         ' Polar
         If Me.Angle() > 0 Then
              ' Positive angle
              str = Me.Radius() + "(cos" + Me.Angle() + " + isin" + Me.Angle() + ")"
         Else
              str = Me.Radius() + "(cos" + Me.Angle() + " - isin" + -Me.Angle() + ")"
         End If
    Else
         ' Rect
         If Me.Imaginary > 0 Then
              ' Positive Imaginary
              str = Me.Real + " + i" + Me.Imaginary
         Else
              str = Me.Real + " - i" + -Me.Imaginary
         End If
    End If
    Return str
End Function
std::string toString(bool asPolar) {

	// Check whether the complex number is a polar or non-polar number
	std::stringstream stream;
	if (asPolar) {
		// Polar, write in the form of cos, sin and radius
		if (this->getAngle() > 0) {
			// Angle is positive
			stream << this->getRadius() << "(cos" << this->getAngle() << " + isin" << this->getAngle() << ")";
		}
		else {
			stream << this->getRadius() << "(cos" << this->getAngle() << " - isin" << -(this->getAngle()) << ")";
		}
	}
	else {
		if (this->imaginary > 0) {
			// imaginary is positive
			stream << this->real << " + i" << this->imaginary;
		}
		else {
			stream << this->real << " - i" << -(this->imaginary);
		}
	}

	return stream.str();
}

现在它将返回信息。总是简单地用这个 .toString() 函数编写一个输出命令会很有用,而不是总是连接字符串来构造表示。

算术运算

由于这个过程涉及数学,很明显算术运算符也会被用来对数字进行加、减、乘、除。在大多数编程语言中,如 C++、C#,你可以重载运算符,以确保你得到一个非常数学化的数字相加的接口。然而在某些语言中,如 Java,你需要创建一个接口;我说的接口是指一个函数,来执行加、减和/或其他算术运算。在以下章节中,你可以发现 Java 在运算符重载方面与其他面向对象编程语言有何不同。

现在,我们将在代码中使用这些函数来执行不同的操作,让我们逐一了解这些操作,并看看如何在我们的案例中实现这样的功能。

二元运算符

首先,让我们来谈谈可以对复数使用的二元运算符,以执行算术运算,这些运算符可以列为:

  1. 加法
  2. 减法
  3. 乘法
  4. 除法

接下来的部分将讨论运算符本身及其在多种编程语言中的用法。

笛卡尔坐标形式复数的运算

首先,我们需要理解只在笛卡尔坐标形式的复数上执行的运算。只有笛卡尔坐标形式的复数可以进行加法或减法,它们的实部和虚部参与了这一部分。极坐标形式的复数不进行这些运算,但它们会进行乘法和除法运算。我们将在下一节中学习它们。

加法

我们可以重载加法运算符,以允许两个复数相加。两个复数相加的逻辑如下:

  1. 实部相互相加。
  2. 虚部相互相加。
  3. 答案再次以复数形式 x + iy 创建。

这个算法的代码;重载运算符或定义一个函数,就像这样:

public static ComplexNumber operator +(ComplexNumber a, ComplexNumber b) {
    return new ComplexNumber(a.Real + b.Real, a.Imaginary + b.Imaginary);
}
ComplexNumber add(final ComplexNumber a) {
    return new ComplexNumber() 
    {{
            this.setReal(this.getReal() + a.real);
            this.setImaginary(this.getImaginary() + a.imaginary);
    \}};
    }
Public Shared Operator +(a As ComplexNumber, b As ComplexNumber) As ComplexNumber
    Return New ComplexNumber(a.Real + b.Real, a.Imaginary + b.Imaginary)
End Operator
ComplexNumber operator + (ComplexNumber a) {
		// Return the sum of the operator
		return ComplexNumber::ComplexNumber(
			this->real + a.real,
			this->imaginary + a.imaginary);
	}

上述代码将产生复数的加法结果。

减法

类似地,我们也可以创建一个函数或重载减法运算符,以从任何其他复数中减去一个复数。逻辑是相似的, slight 的区别在于使用减号,而不是实部和虚部的加法。

  1. 实部相互相减。
  2. 虚部也相互相减。
  3. 答案再次以复数形式 x + iy 创建。

这个的代码也类似,只是符号变了;用减号代替加号。

public static ComplexNumber operator -(ComplexNumber a, ComplexNumber b)
{
    return new ComplexNumber(a.Real - b.Real, a.Imaginary - b.Imaginary);
}
ComplexNumber subtract(final ComplexNumber a) {
    return new ComplexNumber() {{
        this.setReal(this.getReal() - a.getReal());
        this.setImaginary(this.getImaginary() - a.getImaginary());
    }};
}
Public Shared Operator -(a As ComplexNumber, b As ComplexNumber) As ComplexNumber
    Return New ComplexNumber(a.Real - b.Real, a.Imaginary - b.Imaginary)
End Operator
ComplexNumber operator - (ComplexNumber a) {
	// Return the answer of the operator
	ComplexNumber number;
	number.real = this->real - a.real;
	number.imaginary = this->imaginary - a.imaginary;
	return number;
}

极坐标和笛卡尔坐标形式复数的运算

现在还有另外两种运算可以在复数上执行,而且是在两种形式上都执行。

  1. 笛卡尔坐标形式的复数。
    这些运算涉及到它们的实部和虚部。
  2. 极坐标形式的复数。
    这些运算是在复数的角和模上进行的。

这些函数可以通过首先确定复数是极坐标形式还是笛卡尔坐标形式来计算。这将帮助我们创建一个针对特定类型复数的代码块。

乘法

在复数中,乘法过程取决于数的类型。因此,首先必须满足一个条件,检查我们是在乘以笛卡尔坐标类型还是极坐标类型的复数。

你不能将笛卡尔坐标形式与极坐标形式相乘,反之亦然。

我们首先识别复数的类型,一旦完成,我们就可以继续处理。现在让我们把它分成两个小节,并按它们各自的类型进行处理。

笛卡尔坐标形式的复数

在笛卡尔坐标形式的复数中,我们像乘一个简单的 a + b 方程与另一个类似类型的方程一样来乘这些数。

最后一个值有一个负号,因为 iota 的平方等于负一。

极坐标形式的复数

在我们转向代码之前,让我先谈谈极坐标形式的复数。极坐标形式复数的乘法涉及它们的半径和它们所持有的角。其逻辑如下:

  1. 复数的半径相乘。
  2. 角度相加,并且结果被设置为它们的cis 表示法的角度。

代码

现在,计算这个的代码也应该与上面的方程类似。我们可以通过直接调用对象的属性,或者调用它们的函数来获取半径或角度的值,从而从我们的对象中推导出每个值。

public static ComplexNumber operator *(ComplexNumber a, ComplexNumber b)
{
     return new ComplexNumber() 
     {
         Real = (a.Real * b.Real) - (a.Imaginary * b.Imaginary),
         Imaginary = (a.Real * b.Imaginary) + (a.Imaginary * b.Real)
     };
}
ComplexNumber multiply(final ComplexNumber a) {
     return new ComplexNumber() {{
          this.setReal((this.getReal() * a.real) - (this.getImaginary() * a.imaginary));
          this.setImaginary((this.getReal() * a.imaginary) + (this.getImaginary() * a.real));
     }};
}
Public Shared Operator *(a As ComplexNumber, b As ComplexNumber) As ComplexNumber
    Dim number As New ComplexNumber()

    number.Real = (a.Real * b.Real) - (a.Imaginary * b.Imaginary)
    number.Imaginary = (a.Real * b.Imaginary) + (a.Imaginary * b.Real)
    Return number
End Operator
ComplexNumber operator * (ComplexNumber a) {
	// Return the answer of the operator
	return ComplexNumber::ComplexNumber(
		(this->real * a.real) - (this->imaginary * a.imaginary),
		(this->real * a.imaginary) + (this->imaginary * a.real)
	);
}

除法

现在让我们以复数的除法过程为例。对于极坐标和笛卡尔坐标形式的复数,这个过程是不同的,因此在将章节划分为子章节之前,我们不能谈论第一步。

笛卡尔坐标形式的复数

除法首先必须经过有理化,因为复数永远不能出现在分母中。所以首先我们必须对复数进行有理化。一旦分数被有理化并且虚部只在分子中,我们就可以继续进行除法运算了。

然后除法遵循给定的规则继续进行:

注意:方程的第二部分是虚部,我在创建时漏掉了一个 i,对此表示抱歉。

上面的方程显示,分母中的复数首先经过有理化;即乘以其复共轭,然后进行实数除法。这些是一些你当然不想争论的数学规则。你可以阅读维基百科的文章获取更多信息,或查阅数学百科全书以获取这些规则的证明。

极坐标形式的复数

在极坐标形式中,除法相对简单。只需要处理角度和半径。就像乘法一样,角度和半径都参与其中,不过是以相反的方式。现在适用以下规则。

  1. 半径相除。
  2. 角度从第一个复数中减去。然后放入 cis 表示法中。

在相减时必须注意角度,如果结果是负数(例如 20-30 = -10),那么 sin 函数前的符号必须改变,因为 sin(-10) = - sin(10)

代码

现在让我们把上面的东西转换成代码的形式。

public static ComplexNumber operator /(ComplexNumber a, ComplexNumber b)
{
     return new ComplexNumber()
     {
          Real = (a.Real * b.Real) + (a.Imaginary * b.Imaginary) /
               ((b.Real * b.Real) + (b.Imaginary * b.Imaginary)),
          Imaginary = (a.Real * b.Real) - (a.Imaginary * b.Imaginary) /
               ((b.Real * b.Real) + (b.Imaginary * b.Imaginary))
     };
}
ComplexNumber divide(final ComplexNumber a) {
     return new ComplexNumber() {{
          this.setReal((this.getReal() * a.real) + (this.getImaginary() * a.imaginary)
                / (a.real * a.real) + (a.imaginary * a.imaginary));
          this.setImaginary((this.getImaginary() * a.real) - (this.getReal() * a.imaginary)
                / (a.real * a.real) + (a.imaginary * a.imaginary));
     }};
}
Public Shared Operator /(a As ComplexNumber, b As ComplexNumber) As ComplexNumber
    Dim number As New ComplexNumber()

    number.Real = (a.Real * b.Real) + (a.Imaginary * b.Imaginary) / ((b.Real * b.Real) + (b.Imaginary * b.Imaginary))
    number.Imaginary = (a.Real * b.Real) - (a.Imaginary * b.Imaginary) / ((b.Real * b.Real) + (b.Imaginary * b.Imaginary))
    Return number
End Operator
ComplexNumber operator / (ComplexNumber a) {
	// Return the answer of the operator
	return ComplexNumber::ComplexNumber(
		(this->real * a.real) + (this->imaginary * a.imaginary) /
		((a.real * a.real) + (a.imaginary * a.imaginary)),
		(this->real * a.real) - (this->imaginary * a.imaginary) /
		((a.real * a.real) + (a.imaginary * a.imaginary))
	);
}

相等性检查

另一个必须实现的主要功能是检查两个对象是否相等。当然,在某些语言中你可以实现 .Equals() 函数,但让我们为 == 运算符创建我们自己的重载函数。

public static bool operator ==(ComplexNumber a, ComplexNumber b)
{
    // Check whether their values are same
    return (b.Real == a.Real && b.Imaginary == a.Imaginary);
}

public static bool operator !=(ComplexNumber a, ComplexNumber b)
{
    return !(b.Real == a.Real && b.Imaginary == a.Imaginary);
}
boolean equals(ComplexNumber a) {
    // Check whether their values are same
    return (this.real == a.real && this.imaginary == a.imaginary);
}
Public Shared Operator =(a As ComplexNumber, b As ComplexNumber) As Boolean
    ' Check whether their values are same
    Return (b.Real = a.Real AndAlso b.Imaginary = a.Imaginary)
End Operator

Public Shared Operator <>(a As ComplexNumber, b As ComplexNumber) As Boolean
    Return Not (b.Real = a.Real AndAlso b.Imaginary = a.Imaginary)
End Operator
bool operator == (ComplexNumber a) {
	return (this->real == a.real && this->imaginary == a.imaginary);
}

bool operator != (ComplexNumber a) {
	return !(this->real == a.real && this->imaginary == a.imaginary);
}

这将检查一个对象可能等于另一个对象的所有可能方式,如果任何一个必需的值不正确,结果将为 false;因此可以在 if...else 块中使用。

一元运算符

我们也可以对一个复数(笛卡尔坐标形式)应用一元运算符,以得到其负数形式的值。

请注意,这不是复数的共轭,而是一个完全的负数(实部和虚部的值的符号都改变了)。

取反

我们可以对复数的值取反,使其成为自身的相反数;而不是共轭数。一个简单的负号就可以做到这一点。

public static ComplexNumber operator -(ComplexNumber a)
{
    return new ComplexNumber(-a.Real, -a.Imaginary);
}
ComplexNumber negate() {
    return new ComplexNumber() {{
        this.setReal(-this.getReal());
        this.setImaginary(-this.getImaginary());
    }};
}
Public Shared Operator -(a As ComplexNumber) As ComplexNumber
    Return New ComplexNumber(-a.Real, -a.Imaginary)
End Operator
ComplexNumber operator - () {
	ComplexNumber number;
	number.real = -(this->real);
	number.imaginary = -(this->imaginary);
	return number;
}

关注点

以上关于本文的几点可能无法解释本文的实际概念,但它们可以提供一个关于我在撰写本文和创建整个库(用多种语言)时的想法和感受。

复数是可以表示为 x + iy 形式的数。我们可以在许多方面使用这些数,不仅在数学领域,还在物理、化学和生物学等领域。复数是一种特殊类型的数,它包含一个虚数值,从而使其与其他数区分开来。

我们可以在(编程语言中)创建一个类来包含这些数字,然后我们可以创建成员来指定这些数字的值。复数有两种类型:

  1. 极坐标
  2. 笛卡尔坐标

一个极坐标形式的复数包含一个角和一个半径,而一个笛卡尔坐标形式的复数包含一个实数和一个虚数。

对这些数执行的算术运算在许多方面都有所不同,极坐标形式的数不进行加法或减法。对于极坐标形式的复数有一些规则,其中之一是欧拉公式,它被用来推导复数的不同函数。

在编程语言中,你可以重载加法、减法等运算符来对这些数字执行不同的任务。在某些特定语言中,比如 Java,不允许运算符重载,开发者必须为对象创建一个接口,然后以指定的方式执行这些操作。

源代码

本文、库、代码示例以及所有其他资源均归我所有,它们将公开提供给所有人,以便在应用程序中复制和分享。源代码可在GitHub 仓库上找到。

恳请

如果您在文章(包括界面和文章布局)、源代码和教学方法中发现任何问题,您可以 kindly 将其作为建议添加,让我知道我在哪些方面做得不够好。如果您想为库或文章添加一些内容,也可以添加建议。我不是最好的数学家,所以方程中的任何错误和/或任何遗漏的基本复数函数方程也可以在下面的评论中分享。

谢谢。

历史

文章第一版;库。

第二版:添加了目录

第三版:修改了类,移除了未使用和非必需的类成员,将它们转换为在运行时调用的函数,以便正确获取值。

第四版:修正了一个错误,半径应该是平方根,并添加了 cmath 库而不是 math.h。对所有要返回的对象使用了类型初始化。

© . All rights reserved.