### float rounding issue

So I have a function like this
 ``1234567891011121314`` ``````float roundToSignificant(float num, int n) { if(num == 0.0f) return 0.0f; float magnitude = pow(10, (float)n); int shifted = round(num*magnitude); return (float)(shifted/magnitude); } float round(float r) { return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); }``````

which basically rounds a value to the nth floating point.

It also works fine in most cases, however for example `roundToSignificant(900000.05f, 1)` returns `900000.13` but it should return `900000.10`.

When debugging through the code the issue seems to happen at the very last line of the function so the values there look like this -> `return (float)(9000001/10.000000);`

I know calculating around with float values isn't exactly accurate but I would like to know if there is any way to solve this issue here to get the desired result?
Last edited on
Hmm let me pull out my handy dandy debugging super tool for this one. I call it, cout :P.
 ``123456789101112131415161718192021222324252627`` ``````#include #include float round(float); float roundToSignificant(float num, int n) { if(num == 0.0f) return 0.0f; float magnitude = pow(10, (float)n); std::cout<<"1:"< 0.0)?floor(r + 0.5):ceil(r - 0.5); std::cout<<"\n"; return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); } int main() { std::cout<<"final:"<

output:
 1:10 2:1 3:900,000 final:900,000

You might have to work with me here because I'm kind of lost on how you got your numbers.
> returns `900000.13` but it should return `900000.10`.

`900000.10` may not have a floating point representation at all; what you would get is the nearest representable floating point value.

 ``12345678`` ``````#include int main() { const float seq[] = { 900000.000f, 900000.100f, 900000.200f, 900000.300f, 900000.400f } ; for( float f : seq ) std::cout << std::fixed << f << '\n' ; }``````

http://coliru.stacked-crooked.com/a/c836cb891ef855c6
> You might have to work with me here because I'm kind of lost on how you got your numbers.

Why, do you get different values? It could be because you are using a different debugger/platform/compiler (Windows 7, VS2010).

> 900000.10 may not have a floating point representation at all; what you would get is the nearest representable floating point value.

So it might not be an inaccurate value afterall, it just doesn't get more precise? I would actually be okay with that as long as other values in the area near that value get the same value assigned (for storing purposes).
> So it might not be an inaccurate value afterall, it just doesn't get more precise?

Yes. It doesn't get more precise than half a ulp.

 ``1234567891011121314`` ``````#include #include int main() { const float lb = 900000.0 ; const float ub = boost::math::float_next( lb + 1.0 ) ; std::cout << "number of ulps between " << lb << " and " << ub << " is " << boost::math::float_distance( lb, ub ) << "\n\n" ; int n = 0 ; for( float f = lb ; f < ub ; f = boost::math::float_next(f) ) std::cout << std::setw(2) << ++n << ". " << std::fixed << f << '\n' ; }``````

On my implementation:
 ```number of ulps between 900000 and 900001 is 16 1. 900000.000000 2. 900000.062500 3. 900000.125000 4. 900000.187500 5. 900000.250000 6. 900000.312500 7. 900000.375000 8. 900000.437500 9. 900000.500000 10. 900000.562500 11. 900000.625000 12. 900000.687500 13. 900000.750000 14. 900000.812500 15. 900000.875000 16. 900000.937500```

> I would actually be okay with that as long as other values in the area
> near that value get the same value assigned

 The IEEE 754 specification—followed by all modern floating-point hardware—requires that the result of an elementary arithmetic operation (addition, subtraction, multiplication, division, and square root since 1985, and FMA since 2008) be within 0.5 ULP of the mathematically exact result, using John Harrison's definition—that is, that it be the best possible result. - http://en.wikipedia.org/wiki/Unit_in_the_last_place

You might want to read this: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
Last edited on
Thanks for the explanation and links
Topic archived. No new replies allowed.