C#中的复数

3

我有一个任务要写一个复数实现:

Complex c = new Complex(1.2,2.0)

使用属性real和imaginary来获取复数的实部和虚部。用法如下:

double x = c.Real;

编写一个方法以添加两个复数并返回它们的和。实部为两个实部的和,虚部为两个虚部的和。
Complex c = c1.Sum(c2);

编写一个方法来计算两个复数的乘积。如果一个数有分量x1y1,第二个数有分量x2y2
乘积的实部 = x1 * x2 - y1 * y2; 虚部 = x1 * y2 + x2 * y1
所以我知道并且对手动操作复数(例如4 + 5i,其中5i是虚数)相当有信心。
我的问题是,我不确定如何让应用程序知道哪个数是虚数,除非我将一个输入设置为预定义的虚数。但一旦我这样做了,"应用程序"就失去了它的价值,因为它不再是一个复数,而只是一些随机计算应用程序。基本上,我不知道该怎么办。谢谢

7
你为什么不向教授进一步询问呢?这似乎是正确的学术行为。 - David L
我觉得这更像是一个糟糕措辞的问题,因为提问者不知道如何准确表达他所要求的内容。 - Keith Nicholas
2
我认为你想得太多了:“失去其价值是因为它不是一个复数。”你的“Complex”类应该定义有效的操作。如果规则相同,那么这与“复数”有什么不同呢? - Felix Castor
是的,我在最初的问题中没有表达清楚,我并不希望你替我完成作业。我只是在寻求建议,而不是代码。感谢您的回答,非常感激@ Mar B,我已经联系过他了,但不幸的是这是Unisa,他们的回复速度很慢,而且截止日期还不到一周,所以我才来这里问@ David L... - Almendro
4个回答

4

看起来您对复数的构造感到困惑。这里是一个模板,可以帮助您入门。

public class Complex
{
    public Complex(double real, double imaginary)
    {
    }
}

那么首先开始

 static void Main(string[] args)
 {
    Complex c1 = new Complex(1.2,2.0)

    Complex c2 = new Complex(1,3.0)

    Complex c3 = c1.Sum(c2);

    Console.WriteLine(c3.Real);
    Console.WriteLine(c3.Imaginary);

 }

让它运行起来(开始时可以随意输入数字)


谢谢Keith,我很感激。 :) - Almendro

4

由于这个问题已经被提出一段时间,但我相信还有其他人对这个话题感兴趣,所以我决定发布最近在 C# 中实现的复数。因为复数是值类型,所以我使用了结构体而不是类(在这种情况下,结构体更快,我用一个简单的应用程序运行 Mandelbrot 算法 [请参见答案下面的链接] 来测量它),并重载了操作符如 +, -, *, / 以及比较操作符 <, >, =, !=, ==,因此您可以无缝地使用它们(但是,因为复数是二维的,<> 将与平方数量进行比较,而 ==!= 将与等式进行比较)。

我使用了双精度,因为分形图形等需要高精度。但是,如果您的应用程序足够,则也可以使用单精度。

请注意,这需要覆盖 GetHashCode()Equals(object obj)。我还重载了 ++-- 操作符,尽管在复数世界中有几种可能的解释方法:递增/递减实部和虚部或只递增/递减其中之一?

此外,我创建了一个元组 (a, bi) 和复数之间的隐式转换,因此您可以轻松地初始化它们,例如:

complex a = (1, 2), b = (3, 4); // via tuples (re, im)

你甚至可以解析像这样的字符串:

string input = Console.ReadLine();
if (!complex.TryParse(input, out complex c)) 
    Console.WriteLine("Syntax error"); 
else 
    Console.WriteLine($"Parsed value for c = {c}");

然后您可以像使用简单的东西一样使用它们。
var w = a - b;  Console.WriteLine($"a - b = {w}");
var x = a + b;  Console.WriteLine($"a + b = {x}");
var y = a * b;  Console.WriteLine($"a * b = {y}");
var z = a / b;  Console.WriteLine($"a / b = {z}");

为您提供输出

a - b = -2 - 2i
a + b = 4 + 6i
a * b = -5 + 10i
a / b = 0.44 + 0.08i

您甚至可以编写一个for循环,就像这样(请注意您有两个维度!):

for (complex u = (0,0); u <= (5, 5); u.Re++, u.Im++)
{
    Console.WriteLine(u);
}

如果还需要进行比较:

if (u==(1, 1)) Console.WriteLine("u == 1+i");

所需的类实现如下:
/// <summary>
/// Complex numbers
/// Written by Matt, 2022
/// </summary>
struct complex
{
    public double Re, Im;
    public complex(double re, double im)
    {
        this.Re = re; this.Im = im;
    }


    public static complex operator ++(complex c) { ++c.Re; ++c.Im; return c; } // not the only way one can implement this
    public static complex operator --(complex c) { --c.Re; --c.Im; return c; } // not the only way one can implement this
    public static complex operator +(complex a, complex b) => new complex(a.Re + b.Re, a.Im + b.Im);
    public static complex operator -(complex a, complex b) => new complex(a.Re - b.Re, a.Im - b.Im);

    public static double AmountSqr(complex c) => c.Re * c.Re + c.Im + c.Im;
    public static double Amount(complex c) => Math.Sqrt(AmountSqr(c));

    /// <summary>Compares the amount of both complex numbers, returns true if |a|<|b|.</summary>
    public static bool operator <(complex a, complex b) => AmountSqr(a) < AmountSqr(b);
    /// <summary>Compares the amount of both complex numbers, returns true if |a|>|b|.</summary>
    public static bool operator >(complex a, complex b) => AmountSqr(a) > AmountSqr(b);

    /// <summary>Compares the both complex numbers, returns true if a == b.</summary>
    public static bool operator ==(complex a, complex b) => (a.Re == b.Re && a.Im == b.Im);
    /// <summary>Compares the both complex numbers, returns true if a != b.</summary>
    public static bool operator !=(complex a, complex b) => (a.Re != b.Re || a.Im != b.Im);


    // (a+bi)(c+di) = ac-bd + (ad+bc)i  
    public static complex operator *(complex a, complex b) 
            => new complex(a.Re*b.Re-a.Im*b.Im, a.Re*b.Im+a.Im*b.Re);

    // (a+bi)/(c+di) = (ac+bd)/(c*c + d*d) + i(bc-ad)/(c*c + d*d)
    public static complex operator /(complex a, complex b)
    {
        var divisor = (b.Re * b.Re + b.Im * b.Im);
        return new complex((a.Re*b.Re+a.Im*b.Im)/divisor, (a.Im*b.Re-a.Re*b.Im)/divisor);
    }
    
    public static implicit operator complex((double real, double imag) c) 
            => new complex(c.real, c.imag); // via tuples (re, im)

    public override string ToString() 
        => $"{this.Re.ToString().Trim()} {(this.Im < 0 ? "-" : "+")} {Math.Abs(this.Im)}i";
    
    /// <summary>Tries to convert string expressions like "2+3i" or "5-7i" to complex</summary>
    public static bool TryParse(string complexNr, out complex result) 
    {
        bool success = false;
        result = (0, 0);
        try
        {
            result = Parse(complexNr);
            success = true;
        } catch {}
        return success;
    }

    /// <summary>Converts string expressions like "2+3i" or "5-7i" to complex</summary>
    public static complex Parse(string complexNr)
    {
        complex result = (0, 0);
        try
        {
            if (complexNr.Contains("-")) complexNr = complexNr.Replace("-", "+-");
            var tr = complexNr.Split("+").Select(s => s.Trim()).ToArray();
            var realStr = tr[0]; var imagStr = tr[1].TrimEnd('i').Trim();
            result = (double.Parse(realStr), double.Parse(imagStr));
        } 
        catch (Exception ex)
        {
            throw new SyntaxErrorException("Invalid syntax for complex number. Allowed is 'a+bi' or 'a-bi'", ex);   
        }
        return result;
    }
    
    public override bool Equals(object obj)
    {
        return (obj == null) ? false : (this == (complex)obj);
    }

    public override int GetHashCode()
    {
        var hash = new HashCode();
        hash.Add(this.Re); hash.Add(this.Im);
        return hash.ToHashCode();
    }
}

参考资料(Mandelbrot算法用于测量“complex”库的性能):

  1. 曼德博集合(Python,但对C#程序员也易懂)
  2. 曼德博算法(伪代码)

为什么在这种情况下struct更快?你是不是特别指出了某些情况下struct会更慢? - Enigmativity
@Enigmativity - 当然了,我指的是你可以像使用其他数字类型(如int、single、double)一样使用它们,包括所有常见的运算符。所以你可以像处理其他数字类型一样写c1 + c2。而且你可以直接比较c1 < c2(if (c1 < c2) ...)。 - Matt
在不等式运算符中,应该使用“或”而不是“和”吧? - user1429080
@user1429080:你完全正确。谢谢提示,我已经修复了它。 - Matt
@Matt - 我也会放弃 <, >, <=>= 这些运算符,因为它们在虚数中没有意义。 - Enigmativity
显示剩余8条评论

1

“我不确定如何让应用程序知道哪个是虚构的”-- 这里有一种方法:


        Console.WriteLine("Input the real part of the complex number:");
        var real = double.Parse(Console.ReadLine());
        Console.WriteLine("Input the imaginary part of the complex number:");
        var imaginary = double.Parse(Console.ReadLine());
        var complexNumber = new Complex(real, imaginary);

我理解的方式是,应用程序必须向/您/提供实部和虚部的值? - Almendro
@Almendro,你的问题对我来说不太清楚。显然,你手头有一个名为Complex的类,它具有RealImaginary属性。这意味着如果应用程序想要将实数和虚数值传递给/你/,那么应用程序只需要执行以下操作:Console.WriteLine("Real number is: " + c.Real); Console.WriteLine("Imaginary number is: " + c.Imaginary);。应用程序“知道”哪个是虚数,因为程序员明确地创建了一个名为Imaginary的属性,并且程序员明确地只将被指定为“虚数”的输入分配到该属性中。 - Quantic
好的,我明白了。但是我想做的是,在不为虚数创建显式属性的情况下,让程序根据任意两个输入计算出虚数。然而,我认为我过于复杂化了,最好还是直接调用显式属性。 - Almendro
可以通过解析输入字符串,然后验证该字符串是否符合以下条件来使程序基于任意两个随机输入计算出虚数部分:1)只有一个 + 符号;2)在 Split('+')+ 进行操作之后,仅有两个元素;3)在 Trim() 操作之后,其中一个元素后面有且仅有一个字符 i,即为虚数部分。然后您可以传入像 3+5i5i + 33+ 5i 这样的字符串,它们会被解析为“实数为 3,虚数为 5”,而像 3i + 5i3+5 这样的字符串则会因为存在歧义而被视为格式错误并不受支持,从而引发异常。 - Quantic

1
什么是复数?它是一个有着“实部”和“虚部”的数字。虚部本身是一个实数,乘以这个神奇的虚数常量i得到。使得i * i = -1。没有其他更多的内容,所以按照这种方式实现它。为什么会让你的代码失去价值呢?
public struct Complex
{
    public static readonly ImaginaryOne = new Complex(0, 1);
    public doube Real { get; }
    public double Imaginary { get; }
    public Complex(double real, double imaginary)
    {
        Real = real;
        Imaginary = imaginary;
    }
}

而其余部分只是样板文件...

感谢您抽出时间回复我,非常感激。 :) - Almendro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接