Undefined behavior when exceed 64 bits - c++

I have written a function that converts a decimal number to a binary number. I enter my decimal number as a long long int. It works fine with small numbers, but my task is to determine how the computer handles overflow so when I enter (2^63) - 1 the function outputs that the decimal value is 9223372036854775808 and in binary it is equal to -954437177. When I input 2^63 which is a value a 64 bit machine can't hold, I get warnings that the integer constant is so large that it is unsigned and that the decimal constant is unsigned only in ISO C90 and the output of the decimal value is negative 2^63 and binary number is 0. I'm using gcc as a compiler. Is that outcome correct?
The code is provided below:
#include <iostream>
#include<sstream>
using namespace std;
int main()
{
long long int answer;
long long dec;
string binNum;
stringstream ss;
cout<<"Enter the decimal to be converted:"<< endl;;
cin>>dec;
cout<<"The dec number is: "<<dec<<endl;
while(dec>0)
{
answer = dec%2;
dec=dec/2;
ss<<answer;
binNum=ss.str();
}
cout<<"The binary of the given number is: ";
for (int i=sizeof(binNum);i>=0;i--){
cout<<binNum[i];}
return 0;
}

First, “on a 64-bit computer” is meaningless: long long is guaranteed at least 64 bits regardless of computer. If could press a modern C++ compiler onto a Commodore 64 or a Sinclair ZX80, or for that matter a KIM-1, a long long would still be at least 64 bits. This is a machine-independent guarantee given by the C++ standard.
Secondly, specifying a too large value is not the same as “overflow”.
The only thing that makes this question a little bit interesting is that there is a difference. And that the standard treats these two cases differently. For the case of initialization of a signed integer with an integer value a conversion is performed if necessary, with implementation-defined effect if the value cannot be represented, …
C++11 §4.7/3:
“If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined”
while for the case of e.g. a multiplication that produces a value that cannot be represented by the argument type, the effect is undefined (e.g., might even crash) …
C++11 §5/4:
“If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined.”
Regarding the code I I only discovered it after writing the above, but it does look like it will necessarily produce overflow (i.e. Undefined Behavior) for sufficiently large number. Put your digits in a vector or string. Note that you can also just use a bitset to display the binary digits.
Oh, the KIM-1. Not many are familiar with it, so here’s a photo:
It was, reportedly, very nice, in spite of the somewhat restricted keyboard.

This adaptation of your code produces the answer you need. Your code is apt to produce the answer with the bits in the wrong order. Exhaustive testing of decimal values 123, 1234567890, 12345678901234567 show it working OK (G++ 4.7.1 on Mac OS X 10.7.4).
#include <iostream>
#include<sstream>
using namespace std;
int main()
{
long long int answer;
long long dec;
string binNum;
cout<<"Enter the decimal to be converted:"<< endl;;
cin>>dec;
cout<<"The dec number is: "<<dec<<endl;
while(dec>0)
{
stringstream ss;
answer = dec%2;
dec=dec/2;
ss<<answer;
binNum.insert(0, ss.str());
// cout << "ss<<" << ss.str() << ">> bn<<" << binNum.c_str() << ">>" << endl;
}
cout<<"The binary of the given number is: " << binNum.c_str() << endl;
return 0;
}
Test runs:
$ ./bd
Enter the decimal to be converted:
123
The dec number is: 123
The binary of the given number is: 1111011
$ ./bd
Enter the decimal to be converted:
1234567890
The dec number is: 1234567890
The binary of the given number is: 1001001100101100000001011010010
$ ./bd
Enter the decimal to be converted:
12345678901234567
The dec number is: 12345678901234567
The binary of the given number is: 101011110111000101010001011101011010110100101110000111
$ bc
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
obase=2
123
1111011
1234567890
1001001100101100000001011010010
12345678901234567
101011110111000101010001011101011010110100101110000111
$
When I compile this with the largest value possible for a 64 bit machine, nothing shows up for my binary value.
$ bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
2^63-1
9223372036854775807
quit
$ ./bd
Enter the decimal to be converted:
9223372036854775807
The dec number is: 9223372036854775807
The binary of the given number is: 111111111111111111111111111111111111111111111111111111111111111
$
If you choose a larger value for the largest value that can be represented, all bets are off; you may get a 0 back from cin >> dec; and the code does not handle 0 properly.
Prelude
The original code in the question was:
#include <iostream>
using namespace std;
int main()
{
int rem,i=1,sum=0;
long long int dec = 9223372036854775808; // = 2^63 9223372036854775807 = 2^63-1
cout<<"The dec number is"<<dec<<endl;
while(dec>0)
{
rem=dec%2;
sum=sum + (i*rem);
dec=dec/2;
i=i*10;
}
cout<<"The binary of the given number is:"<<sum<<endl;
return 0;
}
I gave this analysis of the earlier code:
You are multiplying the plain int variable i by 10 for every bit position in the 64-bit number. Given that i is probably a 32-bit quantity, you are running into signed integer overflow, which is undefined behaviour. Even if i was a 128-bit quantity, it would not be big enough to handle all possible 64-bit numbers (such as 263-1) accurately.

Related

Why main function cannot return a negative number?

This might be a really simple question for some, but I'm new to C++ and hope someone can answer this for me.
I'm using this online C++ compiler. Here's the simple code I'm running in it:
int main()
{
int x = 1- 2;
std::cout << x << std::endl;
return x;
}
The output is:
-1
...Program finished with exit code 255
Press ENTER to exit console.
That really ponders me. Why would the main() function return 255 when the value of x is -1?
Doesn't main() return an int (not an unsigned int), so it should be able to return a negative number, right?
How does -1 get converted to 255? Something to do with an 8-bit variable? But isn't the int type 16-bit?
This is not related to C language really. The operating system, or possibly just the C runtime (the small piece of the code which sets up things for your C program and actually calls your main function) limits exit code of the program to unsigned 8 bit number.
Very nearly all systems today use two's complement representation for negative numbers, and then bit pattern for -1 is having all bits of the number to be 1. Doesn't matter how many bits, they are all set when value is -1.
The simplest way to convert an int to 8 bit number is to just take 8 lowest bits (which are now all 1 as per above), so you end up with binary number:
11111111
If interpreted as unsigned, then in decimal value of this happens to be 255 (as signed 8 bits it is still -1), which you can check with any calculator which supports binary (such as Windows 10 Calculator app when you switch it to Programmer mode).
Looking at this from the opposite direction: When trying to understand funny numbers related to computers or programming, it is often useful to convert them to binary. If you convert 255 to binary, you get 11111111, and then if you know binary numbers, you should realize this is -1 if interpreted as signed 8 bit number.

Why doesn't this function print all the char array as it takes it?

i was trying to convert from a char array to integers and the atoi function is working properly except when i put a zero in the first index...it didn't print it
#include<iostream>
using namespace std;
int main()
{
char arr[]= "0150234";
int num;
num=atoi(arr);
cout << num;
return 0;
}
I expect the output of 0150234 but the actual output is 150234
I think inside the atoi function you have typecasted the string to integer because of which the 0 gets removed. You can never get a 0 printed before a number since it doesn't make sense.
000001 will always be represented as 1.
I hope this clears your doubt.
Binary number representations (such as int) do not store leading 0s because there is an infinite number of them. Rather they store a fixed number of bits which may have some leading 0 bits.
You can still print the leading 0s if necessary:
std::cout << std::setw(4) << std::setfill('0') << 1 << '\n';
Output:
0001
You're confusing two ideas:
Numbers: These are abstract things. They're quantities. Your computer stores the number in a manner that you should not care about (though it's probably binary).
Representations: These are ways we display numbers to humans, like "150234", or "0x24ADA", or "one hundred and fifty thousand, two hundred and thirty four". You pick a representation when you convert to a string. When streaming to std::cout a representation is picked for you by default, but you can choose your own representation using I/O manipulators, as Maxim shows.
The variable num is a number, not a representation of a number. It does not contain the information «display this as "0150234"». That's what arr provides, because it is a string, containing a representation of a number. So, if that leading zero in the original representation is important to you, when you print num, you have to reproduce that representation yourself.
By the way…
Usually, in the programming world, and particularly in C-like source code:
When we see a string like "150234" we assume that it is the decimal (base-10) representation of a number;
When we see a string like "0x24ADA" (with a leading 0x) we assume that it is the hexadecimal (base-16) representation of a number;
When we see a string like "0150234" (with a leading 0) we assume that it is the octal (base-8) representation of a number.
So, if you do add a leading zero, you may confuse your users.
FYI the conventional base-8 representation of your number is "0445332".

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.

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.