Float to string without rounding - c++

I wanted to extract decimal places from decimal number. Not that hard, right?
So, I converted float to string.
Then, I used substr() to crop the string starting from string.find('.')+1, till the end.
Well.... the problem is here. When we have a number like this: 5.7741589, it's not "precise" that much, it's actually: 5.774159
If it round itself, I can't precisely get the number of decimal places... So question is:
How can I convert decimal number to string, without rounding it?
EDIT: Since a lot of people are asking for actual input and output and code, here it is:
Input: 5.7741589
Output (let's say we want to output just decimal places): 7741589
Output (not expected one): 774159
Code:
float num;
cin>>num;
string s = to_string(num);
s = s.substr(s.find('.')+1,s.length());
cout<<s<<endl;
EDIT2: One more thing. I need this for competitive programming, I can do this exercise with input as string. Imagine you have problem where you have 2 decimal numbers, you need to multiply them and then count number of decimal places. Then you again lose decimal places which is problem.

The rot sets in as soon as you use a binary floating point number to model a decimal number: a floating point scheme models a subset of the real numbers. In this respect it's no different to using an integral type: conceptually the issues that arise are no different.
If you want to model decimal numbers exactly then use a decimal type.

The result you are getting is because of rounding off decimal places. This is because as soon as you enter a floating point number, whatever may be the number of decimal places, it is stored with as many decimal places as the precision of the data type. So for float (which can store 8 decimal places), if you enter
1.1234 ---- Stored as ---> 1.12339997
1.123 ---- Stored as ---> 1.12300003
5.7741589 ---- Stored as ---> 5.77415895
So basically, you are storing the input in those number (8) of decimal places. What can be done is that you can use below snippet to forcefully use the desired number of digits after decimal places and convert it to string.
float num;
cin >> num;
char buf[20];
// 8 is as per the (precision required + 1). So in this case,
// we have 7 digits after decimal, so 8 is used.
sprintf(buf, "%.8f", num);
// Truncating the rounding off
buf[strlen(buf) - 1] = '\0';
string s(buf);
s = s.substr(s.find('.') + 1, s.length());
cout << s << endl;
Though with this approach, it would be necessary that all your inputs are having equal number of decimal places.
This is sort of a workaround, because the value 5.7741589 that you entered is not stored as it is. So, if the source itself is not what you entered, how can you get the desired output with the assumption that source is what you provided.

Let's see what happens (this answer supposes IEEE-754, with floats being 32-bit binary floating-point numbers).
First, you enter the decimal number as input: 5.7741589. This number has to be stored into a 32-bit binary floating point.
This number in binary is 101.11000110001011110100011100010101011010000100011...
To store this into a float, we need to round it (in binary). So cin>>num is lossy. It is rounded to the nearest 32-bit binary floating point number, which is:
in binary: 1.01110001100010111101001 * 2^2 = 101.110001100010111101001.
in decimal: 1.44353973865509033203125 * 2^2 = 5.774158954620361328125.
As you can see, there is no point talking about decimal places, after your input number is converted to float, because your input number has been modified (looking at your number in binary, it got rounded. Looking at the number as decimal, it got a lot of extra digits, its value slightly differs from the original one).
If you want to solve this problem, you need to input the number as string, or you need to use some kind of decimal floating-point library.

Related

Can you help me to understand what "significant digits" means in floating point math?

For what I'm learning, once I convert a floating point value to a decimal one, the "significant digits" I need are a fixed number (17 for double, for example). 17 totals: before and after decimal separator.
So for example this code:
typedef std::numeric_limits<double> dbl;
int main()
{
std::cout.precision(dbl::max_digits10);
//std::cout << std::fixed;
double value1 = 1.2345678912345678912345;
double value2 = 123.45678912345678912345;
double value3 = 123456789123.45678912345;
std::cout << value1 << std::endl;
std::cout << value2 << std::endl;
std::cout << value3 << std::endl;
}
will correctly "show me" 17 values:
1.2345678912345679
123.45678912345679
123456789123.45679
But if I increase precision for the cout (i.e. std::cout.precision(100)), I can see there are other numbers after the 17 range:
1.2345678912345678934769921397673897445201873779296875
123.456789123456786683163954876363277435302734375
123456789123.456787109375
Why should ignore them? They are stored within the variables/double as well, so they will affect the whole "math" later (division, multiplication, sum, and so on).
What does it means "significant digits"? There is other...
Can you help me to understand what “significant digits” means in floating point math?
With FP numbers, like mathematical real numbers, significant digits is the leading digits of a value that do not begin with 0 and then, depending on context, to 1) the decimal point, 2) the last non-zero digit, or 3) the last printed digit.
123. // 3 significant decimal digits
123.125 // 6 significant decimal digits
0.0078125 // 5 significant decimal digits
0x0.00123p45 // 3 significant hexadecimal digits
123000.0 // 3, 6, or 7 significant decimal digits depending on context
When concerned about decimal significant digits and FP types like double. the issue is often "How many decimal significant digits are needed or of concern?"
Nearly all C FP implementations use a binary encoding such that all finite FP are exact sums of power of 2. Each finite FP is exact. Common encoding affords most double to have 53 binary digits is it significand - so 53 significant binary digits. How this appears as a decimal is often the source of confusion.
// Example 0.1 is not an exact sum of powers of 2 so a nearby value is used.
double x = 0.1;
// x takes on the exact value of
// 0.1000000000000000055511151231257827021181583404541015625
// aka 0x1.999999999999ap-4
// aka base2: 0.000110011001100110011001100110011001100110011001100110011010
// The preceding and subsequent doubles
// 0.09999999999999999167332731531132594682276248931884765625
// 0.10000000000000001942890293094023945741355419158935546875
// 123456789012345678901234567890123456789012345678901234567890
Looking at above, one could say x has over 50 decimal significant digits. Yet the value matches the intended 0.1 to 16 decimal significant digits. Or yet since the preceding and subsequent possible double values differ in the 17 place, one could say x has 17 decimal significant digits.
What does it means "significant digits"?
Various meanings of significant digits exist, but for C, 2 common ones are:
The number of decimal significant digits that a textual value to double converts as expected for all double. This is typically 15. C specifies this as DBL_DIG and must be at least 10.
The number of decimal significant digits that a textual value of double needs to be printed to distinguish from another double. This is typically 17. C specifies this as DBL_DECIMAL_DIG and must be at least 10.
Why should ignore them?
It depends of coding goals. Rarely are all digits of the exact value needed. (DBL_TRUE_MIN might have 752 od them.) For most applications, DBL_DECIMAL_DIG is enough. In select apps, DBL_DIG will do. So usually, ignoring digits past 17 does not cause problems.
Keep in mind that floating-point values are not real numbers. There are gaps between the values, and all those extra digits, while meaningful for real numbers, don’t reflect any difference in the floating-point value. When you convert a floating-point value to text, having std::numeric_limits<...>::max_digits10 digits ensures that you can convert the text string back to floating-point and get the original value. The extra digits don’t affect the result.
The extra digits that you see when you ask for more digits are the result of the conversion algorithm trying to do what you asked. The algorithm typically just keeps extracting digits until it reaches the desired precision; it could be written to start outputting zeros after it’s written max_digits10 digits, but that’s an additional complication that nobody bothers with. It wouldn’t really be helpful.
just to add to Pete Becker's answer, I think you're confusing the problem of finding the exact decimal representation of a binary mantissa, with the problem of finding some decimal representation uniquely representing that binary mantissa ( given some fixed rounding scheme ).
Now, regarding the first problem, you always need a finite number of decimal digits to exactly represent a binary mantissa ( because 2 divides 10 ).
For example, you need 18 decimal digits to exactly represent the binary 1.0000000000000001, being 1.00000762939453125 in decimal.
but you need just 17 digits to represent it uniquely as 1.0000076293945312 because no other number having exact value 1.0000076293945312xyz... where 0<=x<5 can exist as a double ( more precisely, the next and prior exactly representable values being 1.0000076293945314720446049250313080847263336181640625 and 1.0000076293945310279553950749686919152736663818359375 ).
Of course, this does not mean that given some decimal number you can ignore all digits past the 17th; it just means that if you apply the same rounding scheme used to produce the decimal at the 17th position and assign it back to a double you'll get the same original double.

How to count the decimal places of an double variable in c++?

for a course at my university i need to write a program which converts a number into
natural language e.g. if the user enters "2.55" the program outputs "two point five five".
And i'm close to finish it the only thing i cant get are numbers after the point.
I'm not allowed to use strings. Here is how i tried to get the count of decimal places:
i=0;
while((wert - (long int)wert) != 0){
wert /= 10;
i++;
}
But it gives me the value of 356 decimal places for the example number "2.55". Is there any method wihout using strings to count the decimal places?
Best Regards
You will not be able to use a double to do this due to floating point precision. For example, a double set to 0.2 will have many more decimal places than 1 since 0.2 cannot be represented precisely. (Why not examine the actual value of the double in your debugger?) 2.55 cannot be represented precisely either.
Probably the simplest thing for you to do here is use a string to represent your number and base your parser on that.
If the user is entering the number, it will be coming in as a string, or shall we say into a byte array, so there is no need to bring floating-point into it at all. Just locate the decimal place in the data and then start counting digits.
NB The question in your title is meaningless. Floating-point variables don't have decimal places, they have binary places, and decimal and binary places are incommensurable. If your professor wants you to use floating-point he needs re-education himself.
The IEEE 64-bit binary number closest to 2.55 is 2.54999999999999982236431605997495353221893310546875, which only has 50 digits after the decimal point.
The repeated division makes no sense. Ignoring rounding error, the values of wert would be 2.55, 0.255, 0.0255, 0.00255, etc. none of which is equal to any long. The loop terminates when wert underflows to zero.
Instead, you should be multiplying by 10. However, if you keep the leading digits you may get a number too large to store as a long before getting equality. Instead, I suggest subtracting off the integer part at each step, and stopping when the result is zero.
That will still lead to a 50 decimal place answer, but if your professor insists on double, maybe that is what is wanted.
char* fractpart(double f)
{
char chrstr[5];
char charary={'1','2','3',....,'0'};
int intary={1,2,3,...,0};
int count=0,x,y;
f=f-(int)f;
while(f<=1)
{
f=f*10;
for(y=0;y<10;y++)
{
if((int)f==intary[y])
{
chrstr[count]=charary[y];
break;
}
}
f=f-(int)f;
if(f<=0.01 || count==4)
break;
if(f<0)
f=-f;
count++;
}
return(chrstr);
}
You have to know the maximal number of digits you have to support after the point.Let's say n digits maximum. Multiply the fractional part of your number by 10^n and then shift the resulting number right until the last digit is different from 0 to remove trailing zeroes. Then print the digits one by one:
void printDigitsAfterPoint(double x) {
int k = Math.round((x-(int) x)*Math.pow10(n));
// remove trailing zeroes
while (k!=0 && k%10==0) {
k/=10;
}
// output digits
while (k!=0) {
output(k%10); // you already should have a method like this...
k/=10;
}
}
Make sure to add code for handling negative values of x. I'm sure your prof will try that...
EDIT: Forgot to change the declaration. Fixed.

C++ String to float with precision

I have a file with number readings (example 5.513208E-05 / 1.146383E-05)
I read the file and store the entries in a temporary string.
After that I convert the temporary string into float variable (which I store in an Multi Dimensional Array).
I use the code below to convert.
getline(infile, temporary_string, ',');
Array[i][0] = ::atof(temporary_string.c_str());
getline(infile, temporary_string);
Array[i][1] = ::atof(temporary_string.c_str());
The problem is that when I print the floats to the screen
5.51321e-05 1.14638e-05 instead of
5.513208E-05 1.146383E-05
How can I get the precise numbers stored ???
You don't specify precision when you read or convert the string. Instead you set the precision when you output the value:
std::cout << std::setprecision(3) << 1.2345 << '\n';
The above will produce the following oputput:
1.23
See e.g. this reference.
Ensure you have double Array[][], not float. A text presentation (base 10) is always approximated by the binary floating point number (base 2), but with luck approximated number of atof has the same presentation, when using the same format. In general one does not do much calculation, and on output uses a reduced precision with setprecision or formats.
Every floating-point representation of numbers has limited precision. In particular, float has 24 bits (1 fixed+23 variable) for its binary mantissa, thus implying a precision of roughly seven decimal digits.
If you need more precision for the stored number, you may wish to consider using double instead of float. On normal PCs, double has 53 bits (1+52) for the binary mantissa, thus allowing a 15-decimal digit precision.
But remember that there's also a problem when those numbers are output. I think the default precision for both printf() and std::ostream is only 6 digits, both for float and for double, unless you specify otherwise. There is no point, however, in demanding a higher precision during output than what the data type provides. So, even though you can say printf("%0.30g", some_float), the extra 23 digits beyond the seven actually supported by the data type might not really produce useful information.

Weird Rounding Occurs in C++ Function

I am writing a function in c++ that is supposed to find the largest single digit in the number passed (inputValue). For example, the answer for .345 is 5. However, after a while, the program is changing the inputValue to something along the lines of .3449 (and the largest digit is then set to 9). I have no idea why this is happening. Any help to resolve this problem would be greatly appreciated.
This is the function in my .hpp file
void LargeInput(const double inputValue)
//Function to find the largest value of the input
{
int tempMax = 0,//Value that the temporary max number is in loop
digit = 0,//Value of numbers after the decimal place
test = 0,
powerOten = 10;//Number multiplied by so that the next digit can be checked
double number = inputValue;//A variable that can be changed in the function
cout << "The number is still " << number << endl;
for (int k = 1; k <= 6; k++)
{
test = (number*powerOten);
cout << "test: " << test << endl;
digit = test % 10;
cout << (static_cast<int>(number*powerOten)) << endl;
if (tempMax < digit)
tempMax = digit;
powerOten *= 10;
}
return;
}
You cannot represent real numbers (doubles) precisely in a computer - they need to be approximated. If you change your function to work on longs or ints there won't be any inaccuracies. That seems natural enough for the context of your question, you're just looking at the digits and not the number, so .345 can be 345 and get the same result.
Try this:
int get_largest_digit(int n) {
int largest = 0;
while (n > 0) {
int x = n % 10;
if (x > largest) largest = x;
n /= 10;
}
return largest;
}
This is because the fractional component of real numbers is in the form of 1/2^n. As a result you can get values very close to what you want but you can never achieve exact values like 1/3.
It's common to instead use integers and have a conversion (like 1000 = 1) so if you had the number 1333 you would do printf("%d.%d", 1333/1000, 1333 % 1000) to print out 1.333.
By the way the first sentence is a simplification of how floating point numbers are actually represented. For more information check out; http://en.wikipedia.org/wiki/Floating_point#Representable_numbers.2C_conversion_and_rounding
This is how floating point number work, unfortunately. The core of the problem is that there are an infinite number of floating point numbers. More specifically, there are an infinite number of values between 0.1 and 0.2 and there are an infinite number of values between 0.01 and 0.02. Computers, however, have a finite number of bits to represent a floating point number (64 bits for a double precision number). Therefore, most floating point numbers have to be approximated. After any floating point operation, the processor has to round the result to a value it can represent in 64 bits.
Another property of floating point numbers is that as number get bigger they get less and less precise. This is because the same 64 bits have to be able to represent very big numbers (1,000,000,000) and very small numbers (0.000,000,000,001). Therefore, the rounding error gets larger when working with bigger numbers.
The other issue here is that you are converting from floating point to integer. This introduces even more rounding error. It appears that when (0.345 * 10000) is converted to an integer, the result is closer to 3449 than 3450.
I suggest you don't convert your numbers to integers. Write your program in terms of floating point numbers. You can't use the modulus (%) operator on floating point numbers to get a value for digit. Instead use the fmod function in the C math library (cmath.h).
As other answers have indicated, binary floating-point is incapable of representing most decimal numbers exactly. Therefore, you must reconsider your problem statement. Some alternatives are:
The number is passed as a double (specifically, a 64-bit IEEE-754 binary floating-point value), and you wish to find the largest digit in the decimal representation of the exact value passed. In this case, the solution suggested by user millimoose will work (provided the asprintf or snprintf function used is of good quality, so that it does not incur rounding errors that prevent it from producing correctly rounded output).
The number is passed as a double but is intended to represent a number that is exactly representable as a decimal numeral with a known number of digits. In this case, the solution suggested by user millimoose again works, with the format specification altered to convert the double to decimal with the desired number of digits (e.g., instead of “%.64f”, you could use “%.6f”).
The function is changed to pass the number in another way, such as with decimal floating-point, as a scaled integer, or as a string containing a decimal numeral.
Once you have clarified the problem statement, it may be interesting to consider how to solve it with floating-point arithmetic, rather than calling library functions for formatted output. This is likely to have pedagogical value (and incidentally might produce a solution that is computationally more efficient than calling a library function).

How to figure out how many decimal digits are in a large double?

Hey so I'm making a function that returns the number of decimals, whole numbers, or TOTAL numbers there are, but have been unable to make it work with either of these ways:
multiplying by a really large number like 10 billion doesn't work because of the innacurate way computers store decimals, making 2.3 2.2999575697
Using a StringStream to convert the number to a string and count the characters doesn't work because it requires you to set the stream to a precision which either takes away or adds unnecesary '0' characters if not set to the actual number of decimals
So WHAT DO I DO NOW? somebody please help =( Thanks!
if you wanna see my function that converts the numb to a string here it is:
////////////////////// Numbs_Digits ////////////////////////////////////////////////
template<typename T>
int Numbs_Digits(T numb, int scope)
{
stringstream ss(stringstream::in| stringstream::out), ss2(stringstream::in| stringstream::out);
unsigned long int length= 0;
unsigned long int numb_wholes;
ss2 << (int)numb;
numb_wholes = ss2.str().length(); ss2.flush();
bool all= false;
ss.precision(11); // HOW DO I MAKE THE PRECISION NUMBER THE NUMBER OF DECIMALS?
switch(scope){
case ALL: all = true;
case DECIMALS: ss << fixed << numb;
length += ss.str().length()- (numb_wholes +1); // +1 for the "."
if(all!= true) break;
case WHOLE_NUMBS:
length += numb_wholes;
if(all!= true) break;
default: break;}
return length;};
If you want to know the maximum number of decimal digits that a long double can store, this value is available in the constant LDBL_DIG defined in cfloat. Note that this number is actually an approximation as the values are stored in binary internally, and thus the range of values is not a power of 10.
Only some decimal numbers can be stored in exact form as a floating point number. Because of this there is no way to determine how many decimal places are significant for any decimal number for which this is not true. As hammar suggested, read up on the floating point storage format, I believe that every programmer should have some knowledge of low level stuff like this :D
multiplying by a really large number like 10 billion doesn't work because of the innacurate way computers store decimals, making 2.3 2.2999575697
This is exactly the problem. Would you be able to look at 2.999575697 and tell me it has two decimal places? This number is an example of a decimal number that cannot be stored in exact form using the floating point format. The best you could do is count the significant decimal places stored in the floating point number that best approximates the original decimal number it was given - which I can't imagine would be much use.
Edited for a more accurate explanation.
Can you not set the ios_base precision to the maximum number of decimal digits in the significand on your platform in cfloat.h, and then, using ios_base::setf(), change the floating point formatting to scientific, which will remove any trailing zeroes from the floating point number (you'll just have to trim the exponent off the end)?