std::cin not working correcly with large numbers - c++

I found a strange behavior of std::cin (using VS 17 under Win 10): when a large number is entered, the number that std::cin is reading is close but different.
Is there any kind of approximation done with large numbers ?
How to get the exact same large number than entered ?
double n(0);
cout << "Enter a number > 0 (0 to exit): ";
cin.clear(); // does not help !
cin >> n; // enter 2361235441021745907775
printf("Selected number %.0f \n", n); // 2361235441021746151424 is processed ?.
Output
Enter a number > 0 (0 to exit):
2361235441021745907775
Selected number 2361235441021746151424

You need to learn about number of significant digits. A double can hold very large values, but it will only handle so many digits. Do a search for C++ doubles significant digits and read any of the 400 web pages that talk about it.
If you need more digits than that, you need to use something other than double. If you know it's an integer, not floating point, you can use long long int which is at least 8 bytes and can hold 2^63-1. If you know it's a positive number, you can make it unsigned long long int and you get the range 0 to at least 18,446,744,073,709,551,615 (2^64-1).
If you need even more digits, you need to find a library that supports arbitrarily long integers. A google for c++ arbitrary precision integer will give you some guidance.

Related

finding number of trailing zeroes in a number

I wanted to find the number of trailing zeroes in a number, so i made the following code. It worked fine for certain numbers but for bigger numbers it started showing anomaly. Like when i input the number"12345678" it show zero 0`s which is correct but when i input "123456789" it shows one zero, what can be the possible mistake in my code???
#include<iostream>
#include<math.h>
using namespace std;
int main(){
int n = 0;
float s;
cin>>s; //the number to be given as input
for(int j = 0;j <100;j++){
s = s/10;
if(s == floor(s)){
n++;
}else{
break;
}
}
cout<<n<<endl;
return 0;
}
Floating point numbers have a limited precision. Usually, float is a 32-bit number, double is a 64-bit one. Float can store integer numbers precisely if the number is less than or equal to 16777216 (it is 2^24).
So, when 123456789 is read into a float variable, will have a different value, it becomes 123456792. At this point, there is no rationale to count trailing zeros.
Double can store integer numbers precisely if it is less than or equal to 9007199254740992 (2^53).
An unsigned long long int can store integer numbers less than 2^64. If you choose this way, use this condition for checking trailing zero: if (number%10==0)
If you only want to count trailing zeros, and that's all, then use std::string instead. This way you can handle as big numbers as you like.

C++ remainder returns 7 at higher numbers

So I am still pretty new to programming and trying to learn C++ so slowly figuring it out.
Right now I am trying to attempt the credit card number problem and trying to isolate each digit in the number so like.
using namespace std;
int main()
{
int creditcardnumber;
cout << "Enter a 16-digit credit card number: "; // asks for credit card number
cin >> creditcardnumber;
cin.ignore();
int d16 = creditcardnumber % 10;
cout << d16;
}
at lower numbers like : 123456
it returns 6 which is what I want
but at a higher number like : 12387128374
it returns 7
I started noticing that it keeps returning 7 every time at higher numbers can anyone explain this and how to resolve it?
that's because the biggest value of int (assuming an int size is 4 bytes) is 2147483647. your test exceeds it by far.
try to use bigger type, like long.
Here is a simple test program to illustrate your problem:
#include <iostream>
int main() {
int x;
std::cin >> x;
std::cout << x << std::endl;
return 0;
}
If the input stream is
123456789123
(for example), the output is
2147483647
What this shows is that if you try to enter a number that is larger than
the largest possible value of an int, you will end up with just
the largest int instead, which is 2147483647.
And every larger number likewise will give the same result.
And of course 2147483647%10 evaluates to 7.
But in the end, I think the most relevant point was already made in
a comment: there is almost surely no good reason for you to store
the credit card "number" in a numeric C++ type;
std::string would be more appropriate.
A 16-digit number requires about 54 bits to represent. int very probably isn't big enough. long may or may not be, depending on your implementation.
If you have a sufficiently modern C++ implementation, long long is guaranteed to be at least 64 bits wide, so you can probably use that.
As for why you're always getting 7, apparently an overflow in
cin >> creditcardnumber;
causes the maximum representable int value to be stored in creditcardnumber. On a typical modern system with 32-bit int, that value is 231-1, or 2147483647. (On a system with 16-bit int, it happens that the maximum value is 32767, and you'd also get 7 as the last digit on overflow.)
I'm not sure what the C++ standard says about the behavior of cin >> n on overflow. On overflow, cin >> n, where n is some type of integer, is defined to set n to the minimum or maximum value of its type. It also sets failbit, so you can detect the error. Reference: http://en.cppreference.com/w/cpp/io/basic_istream/operator_gtgt
Note that even if you use long long, which can hold a 16-digit decimal number, you can still get an overflow if the user enters an invalid number that exceeds 263-1. (If that behaves the same way, the last digit also happens to be 7; there seems to be some interesting mathematics at work here, but it's not relevant to your problem.)
You experience integer overflow. You can check if input succeeded this way
if ( cin >> creditcardnumber) {
// do your things
} else {
cout << "Please enter a valid integer" << endl;
cin.clear();
cin.ignore( numeric_limits<streamsize>::max(), '\n');
}

Using a LONG DOUBLE, "9223372036854775807 - 1" still drops the last digit and comes out as "9223372036854775800"

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.

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)?

C++ count the number of digits of a double

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.