Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I apologize for asking yet another rounding question. However, all the search has not yielded a satisfactory solution to my problem. The only possible answer is that what I am looking for may not be possible at all. Just wanted to make sure if the experts think the same.
So, here is my sample code:
double Round(double dbVal, int nPlaces)
{
const double dbShift = pow(10.0, nPlaces);
return floor(dbVal * dbShift + 0.5) / dbShift;
}
main()
{
string sNum = "1.29585";
double dNum = stod(sNum);
int iNumDecimals = 5;
double dRoundedNum = Round(dNum, iNumDecimals);
}
The number sNum is read as a string from a file. For example, the number in the file is 1.29585. I convert it to double using stod. dNum comes out to be 1.295849999999.... I would like to get back 1.29585 in double. Using a Round function as shown above does not help. The round function also returns 1.295849999999....
Is it possible to get back the exact 1.29585 at all? Any other possible solution?
Thanks in advance for any advice.
Your number is rounded to the closest representable double to the number you provided ( 1.29585 ). To 17 places, it is: 1.29584999999999995
The next largest representable double-precision number is 1 / 252 larger than that: 1.29585000000000017.
That's roughly 1 part in 5 quadrillion. An error of that magnitude, scaled to the circumference of the entire solar system, would only be about 8 centimeters.
So, in terms of rounding, the double you have is correctly rounded to the nearest representable binary value.
By default, floating point numbers are stored in binary. Just as you can't express 1/3 as an exact decimal fraction (you can approximate it with "0.33333333", extending out the 3s until you get sick of it), you can't express all round decimal values exactly in binary.
If you're curious what the above two values look like in binary: (You can refer to the diagram and description here to understand how to interpret that hexadecimal value if you are interested.)
1.29584999999999995 == 0x3FF4BBCD35A85879
1.29585000000000017 == 0x3FF4BBCD35A8587A
For your zillions of calculations, this approximate representation should cause no problem, unless you're computing a series of values that need to be rounded to an exact number of decimal places. Typically, that's only necessary if you're computing actual bank transactions or the like. Bankers want decimal rounding, so that their computations today match the way computations were done 100 years ago so that they have continuity between the pre- and post-computer eras, not because they're magically more accurate.
Double precision arithmetic carries 16 to 17 decimal positions of precision. The fact that it doesn't print as a nice round number of decimal digits doesn't mean it's inaccurate. If you compare the calculation the computer makes with double precision to the same calculation you'd do by hand (even with the aid of a standard calculator displaying 9 to 12 digits of precision), the computer's double precision arithmetic will generally come out ahead.
What you most likely want to do is to make sure to print out your final calculations to the appropriate number of decimal places. For example, you can use std::setprecision() from <iomanip> to control the precision of values printed via std::cout.
EDIT: If your application actually requires decimal arithmetic and decimal rounding, then you will need to look into decimal floating point support, either built into the compiler or in a 3rd party library. Some recent compilers do have support for this, and some processors even have hardware support for decimal floating point. GCC has decimal floating point extensions, for example, as does Intel's compiler. In contrast, Microsoft suggests finding a BCD library, it seems.
Try this way, i don´t remember the format for double right now, i use float.
float num;
sscanf("1.29585", "%f", &num);
std::cout << num << std::endl;
The "I whipped it up in Haskell and translated it" answer:
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
int main()
{
double d = 1.2958499999999;
cout << setprecision(15) << d << endl;
cout << setprecision(15) << double(round(d * 1e5) / 1e5) << endl;
return 0;
}
// outputs:
// 1.2958499999999
// 1.29585
It is hardly a general answer, but it is correct to the letter of the question. I highly recommend understanding the evil that is IEEE floating point using e.g. Jim Buck's reference rather than putting this hack to any great use.
Related
This question already has answers here:
strange output in comparison of float with float literal
(8 answers)
Closed 4 years ago.
#include<iostream.h>
using namespace std;
int main()
{
float x=1.1;
if(x==1.1)
cout<<"yes";
else
cout<<"no";
return 0;
}
I assign value 1.1 to x and checked value of x is 1.1 or not?
You've wandered into an interesting area of almost all programming languages. Floating point values are tricky things, and testing them for equality is very rarely recommended. The basic problem is that floating point values on modern computers are represented as binary decimals with a finite number of digits of precision.
To make this simpler to understand, lets work with base 10 decimals and use a number that can't be accurately represented using them. Take 1/3. If you are representing it as a base 10 decimal you get this:
0.̅3 (there is a bar over the three if it isn't showing up properly). Basically, it goes on forever, there is no finite number of digits that can represent 1/3 as a base ten decimal with perfect accuracy. So, if you only have so many digits, you chop it off and approximate:
0.333333
That's actually 333333/1000000, which is really close to 1/3, but not quite.
C++ has a few different floating point types. And these types usually (it depends on the platform the program is being compiled for) have different numbers of significant digits. By default, a floating point constant is of type double which usually has more digits than a float (and it never has less). Again, using base 10 as an example, since you were storing your value in a float you were doing something like this:
0.333333 == 0.3333333333333333333
which of course is false.
If you wrote your code this way:
#include <iostream>
using namespace std;
int main()
{
float x = 1.1f;
if(x == 1.1f)
cout<<"yes";
else
cout<<"no";
return 0;
}
you would likely get the expected result. Putting an f at the end of a bare floating point value (aka, a floating point literal) tells C++ that it's of type float.
This is all very fascinating of course, and there's a lot to get into. If you would like to learn a lot more about how floating point numbers are really represented, there is a nice Wikipedia page on IEEE 754 floating point representation, which is how most modern processors represent floating point numbers nowadays.
From a practical standpoint, you should rarely (if ever) compare floating point numbers for equality. Usually, a desire to do so indicates some sort of design flaw in your program. And if you really must than use an 'epsilon' comparison. Basically, test to see if your number is 'close enough', though determining what that means in any given situation isn't necessarily a trivial task, which is why it usually represents a design flaw if you need to compare them for equality at all. But, in your case, it could look like this:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
float x=1.1;
if (fabs(x - 1.1) < 0.000001)
cout<<"yes";
else
cout<<"no";
return 0;
}
The reason the compare fails is that you're comparing a double value to a float variable.
Some compilers will issue a warning when you assign a double value to a float variable.
To get the desired output, you could try this:
double x = 1.1;
if (x == 1.1)
or this:
float x = 1.1f;
if (x == 1.1f)
I need to output float point numbers with two digits after the decimal point. In addition, I also need to round off the numbers. However, sometimes I don't get the results I need. Below is an example.
#include <iomanip>
#include <iostream>
using namespace std;
int main(){
cout << setprecision(2);
cout << fixed;
cout<<(1.7/20)<<endl;
cout<<(1.1/20)<<endl;
}
The results are:
0.08
0.06
Since 1.7/20=0.085 and 1.1/20=0.055. In theory I should get 0.09 and 0.06. I know it has something to do with the binary expression of floating point numbers. My questions is how can I get the right results when fixing the number of digits after the decimal point with rounding off?
Edit: This is not a duplicate of another question. Using fesetround(FE_UPWARD) will not solve the problem. fesetround(FE_UPWARD) will round (1.0/30) to 0.04 while the correct results should be 0.03. In addition, fesetround(FE_TONEAREST) doesn't help either. (1.7/20) still round to 0.08.
Edit: Now I understand that this behavior might be due to the half-to-even rounding. But how can I avoid this? Namely, if the result is exact half, it should round up.
Yes, you're right - it has to do with the representation in base 2, and the fact that sometimes the base 2 value will be higher than the base 10 number and sometimes it will be lower. But never by much!
If you want something that matches expectations more often, you can do two stage rounding. A double is generally accurate to at least 15 digits (total, including those to the left of the decimal point). Your first rounding will leave you with a number that has more stability for the second phase of rounding. No rounding is going to match the results you would get in decimal 100%, but it's possible to get very close.
double round_2digits(double d)
{
double intermediate = floor(d * 100000000000000.0 + 0.5); // round to 14 digits
return floor(intermediate / 1000000000000.0 + 0.5) / 100.0;
}
See it in action.
For a totally different approach, you can simply ensure that the base 2 number that you start with is always larger than the desired decimal, instead of being larger half the time and smaller half the time. Simply increment the least significant bit of the number with nextafter before rounding.
double round_2digits(double d)
{
return floor(100.0 * std::nextafter(d, std::numeric_limits<double>::max())) / 100.0;
}
You can define round_with_precision() method of your own, which would invoke tgmath.h provided round() method passing modified value, and then returning the value after dividing with same factor.
#include <tgmath.h>
double round_with_precision(double d, const size_t &prec)
{
d *= pow(10, prec);
return (std::round(d) / pow(10, prec));
}
int main(){
const size_t prec = 2;
cout << round_with_precision(1.7/20, prec) << endl; //prints 0.09
cout << round_with_precision(1.1/20, prec) << endl; //prints 0.06
}
The issue is due to binary floating-point representation and floating-point constants in C. The fact is that 1.7 and 1.1 are not exactly representable in binary. The ISO C standard says (I suppose that this is similar in C++): "Floating constants are converted to internal format as if at translation-time." This means that the active rounding mode (set by fesetround) will not have any influence at all for the constant (it may have an influence for the roundings that occur at run time).
The division by 20 will introduce another rounding error. Depending on the full code and compiler options, it may or may not be done at compile time, so that the active rounding mode may be ignored. In any case, if you expect 0.085 and 0.055 exactly, this is not possible because these values are not representable exactly in binary.
So, even if you have perfect code that rounds double values on 2 decimal digits, this may not work as you want, because of the rounding errors that occurred before, and it is too late to recover the information in a way that works in all cases.
If you want to be able to handle "midpoint" values such as 0.085 exactly, you need to use a number system that can represent them exactly, such as decimal arithmetic (but you may still get rounding errors in other kinds of operations). You may also want to use integers scaled by a power of 10. There is no general answer because this really depends on the application, as any workaround will have drawbacks.
For more information, see all the general articles on floating point and Goldberg's article (PDF version).
For the following program:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
for (float a = 1.0; a < 10; a++)
cout << std::setprecision(30) << 1.0/a << endl;
return 0;
}
I recieve the following output:
1
0.5
0.333333333333333314829616256247
0.25
0.200000000000000011102230246252
0.166666666666666657414808128124
0.142857142857142849212692681249
0.125
0.111111111111111104943205418749
Which is definitely not right right for the lower place digits, particularly with respect to 1/3,1/5,1/7, and 1/9. things just start going wrong around 10^-16 I would expect to see out put more resembling:
1
0.5
0.333333333333333333333333333333
0.25
0.2
0.166666666666666666666666666666
0.142857142857142857142857142857
0.125
0.111111111111111111111111111111
Is this an inherit flaw in the float class? Is there a way to overcome this and have proper division? Is there a special datatype for doing precise decimal operations? Am I just doing something stupid or wrong in my example?
There are a lot of numbers that computers cannot represent, even if you use float or double-precision float. 1/3, or .3 repeating, is one of those numbers. So it just does the best it can, which is the result you get.
See http://floating-point-gui.de/, or google float precision, there's a ton of info out there (including many SO questions) on this subject.
To answer your questions -- yes, this is an inherent limitation in both the float class and the double class. Some mathematical programs (MathCAD, probably Mathematica) can do "symbolic" math, which allows calculation of the "correct" answers. In many cases, the round-off error can be managed, even over really complex computations, such that the top 6-8 decimal places are correct. However, the opposite is true as well -- naive computations can be constructed that return wildly incorrect answers.
For small problems like division of whole numbers, you'll get a decent number of decimal place accuracy (maybe 4-6 places). If you use double precision floats, that will go up to maybe 8. If you need more... well, I'd start questioning why you want that many decimal places.
First of all, since your code does 1.0/a, it gives you double (1.0 is a double value, 1.0f is float) as the rules of C++ (and C) always extends a smaller type to the larger one if the operands of an operation is different size (so, int + char makes the char into an int before adding the values, long + int will make the int long, etc, etc).
Second floating point values have a set number of bits for the "number". In float, that is 23 bits (+ 1 'hidden' bit), and in double it's 52 bits (+1). Yet get approximately 3 digits per bit (exactly: log2(10), if we use decimal number representation), so a 23 bit number gives approximately 7-8 digits, a 53 bit number approximately 16-17 digits. The remainder is just "noise" caused by the last few bits of the number not evening out when converting to a decimal number.
To have infinite precision, we would have to either store the value as a fraction, or have an infinite number of bits. And of course, we could have some other finite precision, such as 100 bits, but I'm sure you'd complain about that too, because it would just have another 15 or so digits before it "goes wrong".
Floats only have so much precision (23 bits worth to be precise). If you REALLY want to see "0.333333333333333333333333333333" output, you could create a custom "Fraction" class which stores the numerator and denominator separately. Then you could calculate the digit at any given point with complete accuracy.
PHP has a decimal type, which doesn't have the "inaccuracy" of floats and doubles, so that 2.5 + 2.5 = 5 and not 4.999999999978325 or something like that.
So I wonder if there is such a data type implementation for C or C++?
The Boost.Multiprecision library has a decimal based floating point template class called cpp_dec_float, for which you can specify any precision you want.
#include <iostream>
#include <iomanip>
#include <boost/multiprecision/cpp_dec_float.hpp>
int main()
{
namespace mp = boost::multiprecision;
// here I'm using a predefined type that stores 100 digits,
// but you can create custom types very easily with any level
// of precision you want.
typedef mp::cpp_dec_float_100 decimal;
decimal tiny("0.0000000000000000000000000000000000000000000001");
decimal huge("100000000000000000000000000000000000000000000000");
decimal a = tiny;
while (a != huge)
{
std::cout.precision(100);
std::cout << std::fixed << a << '\n';
a *= 10;
}
}
Yes:
There are arbitrary precision libraries for C++.
A good example is The GNU Multiple Precision arithmetic library.
If you are looking for data type supporting money / currency then try this:
https://github.com/vpiotr/decimal_for_cpp
(it's header-only solution)
There will be always some precision. On any computer in any number representation there will be always numbers which can be represented accurately, and other numbers which can't.
Computers use a base 2 system. Numbers such as 0.5 (2^-1), 0.125 (2^-3), 0.325 (2^-2 + 2^-3) will be represented accurately (0.1, 0.001, 0.011 for the above cases).
In a base 3 system those numbers cannot be represented accurately (half would be 0.111111...), but other numbers can be accurate (e.g. 2/3 would be 0.2)
Even in human base 10 system there are numbers which can't be represented accurately, for example 1/3.
You can use rational number representation and all the above will be accurate (1/2, 1/3, 3/8 etc.) but there will be always some irrational numbers too. You are also practically limited by the sizes of the integers of this representation.
For every non-representable number you can extend the representation to include it explicitly. (e.g. compare rational numbers and a representation a/b + c/d*sqrt(2)), but there will be always more numbers which still cannot be represented accurately. There is a mathematical proof that says so.
So - let me ask you this: what exactly do you need? Maybe precise computation on decimal-based numbers, e.g. in some monetary calculation?
What you're asking is anti-physics.
What phyton (and C++ as well) do is cut off the inaccuracy by rounding the result at the time to print it out, by reducing the number of significant digits:
double x = 2.5;
x += 2.5;
std::cout << x << std::endl;
just makes x to be printed with 6 decimal digit precision (while x itself has more than 12), and will be rounded as 5, cutting away the imprecision.
Alternatives are not using floating point at all, and implement data types that do just integer "scaled" arithmetic: 25/10 + 25/10 = 50/10;
Note, however, that this will reduce the upper limit represented by each integer type. The gain in precision (and exactness) will result in a faster reach to overflow.
Rational arithmetic is also possible (each number is represented by a "numarator" and a "denominator"), with no precision loss against divisions, (that -in fact- are not done unless exact) but again, with increasing values as the number of operation grows (the less "rational" is the number, the bigger are the numerator and denominator) with greater risk of overflow.
In other word the fact a finite number of bits is used (no matter how organized) will always result in a loss you have to pay on the side of small on on the side of big numbers.
I presume you are talking about the Binary Calculator in PHP. No, there isn't one in the C runtime or STL. But you can write your own if you are so inclined.
Here is a C++ version of BCMath compiled using Facebook's HipHop for PHP:
http://fossies.org/dox/facebook-hiphop-php-cf9b612/dir_2abbe3fda61b755422f6c6bae0a5444a.html
Being a higher level language PHP just cuts off what you call "inaccuracy" but it's certainly there. In C/C++ you can achieve similar effect by casting the result to integer type.
I was wondering whether it is possible to limit the number of characters we enter in a float.
I couldn't seem to find any method. I have to read in data from an external interface which sends float data of the form xx.xx. As of now I am using conversion to char and vice-versa, which is a messy work-around. Can someone suggest inputs to improve the solution?
If you always have/want only 2 decimal places for your numbers, and absolute size is not such a big issue, why not work internally with integers instead, but having their meaning be "100th of the target unit". At the end you just need to convert them back to a float and divide by 100.0 and you're back to what you want.
This is a slight misunderstanding. You cannot think of a float or double as being a decimal number.
Most any attempt to use it as a fixed decimal number of precision, say, 2, will incur problems as some values will not be precisely equal to xxx.xx but only approximately so.
One solution that many apps use is to ensure that:
1) display of floating point numbers is well controlled using printf/sprintf to a certain number of significant digits,
2) one does not do exact comparison between floating point numbers, i.e. to compare to the 2nd decimal point of precision two numbers a, b : abs(a-b) <= epsilon should generally be used. Outright equality is dangerous as 0.01 might have multiple floating point values, e.g. 0.0101 and 0.0103 might result if you do arithmetic, but be indistinguishable to the user if values are truncated to 2 dp, and they may be logically equivalent to your application which is assuming 2dp precision.
Lastly, I would suggest you use double instead of float. These days there is no real overhead as we aren't doing floating point without a maths coprocessor any more! And a float under 32-bit architectures has 7 decimal points of precision, and a double has 15, and this is enough to be significant in many case.
Rounding a float (that is, binary floating-point number) to 2 decimal digits doesn't make much sense because you won't be able to round it exactly in some cases anyway, so you'll still get a small delta which will affect subsequent calculations. If you really need it to be precisely 2 places, then you need to use decimal arithmetic; for example, using IBM's decNumber++ library, which implements ISO C/C++ TR 24773 draft
You can limit the number of significant numbers to output:
http://www.cplusplus.com/reference/iostream/manipulators/setprecision/
but I don't think there is a function to actually lop off a certain number of digits. You could write a function using ftoa() (or stringstream), lop off a certain number of digits, and use atof() (or stringstream) and return that.
You should checks the string rather than the converted float. It will be easier to check the number of digits.
Why don't you just round the floats to the desired precision?
double round(double val, int decimalPlaces)
{
double power_of_10 = pow(10.0, static_cast<double>(decimalPlaces));
return floor(val * power_of_10 + 0.5) / power_of_10;
}
int main()
{
double d;
cin >> d;
// round d to 3 decimal places...
d = round(d, 3);
// do something with d
d *= 1.75;
cout << setprecision(3) << d; // now output to 3 decimal places
}
There exist no fixed point decimal datatype in C, but you can mimic pascal's decimal with a struct of two ints.
If the need is to take 5 digits [ including or excluding the decimal point ], you could simply write like below.
scanf( "%5f", &a );
where a is declared as float.
Fo eg:
If you enter 123.45, scanf will consider the first 5 characters i.e., 4 digits and the decimal point & will store 123.4
If entered 123456, the value of a will be 12345 [ ~ 12345.00 ]
With printf, we would be able to control how many characters can be printed after decimal as well.
printf( "%5.2f \n", a );
The value of 123.4 will be printed as 12.30 [ total 5, including the decimal & 2 digits after decimal ]
But this have a limitation, where if the digits in the value are more than 5, it will display the actual value.
eg: The value of 123456.7, will be displayed as 123456.70.
This [ specifying the no. of digits after the decimal, as mentioned for printf ] I heard can be used for scanf as well, I am not sure sure & the compiler I use doesn't support that format. Verify whether your compiler does.
Now, when it comes to taking data from an external interface, are you talking about serialization here, I mean transmission of data on netwrok.
Then, to my knowledge your approach is fine.
We generally tend to read in the form of char only, to make sure the application works for any format of data.
You can print a float use with printf("%.2f", float), or something similar.