I was wondering, how long in number of characters would the longest a double printed using fprintf be? My guess is wrong.
Thanks in advance.
Twelve would be a bit of an underestimate. On my machine, the following results in a 317 character long string:
#include <limits>
#include <cstdio>
#include <cstring>
int main()
{
double d = -std::numeric_limits<double>::max();
char str[2048] = "";
std::sprintf(str, "%f", d);
std::size_t length = std::strlen(str);
}
Using %e results in a 14 character long string.
Who knows. The Standard doesn't say how many digits of precision a double provides other than saying it (3.9.1.8) "provides at least as much precision as float," so you don't really know how many characters you'll need to sprintf an arbitrary value. Even if you did know how many digits your implementation provided, there's still the question of exponential formatting, etc.
But there's a MUCH bigger question here. Why the heck would you care? I'm guessing it's because you're trying to write something like this:
double d = ...;
int MAGIC_NUMBER = ...;
char buffer[MAGIC_NUMBER];
sprintf(buffer, "%f", d);
This is a bad way to do this, precisely because you don't know how big MAGIC_NUMBER should be. You can pick something that should be big enough, like 14 or 128k, but then the number you picked is arbitrary, not based on anything but a guess that it will be big enough. Numbers like MAGIC_NUMBER are, not suprisingly, called Magic Numbers. Stay away from them. They will make you cry one day.
Instead, there's a lot of ways to do this string formatting without having to care about buffer sizes, digits of precision, etc, that let you just get on with the buisness of programming. Streams is one:
#include <sstream>
double d = ...;
stringstream ss;
ss << d;
string s = ss.str();
cout << s;
...Boost.Format is another:
#include <boost\format\format.hpp>
double d = ... ;
string s = (boost::format("%1%") % d).str();
cout << s;
Its defined in limits:
std::cout << std::numeric_limits<double>::digits << "\n";
std::cout << std::numeric_limits<double>::digits10 << "\n";
Definition:
digits: number of digits (in radix base) in the mantissa
Equivalent to FLT_MANT_DIG, DBL_MANT_DIG or LDBL_MANT_DIG.
digits10: Number of digits (in decimal base) that can be represented without change.
Equivalent to FLT_DIG, DBL_DIG or LDBL_DIG for floating types.
See: http://www.cplusplus.com/reference/std/limits/numeric_limits/
Of course when you print stuff to a stream you can use the stream manipulators to limit the size of the output.
you can decide it by yourself..
double a=1.1111111111111111111111111111111111111111111111111;
printf("%1.15lf\n", a);
return 0;
./a.out
1.111111111111111
you can print more than 12 characters..
If your machine uses IEEE754 doubles (which is fairly widespread now), then the binary precision is 53 bits; The decimal equivalent is approximately 15.95 (calculated via logarithmic conversion), so you can usually rely on 15 decimal digits of precision.
Consult Double precision floating-point format for a brief discussion.
For a much more in-depth study, the canonical paper is What Every Computer Scientist Should Know About Floating-Point Arithmetic. It gets cited here whenever binary floating point discussions pop up, and is worth a weekend of careful reading.
Related
I was searching for functions to reliably convert strings to doubles and then back to strings in c++, so that the output string is exactly the same as the input string. But I could not find reliable functions even after hours of searching and trying out.
To check if the functions are reliable I made the following test:
#include <iostream>
#include <string>
using namespace std;
string double2string(double value){
//...
}
double string2double(string value){
//...
}
int main(){
string strings[] = {
"111111111111110000",
"11111111111111000",
"1111111111111100",
"111111111111110",
"11111111111111",
"1111111111111.1",
"111111111111.11",
"11111111111.111",
"1111111111.1111",
"111111111.11111",
"11111111.111111",
"1111111.1111111",
"111111.11111111",
"11111.111111111",
"1111.1111111111",
"111.11111111111",
"11.111111111111",
"1.1111111111111",
"0.11111111111111",
"0.011111111111111",
"0.0011111111111111",
"0.00011111111111111"
};
double doubles[] = {
111111111111110000,
11111111111111000,
1111111111111100,
111111111111110,
11111111111111,
1111111111111.1,
111111111111.11,
11111111111.111,
1111111111.1111,
111111111.11111,
11111111.111111,
1111111.1111111,
111111.11111111,
11111.111111111,
1111.1111111111,
111.11111111111,
11.111111111111,
1.1111111111111,
0.11111111111111,
0.011111111111111,
0.0011111111111111,
0.00011111111111111
};
for(int i = 0; i < 22; i++){
cout
<< (string2double(strings[i])==doubles[i])
<< " "
<< (double2string(doubles[i])==strings[i])
<< endl;
}
return 0;
}
"Why this test?", you might ask. Let me explain:
A c++ double has 52 bits to hold an integer number. The highest this number can get is 2^52-1, or 4503599627370495. This number is 16 digits long. But since not all 16-digit-long numbers would fit into those bits whithout an overflow, my requirement was to reliably convert only all numbers that are 15 digits long. Leading or trailing zeroes don't count, since they are representable with the 11 exponent bits.
So, basically, I ensured that all those numbers should theoretically fit into a double, without any overflows, so that I can convert them 1:1 back to strings.
Now: Do you know of any functions to convert from double to string and back that can fullfill the test with only "1"s printed out?
It's basically impossible. There are too many ways to specify
a double in text format, and information about this format is
lost once you convert to double. On my machine, for example,
all of the following strings convert to the same double:
1
1.0
1e0
1.000000000000000000001
+1.0
0001.0
and many more. This information is defitively lost once you
have the double.
If you restrict your input to a specific format, say scientific
with exactly 15 digits total, then anything up to 15 digits
should round trip correctly if your machine uses IEEE.
I'm trying to read in two numbers, and display the absolute difference between them. The numbers get ridiculously large, so I had to switch from LONG to LONG DOUBLE and just display them with 0 precision on the decimal. My issue is that with the number listed in the subject, when I scan it into a long double from a string's c_str either in the scan the last digit is being dropped, or more likely the display of the long double is dropping it.
9223372036854775807 - 1 should be 9223372036854775806 but instead it's displaying 9223372036854775800, and when I stop to inspect the long double with the 9223372036854775807 in it, it just shows me "9.2233720368547758e+018"
I would blame this all on a 2 bit processor, but it seems on a 64 bit it's still printing the wrong answer. Has anyone got any way to preserve the entire number?
my includes are stripped of characters that seemed to be messing with the html parser.
#include iostream
#include string
#include math.h
using namespace std;
int main () {
string line;
std::getline(std::cin, line);
while ( std::cin )
{
long double n, m, o;
sscanf ((char *)line.c_str(),"%Lf %Lf",&n, &m);
if(n>=m)
{
o = n - m;
}
else
{
o = m-n;
}
char buffer[100000];
sprintf( buffer , "%0.0Lf\0", o);
cout << buffer << endl;
std::getline(std::cin, line);
}
return 0;
}
I would stop using long double and use long long if your compiler supports it. You said you had previously been using long so I don't think you were storing fractional parts; if that is correct, then long long would be what you want, not long double. I tested your code with long long on MSVC++ 2010 and it gave the expected output.
And as Mysticial noted, double is the same as long double on many compilers today.
long double is not required to provide more precision than double. However, even if it does, you have to tell the compiler that the literal is a long double. Without a decimal point, the compiler will assume 9223372036854775807 is some kind of integer. So you need to write it as 9223372036854775807.0L.
And again, the compiler doesn't have to give you more precision than a double. So don't be too surprised if you don't get any added precision.
After accept answer.
Floating point numbers have finite precision.
In <cfloat> is LDBL_DIG. This is the number of significant decimal digits that code may read text into a long double and will always print the same digits out again.
The is specified to be at least 10 and is often 15+. 9223372036854775807, with its 18 significant decimal digits certainly exceeds your system's value of LDBL_DIG.
Switching to integer math has a far more limited range. long may not work as LONG_MAX may be as small as 2147483647. Better to use long long which can cope with numbers up to at least 9223372036854775807 - just big enough.
I compile and run this code with MSVC2008
long double x = 111111111;
long double y = 222222222;
long double Z = x * y;
cout << z << endl;
When I debug, z equals
24691357975308640
Mathematically z should be
24691357975308642
What's going on ?
Doubles are only precise to around 16 digits. If I counted right, then you have 17 digits, and are correct up to 16. If you want to do this kind of math, and will only have integers, then use ints. For a number that large, you will need to use uint64_t.
Nothing is going on. Doubles have a finite amount of precision, and for that precision the value that you obtain is correct. It is an unfortunate shortcoming of the way you chose to print the value that information about the precision (i.e. the significant digits) was lost.
For example, for a 1+11+(1)+52 float (see here), we have 53 bits of precision, giving us 53 × log102 decimal digits of precision, i.e. 15. So we only print 15 digits:
#include <iomanip>
#include <iostream>
std::cout << std::setfill('0') << std::setprecision(15) << std::scientific
<< Z << std::endl;
The result is:
2.469135797530864e+16
Now we made the precision manifest, and the result is indeed correct at that precision.
If you don't like the magic 15 in the code, you should #include <limits> and use:
std::numeric_limits<decltype(Z)>::digits10
Floating point arithmetic is going on. This is a good read. Basically, computers can problems storing and dealing with floating point numbers, so you get these sorts of arithmetic errors.
Generally, one can write a book answering your question. Long story short - floating point arithmetic is going on. See Floating Point. Also, converting double values to ASCII (for displaying) is also hard and not precise. You may also want to look at arbitrary precision arithmetics.
i want to do what the title says like this:
int number1;
cin>>number1;
num1len=log10(number1)+1;
cout<<"num of digits is "<<num1len<<"\n";
but when the number of digits is 11 and more the answer is always 7(6+1)
Does anyone knows why or what im i doing wrong?
Floating-point data types, including double, store approximations. What you're finding by calling log10 is the number of places to the left of the decimal point, which is affected by at most one by the approximation process.
The question you asked, how to find the number of decimal digits in a number stored in binary floating-point, is meaningless. The number 7.1 has two decimal digits, however its approximate floating-point representation doesn't use decimal digits at all. To preserve the number of decimal digits, you'd need some decimal representation, not the C++ double data type.
Of course, all of this is applicable only to double, per the question title. Your code snippet doesn't actually use double.
What is 'wrong' is the maximum value which can be stored in a (signed) int :
#include <iostream>
#include <numeric>
int main()
{
std::cout << std::numeric_limits<int>::max() << std::endl;
}
Gives me :
2147483647
You are running past the unsigned 32-bit boundary ... your number of 11 digits or more exceeds 0xFFFFFFFF, and so wraps around.
You need to use either unsigned long long or double for your number1 variable:
#include <iostream>
#include <cstdlib>
#include <cmath>
int
main ( int argc, char * argv[] )
{
unsigned long long num; // or double, but note comments below
std::cin >> num;
std::cout << "Number of digits in " << num << " is " << ( (int) std::log10 ( num ) + 1 ) << std::endl;
return 0;
}
Those large numbers will print in scientific notation by default when you send them to std::cout if you choose to use double as your data type, so you would want to throw some formatting in there. If you use an unsigned long long instead, they will print as they were entered, but you have to be sure that your platform supports unsigned long long.
EDIT: As mentioned by others, use of floating point values has other implications to consider, and is most likely not what you are ultimately trying to achieve. AFAIK, the integral type on a platform that yields the largest positive value is unsigned long long, so depending on the values you are looking to work with, see if that is available to you for use.
Others have pointed out that floating point numbers are approximations, so you can't really get an accurate count of digits in it.
But...you can get something approximate, by writing it out to a std::stringstream object, then converting it to a std::string, and getting the lenght of the said string. You'll of course have to deal with the fact that there may be non-digit characters in the string (like minus sign, decimal point, E for exponent etc). Also the number of digits you obtain in this manner would be dependent on formatting options you choose when writing to the stringstream object. But assuming that you know what formatting options you'd like to use, you can get the number of digits subject to these options.
What is the precise meaning of numeric_limits::digits10?
Some other related questions in stackoverflow made me think it is the maximum precision of a double, but
The following prototype starts working (sucess is true) when precision is greater that 17 ( == 2+numeric_limits::digits10)
With STLPort, readDouble==infinity at the end; with microsoft's STL, readDouble == 0.0.
Has this prototype any kind of meaning :) ?
Here is the prototype:
#include <float.h>
#include <limits>
#include <math.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
int main(int argc, const char* argv[]) {
std::ostringstream os;
//int digit10=std::numeric_limits<double>::digits10; // ==15
//int digit=std::numeric_limits<double>::digits; // ==53
os << std::setprecision(17);
os << DBL_MAX;
std::cout << os.str();
std::stringbuf sb(os.str());
std::istream is(&sb);
double readDouble=0.0;
is >> readDouble;
bool success = fabs(DBL_MAX-readDouble)<0.1;
}
numeric_limits::digits10 is the number of decimal digits that can be held without loss.
For example numeric_limits<unsigned char>::digits10 is 2. This means that an unsigned char can hold 0..99 without loss. If it were 3 it could hold 0..999, but as we all know it can only hold 0..255.
This manual page has an example for floating point numbers, which (when shortened) shows that
cout << numeric_limits<float>::digits10 <<endl;
float f = (float)99999999; // 8 digits
cout.precision ( 10 );
cout << "The float is; " << f << endl;
prints
6
The float is; 100000000
numeric_limits::digits10 specifies the number of decimal digits to the left of the decimal point you can represent without a loss of precision. Each type will have a different number of representable decimal values.
See this very readable paper:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2005.pdf
Although DBL_MAX ( = std::numeric_limits::digits10 = 15 digits) is the minimum guaranteed number of digits for a double, the DBL_MAXDIG10 value (= 17 digits) proposed in the paper has the useful properties:
Of being the minimum number of digits needed to survive a round-trip to string form and back and get the same double in the end.
Of being the minimum number of digits needed to convert the double
to string form and show different strings every time you get (A != B) in code.
With 16 or fewer digits, you can get doubles that are not equal in code,
but when they are converted to string form they are the same
(which will give the case where they are different when compared in the code,
but a log file will show them as identical - very confusing and hard to debug!)
When you compare values (e.g. by reviewing them manually by diff'ing two log files) we should remember that digits 1-15 are ALWAYS valid, but differences in the 16th and 17th digits MAY be junk.
The '53' is the bit width of the significand that your type (double) holds. The '15' is the number of decimal digits that can be represented safely with that kind of precision.
digits10 is for conversion: string → double → string
max_digits10 is for conversion: double → string → double
In your program, you are using the conversion (double → string → double). You should use max_digits10 instead of digits10.
For more details about digits10 and max_digits10, you can read:
difference explained by stackoverflow
digits10
max_digits10