Неопределенное поведение при превышении 64 бит

Я написал функцию, которая преобразует десятичное число в двоичное число. Я ввожу свое десятичное число как long long int, Он отлично работает с небольшими числами, но моя задача — определить, как компьютер справляется с переполнением, поэтому, когда я ввожу (2 ^ 63) — 1, функция выводит десятичное значение 9223372036854775808, а в двоичном виде оно равно -954437177. Когда я ввожу значение 2 ^ 63, которое является значением, которое 64-разрядная машина не может содержать, я получаю предупреждения о том, что целочисленная константа настолько велика, что она не имеет знака, и что десятичная константа является беззнаковой только в ISO C90 и выводе десятичной дроби значение отрицательное 2 ^ 63 и двоичное число равно 0. Я использую gcc в качестве компилятора. Это правильный результат?

Код представлен ниже:

#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;
}

0

Решение

Во-первых, «на 64-битном компьютере» не имеет смысла: long long гарантируется как минимум 64 бита независимо от компьютера. Если бы можно было нажать современный компилятор C ++ на Commodore 64 или Sinclair ZX80, или, в этом отношении, KIM-1, long long все равно будет не менее 64 бит. Это независимая от машины гарантия, предоставляемая стандарт C ++.

Во-вторых, указание слишком большого значения не так же, как «переполнение».

Единственное, что делает этот вопрос немного интересным, это то, что есть разница. И что стандарт трактует эти два случая по-разному. Для случая инициализации целого числа со знаком целое значение преобразование выполняется при необходимости, с эффектом, определяемым реализацией, если значение не может быть представлено,…

C ++ 11 §4.7 / 3:
«Если тип назначения подписан, значение не изменяется, если оно может быть представлено в типе назначения (и ширине битового поля); в противном случае значение определяется реализацией »

в то время как для случая, например, умножение, которое производит значение, которое не может быть представлено типом аргумента, эффект не определен (например, может даже произойти сбой)…

C ++ 11 §5 / 4:
«Если во время оценки выражения результат не определен математически или не находится в диапазоне представимых значений для его типа, поведение не определено».

Что касается кода, который я обнаружил, я обнаружил его только после написания вышеупомянутого, но он выглядит так, как будто он обязательно вызовет переполнение (то есть неопределенное поведение) для достаточно большого числа. Поместите ваши цифры в vector или же string, Обратите внимание, что вы также можете просто использовать bitset для отображения двоичных цифр.

О, КИМ-1. Не многие знакомы с ним, поэтому вот фото:

КИМ-1 одноплатный компьютер

Это было, как сообщается, очень приятно, несмотря на несколько ограниченную клавиатуру.

7

Другие решения

Эта адаптация вашего кода дает нужный вам ответ. Ваш код способен дать ответ с битами в неправильном порядке. Полное тестирование десятичных значений 123, 1234567890, 12345678901234567 показывает, что оно работает нормально (G ++ 4.7.1 в 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;
}

Тестовые прогоны:

$ ./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
$

Когда я компилирую это с максимально возможным значением для 64-битной машины, для моего двоичного значения ничего не появляется.

$ 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
$

Если вы выберете большее значение для наибольшего значения, которое может быть представлено, все ставки отключены; вы можете получить 0 обратно от cin >> dec; и код не обрабатывает 0 должным образом.


прелюдия

Оригинальный код в вопросе был:

#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;
}

Я дал этот анализ предыдущего кода:

Вы умножаете равнину int переменная i на 10 для каждой битовой позиции в 64-битном числе. При условии i Вероятно, это 32-битная величина, вы столкнулись с целочисленным переполнением со знаком, что является неопределенным поведением. Даже если i было 128-битное количество, оно не было бы достаточно большим, чтобы обрабатывать все возможные 64-битные числа (например, 263-1) точно.

1

По вопросам рекламы [email protected]