Operasi numerik

Menjelaskan operasi integer wrap, checked, shift, kesalahan konversi tipe, dan hasil floating point.

Wave Foundation

representasi bilangan bulat

Bit integer N memiliki bit nilai N. Bilangan bulat tak bertanda berkisar dari 0 hingga 2^N − 1, dan bilangan bulat bertanda berkisar dari −2^(N−1) hingga 2^(N−1) − 1. Operasi signedness menentukan interpretasi string bit.

Tabel di bawah ini menjelaskan hasil perhitungannya. IR Contoh kode menggunakan representasi printer saat ini.

Penjumlahan, pengurangan, perkalian

Bilangan bulat dasar add·sub·mul menampung bit hasil N yang lebih rendah. overflow tidak menyebabkan trap. Operasi checked mengembalikan hasil wrap yang sama, serta Bool, yang menunjukkan apakah hasil matematika berada di luar rentang signed atau unsigned yang sesuai.

operasi Wrap Hasil Checked overflow
u8: 255 + 1 0 true
i8: 127 + 1 −128 true
u8: 0 − 1 255 true
i8: 12 × 3 36 false

Frontend untuk bahasa yang menghentikan eksekusi di overflow harus menggunakan trap_if eksplisit untuk overflow hasil operasi checked. Operasi default tidak secara implisit menerapkan kebijakan overflow bahasa sumber.

Wrap dan IR menyatakan pemeriksaan eksplisit

Modul berikut dikonfigurasi sebagai Rust builder dan merupakan keluaran printer saat ini yang telah lolos verifikasi. Pengurai teks dan backend eksekusi belum tersedia.

module {
  format_version 2
  semantics_version 1
  target "x86_64-whale-linux"
  datalayout { ptr=64, endian=little }

  declare @f0 "add_u8": whale () -> u8, linkage internal
  declare @f1 "require_no_overflow": whale () -> u8, linkage internal

  fn @add_u8() -> u8, id @f0 {
  entry:
    %v0: u8 = const u8 255
    %v1: u8 = const u8 1
    %v2: u8 = add u8 %v0, %v1
    ret u8 %v2
  }

  fn @require_no_overflow() -> u8, id @f1 {
  entry:
    %v3: u8 = const u8 255
    %v4: u8 = const u8 1
    %v5: tuple<u8, bool> = uadd_chk u8 %v3, %v4
    %v6: u8 = extract %v5, 0
    %v7: bool = extract %v5, 1
    trap_if bool %v7, reason="integer overflow"
    ret u8 %v6
  }

}

Berdasarkan kontrak aritmatika, add_u8 membungkus 256 ke hasil 8-bit 0. require_no_overflow mengekstrak hasil yang dibungkus dengan extract ..., 0 dan tanda luapan Bool dengan extract ..., 1. Jika benderanya adalah true, trap_if menghentikan eksekusi sebelum pengembalian. Ini adalah hasil yang ditentukan, bukan keluaran dari penerjemah yang diimplementasikan.

Pembagian dan sisanya

Pembagian bilangan bulat atau sisa dengan nol menyebabkan jebakan. Membagi nilai minimum yang ditandatangani dengan −1 akan membungkus nilai minimum. Sisanya dalam hal ini adalah nol.

operasi hasil
i8: −128 / −1 −128
i8: −128 % −1 0
Bagilah dengan bilangan bulat 0 trap
sisa bilangan bulat 0 trap

bergeser

Dalam menggeser nilai bit N, string bit count ditafsirkan sebagai unsigned dan sisanya dibagi dengan N digunakan. Itu tidak menghasilkan trap hanya karena count berada di luar rentang dari 0 hingga N−1.

Dalam nilai 8-bit, count 0·8·16 semuanya merupakan pergeseran 0-bit. String bit 11111111 dari 8 bit count digeser sebanyak 7 bit. Hal ini tetap sama meskipun string bit ini mewakili signed −1. unsigned Analisis dilakukan sebelum penghitungan lainnya.

Bahasa sumber yang menolak count negatif atau berlebihan harus memberi tanda centang eksplisit sebelum pergeseran.

konversi tipe

konversi artinya
Zero extension Tingkatkan lebar dengan mengisi bit tingkat tinggi dengan 0
Sign extension Tingkatkan lebarnya dengan menduplikasi bit tanda
sedikit pemotongan Simpan hanya bit tingkat rendah yang sesuai dengan lebar tujuan
Kalahkan penafsiran ulang Menafsirkan string bit yang sama dengan tipe yang berbeda
Konversi numerik tanpa kerugian Jika tidak dapat diungkapkan sambil mempertahankan nilai numeriknya, trap

Misalnya, mengubah 8-bit 11111111 menjadi 16-bit zero extension menjadi 0000000011111111, dan sign extension menjadi 1111111111111111. Sekalipun bit inputnya sama, operasinya berbeda.

konversi float-to-int terpotong menuju nol, lalu periksa rentang bilangan bulat. NaN dan ketidakterbatasan menyebabkan jebakan. Saat mengonversi ke i8, 127,9 menjadi 127, sedangkan 128,0 menjebak. Bool dikonversi ke bilangan bulat 0 atau 1. i1 yang ditandatangani tidak dapat mewakili 1, sehingga tidak dapat menjadi tujuan konversi ini.

Mengonversi alamat menjadi bilangan bulat tidak memulihkan akses penunjuk ke bilangan bulat tersebut. Silakan merujuk ke validitas penunjuk.

aritmatika titik mengambang

Nilai floating point memiliki string bit yang tepat f16·f32·f64. Operasi ini membulatkan ke nilai terdekat pada lebar yang dinyatakan dan, jika tepat di tengah, menggunakan ties-to-even, yang memilih nilai dengan bit paling signifikan dari digit signifikan.

Operasi defaultnya adalah fast-math, implisit FMA, yang tidak mengizinkan penanganan nol paksa pada nilai kecil. Perkalian yang diikuti penjumlahan mempertahankan langkah pembulatan masing-masing dan backend tidak boleh menggabungkannya secara implisit ke dalam satu operasi.

Hasil operasi numerik bisa berupa NaN atau tak terhingga. NaN dari operasi matematika dan perubahan lebar dinormalisasi menjadi satu jumlah tetap NaN tenang per lebar. Simpan dan salin, pertahankan bit NaN asli. Oleh karena itu, perilakunya berbeda saat meneruskan payload NaN ke memori tanpa operasi aritmatika dan saat menghitungnya.

Itu tidak mengekspos tanda status floating-point. Meskipun aritmatika titik-mengambang dasar memungkinkan hasil NaN·tak terhingga, konversi float→int menerapkan aturan trap di atas.

Simpan konstanta yang tepat

Gunakan FloatBits variant atau string bit heksadesimal apa pun dengan lebar yang tepat. Kesetaraan nilai yang disimpan dibandingkan dengan string bit yang berisi negatif 0 dan NaN payload. Verifikator menolak jika lebar tipe IR dan payload berbeda.

use ir::{FloatBits, ModuleBuilder, Target, Type};
fn main() {
    let bits = FloatBits::parse(32, "0xffc01234").unwrap();
    assert_eq!(bits, FloatBits::F32(0xffc01234));
    let target = Target::X86_64WhaleLinux;
    let mut module = ModuleBuilder::new(target.name(), target.data_layout());
    let mut function = module.begin_function("payload", vec![], Type::F32);
    let value = function.const_float_bits(Type::F32, bits);
    function.ret(Some(value));
    function.finish();
    let module = module.finish();
    ir::verify_module(&module).unwrap();
    assert!(ir::print_module(&module).contains("const f32 0xffc01234"));
    println!("{}", bits);
}
0xffc01234

String bit f16, f32, atau f64 dimulai dengan 0x, diikuti dengan tepat 4, 8, atau 16 digit heksadesimal. 0x80000000 mewakili f32 nol negatif; 0x7f800000 mewakili ketidakterbatasan positif. const_float mengonversi nilai host f64 secara numerik; gunakan const_float_bits untuk mempertahankan bit aslinya. Representasi penyimpanan yang tepat tidak berarti backend eksekusi floating-point yang lengkap. Aritmatika waktu kompilasi masih menggunakan perantara host f64, sehingga kontrak pembulatan penuh untuk setiap lebar yang dinyatakan belum diterapkan.