# Number equality / abstraction from precision and representation

I try to have find solution to get away from these heavy problems of number comparisons in Java... at least for numbers in a certain range with a certain precision with certain representation error.

The task is to implement an equality check for numbers that are implementing the Number-interface of the java.lang package. Here again: I would restrict the equality check to the obvious types: byte, short, integer, long, float, double and their object equivalents. Of course BigInteger and BigDecimal should be handled as well.

My first idea was to normalize all numbers to a double value. I came up with following:

``````public class MyNumber {

private double raw;

public MyNumber(Number raw) {
this.raw = Double.parseDouble(raw.toString());
}

@Override
public int hashCode() {
return new Double(this.raw).hashCode();
}

@Override
public boolean equals(Object obj) {

if (obj instanceof MyNumber) {

MyNumber that = (MyNumber) obj;

return Double.toString(that.raw).equals(Double.toString(this.raw));

}

return false;
}

}
``````

I do not search for fancy all covering solution. A solution that keeps me away from the technical explainable but semantic nonsense of...

``````    BigDecimal x = new BigDecimal("1");
BigDecimal y = new BigDecimal("1.00");
Assert.assertFalse(x.equals(y));
``````

I wrote some test cases to show what I mean:

``````public class TestMyNumber {

/**
* Small numbers are equal if they are semantically equal.
*/
@Test
public void test1() {

MyNumber myNumber1 = new MyNumber(0.000000000000001f);
MyNumber myNumber2 = new MyNumber(new BigDecimal("0.000000000000001"));

Assert.assertEquals(myNumber1, myNumber2);

}

/**
* Big numbers are seen as equal if they are semantically equal.
*/
@Test
public void test3() {

MyNumber myNumber1 = new MyNumber(999999999999999.9);
MyNumber myNumber2 = new MyNumber(new BigDecimal("999999999999999.9"));

Assert.assertEquals(myNumber1, myNumber2);

}

/**
* Big numbers are seen as equal if they are semantically equal.
*/
@Test
public void test4() {

MyNumber myNumber1 = new MyNumber(999999999999999.0);
MyNumber myNumber2 = new MyNumber(999999999999999l);

Assert.assertEquals(myNumber1, myNumber2);

}

/**
* Really big numbers are equal. Error is acceptable.
*/
@Test
public void test5() {

MyNumber myNumber1 = new MyNumber(544785684365874268756.1);
MyNumber myNumber2 = new MyNumber(new BigDecimal("544785684365874268756.9"));

Assert.assertEquals(myNumber1, myNumber2);

}

}
``````

My primary goal is to abstract from precision and representation. At least within a range. Speed is nothing I currently care about.

Do you have any hints to achieve this abstraction?

Next Approach:

``````public class MyNumber {

private BigDecimal raw;

public MyNumber(Number raw) {
this.raw = new BigDecimal(Double.parseDouble(raw.toString())).stripTrailingZeros();
}

@Override
public int hashCode() {
return this.raw.hashCode();
}

@Override
public boolean equals(Object obj) {

if (obj instanceof MyNumber) {

MyNumber that = (MyNumber) obj;

return that.raw.equals(this.raw);

}

return false;
}

}
``````

Notes:

Semantically equal numbers are numbers that you can exchange in any operation you want and you do not know if they were exchanged at all because the result remains the same. The point is: 2 is equal to 2.0 is equal to 2.000000000.

MyNumbers will never be a result of an operation only an input parameter.

A Number should be able to be checked for equality. I don't want to care about the technical representation.

• I believe that "abstraction" does not usually mean "introduce significant errors before doing anything". `MyNumber` does a double conversion, from Number to string to Double, going from base N to base 10 to base 2. Do you understand how much error that introduces into your numbers? Can you quantify it? Can you quantify the term "semantically equal"? Dec 6, 2016 at 22:40
• A couple of initial reactions. First, all the integer types are trivial, right? Convert to long and compare. Am I misunderstanding something? As for the floating points, why do you want 24 digits of precision? Not much in the universe has that much precision. Dec 7, 2016 at 0:41
• So you want to store a `BigDecimal` into a `double` ? Dec 7, 2016 at 7:40
• No. I have to deal with an arbitrary input type of "Number". Dec 7, 2016 at 7:45
• Comparing floats is not a good idea at all. They can differ in their mantissa when having a high negative exponent. You should check Python for its bignum implementation.
– user188153
Dec 7, 2016 at 8:18

It's not possible to normalize all Numbers to a binary floating point value.

Numbers are a more complicated issue than you seem to recognize. It's not only about "Java having heavy problems", although handling numbers in Java is cumbersome.

There's a variety of fundamentally different types of numbers: integers, decimal numbers, floating point numbers, fractions, real numbers, complex numbers etc. Some numbers of different types are not mathematically compatible with each other. For instance, there's no an integer representation for the decimal number 0.1. There's no binary floating point representation for it either.

It's strictly not possible to write an equals method for any two Numbers of possibly different types. That's because the class Number doesn't contain any functionality or contract for checking equality. Anyone can subclass it with any custom definition of equality for objects of that particular subclass.

However, it's possible to write a method that's capable of comparing every Number that Java currently provides. For that purpose you could normalize the Numbers to BigDecimals and then use the compareTo-method of the BigDecimal class. It's not very efficient but it should work.

• @oopexpert As COME FROM says, numbers are a more complicated issue than you think they are. For example, did you know that for the number A=9,223,372,036,854,775,805, `long(A) != long(A+1)` but `double(A) == double(A+1)` because double starts to lose precision on such large numbers? I'd recommend reading some of the work on floating point comparisons (such as that done by Knuth) to realize what a minefield numbers can be. Dec 7, 2016 at 20:28