Java floating point mathematics rules

Hello. Not sure if i’m writing to a correct category, those, who are moderating the forum, please feel free to move this topic to where it’s appropriate.

I want to discuss Java rules used to check the floating point operations. My case is: when i use direct comparison

(dValue == 0) ? 0 : (some / dValue);

or Double.equals() i get S1244, but when i use

(dValue < 0.00001 || dValue > -0.00001) ? 0 : (some / dValue);

or any other indirect and more smart comparisons like org.apache.commons.math3.util.Precision.equals() i get S3518.

I have no insights in the implementation of this rule, but the first thing I notice that this also returns 0.0 for negative values, is this intended?

true, both snippets are doing the same thing – trying to avoid division by zero, more or less effectively. but different comparison implementations are triggering different rules, so i guess at least one of them needs to be enhanced…

to be more clear, i’ll edit the second snippet with an additional check

there is a way to avoid an issue by moving calculations to a separate method like this:

    public double safeDivide(double numerator, double denominator, double tolerance) {
        return (Math.abs(denominator) < tolerance) ? 0 : (numerator / denominator);
    }

and invoking this method where rules are triggered. But it’s not a compliant solution…

Hi Ivan,

I looked at the example that you provided, but could not reproduce S3518. Are you sure that the condition is correct? dValue < 0.00001 || dValue > -0.00001 looks like a condition that is always false, maybe you meant dValue < 0.00001 && dValue > -0.00001?

Hello, Tomasz. I think, that it actually doesn’t matter if it’s “and” or “or”, neither of them guarantee that dValue won’t be zero. Could it be a SonarQube for IDE issue to trigger a rule violation?

SonarQube for IDE 10.14.0.80203 (Intellij IDEA)

Could you please share a complete method that reproduces the issue? The problem appears similar to what’s described in the following ticket, but I am not certain if it is the same: JAVASE-20.

As i mentioned in Java floating point mathematics rules - #5 by ivan-igorevich if i do it in a separate method, the rule is not triggered.

but when i do it in more complex method (which i cannot put here uncensored) i get an S3518. It is triggered on line 331.

Thank you for the additional info! Unfortunately, I will not be able to create a ticket without an example reproducing the issue.

2 Likes

Good evening, community, found some time to extract the logic that false positively triggers S3518

package org.example;

public class Main {
    private static final double DIV_EPSILON = 1e-9;
    /**
     * Division rules sample.
     *
     * @return some nice divided double value
     * */
    private static double complexDivide(final double[] times) {
        double sumOk = 0.0;
        double diffOk = 0.0;

        for (int t = 0; t < times.length; t++) {
            if (t % 2 == 0) {
                sumOk += times[t];
                diffOk++;
            }
        }

        return (diffOk < DIV_EPSILON && diffOk > -DIV_EPSILON) ? 0.0 : (sumOk / diffOk);
    }

    public static void main(String[] args) {
        double d = complexDivide(new double[]{1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1});
        System.out.println(d);
        d = complexDivide(new double[]{1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 8});
        System.out.println(d);
    }
}
1 Like

Thank you for the reproducer! I created JAVASE-21 for this issue.

1 Like