Является ли ожидаемым поведением то, что Go допускает переполнение для арифметических операций вместо создания исключения?

Я портирую некоторый код 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)
}

Нет, как вы сами доказали, это не так. Числа усекаются на границе типа данных, в котором они хранятся.

Adrian 28.05.2019 17:35
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
1
1
1 638
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Спецификация: Целочисленное переполнение:

For unsigned integer values, the operations +, -, *, and << are computed modulo 2n, where n is the bit width of the unsigned integer's type. Loosely speaking, these unsigned integer operations discard high bits upon overflow, and programs may rely on "wrap around".

For signed integers, the operations +, -, *, /, and << may legally overflow and the resulting value exists and is deterministically defined by the signed integer representation, the operation, and its operands. Overflow does not cause a run-time panic. A compiler may not optimize code under the assumption that overflow does not occur. For instance, it may not assume that x < x + 1 is always true.

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

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

Например:

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

Спасибо за объяснение! Очень ценю это!

Mazeryt 28.05.2019 17:52

Возможно, стоит отметить, что переполнение также прекрасно работает в Rust, если вы компилируете для выпуска, а не для отладки. Существует u64::checked_mul(), если это нежелательно.

Fynn Becker 29.05.2019 14:13

Другие вопросы по теме