Ожидается ли поведение, что Go допускает переполнение для арифметических операций вместо генерирования исключения? - PullRequest
0 голосов
/ 28 мая 2019

Я портирую некоторый код Go в Rust, и я понял, что Rust паникует, когда переполнение происходит во время умножения, в то время как Go допускает переполнение.

Тестовый код ниже, который не вызывает переполнение, но печатает уменьшенное значение.(проверено: https://play.golang.org/)

func main() {
    fmt.Println("test\n")
    var key uint64 = 15000;

    key = key*2862933555777941757 + 1

    fmt.Println(key)
}

1 Ответ

9 голосов
/ 28 мая 2019

Spec: Целочисленное переполнение:

Для целых значений без знака операции +, -, * и << вычисляются по модулю 2 <sup>n , где n - ширина в битах целого числа без знака тип. Грубо говоря, эти целочисленные операции без знака отбрасывают старшие биты при переполнении, и программы могут полагаться на "циклический переход" .

Для целых чисел со знаком операции +, -, *, / и << могут юридически переполняться, и результирующее значение существует и детерминировано определяется целочисленным представлением со знаком, операцией и ее операндами. <strong>Переполнение не вызывает паники во время выполнения . Компилятор может не оптимизировать код в предположении, что переполнение не происходит. Например, он может не предполагать, что x < x + 1 всегда верно.

Как указано выше, переполнение существует и не вызывает паники во время выполнения.

Но нужно соблюдать осторожность, как если бы у вас было константных выражений , поскольку они имеют произвольную точность, если результат должен быть преобразован с фиксированной точностью, если он не вписывается в действительный целевой тип диапазон, это приводит к ошибке времени компиляции.

Например:

const maxuint64 = 0xffffffffffffffff
var key uint64 = maxuint64 * maxuint64

fmt.Println(key)

Вышеуказанные выходы:

constant 340282366920938463426481119284349108225 overflows uint64

maxuint64 * maxuint64 - это константное выражение, которое вычисляется правильно (его значение равно 340282366920938463426481119284349108225), но когда это значение должно быть присвоено переменной key типа uint64, оно приводит к времени компиляции ошибка, потому что это значение не может быть представлено значением типа uint64. Но это не паника во время выполнения.

Смотрите похожие вопросы:

Golang: целевое переполнение int

Отличается ли оценка компилятора Go для константного выражения и другого выражения

Как сохранить большой float64 в строке без переполнения?

Правильный способ приведения uint16 к int16 в Go

...