A weird quirk about floats......

This is a discussion on A weird quirk about floats...... within the C++ Programming forums, part of the General Programming Boards category; I am working on an RPG and I use floating point variables for raw character stats. When they are displayed ...

A weird quirk about floats......

I am working on an RPG and I use floating point variables for raw character stats. When they are displayed (or used in combat) they are truncated to integers. I use the floating point variables to an accuracy of 0.1.

I noticed that on a level up routine, if the number added to a particular stat (in this case, Agility), for instance, 1.2, would make the raw stat equal to a whole integer (e.x., 11.8 + 1.2 =13), the program would store it as 12.999999, and thus it would display improperly. On the next increase, the discrepancy would correct itself though......but the display would be wrong until then.

If you know that everything is "supposed" to be in units of 0.1, I see one "quick fix" and one "real fix":
The quick fix would be to, instead of starting at zero, start at 0.05. This is way bigger than the inherent error in floats (which is in the sixth significant digit, as I recall), but small enough to not give incorrect results.
The real fix would be to use fixed point instead of floating point. (In other words, use an int variable to store "tenths of points", so instead of 11.8+1.2 not quite =13.0, you have 118+12=130.)

tabstop, The solution you propose as the real fix is the solution that a lot of shops use to curcumvent that issue because often you don't need more than one or two places.

Heck if you really wanted to you could build an a class using int for the raw data but make it print out as a number with 2 decimal places, but that may be overkill for this application, and you would cut the max size of your numbers (but a int64 should be big enough for any realistic numbers in your game that would need decimals). In fact that gives me something to do, I think I am going to do that right now.

Maybe not, but there are functions in <math.h> (or <cmath>) that round down (eg floor()), round up (eg ceil()). It is trivial to use these to create your own rounding functions (eg nearest integer, etc).

Maybe not, but there are functions in <math.h> (or <cmath>) that round down (eg floor()), round up (eg ceil()). It is trivial to use these to create your own rounding functions (eg nearest integer, etc).

And also, C99 has introduced round, so perhaps your compiler makers have extended it to C++ (it appears that gcc/g++ has).

If you want all of your floats to only be accurate to 0.1, then simply store them as the number of tenths in an int instead.
I.e.
1.6 becomes 16
0.5 becomes 5
To multiply say 1.6 by 0.5 you also divide by 10 (16 * 5) / 10 = 8 which means 0.8
To divide say 1.6 by 0.5 you first multiply by 10: (10 * 16) / 5 = 32 which means 3.2
Add and subtract works as normal.

This is called fixed-point math. It's faster when the fixed-point scaling is a power of two, which is the more common case, and in any case it has perfect accuracy compared to using floats.

And also, C99 has introduced round, so perhaps your compiler makers have extended it to C++ (it appears that gcc/g++ has).

Relying on a C++ compiler supporting C99 features (or vice versa) is not a particularly good idea, unless you are willing to be locked into exactly one compiler, and possibly have your code break between versions of that compiler.

Relying on a C++ compiler supporting C99 features (or vice versa) is not a particularly good idea, unless you are willing to be locked into exactly one compiler, and possibly have your code break between versions of that compiler.

Rubbish. Calling a function that exists with one particular implementation is an effective way to lock yourself into that implementation -- unless, of course, you are writing trivial code that only you (as the lowest common denominator) will reuse. While such decisions are necessary sometimes, it is a bad decision if there are simple alternatives using portable approaches and a particularly bad decision in production environments in which code is reused, any changes require regression testing of affected applications, etc etc.

If you want want precision at 0.1 it should be 0.05 and you cant cast to int

As a matter of fact, it is an extremly poor idea to attempt to round a floating point value to the nearest multiple of 0.1 because such values cannot be represented by a floating point variable. This is a side effect of the fact that 1/10 (decimal, base 10) CANNOT be represented within a finite number of binary (base 2) digits.

If you want data to be output as 0.1 rather than 0.0999991 simply print it to two decimal places. In other words, do the formatting of output rather than trying to tweak the value of the floating point variable.