Rounding doubles - .5 - sprintf - c++

I'm using the following code for rounding to 2dp:
sprintf(temp,"%.2f",coef[i]); //coef[i] returns a double
It successfully rounds 6.666 to 6.67, but it doesn't work properly when rounding
5.555. It returns 5.55, whereas it should (at least in my opinion) return 5.56.
How can I get it to round up when the next digit is 5? i.e. return 5.56.
edit: I now realise that this is happening because when I enter 5.555 with cin it gets
saved as 5.554999997.
I'm going to try rounding in two stages- first to 3dp and then to 2dp. any other
(more elegant) ideas?

It seems you have to use math round function for correct rounding.
printf("%.2f %.2f\n", 5.555, round(5.555 * 100.)/100.);
This gives the following output on my machine:
5.55 5.56

The number 5.555 cannot be represented as an exact number in IEEE754. Printing out the constant 5.555 with "%.50f" results in:
5.55499999999999971578290569595992565155029300000000
so it will be rounded down. Try using this instead:
printf ("%.2f\n",x+0.0005);
although you need to be careful of numbers that can be represented exactly, since they'll be rounded up wrongly by this expression.
You need to understand the limitations of floating point representations. If it's important that you get accuracy, you can use (or code) a BCD or other decimal class that doesn't have the shortcoming of IEEE754 representation.

How about this for another possible solution:
printf("%.2f", _nextafter(n, n*2));
The idea is to increase the number away from zero (the n*2 gets the sign right) by the smallest possible amount representable by floating point math.
Eg:
double n=5.555;
printf("%.2f\n", n);
printf("%.2f\n", _nextafter(n, n*2));
printf("%.20f\n", n);
printf("%.20f\n", _nextafter(n, n*2));
With MSVC yields:
5.55
5.56
5.55499999999999970000
5.55500000000000060000

This question is tagged C++, so I'll proceed under that assumption. Note that the C++ streams will round, unlike the C printf family. All you have to do is provide the precision you want and the streams library will round for you. I'm just throwing that out there in case you don't already have a reason not to use streams.

You could also do this (saves multiply/divide):
printf("%.2f\n", coef[i] + 0.00049999);

Related

What does "double + 1e-6" mean?

The result of this cpp is 72.740, but the answer should be like 72.741
mx = 72.74050000;
printf("%.3lf \n", mx);
So I found the solution on website, and it told me to add "+1e-7" and it works
mx = 72.74050000;
printf("%.3lf \n", mx + 1e-7);
but I dont know the reason in this method, can anyone explain how it works?
And I also try to print it but nothing special happens..., and it turn out to be 72.7405
mx = 72.74050003;
cout << mx + 1e-10;
To start, your question contains an incorrect assumption. You put 72.7405 (let's assume it's precise) on input and expect 72.741 on output. So, you assume that rounding in printf will select higher candidate of possible twos. Why?
Well, one could consider this is your task, according to some rules (e.g. fiscal norms for rounding in bills, in taxation, etc.) - this is usual. But, when you use standard de facto floating of C/C++ on x86, ARM, etc., you should take the following specifics into account:
It is binary, not decimal. As result, all values you showed in your example are kept with some error.
Standard library tends to use standard rounding, unless forced to use another method.
The second point means that default rounding in C floating is round-to-nearest-ties-to-even (or, shortly, half-to-even). With this rounding, 72.7405 will be rounded to 72.740, not 72.741 (but, 72.7415 will be rounded to 72.742). To ask for rounding 72.7405 -> 72.741, you should have installed another rounding mode: round-to-nearest-ties-away-from-zero (shortly: round-half-away). This mode is request, to refer to, in IEEE754 for decimal arithmetic. So, if you used true decimal arithmetic, it would suffice.
(If we don't allow negative numbers, the same mode might be treated as half-up. But I assume negative numbers are not permitted in financial accounting and similar contexts.)
But, the first point here is more important: inexactness of representation of such values can be multiplied by operations. I repeat your situation and a proposed solution with more cases:
Code:
#include <stdio.h>
int main()
{
float mx;
mx = 72.74050000;
printf("%.6lf\n", mx);
printf("%.3lf\n", mx + 1e-7);
mx *= 3;
printf("%.6lf\n", mx);
printf("%.3lf\n", mx + 1e-7);
}
Result (Ubuntu 20.04/x86-64):
72.740501
72.741
218.221497
218.221
So you see that just multiplying of your example number by 3 resulted in situation that the compensation summand 1e-7 gets not enough to force rounding half-up, and 218.2215 (the "exact" 72.7405*3) is rounded to 218.221 instead of desired 218.222. Oops, "Directed by Robert B. Weide"...
How the situation could be fixed? Well, you could start with a stronger rough approach. If you need rounding to 3 decimal digits, but inputs look like having 4 digits, add 0.00005 (half of least significant digit in your results) instead of this powerless and sluggish 1e-7. This will definitely move half-voting values up.
But, all this will work only if result before rounding have error strictly less than 0.00005. If you have cumbersome calculations (e.g. summing hundreds of values), it's easy to get resulting error more than this threshold. To avoid such an error, you would round intermediate results often (ideally, each value).
And, the last conclusion leads us to the final question: if we need to round each intermediate result, why not just migrate to calculations in integers? You have to keep intermediate results up to 4 decimal digits? Scale by 10000 and do all calculations in integers. This will also aid in avoiding silent(*) accuracy loss with higher exponents.
(*) Well, IEEE754 requires raising "inexact" flag, but, with binary floating, nearly any operation with decimal fractions will raise it, so, useful signal will drown in sea of noise.
The final conclusion is the proper answer not to your question but to upper task: use fixed-point approaches. The approach with this +1e-7, as I showed above, is too easy to fail. No, don't use it, no, never. There are lots of proper libraries for fixed-point arithmetic, just pick one and use.
(It's also interesting why %.6f resulted in printing 72.740501 but 218.221497/3 == 72.740499. It suggests "single" floating (float in C) gets too inaccurate here. Even without this wrong approach, using double will postpone the issue, masking it and disguising as a correct way.)
If you will output the value like
printf( "mx = %.16f\n", mx );
you will see
mx = 72.7404999999999973
So to make the result like 72.741 due to rounding in outputting with a call of printf you need to make the next digit equal to 5 instead of 4. It is enough to add 0.00001.
Here is a demonstration program.
#include <iostream>
#include <iomanip>
#include <cstdio>
int main( void )
{
double mx = 72.74050000;
printf( "mx = %.3f\n", mx + 0.00001);
std::cout << "mx = " << std::setprecision( 5 ) << mx + 0.00001 << '\n';
}
The program output is
mx = 72.741
mx = 72.741
0.00001 is the same as 1e-5.

C++ Rounding float-pointing value to number of fractional digits

I have tried std::round but it doesn't give me result that I want exactly. So my question is I have program in C# and I am converting to C++ and I faced with this problem. C# Math.round and C++ round are different. So this causes wrong calculations.
C# code:
Console.WriteLine(Math.Round(0.850, 1));
Output:
0,8
C++ code:
std::cout << roundf(0.850f) << std::endl;
Output:
1
So like you see they are different. How can I solve this ?
The C# version is rounding a double to one decimal place, the C++ version is rounding a float to the nearest integer.
Rounding a binary floating point to a fixed number of decimal places doesn't really make much sense, as the rounded number will still most likely be an approximation. For example 0.8 cannot be represented exactly in binary floating point.
The C++ round function only rounds to the nearest integral value, which, given the above, is a sensible choice.
You can recover the C# behaviour (rounding to 1 decimal place) with std::round(0.850 * 10) / 10.
Note that I've dropped the f suffix to match the C# double type.

I'm trying to round a float to two decimal points but it's incorrect. How to fix this rounding error in C++?

I'm having trouble with rounding floats. I'm solving a task where you need to round your result to two decimal points. But I can't do it when the third decimal point is 5 because it's stored incorrectly.
For example: My result is equal to 1.005 and that should be rounded to 1.01. But C++ rounds it to 1.00 because the original float is stored as 1.0049999... and not 1.005.
I've already tried always adding a very small float to the result but there are some other test cases which are then rounded up but should be rounded down.
I know how floating-point works and that it is often not completely accurate. I'm just wondering whether anyone has found a way around this specific problem.
When you say "my result is equal to 1.005", you are assuming some count of true decimal digits. This can be 1.005 (three digits of fractional part), 1.0050 (four digits), 1.005000, and so on.
So, you should first round, using some usual rounding, to that count of digits. It is simpler to do this in integers: for example, with 6 fractional digits, it means some usual round(), rint(), etc. after multiplication by 1,000,000. With this step, you are getting exact decimal number. After this, you are able to make the required final rounding to what you need.
In your example, this will round 1,004,999.99... to 1,005,000. Then, divide by 10000 and round again.
(Notice that there are suggestions to make this rounding in yet specific way. The General Decimal Arithmetic specification and IBM arithmetic manuals suggest this rounding is done in the way that exact fractional part 0.5 shall be rounded away from zero unless least significant result bit becomes 0 or 5, in that case it is rounded toward zero. But, if you have no such rounding available, a general away-from-zero is also suitable.)
If you are implementing arithmetic for money accounting, it is reasonable to avoid floating point at all and use fixed-point arithmetic (emulated with integers, if needed). This is better because you the methods I've described for rounding are inevitably containing conversion to integers (and back), so, it's cheaper to use such integers directly. You will get inexact operation checking as well (by cost of explicit integer overflow).
If you can use a library like boost with its Multiprecision support.
Another option would be to use a long double, maybe that's precise enough for you.

How to control double precision computing to avoid rounding errors in C++ linux x86_64?

In a C++ code on linux x86_64, I need to double precision computing (+ or -).
26.100000000000001 - 26 + 0.10000000000000001
I got:
0.20000000000000143
I want to get 0.2.
here, the display format is not import, the computing results will be used for some if-else branch conditions. So, I only want the if-else conditions compare the 4 digits after the decimal digit.
It seems a rounding error ?
How to restrict the computing precision to 4 digits after decimal point ?
I do not want to call any functions in order to avoid overhead.
I do not want to use stringstream due to transformation overhead.
Any better ideas ?
thanks
The computing precision is fine. It's the display precision you're trying to control. You can do that with setprecision() if using <iostream> or a formatter like "%.4f" if using <stdio.h>.
You are already calling functions since you are displaying the result as decimal!
P.S. 0.1 cannot be exactly represented by a float, double, or any binary-mantissa format. It factors into (1/2) * (1/5), and decimal 1/5 is an infinitely-repeating digit sequence in binary.
P.P.S. Go look at GMP. It might be your best hope.
If you just want to print it it, you can use printf("%10.4lf"). You can alter the precision to anything you want, of course.
If you are only interested in equality up to four decimal places, multiply everything by 10,000 and use integer arithmetic. (You might need to round after multiplying by 10,000.)

Write a float with full precision in C++

In C++, can I write and read back a float (or double) in text format without losing precision?
Consider the following:
float f = ...;
{
std::ofstream fout("file.txt");
// Set some flags on fout
fout << f;
}
float f_read;
{
std::ifstream fin("file.txt");
fin >> f;
}
if (f != f_read) {
std::cout << "precision lost" << std::endl;
}
I understand why precision is lost sometimes. However, if I print the value with enough digits, I should be able to read back the exact same value.
Is there a given set of flags that is guaranteed to never lose precision?
Would this behaviour be portable across platforms?
If you don't need to support platforms that lack C99 support (MSVC), your best bet is actually to use the %a format-specifier with printf, which always generates an exact (hexadecimal) representation of the number while using a bounded number of digits. If you use this method, then no rounding occurs during the conversion to a string or back, so the rounding mode has no effect on the result.
Have a look at this article: How to Print Floating-Point Numbers Accurately and also at that one: Printing Floating-Point Numbers Quickly and Accurately.
It is also mentioned on stackoverflow here, and there is some pointer to an implementation here.
if I print the value with enough digits, I should be able to read back the exact same value
Not if you write it in decimal - there's not an integer relationship between the number of binary digits and the number of decimal digits required to represent a number. If you print your number out in binary or hexadecimal, you'll be able to read it back without losing any precision.
In general, floating point numbers are not portable between platforms in the first place, so your text representation is not going to be able to bridge that gap. In practice, most machines use IEEE 754 floating point numbers, so it'll probably work reasonably well.
You can't necessarily print the exact value of a "power of two" float in decimal.
Think of using base three to store 1/3, now try and print 1/3 in decimal perfectly.
For solutions see: How do you print the EXACT value of a floating point number?