1

Code: My original large code had such a problem, so I broke it down into the below smallest code sample:

public class test {
    static double precision = 2;

    public static void main(String[] args) {
        for (; precision < 100; precision++) {
            int PI = (int) Math.round(Math.PI * precision);

            double x1 = makePrecise(Math.PI / 2), x2 = makePrecise(PI / precision - Math.PI / 2);

            if (x1 == x2)
                System.out.println(precision + "\t" + x1 + "\t" + PI / precision + "\t" + (x1 + x2));
            else
            System.out.println(precision + "\t" + x1 + "\t" + x2 + "\t" + PI / precision + "\t" + (x1 + x2));
        }
    }

    static double makePrecise(double num) {
        return Math.round(num * precision) / precision;
    }
}

My problem:

I do not understand why x1 == x2 only at some specific values of precision. Either they should be equal at all values of precision, or the values at which they are equal should follow a trend. Unfortunately, as you can see below, there is really no trend here. At lower values of precision, it's like +3/+2/+2/+3/+2/+2/... but at higher precision values it's like +1/+2/+2/+2/+1/+2/+2/+2/+1.... I do not exactly understand the underlying working here.

Please explain exactly why such a output is generated, especially since there doesn't seem to be any trend in it.


Output for x1==x2: (for reference)

2.0 1.5 3.0 3.0
5.0 1.6 3.2 3.2
7.0 1.5714285714285714  3.142857142857143   3.142857142857143
9.0 1.5555555555555556  3.111111111111111   3.111111111111111
12.0    1.5833333333333333  3.1666666666666665  3.1666666666666665
14.0    1.5714285714285714  3.142857142857143   3.142857142857143
16.0    1.5625  3.125   3.125
19.0    1.5789473684210527  3.1578947368421053  3.1578947368421053
21.0    1.5714285714285714  3.142857142857143   3.142857142857143
[rows deleted to avoid bloat]
79.0    1.5696202531645569  3.1392405063291138  3.1392405063291138
81.0    1.5679012345679013  3.1358024691358026  3.1358024691358026
82.0    1.5731707317073171  3.1463414634146343  3.1463414634146343
84.0    1.5714285714285714  3.142857142857143   3.142857142857143
86.0    1.569767441860465   3.13953488372093    3.13953488372093
88.0    1.5681818181818181  3.1363636363636362  3.1363636363636362
89.0    1.5730337078651686  3.146067415730337   3.146067415730337
91.0    1.5714285714285714  3.142857142857143   3.142857142857143
93.0    1.5698924731182795  3.139784946236559   3.139784946236559
95.0    1.568421052631579   3.136842105263158   3.136842105263158
96.0    1.5729166666666667  3.1458333333333335  3.1458333333333335
98.0    1.5714285714285714  3.142857142857143   3.142857142857143

Output for x1 != x2

3.0 1.6666666666666667  1.3333333333333333  3.0 3.0
4.0 1.5 1.75    3.25    3.25
6.0 1.5 1.6666666666666667  3.1666666666666665  3.166666666666667
8.0 1.625   1.5 3.125   3.125
10.0    1.6 1.5 3.1 3.1
11.0    1.5454545454545454  1.6363636363636365  3.1818181818181817  3.1818181818181817
13.0    1.5384615384615385  1.6153846153846154  3.1538461538461537  3.153846153846154
15.0    1.6 1.5333333333333334  3.1333333333333333  3.1333333333333337
17.0    1.588235294117647   1.5294117647058822  3.1176470588235294  3.117647058823529
18.0    1.5555555555555556  1.6111111111111112  3.1666666666666665  3.166666666666667
20.0    1.55    1.6 3.15    3.1500000000000004
22.0    1.5909090909090908  1.5454545454545454  3.1363636363636362  3.1363636363636362
[rows deleted to avoid bloat]
78.0    1.5769230769230769  1.564102564102564   3.141025641025641   3.141025641025641
80.0    1.575   1.5625  3.1375  3.1375
83.0    1.5662650602409638  1.5783132530120483  3.144578313253012   3.144578313253012
85.0    1.576470588235294   1.5647058823529412  3.1411764705882352  3.1411764705882352
87.0    1.5747126436781609  1.5632183908045978  3.1379310344827585  3.137931034482759
90.0    1.5666666666666667  1.5777777777777777  3.1444444444444444  3.1444444444444444
92.0    1.576086956521739   1.565217391304348   3.141304347826087   3.141304347826087
94.0    1.574468085106383   1.5638297872340425  3.1382978723404253  3.1382978723404253
97.0    1.5670103092783505  1.577319587628866   3.1443298969072164  3.1443298969072164
99.0    1.5757575757575757  1.5656565656565657  3.1414141414141414  3.1414141414141414

Complete output


PS: As you can see in both the outputs, x1+x2==PI always. So, the only floating-point arithmetic that I ever did in this code ((PI / precision - Math.PI / 2)) is indeed not broken. Hence, my question is not a duplicate of Is floating point math broken?

Gaurang Tandon
  • 6,504
  • 11
  • 47
  • 84
  • 1
    Possible duplicate of [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Joe C Jan 13 '18 at 11:37
  • @JoeC By just marking this a duplicate you haven't really explained how my query got explained there. I think I posted a very pointed question and without your explanation I can't see the connection between this and that question. – Gaurang Tandon Jan 13 '18 at 11:40
  • Then you should [edit] your question to explain precisely why it is not a duplicate. It might help, for example, to show those values of `precision` where the outputs do not match, and what these differences are. – Joe C Jan 13 '18 at 11:44
  • @JoeC Please have a look i edited it. – Gaurang Tandon Jan 13 '18 at 11:52
  • And I have retracted my duplicate vote. However, having quickly done the maths myself, I'm slightly puzzled why you expect `x1 == x2` on, for example, `precision = 3`. The values I'm getting are precisely what your output is displaying. – Joe C Jan 13 '18 at 11:57
  • @JoeC Well that _is_ my question. Why is `x1==x2` at some values, and not equal at others? `x1!=x2` at `precision=3`, as you correctly pointed out, but then `x1!=x2` at `precision=9,27,81` all of whom are only the powers of 3. – Gaurang Tandon Jan 13 '18 at 11:59
  • I will answer your question to explain why they are different for `precision = 3`. If the question is "what is the pattern?", then that question is off-topic for Stack Overflow as it's really a maths question and not a programming one. – Joe C Jan 13 '18 at 12:08
  • @JoeC " then that question is off-topic for Stack Overflow as it's really a maths question" Yes I thought about that. But, if I post this on MSE it'll get closed for presence of code anyway. Moreover, several coding questions ask for algorithms which are basically only mathematics. I think at such a cross-junction of math and code, it is better to leave the question open. – Gaurang Tandon Jan 13 '18 at 12:13
  • Comparing floating point numbers with `==` is unreliable. The answers to the question linked in the first comment explains why. – Code-Apprentice Jan 13 '18 at 12:16
  • @Code-Apprentice The linked question compares `0.1 + 0.2 == 0.3` which is indeed a floating point problem as `0.1 + 0.2` gives `0.30000000000000004`. But, as you can see in the output I attached, `x1` and `x2` have pretty significant differences (at `precision=15.0, x1=1.6, x2=1.5333333333333334`) so I don't think that linked question is valid in this case. – Gaurang Tandon Jan 13 '18 at 12:19

1 Answers1

1

Doing the maths for precision = 3:

PI = Math.round(3.14 * 3) 
   = Math.round(9.42) 
   = 9
x1 = Math.round(3.14 / 2 * 3) / 3 
   = Math.round(1.57 * 3) / 3 
   = Math.round(4.71) / 3 
   = 5/3
x2 = Math.round((9 / 3 - 3.14 / 2) * 3) / 3 
   = Math.round((3 - 1.57) * 3) / 3 
   = Math.round(1.43 * 3) / 3 
   = Math.round(4.29) / 3 
   = 4/3
Joe C
  • 15,324
  • 8
  • 38
  • 50