This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 6 years ago.
There is an input to my software for processing: float totalPurchased. I am coding with C++11/GCC/GDB/Linux.
The totalPurchase price informed is 14.92 as it is read from a file.
However, when the program runs, it shows 14.920001 out of no where. I don't want to round the value 14.92 to up 15.00 or down 14.00; the only thing I really need is to have the input right, without the compiler adding up things that does not exist as input.
The problem is that this 0.000001 is breaking a part the whole software calculation in the long run.
How to get rid of this 0.000001, and make sure that it appears the actual value that was read from the file into my float variable: 14.92?
All comments and suggestions are highly appreciated.
Unfortunately, floating point can't represent your number exactly: 14.92 is a repeating fraction in binary.
The question you want to ask yourself is: why does such a small offset break your calculation? If you really need to compare values so exactly, then perhaps floating point is not the appropriate datatype.
If you need something like, say, an exact percentage, or an exact number of cents, you can store 100* the number. This is a persistent problem in accounting, which is why accountants don't use floating point to add their money.
Use a fixed point library such as this.
For myself, in this domain, I would store price as integer pennies and do something along the line of
sprintf("%i.%02i", price/100, price%100)
Caveats for negative numbers, and in some applications you might want sub-penny precision, but you get the idea. A full fixed-point library is overkill for things like this, I think.
Actually, because I like to Do The Right Thing I would do something like this
class CashValue
{
public:
static CashValue parse (const std::string &);
float to_float () const;
CashValue & operator + (const CashValue &);
// etc
private:
int m_pennies;
};
Thus making the significance of the unit explicit. Only support operations for which exact solutions exist. If you want to do something like this
price *= pow (1.0 + (percent_interest/100.0), years)
then my interface would force you to verbosely convert it first, making you think about the issues when they become relevant, but still supporting safe operations such as addition transparently and accurately.
Related
Is there some clever and reliable way to print series of bits as an IEEE-754 without actually using a float type?
I have found a way to print fractions, which allows me to represent the float as a a fraction. However, I then came to realize that the exponent may range from -127 to 128 (after adjusting with bias), which may result in the multiplication mantissa * 2^128. The fraction method relies on representing the numerator as an integer, and I would require a really large integer to do this multiplication. I mean, I could use "custom" type to represent this large value (i.e. https://gmplib.org/), but I would prefer if to avoid this. If we multiplied by 10^x, I could simply adjust the decimal point and add some zeros, but sadly that's not the case either.
I have not been able to find anything that mentions any solution for this. Probably due to the fact that googling stuff like "print from
Why am I actually trying to do this?
I'm only doing this to get a better understanding of how floats (IEEE-754 in particular) work, and I find that it always help to do some practical example. So I thought "Hey, why not try to code it?". This has no practical application (that I know of)!
So, almost immediately after posting this, I finally succeded in finding the resources I've been looking for.
https://www.ryanjuckett.com/printing-floating-point-numbers/ talks about it, and references other relevant sources.
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 4 years ago.
Here is how my calculator should work:
There is a JSON value where I can write the first multiplier - something like this:
{
"value1": 1.4
}
On the calculator I can write the second multiplier - only 10^n numbers (10, 100, ..., 10000000). And my calc should return me an integer, as I know that always people who use my calc with write less numbers after the decimal point for the first multiplier than we have 0s on the calc for the second multiplier. Yes, my calc is a very-very strange one.
Here are valid inputs:
v1=1.4; v2=100;
v1=1.414; v2=100000;
v1=1.1; v2=100;
What happens when I do this, for example for value1=1.4 and value2=10000 I get 13900. As far as float cannot hold any number sometimes it stores different numbers. For 1.4 internally it stores 1.399999 on my machine. I know why, but you know the QA engineer who tests my app tells me that I need to get 14000. Your calc does not work. How to make my calc so that I will print correct number?
P.S. Of course I have cut out my real problem from the context but the thing is that I have a float in a file and a 10^n number in my program as a user input. How to get correct result?
EDIT1: I don't ask why float works that way. I know why. I ask how to solve the problem even when float works that way.
EDIT2: I use RapidJson to read the JSON file which already returns me wrong number as a double precision number. I can't use libraries that provide with higher precision floating points.
Round the result when you format it for display. A double precision value is correct to about 15 significant digits, so if you round the result to 12 significant digits you're not going to surprise the user.
I am trying to convert a char * containing just a floating point value to a type float, but both sscanf_s and atof both produce the same invalid result.
char t[] = "2.10";
float aFloat( 0.0f ), bFloat( 0.0f );
sscanf_s( t, "%f", &aFloat );
bFloat = atof( t );
Output:
aFloat: 2.09999990
bFloat: 2.09999990
When I looked at similar questions in an attempt to ascertain the answer I attempted their solutions to no avail.
Converting char* to float or double
The solution given here was to include 'stdlib.h', and after doing so I changed the call to atof to an explicit call 'std::atof', but still no luck.
Unfortunately, not all floating point values can be explicitly represented in binary form. You will get the same result if you say
float myValue = 2.10;
I see the excellent answer in comments is missing (or I didn't find it there easily) one other option how to deal with it.
You should have wrote, why you need floating point number. If you by accident happen to work with monetary amounts (and not too huge ones), you can create custom parser of input values, and custom formatter for value output, to read it as 64b integer (*100), and work in your whole application with 100*amount values. If you are working with really huge amounts, use some library for big numbers, or you may create your own, working with char* numbers.
It's a special case of Fixed-point arithmetic.
If you are interested into "just to solve this", without coding too much, head for big numbers library anyway, even the *100 fixed-point variant is easy to write with bugs - if it's your first time and you don't have enough resources to do it correctly (TDD advised).
But definitely learn how the numbers are stored in computer, and why float/double can't represent all numbers. Float 2.1 for computer (base 2 used internally) is similar case to human's 1/3, which can't be represented in base 10 without infinite number of decimal places (and how 1.0 == 0.99999... in base 10). (thanks #tobi303)
After reading your new comment, if "Does this not have a big impact on financial applications?"
Answer: nope, zero impact, nobody sane (and professional) would create financial application with floats or doubles.
This question already has answers here:
Why are floating point numbers inaccurate?
(5 answers)
Closed 7 years ago.
In my project I have to read some numeric data form an xml file ,use it ,and save it on disk in an another directory.
Skipping the file paring it comes to the problem of std::string to float conversion:
std::string sFloatNumber;
float fNumber = std::atof(sFloatNumber);
Which works fine but I noticed small deviations between value written in std::string and the one recieved after conversion to float (about ~0.0001).
Deviation is small but after number of such operations can accumulate to a big inacurracy later on.
So I ask if there is some conversion between std::string and float that has 1:1 accuracy?
You can't really can't make the conversion more precise than what you'd achieve by using the inbuilt operators for this. The reason is that floats can't represent all numbers. What they can represent is the number closest to the one you input, and I guess that is what they are showing. So there is no way possible in which you can convert a string exactly into a float.
If you want more accuracy, I suggest you use double. However, that also has a limit on the accuracy, but much better than float nonetheless. The reason for this is that double uses 64 bits to represent a number, whereas a float uses 32 bits. But their method of storing a number is similar, and so the same restrictions apply.
I am having a bit of a problem here.
I have two int values, one for dollars and one for cents. My job is to combine them into one double value and I am having some trouble.
Here's an example of what I want to be able to do:
int dollars = 10
int cents = 50
<some code which I haven't figured out yet>
double total = 10.50
I want to think it is relatively simple, but I'm having a hard time figuring it out.
Thanks for the help!
Start by thinking how you would solve this as a simple arithmetic problem, with pencil and paper (nothing to do with C). Once you find a way to do it manually, I'm sure the way to program it will seem trivial.
How about double total = double(dollars) + double(cents) / 100.0;?
Note that double is not a good data type to represent 10-based currencies, due to its inability to represent 1/100 precisely. Consider a fixed-point solution instead, or perhaps a decimal float (those are rare).
That's not difficult... you have to convert dollars to a double1 and add cents multiplied for 0.01 (or divided by 100. - notice the trailing dot, that's to indicate that 100. is a double constant, so / will perform a floating-point division instead of an integer division).
... but be aware of the fact that storing monetary values in binary floating-point variables is not a good idea at all, because binary doesn't have a finite representation of many "exact" decimal amounts (e.g. 0.1), that will be stored in an approximate representation. Working with such values may yield "strange" results when you start to do some arithmetic with them.
Actually, depending on your expression, it's probably not necessary due to implicit casts.
If you're interested in 'the whole idea' of programming and not only in getting your homework right, I suggest you think about this: "Is there any way I can represent a whole dollar as a certain amount of cents?" Why should you ask this? Because if you want to represent two different 'types' of certain values as one value, you need to 'normalize' them or 'standardize' them in a way so that there is not any data loss or corruption (or at least for the smaller problems).
Also I agree with Kerrek SB, representing money as double might not be the best solution.
Isn't it just as easy: total = dollars + (cents/100); ?
No reason to complicate this.