Retrieve the string “0.1” from after assignment to a double variable - c++

I have a naive question about the high-precision number conversion (in C++ here).
Suppose the user assigns 0.1 to the double variable x_d with this statement,
x_d = 0.1
It is known that x_d thus obtained is no more exactly 0.1, due to the inevitable machine rounding.
I wonder whether we still have a way to get back the original highly precise string “0.1”, from the double variable x_d? Clearly, it is useless to use std::to_string (x_d) here. Even a high precision library like boost::multiprecision or MPFR seem to be helpless. For example, std::to_string(boost:cpp_dec_float_10000(x_d) ) cannot recover back the lost precision.
So my question is, can we retrieve back the string “0.1” from a double x_d that is assigned using the statement x_d = 0.1?

Let's assume that during the assignment, the decimal number 0.1 is rounded to a double value X that does not equal the decimal number 0.1. Now, assume some other computation results in the valueX, but without it being rounded. In order to distinguish those two, you would have to store the origin somewhere. For that, there is simply no place in a double (assuming common implementations), so the answer to your question is "no".

Related

Should I add a tiny amount when trying to use std::round()?

Here is a situation where a round_to_2_digits() function is rounding down when we expected it to round up. This turned out to be the case where a number cannot be represented exactly in a double. I don't remember the exact value, but say this:
double value = 1.155;
double value_rounded = round_to_2_digits( value );
The value was the output of a function, and instead of being exactly 1.155 like the code above, it actually was returning something like 1.15499999999999999. So calling std::round() on it would result in 1.15 instead of 1.16 like we thought.
Questions:
I'm thinking it may be wise to add a tiny value in round_to_2_digits() prior to calling std::round().
Is this standard practice, or acceptable? For example, adding the 0.0005 to the value being rounded.
Is there a mathematical term for this kind of "fudge factor"?
EDIT: "epsilon" was the term I was looking for.
And since the function rounds to only 2 digits after the decimal point, should I be adding 0.001? 0.005? 0.0005?
The rounding function is quite simple:
double round_to_2_decimals( double value )
{
value *= 100.0;
value = std::round(value);
value /= 100.0;
return value;
}
Step one is admitting that double may not be the right data type for your application. :-) Consider using a fixed-point type, or multiplying all of your values by 100 (or 1000, or whatever), and working with integer values.
You can't actually guarantee that adding any particular small epsilon won't give you the wrong results in some other situation. What if your value actually was 1.54999999..., and you rounded it up? Then you'd have the wrong value the other way.
The problem with your suggested solution is that at the end of it, you're still going to have a binary fraction that's not necessarily equal to the decimal value you're trying to represent. The only way to fix this is to use a representation that can exactly represent the values you want to use.
This question doesn't make a lot of sense. POSIX mandates std::round rounds half away from zero. So the result should in fact be 116 not 115. In order to actually replicate your behavior, I had to use a function that pays attention to rounding mode:
std::fesetround(FE_DOWNWARD);
std::cout << std::setprecision(20) << std::rint(1.155 * 100.0);
This was tested on GCC 5.2.0 and Clang 3.7.0.

Should I worry about precision when I use C++ mathematical functions with integers?

For example, The code below will give undesirable result due to precision of floating point numbers.
double a = 1 / 3.0;
int b = a * 3; // b will be 0 here
I wonder whether similar problems will show up if I use mathematical functions. For example
int a = sqrt(4); // Do I have guarantee that I will always get 2 here?
int b = log2(8); // Do I have guarantee that I will always get 3 here?
If not, how to solve this problem?
Edit:
Actually, I came across this problem when I was programming for an algorithm task. There I want to get
the largest integer which is power of 2 and is less than or equal to integer N
So round function can not solve my problem. I know I can solve this problem through a loop, but it seems not very elegant.
I want to know if
int a = pow(2, static_cast<int>(log2(N)));
can always give correct result. For example if N==8, is it possible that log2(N) gives me something like 2.9999999999999 and the final result become 4 instead of 8?
Inaccurate operands vs inaccurate results
I wonder whether similar problems will show up if I use mathematical functions.
Actually, the problem that could prevent log2(8) to be 3 does not exist for basic operations (including *). But it exists for the log2 function.
You are confusing two different issues:
double a = 1 / 3.0;
int b = a * 3; // b will be 0 here
In the example above, a is not exactly 1/3, so it is possible that a*3 does not produce 1.0. The product could have happened to round to 1.0, it just doesn't. However, if a somehow had been exactly 1/3, the product of a by 3 would have been exactly 1.0, because this is how IEEE 754 floating-point works: the result of basic operations is the nearest representable value to the mathematical result of the same operation on the same operands. When the exact result is representable as a floating-point number, then that representation is what you get.
Accuracy of sqrt and log2
sqrt is part of the “basic operations”, so sqrt(4) is guaranteed always, with no exception, in an IEEE 754 system, to be 2.0.
log2 is not part of the basic operations. The result of an implementation of this function is not guaranteed by the IEEE 754 standard to be the closest to the mathematical result. It can be another representable number further away. So without more hypotheses on the log2 function that you use, it is impossible to tell what log2(8.0) can be.
However, most implementations of reasonable quality for elementary functions such as log2 guarantee that the result of the implementation is within 1 ULP of the mathematical result. When the mathematical result is not representable, this means either the representable value above or the one below (but not necessarily the closest one of the two). When the mathematical result is exactly representable (such as 3.0), then this representation is still the only one guaranteed to be returned.
So about log2(8), the answer is “if you have a reasonable quality implementation of log2, you can expect the result to be 3.0`”.
Unfortunately, not every implementation of every elementary function is a quality implementation. See this blog post, caused by a widely used implementation of pow being inaccurate by more than 1 ULP when computing pow(10.0, 2.0), and thus returning 99.0 instead of 100.0.
Rounding to the nearest integer
Next, in each case, you assign the floating-point to an int with an implicit conversion. This conversion is defined in the C++ standard as truncating the floating-point values (that is, rounding towards zero). If you expect the result of the floating-point computation to be an integer, you can round the floating-point value to the nearest integer before assigning it. It will help obtain the desired answer in all cases where the error does not accumulate to a value larger than 1/2:
int b = std::nearbyint(log2(8.0));
To conclude with a straightforward answer to the question the the title: yes, you should worry about accuracy when using floating-point functions for the purpose of producing an integral end-result. These functions do not come even with the guarantees that basic operations come with.
Unfortunately the default conversion from a floating point number to integer in C++ is really crazy as it works by dropping the decimal part.
This is bad for two reasons:
a floating point number really really close to a positive integer, but below it will be converted to the previous integer instead (e.g. 3-1×10-10 = 2.9999999999 will be converted to 2)
a floating point number really really close to a negative integer, but above it will be converted to the next integer instead (e.g. -3+1×10-10 = -2.9999999999 will be converted to -2)
The combination of (1) and (2) means also that using int(x + 0.5) will not work reasonably as it will round negative numbers up.
There is a reasonable round function, but unfortunately returns another floating point number, thus you need to write int(round(x)).
When working with C99 or C++11 you can use lround(x).
Note that the only numbers that can be represented correctly in floating point are quotients where the denominator is an integral power of 2.
For example 1/65536 = 0.0000152587890625 can be represented correctly, but even just 0.1 is impossible to represent correctly and thus any computation involving that quantity will be approximated.
Of course when using 0.1 approximations can cancel out leaving a correct result occasionally, but even just adding ten times 0.1 will not give 1.0 as result when doing the computation using IEEE754 double-precision floating point numbers.
Even worse the compilers are allowed to use higher precision for intermediate results. This means that adding 10 times 0.1 may give back 1 when converted to an integer if the compiler decides to use higher accuracy and round to closest double at the end.
This is "worse" because despite being the precision higher the results are compiler and compiler options dependent, making reasoning about the computations harder and making the exact result non portable among different systems (even if they use the same precision and format).
Most compilers have special options to avoid this specific problem.

How to reestablish double in c++

When representing double number its precision corrupts in some degree. For example number 37.3 can be represented as 37.29999999999991.
I need reestablishing of corrupted double number (My project requires that). One approach is converting double into CString.
double d = 37.3;
CString str;
str.Format("%.10f", d);
Output: str = 37.3;
By this way I could reestablish corrupted d. However, I found a counterexample. If I set
d = 37.3500;
then its double representation sometimes be equal to 37.349998474121094. When converting d to CString output is still 37.3499984741, which is not equal to 37.3500 actually.
Why converting 37.3500 didn't give desired answer, while 37.3 gave? Is there any ways to reestablish double?
Thanks.
Why converting 37.3500 didn't give desired answer, while 37.3 gave?
By accident. The representation of 37.3 happened to be close enough that rounding to 10 decimal places gave the expected result, while 37.3499984741 didn't.
Is there any ways to reestablish double?
No, once information has been lost, you can't recover it. If you need an exact representation of decimal numbers, then you'll need a different format than binary floating point. There's no suitable decimal type in the C++ language or standard library; depending on your needs, you might consider libraries such as Boost.Multiprecision or GMP. Alternatively, if you can limit the number of decimal places you need, you might be able to multiply all your numbers by that scale and work with exact integers.
It can be done to some extend, but not easily. Since the string representation is base 10, but the internal representation in base 2, there is rounding involved when converting one into the other. So when you convert the decimal "37.35" to double, the result is not identical to the original number. When converting that number back to a string, the computer cannot know for sure what number was there in the first place, because there are several decimal numbers that result in the same double. However, you can add the constraint that you want the shortest possible decimal string that results in the given double, then there is a very good chance that it recovers your original string precisely. An algorithm using that constraint has been developed by David Gay. Here's the source code, you need both g_fmt.c and dtoa.c, and here is a paper about it. This is the default algorithm used in Python since Version 3.1.

Conversion from string to double - Possibility and errors

I am aware that the string 2.34 would never be equal to the double 2.34. No matter what library or algorithm you tried (lexical_cast,atof). Also 2.3400 can not be represented as double type. Instead it will be equal to 2.3399999999999999 . A little background I am working on an application that passes of values to an external application using its api. Think of it as some sort of a trading application. The user can pass values using the applications api or the user can pass value by using the application directly.Now when the user uses the application directly and the user types in 2.34 the value is processed as 2.34 however when I use the API which requires double as a parameter I pass 2.34 and it passes of as 2.3399999999999999 which is not acceptable. My question is how would the application be handling this and is there a way to store 2.34000.. in a double so that I could pass it to an API ?
If you need to pass decimal values through an API which takes double but you need to get the exact values, there isn't much of a problem: As long as you don't use more than std::numeric_limits<double>::digits10 digits, you can recover the original decimal value although not necessarily the same representation (trailing fractional zeros will be lost). To do so, you need to convert the original decimal string into the closest representation as double and later use a suitable algorithm to restore the best decimal representation again. The parsing and formatting functions from the C and C++ standard libraries will do that correctly for you.
Note that you shouldn't try to do any arithmetic on the double values when you want to restore the original decimal values: the result of double arithmetic will use binary rounding and the values won't be the closest decimal values. However, as long as you only transfer the double values, there is no problem.
Since you mention "trading application" I will conclude that the numbers represent currencies. If that is the case you are probably dealing with a fixed number of fractional digits as well. In that case you can scale your floating point numbers by multiplying them by 10 ^ number_of_fractional_digits, essentially making them integer values. Floating point numbers can accurately store integer values (as long as they do not exceed the floating point type's range).
Another possibility - if the assumptions above are correct - would be to use Binary-coded decimals.
The one way to work around floating point precision issues is using a well made fraction class. You may code one for yourself or use the ones provided by common math libraries. Such classes will represent your 2.34 as 234/100 internally, which will lead higher amount of memory consumption compared to a single float.

Rounding problem with double type [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Why don't operations on double-precision values give expected results?
I am experiencing a peculiar problem in C++. I created a variable of type Double. Then I did some calculations with some values assigned to other variables and assigned the result to the double variable I declared. It gave me a result with a long decimal part. I want it to round to only 2 decimal places. and store it into the variable. But even after several attempt rounding, I couldnt round it to 2 decimal places.
Then I tried another way to check what the real problem is. I created a Double variable and assigned it the value 1.11. But when I debugged it by putting a break point and added a watch for that variable, I could find that the value now stored in the variable is 1.109999999999.
My question is, why is it showing like that? Isnt there any way in which we can round the variable into two decimal places? Why is it showing a long decimal part even if we assign a number with just two decimal places?
Please suggest a way to store numbers - whether it is calculated or directly assigned - as it is, in a double variable rather than a number with a long decimal part.
In the set of double values, there is no such thing as the number 1.11 because internally, double uses a binary representation (as opposed to humans who are used to a decimal representation). Most finite decimal numbers (such as 1.11) have an infinite representation in binary, but since memory is limited, you lose some precision because of rounding.
The closest you can get to 1.11 with the double data type is 1.1100000000000000976996261670137755572795867919921875, which is internally represented as 0x3ff1c28f5c28f5c3.
Your requirement of two decimal places sounds like you are working with money. A simple solution is to store the cents in an integer (as opposed to the dollars in a double):
int cents = 111;
This way, you don't lose any precision. Another solution is to use a dedicated decimal data type.
the floating-point types like float and double are not 100% precise. They may store 14.3 as 14.299999... and there is nothing wrong about that. That is why you should NEVER compare two floats or doubles with == operator, instread you should check if the absolute value of their difference is smaller than a certain epsilon, like 0.000000001
Now, if you want to output the number in a pleasant way, you can use setprecision from <iomanip>
E.g.
#include <iostream>
#include <iomanip>
int main()
{
double d = 1.389040598345;
std::cout << setprecision(2) << d; //outputs 1.39
}
If you want to obtain the value of d rounded 2 decimal places after the point, then you can use this formula
d = floor((d*100)+0.5)/100.0; //d is now 1.39
Not every decimal number has an exact, finite, binary floating-point representation. You've already found one example, but another one is 0.1 (decimal) = 0.0001100110011... (binary).
You either need to live with that, or use a decimal floating-point library (which will be less efficient).
My recommendation would be to store numbers to full precision, and only round when you need to display them to humans.