Я знаю, Int32.MaxValue * Int32.MaxValue
приведет к числу, больше, чем Int32
; Но, разве этот оператор не должен повышать некоторое исключение?
Я натыкался на это при выполнении чего-то как IF (X * Y > Z)
где все Int32
. X
и Y
являются достаточно достаточно большими, Вы получаете поддельное значение от X * Y
.
Почему это так и как обойти это? помимо кастинга всего к Int64
.
Вы отключили проверку переполнения в своем проекте. При включенном режиме проверки будет выброшено исключение.
Потому что int32 ограничивает результаты 32 битами.
Итак, если вы посмотрите на математику на байтовом уровне.
FFFFFFFF * FFFFFFFF = FFFFFFFE00000001
Как видите, младшие 4 байта = 1.
Вы должны спросить об этом:
checked {
int a = int.MaxValue;
int b = int.MaxValue;
int c = a * b; // kaboom
}
Int32.MaxValue (используя значение, указанное здесь ) - 2 147 483 647.
В базе 2, то есть: 111 1111 1111 1111 1111 1111 1111 1111
... 2 ^ 31-1. Первый бит - это знаковый бит.
Если вы умножите это на себя, вы получите: 11 1111 1111 1111 1111 1111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0001
Возвращаясь к исходной проблеме «почему это 1?», поскольку Integer.MaxValue является максимальным значением, это вызывает целочисленное переполнение. Результат усекается до 31 младшего бита, который равен 0 плюс 1.
Редактировать: Вот учебник по двоичному умножению. Используя простой случай всех единиц: 111 * 111
вы получите: 00111 01110 + 11100 = 100001
Вы можете расширить это значение для случая Int32.MaxValue. Я сократил его до трех цифр для краткости.
Кроме того, как сказано в другом ответе, в C # эти переполнения будут происходить по умолчанию.
По умолчанию арифметические операции C # выполняются в неконтролируемом контексте, то есть значения меняются.
Вы можете использовать проверенные и непроверенные ключевые слова для управления этим поведением.
Интересно отметить, что это работает независимо от используемой базы:
(n-1)*(n-1) mod n
n^2 - 2n + 1 mod n
0 - 0 + 1 mod n
1 mod n