0

the situation is drammatic... It's 5 days that i must resolve this problem and i can't get out.

The problem: a simple operation as a product make always wrong result. Why?

Extract of the code:

//all vars are float
// resultVec is a vector [3]
// Rs is a vector [3]
// accelerationvalues is a vector [3]
   resultVec[0]=Rs[0]*accelerationvalues[0]+Rs[1]*accelerationvalues[1]+Rs[2]*accelerationvalues[2];

//debug to print result

Log.d("e", "("+Rs[0]+")*("+accelerationvalues[0]+")+("+Rs[1]+")*("+accelerationvalues[1]+")+("+Rs[2]+")*("+accelerationvalues[2]+")="+(resultVec[0]));

And this is the Log Cat result: enter image description here But you can simply try that this is wrong: search on google

(0.040147018)*(-0.9942854)+(0.9984244)*(-0.32688835)+(0.039202508)*(9.343558)

And you'll find that the true result is 8.67678679 × 10-9 that is very different from the other..This error is repeated always i execute the programm, some time the difference is in the sign too!

What is the problem?

I've tried all the way to solve it! (some are posted below):

You can find the full source here.

  1. save Rs and accelerationvalues in an arraylist and perform calculation outside the listner. No result.
  2. Convert float to double, no result.
  3. Many others ways

P.S. This problem occour only for resultVec[0] and resultVec[1], instead resultVec[2] is well calculated.

Community
  • 1
  • 1
Lork
  • 889
  • 3
  • 12
  • 24
  • 2
    How much do you understand about binary floating point? In particular, if you were using `float` then are you aware that only has a precision of 7 significant digits? – Jon Skeet Nov 07 '11 at 11:07
  • How did you convert float to double? – Max Nov 07 '11 at 11:10
  • Tell me: why the error occours only for `resultVec[0]` and `resultVec[1]` but NEVER for `resultVec[2]`? – Lork Nov 07 '11 at 11:11
  • @Max Here there is no conversion, but in older tests, i used `(double) var` for conversion, isn't ok? check also my prew comment – Lork Nov 07 '11 at 11:13
  • 1
    @Lork: you cannot simply look at two floating-points results (for example the one in your log and the one from Google?) and decide *"they're wrong"*. That's simply not of floating-point results are compared. You need to compare them using an *epsilon*. When taking into account the error propagation and when using the correct epsilon, you may very well find out that the two results are actually identical. *(I'm not saying they are in this case, but your methodology is wrong for sure)* – TacticalCoder Nov 07 '11 at 11:46
  • 1
    I'm pretty sure the true result is 8.676786 **80** E-9. But such a small error probably won't make a difference. – Ishtar Nov 07 '11 at 11:46

4 Answers4

2

you're multiplying floating point numbers, accumulating rounding errors all the way down. Using double-precision won't solve the underlying issue, which is that binary computers cannot accurately represent decimal floating point numbers.

Read this: http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html for an overview of the problem.

You'll likely find you need to perform the calculations using the BigDecimal class.

mcfinnigan
  • 11,442
  • 35
  • 28
  • 3
    Great link there: Goldberg's paper is one of my favorite ; ) But I don't agree that he should likely perform the calculations using the BigDecimal class. People have been writing (and keep writing) games (both on older machines and on mobile devices) by either using float/double computations and correctly keeping track of error propagation or by using "integer math". Creating lots of BigDecimal objects (up to 60 times a second times up to hundreds of little objects on the screen times all the computation needed) is a sure way to kill an app's perfs. – TacticalCoder Nov 07 '11 at 11:42
  • Agreed, BigDecimal is using a hammer to squash a snail, but without any further context to what OP is doing and his obvious unfamiliarity with FP, it could be the best option. On another note, I think all new programmers should be grabbed by the scruff of the neck and be made to read the above paper :-) – mcfinnigan Nov 07 '11 at 11:52
1

This is not android's fault, it is how you designed the app.

Execute this in a plain Java application:

public class ArithmTest {

    public static void main(String[] args) {
        double d1 = (0.040147018)*(-0.9942854)+(0.9984244)*(-0.32688835)+(0.039202508)*(9.343558);
        System.out.println(d1);

        float f1 = 0.040147018f;
        float f2 = -0.9942854f;

        float f3 = 0.9984244f;
        float f4 = -0.32688835f;

        float f5 = 0.039202508f;
        float f6 = 9.343558f;

        System.out.println(f1*f2 + f3*f4 + f5*f6);

    }
}

As you can see, the first one is the same as Google's, and the second printout is your app's value. To solve this, I think you should use double instead of float in every variable you declared, e.g.: accelerationvalues and resultVec.

Mister Smith
  • 27,417
  • 21
  • 110
  • 193
0

I think that you should to use double type instead of float

Max
  • 2,293
  • 5
  • 32
  • 48
0

You might be running into the limited precision of floating point values. In order to confirm this you can change the float into double or use BigDecimal.

Thirler
  • 20,239
  • 14
  • 63
  • 92