Right now I have a line of code like this:

float x = (([self.machine micSensitivity] - 0.0075f) / 0.00025f);

Where [self.machine micSensitivity] is a float containing the value 0.010000

So,

0.01 - 0.0075 = 0.0025
0.0025 / 0.00025 = 10.0

But in this case, it keeps returning 9.999999

I'm assuming there's some kind of rounding error but I can't seem to find a clean way of fixing it. micSensitivity is incremented/decremented by 0.00025 and that formula is meant to return a clean integer value for the user to reference so I'd rather get the programming right than just adding 0.000000000001.

Thanks.

有帮助吗?

解决方案

that formula is meant to return a clean integer value for the user to reference

If that is really important to you, then why do you not multiply all the numbers in this story by 10000, coerce to int, and do integer arithmetic?

Or, if you know that the answer is arbitrarily close to an integer, round to that integer and present it.

其他提示

Floating-point arithmetic is binary, not decimal. It will almost always give rounding errors. You need to take that into account. "float" has about six digit precision. "double" has about 15 digits precision. You throw away nine digits precision for no reason.

Now think: What do you want to display? What do you want to display if the result of your calculation is 9.999999999? What would you want to display if the result is 9.538105712?

None of the numbers in your question, except 10.0, can be exactly represented in a float or a double on iOS. If you want to do float math with those numbers, you will have rounding errors.

You can round your result to the nearest integer easily enough:

float x = rintf((self.machine.micSensitivity - 0.0075f) / 0.00025f);

Or you can just multiply all your numbers, including the allowed values of micSensitivity, by 4000 (which is 1/0.00025), and thus work entirely with integers.

Or you can change the allowed values of micSensitivity so that its increment is a fraction whose denominator is a power of 2. For example, if you use an increment of 0.000244140625 (which is 2-12), and change 0.0075 to 0.00732421875 (which is 30 * 2-12), you should get exact results, as long as your micSensitivity is within the range ±4096 (since 4096 is 212 and a float has 24 bits of significand).

The code you have posted is correct and functioning properly. This is a known side effect of using floating point arithmetic. See the wiki on floating point accuracy problems for a dull explanation as to why.

There are several ways to work around the problem depending on what you need to use the number for.

If you need to compare two floats, then most everything works OK: less than and greater than do what you would expect. The only trouble is testing if two floats are equal.

// If x and y are within a very small number from each other then they are equal.
if (fabs(x - y) < verySmallNumber) { // verySmallNumber is usually called epsilon.
    // x and y are equal (or at least close enough)
}

If you want to print a float, then you can specify a precision to round to.

// Get a string of the x rounded to five digits of precision.
NSString *xAsAString = [NSString stringWithFormat:@"%.5f", x];

9.999999 is equal 10. there is prove: 9.999999 = x then 10x = 99.999999 then 10x-x = 9x = 90 then x = 10

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top