The operations +, -, *, can underflow and overflow. When checking is enabled this will panic. When checking is disabled this will two's complement wrap.
Если я правильно понял, по умолчанию также как С++ тихо проглатывает, но можно включить проверки на каждый чих и получить вменяемый panic ценой ухудшения быстродействия?
интересно, есть хоть один язык, в котором переполнение при умножение приводит к ошибке компиляции, а не тихое проглатывание с экзепшеном (паникой и т.п.) в рантайме?
сишный вариант, сложилось исторически, многие вещи завязаны на сигналы от конкретной ос, плюс возможности cpu, об арифметических переполнениях и делениях на ноль обычно сигнализируют биты флагов в процессорах, но наслышан что в risc-v такого нету, а нету там потому что в сях на эти флаги кладут, тогда зачем делать? :)
Алсо, если не хочется возни с SMT-солверами и прочим матаном, можно просто сделать, чтобы сложение и умножение выдавали результат большего типа. Например, int64*int64 -> int128 и т.п.
Но обработка всех возможных ошибок наверное есть в специальных математических типах, операции над которыми не имеют ограничений по битности и т.д. Это очень узкие кейсы расчетов высокой точности. Из этого следует, что нужно смотреть такие языки как R, Julia, Wolfram и т.д.
$ cat main.rs
fn main() {
println!("Hello, world!");
let a: u32 = 1000000000;
let b: u32 = 2000000000;
let ab: u32 = a * b;
println!("{}", ab);
}
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `/home/intelfx/example/target/debug/example`
Hello, world!
thread 'main' panicked at 'attempt to multiply with overflow', src/main.rs:5:19
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
$ cargo run --release
Finished release [optimized] target(s) in 0.00s
Running `/home/intelfx/example/target/release/example`
Hello, world!
1321730048
и какое он имеет отношение к искомой площади прямоугольника?
Он будет остатком от деления искомой площади треугольника на 2^32.
$ bc
bc 1.07.1
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
scale=0
(1000000000 * 2000000000) % (2^32)
1321730048
А как ты себе это представляешь? компилятор видит что перемножаются два числа которые он загрузил из памяти и про которые он ни сном ни духом, как он тебе будет понимать переполнение?
В С++ это просто undefined behavour, т.е. никак не обратывается.
В C++ это не всегда UB. Переполнение signed - UB, переполнение unsigned - определено стандартом (точные пункты не подскажу, говорю по памяти).
В rust, при использовании обычных операций, если не ошибаюсь, происходит либо переполнение с предсказуемым результатом, либо паника. Зависит от опций компиляции (проверять или не проверять), а так же (возможно) от целевой платформы. Если нужно какое-то кокнретное поведение независимо от этого, то можно использовать специальные функции, например: wrapping_mul, saturating_mul, overflowing_mul, checked_mul.
program int64overflowtest;
var
x: Int64;
begin
x := 99999999999 * 999999999;
writeln(x);
end.
Compiling int64overflowtest.pas
int64overflowtest.pas(5,19) Error: Overflow in arithmetic operation
int64overflowtest.pas(8) Fatal: There were 1 errors compiling module, stopping
Fatal: Compilation aborted
===
program int64overflowtest;
var
x: Int64;
begin
x := 9223372036854775807 + 1;
writeln(x);
end.
Compiling int64overflowtest.pas
int64overflowtest.pas(5,27) Warning: range check error while evaluating constants (9223372036854775808 must be between -9223372036854775808 and 9223372036854775807)
Linking int64overflowtest
$ ./int64overflowtest
-9223372036854775808
===
program int64overflowtest;
var
x, y: Int64;
begin
x := 99999999999;
y := 999999999;
x := x * y;
writeln(x);
end.
интересно, есть хоть один язык, в котором переполнение при умножение приводит к ошибке компиляции, а не тихое проглатывание с экзепшеном (паникой и т.п.) в рантайме?
program int64overflowtest2;
uses sysutils;
var
x, y, z: Int64;
begin
if ParamCount < 2 then begin
writeln('usage: int64overflowtest2 x y');
exit;
end;
if TryStrToInt64(ParamStr(1), x) = False then x := 0;
if TryStrToInt64(ParamStr(2), y) = False then y := 0;
z := x * y;
writeln(z);
end.
{$mode objfpc}
{$Q+}
uses
sysutils;
var
x, y, z : Int64;
begin
readln(x, y);
Try
z := x * y;
writeln('z = ', z);
Except on EIntOverflow do
writeln('too large');
end;
end.