0

This is a Java code that should test whether the first three digits after the decimal point are identical. And I need to write this program without a main method.

public class areEqualByThreeDecimalPlaces {
    public static boolean areEqualByThreeDecimalPlaces(double d_1, double d_2) {
        double value_1 = Math.round(1000*d_1);
        double value_2 = Math.round(1000*d_2);

        if (value_1 == value_2) {
            return true;
        } else return false;
    }
}

Input:

(-3.1756, -3.175)

Expected Output:

true

Output received:

false

By using the Math.round it is rounding the value of -3.1756 to -3.176. But I want to check if the three digits after the decimal point are similar.

How do I correct my code?

ThisaruG
  • 3,222
  • 7
  • 38
  • 60
  • 2
    If I understand correctly, you want to _truncate_ both doubles to three decimal places? – Slaw Dec 04 '21 at 09:52

3 Answers3

1

Going off this code the two values just won't be equal. value_1 = -3176.0 value_2 = -3175.0

If you want to learn a little more about truncating doubles, take a look at this. How can I truncate a double to only two decimal places in Java?

Dharman
  • 30,962
  • 25
  • 85
  • 135
Tom
  • 11
  • 5
0

You could to use ceil instead of round

double value_1 = Math.ceil(d_1 * 1000);
double value_2 = Math.ceil(d_2 * 1000);

EDIT

Thanks to Alex Rudenko's comment, I realized that the correct solution would be using ceil for negative numbers and floor for positive numbers

double value_1 = d_1 < 0 ? Math.ceil(d_1 * 1000) : Math.floor(d_1 * 1000);
double value_2 = d_2 < 0 ? Math.ceil(d_2 * 1000) : Math.floor(d_2 * 1000);

Fabio

Fabio Scagliola
  • 338
  • 2
  • 11
  • 1
    This is a quick and incorrect solution: `Math.ceil` would work for a narrow case of negative inputs, for positive inputs `Math.floor` would be needed, so the sign should be taken into account. And anyway this does not compare _3 digits in the fractional part_. – Nowhere Man Dec 04 '21 at 22:10
  • Thank you for your remark, @AlexRudenko. Now that you make me think about it, the correct solution would be using `Math.ceil` for negative numbers and `Math.floor` for positive numbers. I will edit my answer accordingly – Fabio Scagliola Dec 05 '21 at 09:43
0

The code to check if the first three digits after the decimal point are identical should just truncate the integer part and keep only the digits in the fractional part by subtracting initial integer part.

Also, it may be needed to use Math.abs or Math.sign to compare the values retrieved from positive and negative inputs:
areEqualByThreeDecimalPlaces(3.1751, -3.1758) == true.

And the last thing: in order to avoid integer overflow for large inputs when multiplying by 1000 it's better to use long.

So the example implementation may look like this:

public static boolean areEqualByThreeDecimalPlaces(double d1, double d2) {
    long value1 = Math.abs((long) (d1 * 1000L) - (long) d1 * 1000L); 
    long value2 = Math.abs((long) (d2 * 1000L) - (long) d2 * 1000L);

    System.out.print(value1 + " == " + value2 + " ? ");
    return value1 == value2;
}

or using a lambda for DoubleToLongFunction:

public static boolean areEqualByThreeDecimalPlaces(double d1, double d2) {
    DoubleToLongFunction f = (d) -> Math.abs((long) (d * 1000L) - (long) d * 1000L);

    return f.applyAsLong(d1) == f.applyAsLong(d2);
}

Tests:

System.out.println(areEqualByThreeDecimalPlaces(-3.175, -3.1752));
System.out.println(areEqualByThreeDecimalPlaces(3.175, 3.1752));
System.out.println(areEqualByThreeDecimalPlaces(3.1751, -3.1758));
System.out.println(areEqualByThreeDecimalPlaces(5_123_456_789.123987, -90_123_456_789.123456));

Output:

175 == 175 ? true
175 == 175 ? true
175 == 175 ? true
123 == 123 ? true
Nowhere Man
  • 19,170
  • 9
  • 17
  • 42