bitlvl
SR

Kalkulator prekoračenja i celobrojne aritmetike

Ukucajte izraz, izaberite tip i jezik i vidite tačno šta mašina radi: koji operandi se promovišu ili konvertuju, gde rezultat prestaje da staje, da li je to wraparound, panic ili nedefinisano ponašanje, i bitove pre i posle.

Rezultati i poruke ovog alata prikazuju se na engleskom.

Zašto celi brojevi iznenađuju ljude

Mašinski ceo broj ima fiksan broj bitova, pa svaka operacija može da proizvede vrednost koja ne staje. Šta se tada dešava ne odlučuje hardver (koji jednostavno prelama vrednost, wraparound), već jezik:

JezikPrekoračenje sa znakomPrekoračenje bez znakaPomeranje za ≥ širinuDeljenje nulom
C / C++nedefinisano ponašanje: optimizator pretpostavlja da se nikad ne dešavaprelama se modulo 2ⁿ (definisano)nedefinisanonedefinisano (SIGFPE na x86)
Rustpanic u debug režimu, prelamanje u release; checked_/wrapping_/saturating_/overflowing_ su eksplicitniisto kao sa znakompanic u debug režimupanic
Goprelama se (definisano)prelama se0 / −1, bez panicapanic
Javaprelama se (definisano); Math.addExact baca izuzetaknema neoznačenih tipova (char je 16-bitni neoznačen)broj pomeranja maskiran na 5/6 bitovaArithmeticException
JavaScriptbrojevi su double: tačni do 2⁵³, zatim zaokruživanje; bitovski operatori rade nad int32broj pomeranja maskiran na 5 bitovaInfinity / NaN

Pravila C-a koja ujedaju

  • Promocija celih brojeva. Sve manje od int postaje int pre aritmetike, pa je uint8_t a = 200, b = 100; a + b jednako 300, a tek dodela nazad u uint8_t odseca na 44. ~x nad uint8_t daje negativan int.
  • Uobičajene aritmetičke konverzije. Kada se označeni sretne sa neoznačenim iste širine, označena strana postaje neoznačena: -1 > 0u je tačno, if (len - 1 < 0) nikad nije tačno kada je len tipa size_t.
  • Prekoračenje sa znakom je UB. if (x + 1 < x) kao proveru prekoračenja GCC i Clang brišu sa uključenom optimizacijom, jer smeju da pretpostave da x + 1 nikad ne prekoračuje. Proveravajte pre operacije (x > INT_MAX - y) ili koristite __builtin_add_overflow.
  • Pomeranja. Pomeranje za širinu ili više, ili pomeranje negativne vrednosti ulevo, je nedefinisano; x86 maskira broj pomeranja, ARM daje nulu, kompajler radi šta god njegov model kaže.
  • Deljenje. Odseca ka nuli, pa je -7 / 2 == -3 i -7 % 2 == -1; INT_MIN / -1 prekoračuje i zaista izaziva trap na x86.

Čitanje izlaza

Rezultat se prikazuje u tipu u kome završava, sa svojim obrascem bitova i istim bitovima pročitanim sa suprotnom označenošću, što je ono što vidite kada vrednost pređe granicu (int) / (unsigned) ili se sačuva i pročita kroz drugi tip. Lista koraka je redosled izračunavanja sa tipom u svakom koraku; napomene su mesta gde je jezik uradio nešto drugo osim obične aritmetike.

Pitanja

Zašto se rezultat za C razlikuje od onoga što je moj program ispisao?

Za nedefinisano ponašanje ne postoji jedan tačan odgovor: ova stranica prikazuje wraparound vrednost koju proizvodi neoptimizovan kod i označava korak kao UB. Sa -O2 kompajler je možda pretpostavio da prekoračenje ne može da se desi i proizveo drugačiji kod. Kompajlirajte sa -fsanitize=undefined da vidite tačno mesto.

Šta radi izbor tipa?

To je tip literala koji nemaju sufiks ni kastovanje, što je u C-u podrazumevano int. Izaberite u8 i ukucajte 200 + 100 da vidite kako Rust panikuje, a C promoviše u int i uspeva.

Kako da napišem kastovanje?

C stil: (u8) expr, (uint32_t) expr, (int) expr. Rust stil: expr as u8. Oba rade u svakom jezičkom režimu. INT_MAX, INT_MIN, UINT_MAX, LONG_MAX, SIZE_MAX su dostupni kao imena.

Da li radi sa 128 bita?

Da: i128 i u128 se izračunavaju tačno (sva aritmetika se radi sa proizvoljnom preciznošću, pa se zatim uklapa u tip).

Šta je sa brojevima u pokretnom zarezu?

Ne ovde; to pokriva IEEE 754 vizuelizator float brojeva na ovom sajtu. Ovaj alat se bavi samo onim što se dešava celim brojevima u tipovima fiksne širine.