【问题标题】:C# Struct on a Mandelbrot set?Mandelbrot 集上的 C# 结构?
【发布时间】:2012-09-06 22:00:29
【问题描述】:

之前在 C#.Net Mandelbrot 集合上发布了一个问题,该问题得到了有益的回答,但是我不得不回到这个 Mandelbrot 集合并在它的双变量上实现一个结构,定义(虚构和真实)坐标.

作为一个刚接触结构并且对它们有点生疏的人,我想就我做错了什么以及如何改进上述代码提供一些建议,我相信它可以稍微优化一下。这是使用结构的正确方法吗?如果不是,有哪些替代方案或最佳技术?谢谢。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace wmcMandelbrot
{
struct doubleVar
{

    public double realCoord, imagCoord;
    public double realTemp, imagTemp, realTemp2, arg;
    public double newIcoord, newIcoord1, newIcoord2;
    public double rCoord, rCoord1, rCoord2;
 }


class Program
{
    static void Main(string[] args)
    {

        doubleVar doubleNum;
        int iterations;

        Console.WriteLine("Enter first imaginary coord: ");
        doubleNum.newIcoord = Convert.ToDouble(Console.ReadLine());

        Console.WriteLine("Enter second imaginary coord: ");
        doubleNum.newIcoord1 = Convert.ToDouble(Console.ReadLine());

        Console.WriteLine("Enter third imaginary coord: ");
        doubleNum.newIcoord2 = Convert.ToDouble(Console.ReadLine());

        Console.WriteLine("Enter first real coord: ");
        doubleNum.rCoord = Convert.ToDouble(Console.ReadLine());

        Console.WriteLine("Enter second real coord: ");
        doubleNum.rCoord1 = Convert.ToDouble(Console.ReadLine());

        Console.WriteLine("Enter third real coord: ");
        doubleNum.rCoord2 = Convert.ToDouble(Console.ReadLine());

        for (doubleNum.imagCoord = doubleNum.newIcoord; doubleNum.imagCoord >= -doubleNum.newIcoord1; doubleNum.imagCoord -= doubleNum.newIcoord2)
        {
            for (doubleNum.realCoord = -doubleNum.rCoord; doubleNum.realCoord <= doubleNum.rCoord1; doubleNum.realCoord += doubleNum.rCoord2)
            {
                iterations = 0;
                doubleNum.realTemp = doubleNum.realCoord;
                doubleNum.imagTemp = doubleNum.imagCoord;
                doubleNum.arg = (doubleNum.realCoord * doubleNum.realCoord) + (doubleNum.imagCoord * doubleNum.imagCoord);
                while ((doubleNum.arg < 4) && (iterations < 40))
                {
                    doubleNum.realTemp2 = (doubleNum.realTemp * doubleNum.realTemp) - (doubleNum.imagTemp * doubleNum.imagTemp) - doubleNum.realCoord;
                    doubleNum.imagTemp = (2 * doubleNum.realTemp * doubleNum.imagTemp) - doubleNum.imagCoord;
                    doubleNum.realTemp = doubleNum.realTemp2;
                    doubleNum.arg = (doubleNum.realTemp * doubleNum.realTemp) + (doubleNum.imagTemp * doubleNum.imagTemp);
                    iterations += 1;
                }
                switch (iterations % 4)
                {
                    case 0:
                        Console.Write(".");
                        break;
                    case 1:
                        Console.Write("o");
                        break;
                    case 2:
                        Console.Write("O");
                        break;
                    case 3:
                        Console.Write("@");
                        break;
                }
            }
            Console.Write("\n");
        }
        Console.ReadKey();




    }
  }
}

【问题讨论】:

  • 你现在没有从该结构中获得任何价值。通常你会使用一个来传递一些相关的值。或作为轻量级,例如价值观和方法。 PS 如果你在 .net 4 以上,你可能想看看 System.Numerics.Complex 结构
  • 获取类似函数的值?

标签: c# struct mandelbrot


【解决方案1】:

我认为您应该使用结构来表示每个复数。然后,该结构可以包含将这些复数加、减、乘的函数:

例如。

struct Complex
{
    public double real;
    public double imag;

    public Complex(double r, double i)
    {
        real = r;
        imag = i;
    }

    public Complex add(Complex operand)
    {
        return new Complex(real + operand.real, imag + operand.imag);
    }

    public Complex multiply(Complex operand)
    {
        return new Complex(real * operand.real - imag * operand.imag, real * operand.imag + operand.real * imag);
    }
}

然后要使用结构,您可以执行类似的操作

Complex c = new Complex( ...coordinate goes here... );
Complex z = new Complex(0,0);

// z -> z^2 + c
Complex result = z.multiply(z).add(c);

等等

您还可以将“sq”(数字平方)或“pow”(提高到给定的幂)或“arg”(在上面的代码中)添加到复数结构。天空是极限!请注意,这些函数不必返回另一个复数,例如“arg”将返回一个双精度数。

此外,如果您总是将两个复数(地图点和 z 值)组合在一起,您可以创建一个结构来保存两个复数:

struct MapPoint
{
    Complex c;
    Complex z;
}

等等。对我来说,将事物分组在逻辑上不可分割的结构或始终作为一个组工作的事物是有意义的。

【讨论】:

  • 在这种情况下切换到班级不会有任何好处。
  • 感谢您的回答,但必须同意 James 的观点,因为这个 mandelbrot 集只是一个简单的控制台应用程序,因此实际上并不需要一个类。
  • @james Ahh 我没有意识到结构可以有成员函数。话虽如此,使用结构比类有好处吗?
  • @WayneUroda "使用结构体对类有好处吗" - 如果您要处理大量实例,则使用结构体会有一些性能提升。结构应该用于轻量级对象,这在这种情况下是有意义的。公平地说,切换到类不一定是的事情,但是,将类用于这样的简单数据可能不是一个好的设计(除非您打算扩展功能稍后)。
  • 类在人们经常从旧事物中创造新事物并且没有有意义的引用身份概念的情况下非常糟糕。如果要创建一个ComplexClass 实例来保存两个复数的乘积,则该计算的结果必须保存在内存中,直到下一次垃圾回收,即使没有其他需要它。相比之下,如果是ComplexStruct,则旧计算的结果可能会被新计算的结果直接覆盖。
【解决方案2】:

只存储定义坐标所需的值(读取和虚部)而不存储任何临时值是有意义的。计算值也可以是属性,如下所示:

public struct MapPoint
{
    public double realCoord, imagCoord;
    public double realConst, imagConst;

    public MapPoint(double realConst, double imagConst)
        : this(realConst, imagConst, realConst, imagConst) { }

    public MapPoint(double realCoord, double imagCoord, double realConst, double imagConst)
    {
        this.realCoord = realCoord;
        this.imagCoord = imagCoord;
        this.realConst = realConst;
        this.imagConst = imagConst;
    }
    public double Argument // calculated property
    {
        get { return realCoord * realCoord + imagCoord * imagCoord; }
    }

    public MapPoint Iterate()
    {
        // Do the z = z^2+c thing

        return new MapPoint(
            realCoord * realCoord - imagCoord * imagCoord + realConst,
            2 * realCoord * imagCoord + realConst,
            realConst, imagConst);
    }
}

现在像这样使用这个结构:

void Main() {
    for( double y=...
      for( double x=...

        int iterations = 0;
        MapPoint point = new MapPoint(x, y);

        while (iterations < 40 || point.Argument < 4.0)
        {
            point = point.Iterate();
            iterations++;
        }

        switch (iterations % 4)
        {
            //...
        }
    ...
}

关键是所有计算都在结构内部完成,靠近存储信息的地方。这样,结构可以在其他地方重用,而无需再次重新编写计算块。此外,任何临时值在不需要时都会被丢弃,并且不会存储在重要值旁边。

请承诺阅读结构 herehere,然后将上面的代码重写为您自己的代码。

【讨论】:

  • 很好的答案!我花了一段时间才打破虽然大声笑但感谢您的帮助和结构的链接。希望其他人在遇到结构时遇到这个问题。再次感谢!
  • 可能值得注意的是,虽然第二个链接的帖子建议将结构字段包装在属性中,但通常最好让它们公开公共字段而不是让可变属性由私有字段支持。适用于在属性后面封装类字段的一般优势都不适用于结构,并且这种封装的性能损失通常大于类。
  • @supercat,我同意。我肯定会在公共字段中添加 readonly 关键字,并允许以原子方式更改整个结构,以确保它通过构造函数并且值始终有效。
  • @ja72:在大多数情况下,我认为最好不要让结构尝试对自己强制执行不变量,而是指定接收结构并期望它满足某些条件的代码应该验证那些状况。结构本质上是用胶带捆绑在一起的存储位置的集合。虽然有时结构可以有效地伪装成更多的东西,但我认为结构应该表现为变量的集合,可能带有一些辅助方法,没有充分的理由让它们这样做。
  • @ja72:我个人认为,如果装箱必须是显式的而不是隐式的,.net 会更好,并且它不会试图假装结构和类是同一件事。有些人认为可变结构是邪恶的,因为它们不像类,但这就是可变结构有用的全部原因。在许多情况下,分段可变对象比不可变对象更方便,只是通常没有实用的方法可以知道任何持有对象引用的对象是否期望它不会改变。结构消除了这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 2013-04-13
相关资源
最近更新 更多