How to determine the last nonzero decimal digit in a float? - c++

I am writing a float printing and formatting library and want to avoid printing trailing zero digits.
For this I would like to accurately determine the last nonzero digit within the first N decimal places after the decimal point. I wonder whether there is a particular efficient way to do this.

This (non-trivial) problem has been fully solved. The idea is to print exactly enough digits so that if you converted the printed digits back to a floating-point number, you would get exactly the number you started with.
The relevant paper is "Printing Floating-Point Numbers Quickly and Accurately", by Robert Burger and R. Kent Dybvig. You can download it here.

You will have to convert the float to a string and then trim the trailing zeros.
I don't think this is very efficient, but i feel there is probably no simplier algorithm

std::cout.precision(n);
//where n is the digits you want to display after the decimal.
If there is a zero present before the precision limit but after decimal,
it will be avoided automatically.
eg. std::cout.precision(5);
then my conidition is evaluated to be 5.55000
only 5.55 will be printed

The obvious solution is to put all digits in a char[N] and check the last digit before printing. But I bet you have thought about that yourself.
The only other solution I can think of, is that the decimal part of 2^(-n) has n non-zero digits.
So if the last non-zero in the binary representation is 2^(-n), there will be exactly n non-zero digits in the decimal expansion. Therefor looking at the binary representation will tell you something about the decimal representation.
However, this is only a partial solution, as rounding could introduce additional trailing zeros.

Related

C++ set precision of a double (not for output)

Alright so I am trying to truncate actual values from a double with a given number of digits precision (total digits before and after, or without, decimal), not just output them, not just round them. The only built in functions I found for this truncates all decimals, or rounds to given decimal precision.
Other solutions I have found online, can only do it when you know the number of digits before the decimal, or the entire number.
This solution should be dynamic enough to handle any number. I whipped up some code that does the trick below, however I can't shake the feeling there is a better way to do it. Does anyone know of something more elegant? Maybe a built in function that I don't know about?
I should mention the reason for this. There are 3 different sources of observed values. All 3 of these sources agree to some level in precision. Such as below, they all agree within 10 digits.
4659.96751751236
4659.96751721355
4659.96751764253
However I need to only pull from 1 of the sources. So the best approach, is to only use up to the precision all 3 sources agree on. So its not like I am manipulating numbers and then need to truncate precision, they are observed values. The desired result is
4659.967517
double truncate(double num, int digits)
{
// check valid digits
if (digits < 0)
return num;
// create string stream for full precision (string conversion rounds at 10)
ostringstream numO;
// read in number to stream, at 17+ precision things get wonky
numO << setprecision(16) << num;
// convert to string, for character manipulation
string numS = numO.str();
// check if we have a decimal
int decimalIndex = numS.find('.');
// if we have a decimal, erase it for now, logging its position
if(decimalIndex != -1)
numS.erase(decimalIndex, 1);
// make sure our target precision is not higher than current precision
digits = min((int)numS.size(), digits);
// replace unwanted precision with zeroes
numS.replace(digits, numS.size() - digits, numS.size() - digits, '0');
// if we had a decimal, add it back
if (decimalIndex != -1)
numS.insert(numS.begin() + decimalIndex, '.');
return atof(numS.c_str());
}
This will never work since a double is not a decimal type. Truncating what you think are a certain number of decimal digits will merely introduce a new set of joke digits at the end. It could even be pernicious: e.g. 0.125 is an exact double, but neither 0.12 nor 0.13 are.
If you want to work in decimals, then use a decimal type, or a large integral type with a convention that part of it holds a decimal portion.
I disagree with "So the best approach, is to only use up to the precision all 3 sources agree on."
If these are different measurements of a physical quantity, or represent rounding error due to different ways of calculating from measurements, you will get a better estimate of the true value by taking their mean than by forcing the digits they disagree about to any arbitrary value, including zero.
The ultimate justification for taking the mean is the Central Limit Theorem, which suggests treating your measurements as a sample from a normal distribution. If so, the sample mean is the best available estimate of the population mean. Your truncation process will tend to underestimate the actual value.
It is generally better to keep every scrap of information you have through the calculations, and then remember you have limited precision when outputting results.
As well as giving a better estimate, taking the mean of three numbers is an extremely simple calculation.

C++ Type of variables - value

I am the beginner, but I think same important thinks I should learn as soon as it possible.
So I have a code:
float fl=8.28888888888888888888883E-5;
cout<<"The value = "<<fl<<endl;
But my .exe file after run show:
8.2888887845911086e-005
I suspected the numbers to limit of the type and rest will be the zero, but I saw digits, which are random. Maybe it gives digits from memory after varible?
Could you explain me how it does works?
I suspected the numbers to limit of the type and rest will be the zero
Yes, this is exactly what happens, but it happens in binary. This program will show it by using the hexadecimal printing format %a:
#include <stdio.h>
int main(int c, char *v[]) {
float fl = 8.28888888888888888888883E-5;
printf("%a\n%a\n", 8.28888888888888888888883E-5, fl);
}
It shows:
0x1.5ba94449649e2p-14
0x1.5ba944p-14
In these results, 0x1.5ba94449649e2p-14 is the hexadecimal representation of the double closest to 8.28888888888888888888883*10-5, and 0x1.5ba944p-14
is the representation of the conversion to float of that number. As you can see, the conversion simply truncated the last digits (in this case. The conversion is done according to the rounding mode, and when the rounding goes up instead of down, it changes one or more of the last digits).
When you observe what happens in decimal, the fact that float and double are binary floating-point formats on your computer means that there are extra digits in the representation of the value.
I suspected the numbers to limit of the type and rest will be the zero
That is what happens internally. Excess bits beyond what the type can store are lost.
But that's in the binary representation. When you convert it to decimal, you can get trailing non-zero digits.
Example:
0b0.00100 is 0.125 in decimal
What you're seeing is a result of the fact that you cannot exactly represent a floating-point number in memory. Because of this, floats will be stored as the nearest value that can be stored in memory. A float usually has 24 bits used to represent the mantissa, which translates to about 6 decimal places (this is implementation defined though, so you shouldn't rely on this). When printing more than 6 decimal digits, you'll notice your value isn't stored in memory as the value you intended, and you'll see random digits.
So to recap, the problem you encountered is caused by the fact that base-10 decimal numbers cannot be represented in memory, instead the closest number to it is stored and this number will then be used.
each data type has range after this range all number is from memory or rubbish so you have to know this ranges and deal with it when you write code.
you can know this ranges from here or here

How to read 2 decimal places without round in Coldfusion

Sample Code
<cfset b = 5.5566>
<cfset c = numberFormat(b,"9.99")>
<cfdump var="#c#">
I need c= 5.55 only. How can I do this ,because numberFormat rounds the number?
As Dan points out, truncating / rounding down is an uncommon scenario, and you should double-check this is what the client actually wants, and why they want it (i.e. they might think they want it but have incorrect reasoning.)
If there is a valid reason to do it, the easiest way is probably to use the int function - equivalent to "floor" in some languages - it will round numbers down to the next integer, so 1.999 becomes 1.
(If negative numbers are a factor, consider instead fix which rounds towards the smaller integer, that is, towards zero.)
Since you want two decimal places, you would use it like this:
c = int(b*100)/100
Where the mulitply and divide by 100 is what provides the two decimal places.
For an arbitrary number of decimal places, you can replace the 100s with 10dp - where dp is the number of decimal places, for example:
c = int(b*10^dp)/10^dp
If you're doing that, it's probably worth wrapping it in a suitably named function so it's more readable. (And if necessary adding a comment to explain why you're rounding down rather than the more common rounding to nearest value.)
For the sake of showing another way, this could also be solved with a regex replace:
c = b.replaceAll('(?<=\.\d\d)\d+$','')
That removes all digits that are preceeded by the decimal place and two digits, until the end of string.
However, this is mentioned solely for educational purposes - the int solution is going to be more efficient.

Does the dot in the end of a float suggest lack of precision?

When I debug my software in VS C++ by stepping the code I notice that some float calculations show up as a number with a trailing dot, i.e.:
1232432.
One operation that lead up to this result is this:
float result = pow(10, a * 0.1f) / b
where a is a large negative number around -50 to -100 and b is most often around 1. I read some articles about problem with precision when it comes to floating-points. My question is just if the trailing dot is a Visual-Studio-way of telling me that the precision is very low on this number, i.e. in the variable result. If not, what does it mean?
This came up at work today and I remember that there was a problem for larger numbers so this did to occur every time (and by "this" I mean that trailing dot). But I do remember that it happened when there was seven digits in the number. Here they wright that the precision of floats are seven digits:
C++ Float Division and Precision
Can this be the thing and Visual Studio tells me this by putting a dot in the end?
I THINK I FOUND IT! It says "The mantissa is specified as a sequence of digits followed by a period". What does the mantissa mean? Can this be different on a PC and when running the code on a DSP? Because the thing is that I get different results and the only thing that looks strange to me is this period-thing, since I don't know what it means.
http://msdn.microsoft.com/en-us/library/tfh6f0w2(v=vs.71).aspx
If you're referring to the "sig figs" convention where "4.0" means 4±0.1 and "4.00" means 4±0.01, then no, there's no such concept in float or double. Numbers are always* stored with 24 or 53 significant bits (7.22 or 15.95 decimal digits) regardless of how many are actually "significant".
The trailing dot is just a decimal point without any digits after it (which is a legal C literal). It either means that
The value is 1232432.0 and they trimed the unnecessary trailing zero, OR
Everything is being rounded to 7 significant digits (in which case the true value might also be 1232431.5, 1232431.625, 1232431.75, 1232431.875, 1232432.125, 1232432.25, 1232432.375, or 1232432.5.)
The real question is, why are you using float? double is the "normal" floating-point type in C(++), and float a memory-saving optimization.
* Pedants will be quick to point out denormals, x87 80-bit intermediate values, etc.
The precision is not variable, that is simply how VS is formatting it for display. The precision (or lackof) is always constant for a given floating point number.
The MSDN page you linked to talks about the syntax of a floating-point literal in source code. It doesn't define how the number will be displayed by whatever tool you're using. If you print a floating-point number using either printf or std:cout << ..., the language standard specifies how it will be printed.
If you print it in the debugger (which seems to be what you're doing), it will be formatted in whatever way the developers of the debugger decided on.
There are a number of different ways that a given floating-point number can be displayed: 1.0, 1., 10.0E-001, and .1e+1 all mean exactly the same thing. A trailing . does not typically tell you anything about precision. My guess is that the developers of the debugger just used 1232432. rather than 1232432.0 to save space.
If you're seeing the trailing . for some values, and a decimal number with no . at all for others, that sounds like an odd glitch (possibly a bug) in the debugger.
If you're wondering what the actual precision is, for IEEE 32-bit float (the format most computers use these days), the next representable numbers before and after 1232432.0 are 1232431.875 and 1232432.125. (You'll get much better precision using double rather than float.)

How do I determine the number of places following a decimal in a floating point value?

In C++ you can use std::numeric_limits<FloatingPointType>::digits10 to find out exactly how many places of precision you can get before the decimal place. How do I find out how many decimal places I can get following it, if I know the number will always be fixed-point between 0 and 1 inclusive?
Edit: The reason I ask is that I have an external RNG generating doubles and piping them through to a second program using standard input and output, so if the randomly generated numbers aren't output correctly to standard output, the second program can't grab their full values through standard input because they get truncated by the output of the first program, then rounded to representable values by the second program. I'd like to pipe the values between programs fully intact.
Thanks
std::numeric_limits<FloatingPointType>::digits10 is the total number of decimal digits the type can exactly represent. If you write a number as 1234.56 or 1.23456 ⋅ 103 or 123456 ⋅ 10-2 doesn't matter for the number of exact digits, so there is no distinction between before and after the decimal place.
The maximum number of significant digits you can have is given by std::numeric_limits<...>::digits. This is typically 24 and 53 for IEEE floats and doubles, respectively.
The C++ standard doesn't guarantee you anything.
If you have to strictly control the number of places after the decimal point, you have to write your own code to do so (fixed-format output for instance).
Ultimately it depends on the compiler you are using.
You would get better luck by using C and printf's formatting controls if you need control over the number of decimal places.
If you will always need a certain number of digits you'd be well advised to look into boost. For example the format library, or the numeric conversion library. If you haven't already, you also should read the Goldberg article about floating point numbers
You can use setprecision(n);, where n is the number of digits after the decimal point.
For example, if I want 15 decimals in my output:
cout<< setprecision(15);
Note: don't forget to include the header file to use this function:
#include<iomanip>