Android (big) fail on float values product

2020-08-04 10:52发布

问题:

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: 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.

回答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.



回答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.



回答3:

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



回答4:

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.