largenumber — Почему я не могу разделить большое число на отрицательное число Переполнение стека

Там нет реальной необходимости решения этого, я просто хочу знать, почему.
Давайте возьмем два числа:

#include <iostream>
using namespace std;

int main()
{
unsigned long long int a = 17446744073709551615;
signed long long int b = -30000000003;
signed int c;
c = a/b;
cout << "\n\n\n" << c << endl;
}

Теперь в последнее время я получаю нулевой ответ. Размер моего длинного длинного составляет 8 байтов, так что более чем достаточно, чтобы взять его с беззнаковой меткой. Переменная C также должна быть достаточно большой, чтобы обрабатывать ответ. (Это должно быть -581 558 136, согласно Google). Так…

Изменить Я хотел бы отметить, что на моей машине …

Использование numeric_limits a хорошо ложится в пределах максимума 18446744073709551615, а b попадает в минимальные пределы -9223372036854775808.

1

Решение

У вас происходит ряд неявных преобразований, большинство из которых не нужны.

unsigned long long int a = 17446744073709551615;

Десятичный целочисленный литерал без суффикса имеет тип int, long int, или же long long int; это никогда не беззнаковый тип. Это конкретное значение почти наверняка превышает максимальное значение long long int (263-1). Если ваш компилятор не имеет целочисленный тип со знаком шире 64 бит, это делает вашу программу плохо сформированной.

Добавить ULL суффикс, чтобы гарантировать, что литерал имеет правильный тип:

unsigned long long int a = 17446744073709551615ULL;

Значение оказывается между 263-1 и 264-1, поэтому он подходит для 64-разрядного типа без знака, но не для 64-разрядного типа со знаком.

(На самом деле только U было бы достаточно, но это не мешает быть явным.)

signed long long int b = -30000000003;

Это не должно быть проблемой. 30000000003 имеет некоторый целочисленный тип со знаком; если ваш компилятор поддерживает long longшириной не менее 64 бит, переполнения нет. Тем не менее, пока вам нужен суффикс на значении a, не мешало бы быть явным:

signed long long int b = -30000000003LL;

Теперь у нас есть:

signed int c;
c = a/b;

Разделение unsigned long long по signed long long вызывает преобразование подписанного операнда в unsigned long long, В этом случае конвертируемое значение является отрицательным, поэтому оно преобразуется в большое положительное значение. преобразование -30000000003 в unsigned long long доходность 18446744043709551613, Разделив 17446744073709551615 от 18446744043709551613 дает ноль.

Если ваш компилятор не поддерживает целые числа шире 64 бит (большинство не поддерживает), вы не сможете непосредственно делить 17446744073709551615 от -30000000003 и получите математически правильный ответ, поскольку нет целочисленного типа, который может представлять оба значения. Все арифметические операторы (кроме операторов сдвига) требуют операнды одного типа с неявными преобразованиями, применяемыми по мере необходимости.

В этом конкретном случае вы можете разделить 17446744073709551615ULL от 30000000003ULL а затем учитывать знак. (Проверьте правила языка для деления отрицательных целых чисел.)

Если вам действительно нужно сделать это в целом, вы можете прибегнуть к плавающей запятой (что означает, что вы, вероятно, потеряете некоторую точность) или использовать какой-либо целочисленный арифметический пакет произвольной ширины, например GMP.

6

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

b рассматривается как число без знака, которое больше, чем a. Следовательно, вы получаете ответ как 0.

Попробуйте использовать это как

c = abs(a) / abs (b)
if ((a < 0 && b > 0 ) || (a> 0 && b < 0))
return -c;
return c;
0

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