-2

I am not sure how to implement a comparable interface into my complex class. I have the following example code that I am using to try and get my head around it. I know it should be something like public double compareTo (Complex o) and something like that but I am not so sure on how to do it. Any suggestions on how i will implement it?:

import java.util.Scanner;

public class Complex implements Cloneable, Comparable {
    private double real;
    private double imag;

    /*
     * public Object clone() throws CloneNotSupportedException { Complex
     * objClone = new Complex(); objClone.setReal(this.real);
     * objClone.setImag(this.imag); return objClone; }
     */

    public Complex(double real, double imag) {
        this.real = real;
        this.imag = imag;
    }

    public Complex(double real) {
        this.real = real;
    }

    public Complex() {

    }

    public void setReal(double real) {
        this.real = real;
    }

    public void setImag(double imag) {
        this.imag = imag;
    }

    public double getReal() {
        return real;
    }

    public double getImag() {
        return imag;
    }

    public void add(Complex num1, Complex num2) {
        this.real = num1.real + num2.real;
        this.imag = num1.imag + num2.imag;

    }

    public Complex subtract(Complex num) {
        Complex a = this;
        double real = a.real - num.real;
        double imag = a.imag - num.imag;
        return new Complex(real, imag);
    }

    public Complex multiply(Complex num) {
        Complex a = this;
        double real = a.real * num.real - a.imag * num.imag;
        double imag = a.real * num.imag + a.imag * num.real;
        return new Complex(real, imag);
    }

    public Complex divide(Complex c1, Complex c2) {
        return new Complex((c1.real * c2.real + c1.imag * c2.imag) / (c2.real * c2.real + c2.imag * c2.imag),
                (c1.imag * c2.real - c1.real * c2.imag) / (c2.real * c2.real + c2.imag * c2.imag));
    }

    public double absolute() {
        return Math.sqrt(real * real + imag * imag);
    }

    public String toString() {
        return this.real + " + " + this.imag + "i";
    }

    @Override
    public Complex clone() throws CloneNotSupportedException {
        super.clone();
        return new Complex(real, imag);
    }

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        System.out.print("Enter the first set of complex numbers respectively: ");
        double a = in.nextDouble();
        double b = in.nextDouble();

        Complex c1 = new Complex(a, b);

        System.out.print("Enter the second set of complex numbers respectively: ");
        double c = in.nextDouble();
        double d = in.nextDouble();

        Complex c2 = new Complex(c, d);

        Complex result = new Complex(c, d);
        result.add(c1, c2);

        System.out.println("(" + a + " + " + b + "i) + (" + c + " + " + d + "i) = " + result.toString());
        System.out.println("(" + a + " + " + b + "i) - (" + c + " + " + d + "i) = " + c1.subtract(c2));
        System.out.println("(" + a + " + " + b + "i) * (" + c + " + " + d + "i) = " + c1.multiply(c2));
        System.out.println("(" + a + " + " + b + "i) / (" + c + " + " + d + "i) = " + result.divide(c1, c2).toString());
        System.out.println("|" + a + " + " + b + "i| = " + c1.absolute());

    }

    public double compareTo(Complex other) {

        return this.getReal() - other.getReal();
    }

}
Mureinik
  • 297,002
  • 52
  • 306
  • 350
Kamal
  • 37
  • 2
  • 10
  • Your compareTo method should return double, but you return Complex object. – solomkinmv Mar 12 '16 at 12:17
  • @TheStigger shouldn't it return int? – SOFe Mar 12 '16 at 12:20
  • You can't compare Complex numbers (in Maths). But you can compare by your rules. Like compare only by real part. Or by absolute value. Link: http://www.cut-the-knot.org/do_you_know/complex_compare.shtml – solomkinmv Mar 12 '16 at 12:21
  • Side note: do **not** use a static main to test your code. Write unit tests! Having code sitting there that points numbers as strings ... makes it so easy to miss subtle implementation errors. Instead: write unit tests. There you specify (ideally before you implement the actual function) the expected results of operations. When the tests pass, you can be sure that you got the expected results. And you can be sure that any change ... that doesn't break the unit tests is OK. Believe me: using Junit trumpets a static main in almost all situations by far! – GhostCat Mar 12 '16 at 12:27

3 Answers3

2

First, the compareTo method of Comparator interface returns int, not double. Second, if you want to compare two double values in Comparator, you should never use a - b pattern. Instead, use predefined Double.compare method:

public int compareTo(Complex other) {
    return Double.compare(this.getReal(), other.getReal());
}

This method carefully handles all the special values like -0.0 or NaN which are not very easy to handle manually. Note that similar methods exist for other types: Integer.compare, Long.compare and so on. It's preferred to use them.

Of course it should be noted that there's no natural order for complex numbers. Here you just compare the real parts, completely ignoring the imaginary parts.

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
2

From a mathematical standpoint, Complex numbers can't be ordered, and as such aren't a good fit for the the Comparable interface. To quote the wikipedia article:

Because complex numbers are naturally thought of as existing on a two-dimensional plane, there is no natural linear ordering on the set of complex numbers.
There is no linear ordering on the complex numbers that is compatible with addition and multiplication. Formally, we say that the complex numbers cannot have the structure of an ordered field. This is because any square in an ordered field is at least 0, but i2 = −1.

Having said that, there's nothing technically stopping you from implementing this interface. E.g., you can decide that you are sorting by the real part first and by the imaginary part second. Note that the contract of the compareTo method requires you to return an int, not a double. Also, you should define your class as extending Comparable<Complex> instead of a raw Comparable, so you don't have to mess around with casting and runtime type checking:

@Override
public int compareTo(Complex other) {
    int realCompare = Double.compare(getReal(), other.getReal());
    if (realCompare != 0) {
        return realCompare;
    }
    return = Double.compare(getImag(), other.getImag()); 
}

EDIT:
The improvements in JDK 8's Comparator interface allow for a much more elegant implementation with the same behavior:

public int compareTo(Complex other) {
    return Comparator.comparingDouble(Complex::getReal)
                     .thenComparingDouble(Complex::getImag)
                     .compare(this, other);
}
Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • 1
    Would you mind using `Object` as a parameter and cast it within the method. Otherwise the override isn't legal. – Yassin Hajaj Mar 12 '16 at 12:27
  • 1
    @YassinHajaj Thanks for noticing! The proper way to do this in modern java would be to extend `Comparable` instead of just `Comparable`. I've added a note to my answer. – Mureinik Mar 12 '16 at 12:30
  • 1
    I have to thank you because I did not know that :). – Yassin Hajaj Mar 12 '16 at 12:31
1

A few points worth noting.

  1. As other answers have noted you generally should only implement Comparable if there's a natural ordering for instances of the class. As there's no natural ordering for complex numbers you likely shouldn't implement Comparable.

  2. If you are going to provide a natural ordering then you should implement Comparable<Complex> to denote comparing to other instances of Complex (rather than comparing to other objects).

  3. A better alternative to implementing Comparable is to provide one or more Comparator objects for your class that can be used to provide as many orderings as you want. For example:

    public class Complex {
        private double real;
        private double imaginary;
    
        public static final Comparator<Complex> COMPARE_BY_REAL =
            Comparator.comparingDouble(Complex::getReal);
    
        public static final Comparator<Complex> COMPARE_BY_IMAGINARY =
            Comparator.comparingDouble(Complex::getImaginary);
    
        public static final Comparator<Complex> COMPARE_BY_MODULUS =
            Comparator.comparingDouble(Complex::getModulus);
    
        private double getModulus() {
            return Math.sqrt(real * real + imaginary * imaginary);
        }
     }
    

Then the user of the class can choose the ordering that makes sense to the use:

Optional<Complex> closestToOrigin = complexList.stream().min(Complex::COMPARE_BY_MODULUS);
sprinter
  • 27,148
  • 6
  • 47
  • 78