Как программировать арифметику на общих объектах, которые становятся определены только позже? - PullRequest
0 голосов
/ 13 декабря 2018

Я хочу запрограммировать арифметику для объектов, которые могут иметь различную природу и быть определены позже (действительное число, комплексные числа, матрицы, ...).Как только арифметика будет реализована, я все еще могу добавлять новые типы.Общей особенностью является то, что все они характеризуются набором действительных чисел (double []), но реализация для сложения, умножения и т. Д. Отличается.

Я связал определение interface:

interface GeneralNumber
{
    void set(double[] z)
    double element(int i);
    GeneralNumber addition(GeneralNumber a, GeneralNumber b);
}

Тогда:

public class ComplexNumber implements GeneralNumber
{
    double[] k;

    @Override
    public void set(double[] z)
    {
        k[0]=z[0];
        k[1]=z[1];
    }

    @Override
    public double element(int i)
    {
        return k[i];
    }

    @Override
    GeneralNumber addition(GeneralNumber a, GeneralNumber b)
    {
        double aR = a.element(0);
        double aI = a.element(1);

        double bR = b.element(0);
        double bI = b.element(1);

        double[] c = {aR+bR,aI+bI};

        GeneralNumber result = new ComplexNumber();
        result.set(c);

        return result;
    }

В третьем классе, когда я программирую некоторые алгебраические операции на GeneralNumber, я сталкиваюсь с проблемами.Представьте себе, что в третьем классе я вызываю метод computeSomething с ComplexNumber объектами (поэтому информация tpye там есть ) и пытается сделать что-то подобное (что не работает)

GeneralNumber computeSomething(GeneralNumber a, GeneralNumber b)
{
    GeneralNumber c = GeneralNumber.addition(a,b)
    ....
}

Я бы хотел, чтобы Java распознала входные данные как ComplexNumber и использовала метод addition из ComplexNumber, как если бы это был статический метод.

Иглы говорят, чтоЯ не могу создать новые GeneralNumber экземпляры, потому что Java не знает, какой из них (я могу только попытаться клонировать существующие GeneralNumbers и затем работать с ними ..).Должен быть какой-то элегантный способ ... Например, я могу захотеть сделать что-то вроде

GeneralNumber unity = new GeneralNumber.generateFromDouble(1.0);

, потому что 1.0 (или, как правило, действительное число) очень часто можно легко обобщить для более общего объекта единства (единичная матрица, матрица с числом по диагонали и т. д.).Ясно, что «тип» «GeneralNumber» должен где-то появляться ... но где, чтобы весь подход был элегантным?Быть хорошей практикой?

Я пытался использовать абстрактный класс, но дела обстоят не лучше, я все же сталкиваюсь в основном с теми же проблемами.При попытке работать с GeneralNumber в computeSomething я не могу использовать static:

GeneralNumber.addition(a,b)

В GeneralNumber это не реализовано, а в ComplexNumber это не может быть static.

Может быть, здесь помогут дженерики Java ... Я размышлял, не найдя решения.

Вопрос очевиден:

Как программировать арифметику, которая подходит для разных объектов, каждый объект (тип) реализует свою собственную версию операции (например, сложение, умножение) по-своемукоторый выглядит как static?

Ответы [ 3 ]

0 голосов
/ 13 декабря 2018

Поскольку вы только добавляете числа одного и того же типа, безопасно реализовать generalNumber addition(generalNumber b); Внутри него будет использоваться this как a из исходной функции

И использование будет выглядеть следующим образом:

generalNumber computeSomething(generalNumber a, generalNumber b)
    {
       generalNumber c = a.addition(b); // now c is a + b
       .... 
       return c;
    }
0 голосов
/ 13 декабря 2018

Основными арифметическими операциями являются сложение, вычитание, умножение и деление.И это по сути алгебраические операции .Это означает, что они являются операциями над алгебраической структурой, и эта структура по сути то, что вы пытались смоделировать с помощью вашего интерфейса.В частности, структура, которая вам нужна для этих операций, представляет собой Поле .

. Уже есть библиотеки, которые моделируют Field класс и дают представление о том, насколько сложноэто может быть, если вы пытаетесь сделать это right .В самом чистом смысле не существует такого понятия, как «вычитание», а только добавление обратного элемента .Точно так же деление - это умножение на мультипликативное обратное , где 0,0 - нечетный случай, когда такого элемента не существует.Уч.

Точная семантика таких методов, как double element_i(int i);, должна быть указана.Конечно, это имеет смысл для комплексных чисел, но не для всех возможных реализаций.

A очень упрощенный эскиз возможного GeneralNumber интерфейса и одна реализация показана здесь:

class Arithmetic
{
    static <T> GeneralNumber<T> computeSomething(
        GeneralNumber<T> a, GeneralNumber<T> b)
    {
        GeneralNumber<T> c = a.add(b);             // c      = a + b
        GeneralNumber<T> d = c.additiveInverse();  // d      = -c
        GeneralNumber<T> result = c.multiply(d);   // result = c * d
        return result;
    }
}

interface GeneralNumber<T>
{
    T get();

    GeneralNumber<T> add(GeneralNumber<T> a);
    GeneralNumber<T> additiveInverse();
    GeneralNumber<T> additiveNeutral();

    GeneralNumber<T> multiply(GeneralNumber<T> a);
    GeneralNumber<T> multiplicativeInverse();
    GeneralNumber<T> multiplicativeNeutral();
}

class GeneralDoubleNumber implements GeneralNumber<Double>
{
    static GeneralDoubleNumber of(double d)
    {
        return new GeneralDoubleNumber(d);
    }

    private final double value;
    public GeneralDoubleNumber(double d)
    {
        this.value = d;
    }

    @Override
    public Double get()
    {
        return value;
    }

    @Override
    public GeneralNumber<Double> add(GeneralNumber<Double> a)
    {
        return of(get() + a.get());
    }

    @Override
    public GeneralNumber<Double> additiveInverse()
    {
        return of(-get());
    }

    @Override
    public GeneralNumber<Double> additiveNeutral()
    {
        return of(0.0);
    }

    @Override
    public GeneralNumber<Double> multiply(GeneralNumber<Double> a)
    {
        return of(get() * a.get());
    }

    @Override
    public GeneralNumber<Double> multiplicativeInverse()
    {
        return of(1.0 / get());
    }

    @Override
    public GeneralNumber<Double> multiplicativeNeutral()
    {
        return of(1.0);
    }

}

Но учтите, что в некоторых случаях имеет смысл вытягивать операции из структур, над которыми они работают.И имейте в виду, что сложность всего этого имеет тенденцию выходить из-под контроля, если учесть тот факт, что арифметические операции могут изменять область .Разница между Instant и Instant должна быть не Instant, а Duration ...

0 голосов
/ 13 декабря 2018

Может быть что-то вроде:

import java.util.Arrays;
interface generalNumber {
    void set(double[] z);
    double element_i(int i);
    generalNumber addition(generalNumber a);
    static generalNumber addition(generalNumber a,generalNumber b) {
        return a.addition(b);
    }
}
class complexNumber implements generalNumber {
    double[] k;
    @Override public void set(double[] z) {
        k=new double[2];
        k[0]=z[0];
        k[1]=z[1];
    }
    @Override public double element_i(int i) {
        return k[i];
    }
    @Override public generalNumber addition(generalNumber a) {
        if(!(a instanceof complexNumber)) throw new RuntimeException(a+" is not a "+getClass().getName());
        double aR=this.element_i(0);
        double aI=this.element_i(1);
        double bR=a.element_i(0);
        double bI=a.element_i(1);
        double[] c= {aR+bR,aI+bI};
        generalNumber result=new complexNumber();
        result.set(c);
        return result;
    }
    @Override public String toString() {
        return "complexNumber [k="+Arrays.toString(k)+"]";
    }
}
class copyOfComplexNumber implements generalNumber {
    double[] k;
    @Override public void set(double[] z) {
        k=new double[2];
        k[0]=z[0];
        k[1]=z[1];
    }
    @Override public double element_i(int i) {
        return k[i];
    }
    @Override public generalNumber addition(generalNumber a) {
        if(!(a instanceof copyOfComplexNumber)) throw new RuntimeException(a+" is not a "+getClass().getName());
        double aR=this.element_i(0);
        double aI=this.element_i(1);
        double bR=a.element_i(0);
        double bI=a.element_i(1);
        double[] c= {aR+bR,aI+bI};
        generalNumber result=new complexNumber();
        result.set(c);
        return result;
    }
    @Override public String toString() {
        return "copyOfComplexNumber [k="+Arrays.toString(k)+"]";
    }
}
public class So53765596_how_program_arithmetics_on_general_objects_which_become_defined_only_later {
    generalNumber computeSomething(generalNumber a,generalNumber b) {
        return generalNumber.addition(a,b);
    }
    public static void main(String[] args) {
        double[] a_=new double[] {1,2};
        double[] b_=new double[] {3,4};
        generalNumber a=new complexNumber();
        a.set(a_);
        generalNumber b=new complexNumber();
        b.set(b_);
        System.out.println(a+"+"+b+"="+generalNumber.addition(a,b));
        a=new copyOfComplexNumber();
        a.set(a_);
        b=new copyOfComplexNumber();
        b.set(b_);
        System.out.println(a+"+"+b+"="+generalNumber.addition(a,b));
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...