C # Struct на множестве Мандельброта?

Ранее был опубликован вопрос о наборе Мандельброта C # .Net, на который был дан полезный ответ, однако мне пришлось вернуться к этому набору Мандельброта и реализовать структуру на его двойных переменных, которые определяют (мнимые и реальные) координаты.

Как человек, который плохо знаком со структурами и немного устарел с ними, я хотел бы получить небольшой совет о том, что я делаю неправильно и как улучшить указанный код, поскольку, просто взглянув на него, я уверен, что его можно немного оптимизировать. . Это правильный способ использования структуры? Если нет, то каковы альтернативы или лучшие методы? Спасибо.

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();




    }
  }
}

person wilbomc    schedule 06.09.2012    source источник
comment
В настоящий момент вы не получаете никакой ценности от этой структуры. Обычно вы использовали бы один для передачи ряда связанных значений. Или как легкая весовая категория, например ценности и методы. PS Если вы используете .net 4 и далее, вы можете взглянуть на структуру System.Numerics.Complex   -  person Tony Hopkinson    schedule 07.09.2012
comment
Получить значение, подобное значению функции?   -  person wilbomc    schedule 07.09.2012


Ответы (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)
        {
            //...
        }
    ...
}

Ключ к этому в том, что все расчеты выполняются внутри конструкции, рядом с местом, где хранится информация. Таким образом, структуру можно повторно использовать в других местах с минимальными усилиями, без необходимости заново перезаписывать блок вычислений. Также любые временные значения выбрасываются, когда они не нужны, и не сохраняются рядом с важными значениями.

Обещайте ознакомиться со структурами здесь и здесь, а затем перепишите приведенный выше код как свой собственный.

person John Alexiou    schedule 07.09.2012
comment
Отличный ответ! Мне потребовалось время, чтобы сломаться, хотя lol, но спасибо за помощь и за ссылки на структуры. Надеюсь, что другие столкнутся с этим, если они борются со структурами. Еще раз спасибо! - person wilbomc; 07.09.2012
comment
Возможно, стоит отметить, что, хотя во втором связанном сообщении предлагается обернуть поля структуры в свойства, обычно лучше просто предоставить им доступ к общедоступным полям, чем иметь изменяемые свойства, поддерживаемые частными полями. Ни одно из обычных преимуществ, которые были бы применимы к инкапсуляции полей класса за свойствами, не применимы к структурам, и потери производительности для такой инкапсуляции обычно больше, чем для классов. - person supercat; 19.09.2012
comment
@supercat, согласен. Я бы определенно добавил ключевое слово readonly в общедоступные поля и разрешил атомарно изменять всю структуру, чтобы убедиться, что она проходит через конструктор и значения всегда действительны. - person John Alexiou; 19.09.2012
comment
@ ja72: В большинстве случаев я думаю, что лучше не позволять структурам пытаться принудительно применять инварианты к себе, а вместо этого указывать тот код, который получает структуру и ожидает, что она будет соответствовать определенным условиям, чтобы проверить эти условия. Структура - это, по сути, набор мест хранения, связанных вместе изолентой. Хотя бывают случаи, когда структура может с пользой притворяться чем-то большим, я думаю, что структуры должны вести себя как коллекции переменных, возможно, с некоторыми вспомогательными методами, при отсутствии веских причин поступать иначе. - person supercat; 19.09.2012
comment
@ ja72: Лично я думаю, что .net было бы лучше, если бы бокс был явным, а не неявным, и он не пытался делать вид, что структуры и классы - это одно и то же. Некоторые люди считают изменяемые структуры злом, потому что они не действуют как классы, но именно поэтому изменяемые структуры полезны. Во многих случаях кусочно-изменяемые объекты были бы более удобными, чем неизменяемые, за исключением того, что часто нет практического способа узнать, может ли что-либо, содержащее ссылку на объект, ожидать, что оно не изменится. Структуры устраняют эту проблему. - person supercat; 19.09.2012

Я думаю, вам следует использовать структуру для представления каждого комплексного числа. Затем эта структура может содержать функции для сложения, вычитания и умножения этих комплексных чисел вместе:

eg.

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;
}

И так далее. Для меня имеет смысл сгруппировать вещи в логически неделимые структуры или вещи, над которыми всегда работают, как группу.

person Wayne Uroda    schedule 07.09.2012
comment
В этом сценарии не было бы никакой пользы от перехода на класс. - person James; 07.09.2012
comment
Спасибо за ответ, но должны согласиться с Джеймсом в том, что класс на самом деле не нужен, поскольку этот набор Мандельброта представляет собой простое консольное приложение. - person wilbomc; 07.09.2012
comment
@james Ах, я не понимал, что у структур могут быть функции-члены. Сказав это, есть ли преимущество в использовании структуры над классом? - person Wayne Uroda; 10.09.2012
comment
@wilbomc, я согласен, что ваше приложение сейчас маленькое, но что, если (гипотетически) требования должны были измениться, и вам также пришлось бы включить, скажем, набор Джулии - в этом случае вы могли бы повторно использовать реализацию для комплексного числа (будь то он основан на классах или структурах, это не имеет никакого значения - замените слово class на struct в приведенном выше коде, и он будет вести себя так же. Повторное использование - одна из основных целей объектно-ориентированного программирования, а также группировка данные вместе с операциями, которые работают с этими данными. - person Wayne Uroda; 10.09.2012
comment
@WayneUroda есть ли преимущество использования структуры над классом - если вы имеете дело с большим количеством экземпляров, использование структур может дать некоторый прирост производительности. Структуры следует использовать для легких объектов, что в данном сценарии имеет смысл. Честно говоря, переключение на класс не обязательно будет плохим, однако, вероятно, использование класса для простых данных, подобных этому, не лучший дизайн (если вы не собираетесь расширять функциональность позже). - person James; 10.09.2012
comment
Вернусь ли я к версии с консольным окном? Наверное, нет, если только не исправить мелкие проблемы. Однако, обладая немного большим опытом работы с ООП и классами, я, скорее всего, перепишу набор Мандельброта с нуля, используя объекты графического интерфейса Visual Studio, и на этом этапе я, безусловно, рассмотрю возможность использования класса, а не структуры. - person wilbomc; 11.09.2012
comment
Классы очень плохи в ситуациях, когда кто-то часто будет создавать новые вещи из старых и где нет значимой концепции ссылочной идентичности. Если бы нужно было создать экземпляр ComplexClass для хранения произведения двух комплексных чисел, этот результат этого вычисления должен был бы храниться в памяти до следующей сборки мусора, даже если он больше ничему не нужен. Напротив, если один ComplexStruct, результаты старых вычислений могут быть напрямую перезаписаны результатами более новых. - person supercat; 19.09.2012
comment
Спасибо @supercat, который проясняет преимущества. Очень интересно. - person Wayne Uroda; 20.09.2012