Saya sedang menulis sebuah program dalam C ++ untuk menemukan semua solusi dari a b = c , di mana sebuah , b dan c bersama-sama menggunakan semua angka 0-9 tepat sekali. Program dilingkarkan di atas nilai-nilai yang dan b , dan berlari digit penghitungan rutin setiap kali di sebuah , b dan a b untuk memeriksa apakah kondisi digit puas.
Namun, solusi palsu dapat dihasilkan ketika sebuah b meluap batas integer. Saya akhirnya memeriksa ini menggunakan kode seperti:
unsigned long b, c, c_test;
...
c_test=c*b; // Possible overflow
if (c_test/b != c) {/* There has been an overflow*/}
else c=c_test; // No overflow
Apakah ada cara yang lebih baik untuk menguji luapan? Saya tahu bahwa beberapa chip memiliki flag internal yang diatur ketika terjadi overflow, tetapi saya belum pernah melihatnya diakses melalui C atau C ++.
Waspadalah bahwa overflow yang ditandatangani int
adalah perilaku tidak terdefinisi dalam C dan C ++ , dan karenanya Anda harus mendeteksinya tanpa benar-benar menyebabkannya. Untuk limpahan int yang ditandatangani sebelum penambahan, lihat Mendeteksi limpahan yang ditandatangani di C / C ++ .
sumber
-ftrapv
akan membuatnya menghasilkan SIGABRT pada overflow integer yang ditandatangani. Lihat di sini .clz
instruksi atau__clz(unsigned)
fungsi untuk menentukan peringkat nomor (di mana bit tertinggi adalah). Karena saya tidak yakin apakah ini tersedia di x86 atau x64, saya akan menganggapnya tidak dan mengatakan bahwa menemukan bit yang paling signifikan akan mengambillog(sizeof(int)*8)
instruksi terburuk .Jawaban:
Saya melihat Anda menggunakan bilangan bulat yang tidak ditandatangani. Menurut definisi, di C (saya tidak tahu tentang C ++), aritmatika yang tidak ditandatangani tidak melimpah ... jadi, setidaknya untuk C, poin Anda bisa diperdebatkan :)
Dengan bilangan bulat yang ditandatangani, setelah terjadi overflow, perilaku tidak terdefinisi (UB) telah terjadi dan program Anda dapat melakukan apa saja (misalnya: render tes tidak meyakinkan).
Untuk membuat program yang sesuai, Anda perlu menguji untuk overflow sebelum membuat kata overflow. Metode ini dapat digunakan dengan bilangan bulat tidak bertanda juga:
Untuk pembagian (kecuali untuk
INT_MIN
dan-1
kasus khusus), tidak ada kemungkinan untuk beralihINT_MIN
atauINT_MAX
.sumber
x >= 0
-x > 0
akan cukup (jikax == 0
, makax + a
tidak bisa meluap karena alasan yang jelas).if ((a < INT_MIN / x))
Tes sudah terlambat. Sebuahif (x == -1)
tes diperlukan pertama.Ada adalah cara untuk menentukan apakah operasi cenderung meluap, menggunakan posisi yang paling signifikan satu-bit dalam operan dan pengetahuan biner-matematika dasar sedikit.
Sebagai tambahan, setiap dua operan akan menghasilkan (paling banyak) satu bit lebih banyak dari operand tertinggi satu bit terbesar. Sebagai contoh:
Untuk penggandaan, setiap dua operan akan menghasilkan (paling banyak) jumlah bit dari operan. Sebagai contoh:
Demikian pula, Anda dapat memperkirakan ukuran maksimum hasil
a
hingga kekuatanb
seperti ini:(Pengganti jumlah bit untuk target integer Anda, tentu saja.)
Saya tidak yakin dengan cara tercepat untuk menentukan posisi bit tertinggi dalam sebuah angka, berikut ini adalah metode brute-force:
Itu tidak sempurna, tetapi itu akan memberi Anda ide yang baik apakah ada dua angka yang bisa meluap sebelum Anda melakukan operasi. Saya tidak tahu apakah itu akan lebih cepat daripada hanya memeriksa hasilnya seperti yang Anda sarankan, karena loop dalam
highestOneBitPosition
fungsi, tetapi mungkin (terutama jika Anda tahu berapa banyak bit di operan sebelumnya).sumber
log2
, tetapi itu tidak selalu jelas bagi seseorang yang tidak memiliki latar belakang matematika.multiplication_is_safe
0x8000 * 0x10000
akan melimpah (posisi bit adalah 16 + 17 = 33 yang > 32 ), meskipun tidak karena0x8000 * 0x10000 = 0x80000000
yang jelas masih cocok dengan int 32 bit yang tidak ditandatangani. Ini hanya satu dari banyak contoh yang kode ini tidak berfungsi.0x8000 * 0x10001
, ...0x8000 * 0x10000
bukan "aman," menurut definisi ini, meskipun ternyata baik-baik saja.Dentang 3.4+ dan GCC 5+ menawarkan builtin aritmatika yang diperiksa. Mereka menawarkan solusi yang sangat cepat untuk masalah ini, terutama jika dibandingkan dengan pemeriksaan keamanan pengujian bit.
Sebagai contoh dalam pertanyaan OP, itu akan berfungsi seperti ini:
Dokumentasi Dentang tidak menentukan apakah
c_test
berisi hasil meluap jika terjadi overflow, tetapi dokumentasi GCC mengatakan itu. Mengingat bahwa keduanya suka__builtin
-compatible, mungkin aman untuk berasumsi bahwa ini adalah cara kerja dentang juga.Ada
__builtin
untuk setiap operasi aritmatika yang dapat meluap (penjumlahan, pengurangan, penggandaan), dengan varian yang ditandatangani dan tidak ditandatangani, untuk ukuran int, ukuran panjang, dan ukuran panjang yang panjang. Sintaks untuk namanya adalah__builtin_[us](operation)(l?l?)_overflow
:u
untuk tidak ditandatangani ataus
untuk ditandatangani ;add
,sub
ataumul
;l
suffix berarti operan adalahint
s; satul
berartilong
; dual
s berartilong long
.Jadi untuk penambahan bilangan bulat panjang bertanda tangan yang dicentang, itu akan menjadi
__builtin_saddl_overflow
. Daftar lengkap dapat ditemukan di halaman dokumentasi Dentang .GCC 5 + dan dentang 3.8+ juga menawarkan builtin generik yang bekerja tanpa menentukan jenis nilai-nilai:
__builtin_add_overflow
,__builtin_sub_overflow
dan__builtin_mul_overflow
. Ini juga bekerja pada jenis yang lebih kecil dariint
.Builtin lebih rendah ke apa yang terbaik untuk platform. Pada x86, mereka memeriksa carry, overflow, dan tanda bendera.
Cl.exe Visual Studio tidak memiliki padanan langsung. Untuk penambahan dan pengurangan yang tidak ditandatangani, termasuk
<intrin.h>
akan memungkinkan Anda untuk menggunakanaddcarry_uNN
dansubborrow_uNN
(di mana NN adalah jumlah bit, sukaaddcarry_u8
atausubborrow_u64
). Tanda tangan mereka agak tumpul:c_in
/b_in
adalah flag carry / meminjam pada input, dan nilai kembali adalah carry / pinjam pada output. Tampaknya tidak memiliki padanan untuk operasi atau multiplikasi yang ditandatangani.Kalau tidak, Dentang untuk Windows sekarang sudah siap produksi (cukup baik untuk Chrome), sehingga bisa menjadi pilihan juga.
sumber
__builtin_sub_overflow
pasti tidak dalam dentang 3.4.__builtin_add_overflow
dan teman-teman harus sudah tersedia di Dentang 3.8.Beberapa kompiler menyediakan akses ke flag integer overflow di CPU yang dapat Anda uji tetapi ini bukan standar.
Anda juga bisa menguji kemungkinan overflow sebelum Anda melakukan perkalian:
sumber
b == ULONG_MAX / a
? Maka masih bisa muat, mengingat yanga
membelahULONG_MAX
tanpa residual.Peringatan: GCC dapat mengoptimalkan jauh pemeriksaan luapan saat dikompilasi
-O2
. Opsi-Wall
akan memberi Anda peringatan dalam beberapa kasus sepertitetapi tidak dalam contoh ini:
Satu-satunya cara yang aman adalah memeriksa luapan sebelum terjadi, seperti yang dijelaskan dalam makalah CERT , dan ini akan sangat membosankan untuk digunakan secara sistematis.
Kompilasi dengan
-fwrapv
memecahkan masalah, tetapi menonaktifkan beberapa optimasi.Kami sangat membutuhkan solusi yang lebih baik. Saya pikir kompiler harus mengeluarkan peringatan secara default ketika membuat optimasi yang mengandalkan overflow tidak terjadi. Situasi saat ini memungkinkan kompiler untuk mengoptimalkan cek overflow, yang menurut saya tidak dapat diterima.
sumber
for(int k = 0; k < 5; k++) {...}
haruskah memunculkan peringatan?k
dapat dengan mudah ditentukan pada waktu kompilasi. Kompiler tidak harus membuat asumsi.n
kurang dari 32, sebelum memancarkan instruksi shift yang hanya menggunakan 5 bit yang lebih rendahn
?Dentang sekarang mendukung pemeriksaan overflow dinamis untuk bilangan bulat yang ditandatangani dan tidak ditandatangani. Lihat sakelar -fsanitize = integer . Untuk saat ini, ini adalah satu-satunya kompiler C ++ dengan dynamic overflow yang didukung sepenuhnya untuk keperluan debug.
sumber
Saya melihat bahwa banyak orang menjawab pertanyaan tentang meluap, tetapi saya ingin mengatasi masalah aslinya. Dia mengatakan masalahnya adalah menemukan b = c sehingga semua digit digunakan tanpa mengulangi. Oke, bukan itu yang dia tanyakan dalam posting ini, tapi saya masih berpikir bahwa itu perlu untuk mempelajari batas atas masalah dan menyimpulkan bahwa dia tidak perlu menghitung atau mendeteksi luapan (catatan: Saya tidak cakap dalam matematika jadi saya melakukan langkah demi langkah ini, tetapi hasil akhirnya sangat sederhana sehingga ini mungkin memiliki rumus sederhana).
Poin utama adalah bahwa batas atas yang dibutuhkan oleh masalah untuk a, b atau c adalah 98.765.432. Pokoknya, mulailah dengan memecah masalah di bagian sepele dan non sepele:
Sekarang kita hanya perlu menunjukkan bahwa tidak ada solusi lain yang mungkin dan hanya permutasi yang valid (dan kemudian kode untuk mencetaknya adalah sepele). Kami kembali ke batas atas. Sebenarnya batas atas adalah c ≤ 98.765.432. Ini adalah batas atas karena ini adalah angka terbesar dengan 8 digit (total 10 digit minus 1 untuk masing-masing a dan b). Batas atas ini hanya untuk c karena batas untuk a dan b harus jauh lebih rendah karena pertumbuhan eksponensial, seperti yang dapat kita hitung, bervariasi b dari 2 hingga batas atas:
Perhatikan, misalnya baris terakhir: dikatakan bahwa 1,97 ^ 27 ~ 98M. Jadi, misalnya, 1 ^ 27 == 1 dan 2 ^ 27 == 134.217.728 dan itu bukan solusi karena memiliki 9 digit (2> 1,97 sehingga sebenarnya lebih besar dari apa yang harus diuji). Seperti dapat dilihat, kombinasi yang tersedia untuk pengujian a dan b sangat kecil. Untuk b == 14, kita perlu mencoba 2 dan 3. Untuk b == 3, kita mulai dari 2 dan berhenti di 462. Semua hasil yang diberikan kurang dari ~ 98M.
Sekarang coba saja semua kombinasi di atas dan cari yang tidak mengulangi angka apa pun:
Tak satu pun dari mereka cocok dengan masalah (yang juga bisa dilihat dengan tidak adanya '0', '1', ..., '9').
Contoh kode yang menyelesaikannya mengikuti. Perhatikan juga bahwa ini ditulis dengan Python, bukan karena membutuhkan bilangan bulat presisi yang sewenang-wenang (kode tidak menghitung apa pun yang lebih besar dari 98 juta), tetapi karena kami menemukan bahwa jumlah tes sangat kecil sehingga kami harus menggunakan bahasa tingkat tinggi untuk memanfaatkan wadah dan pustaka bawaannya (juga perhatikan: kode memiliki 28 baris).
sumber
Berikut adalah solusi "non-portabel" untuk pertanyaan tersebut. Intel x86 dan x64 CPU memiliki apa yang disebut EFLAGS-register , yang diisi oleh prosesor setelah setiap operasi aritmatika integer. Saya akan melewatkan deskripsi terperinci di sini. Bendera yang relevan adalah Bendera "Overflow" (mask 0x800) dan "Carry" Flag (mask 0x1). Untuk menafsirkannya dengan benar, orang harus mempertimbangkan apakah operan bertipe ditandatangani atau tidak.
Berikut ini adalah cara praktis untuk memeriksa flag dari C / C ++. Kode berikut akan bekerja pada Visual Studio 2005 atau lebih baru (baik 32 dan 64 bit), serta pada GNU C / C ++ 64 bit.
Jika operan dikalikan tanpa overflow, Anda akan mendapatkan nilai balik 0 dari
query_intel_eflags(0x801)
, yaitu, carry atau flag overflow tidak diatur. Dalam kode contoh utama yang disediakan (), terjadi overflow dan kedua flag diset ke 1. Pemeriksaan ini tidak menyiratkan perhitungan lebih lanjut, jadi harus cukup cepat.sumber
Jika Anda memiliki tipe data yang lebih besar daripada yang ingin Anda uji (mis. Anda menambahkan 32-bit dan Anda memiliki tipe 64-bit), maka ini akan mendeteksi jika terjadi overflow. Contoh saya adalah untuk menambahkan 8-bit. Tapi itu bisa ditingkatkan.
Ini didasarkan pada konsep-konsep yang dijelaskan pada halaman ini: http://www.cs.umd.edu/class/spring2003/cmsc311/Notes/Comb/overflow.html
Sebagai contoh 32-bit,
0xFF
menjadi0xFFFFFFFF
dan0x80
menjadi0x80000000
dan akhirnyauint16_t
menjadiuint64_t
.CATATAN : ini menangkap penambahan / pengurangan bilangan bulat bilangan bulat, dan saya menyadari bahwa pertanyaan Anda melibatkan multiplikasi. Dalam hal ini, pembagian kemungkinan merupakan pendekatan terbaik. Ini biasanya merupakan cara
calloc
implementasi memastikan bahwa parameter tidak meluap ketika mereka dikalikan untuk mendapatkan ukuran akhir.sumber
Cara paling sederhana adalah mengubah
unsigned long
s Anda menjadiunsigned long long
s, lakukan penggandaan Anda, dan bandingkan hasilnya dengan 0x100000000LL.Anda mungkin akan menemukan bahwa ini lebih efisien daripada melakukan pembagian seperti yang telah Anda lakukan dalam contoh Anda.
Oh, dan itu akan bekerja di C dan C ++ (karena Anda telah menandai pertanyaan dengan keduanya).
Baru saja melihat manual glibc . Ada yang menyebutkan jebakan integer overflow (
FPE_INTOVF_TRAP
) sebagai bagian dariSIGFPE
. Itu akan ideal, terlepas dari bagian-bagian buruk dalam manual:Sedikit memalukan kok.
sumber
ULONG_MAX
yang lebih mudah untuk mengetik dan lebih portabel daripada hard-coding0x100000000
.long
danlong long
memiliki ukuran yang sama (misalnya pada banyak kompiler 64-bit).Berikut adalah cara yang sangat cepat untuk mendeteksi overflow untuk setidaknya penambahan, yang mungkin memberikan petunjuk untuk multiplikasi, pembagian, dan kekuatan.
Idenya adalah persis karena prosesor hanya akan membiarkan nilai membungkus kembali ke nol dan bahwa C / C ++ akan diabstraksi dari prosesor tertentu, Anda dapat:
Ini keduanya memastikan bahwa jika satu operan nol dan satu tidak, maka overflow tidak akan terdeteksi secara salah dan secara signifikan lebih cepat daripada banyak operasi BUKAN / XOR / DAN / seperti yang disarankan sebelumnya.
Seperti yang ditunjukkan, pendekatan ini, meskipun lebih baik daripada cara lain yang lebih rumit, masih dapat dioptimalkan. Berikut ini adalah revisi dari kode asli yang berisi optimisasi:
Cara yang lebih efisien dan murah untuk mendeteksi multiplication overflow adalah:
Ini menghasilkan UINT32_MAX saat overflow, atau hasil perkalian. Ini adalah perilaku yang tidak ditentukan untuk memungkinkan perkalian untuk melanjutkan untuk bilangan bulat yang ditandatangani dalam kasus ini.
sumber
x+y>=256
danvalue=x+y-256
. Karenay<256
selalu berlaku, (y-256) adalah negatif danvalue < x
selalu benar. Buktinya untuk kasus non overflow sangat mirip.uint32_t x[N], y[N], z[N], carry=0; for (int i = 0; i < N; i++) { z[i] = x[i] + y[i] + carry; carry = z[i] < (x[i] | y[i]); }
Jika Anda tidakor
nilainya, Anda tidak akan dapat membedakan antara satu operan dan carry bit menjadi nol dan satu operand0xffffffff
dan carry bit menjadi satu.Anda tidak dapat mengakses flag overflow dari C / C ++.
Beberapa kompiler memungkinkan Anda untuk memasukkan instruksi trap ke dalam kode. Pada GCC opsinya adalah
-ftrapv
.Satu-satunya hal yang portabel dan kompiler yang dapat Anda lakukan adalah memeriksa sendiri kelebihannya. Sama seperti yang Anda lakukan dalam contoh Anda.
Namun,
-ftrapv
tampaknya tidak melakukan apa pun pada x86 menggunakan GCC terbaru. Saya kira itu adalah sisa dari versi lama atau khusus untuk beberapa arsitektur lain. Saya mengharapkan kompiler untuk memasukkan INTO opcode setelah setiap penambahan. Sayangnya tidak melakukan ini.sumber
Untuk bilangan bulat yang tidak ditandatangani, cukup periksa bahwa hasilnya lebih kecil dari salah satu argumen:
Untuk bilangan bulat yang ditandatangani, Anda dapat memeriksa tanda-tanda argumen dan hasilnya.
Bilangan bulat dari tanda yang berbeda tidak dapat melimpah, dan bilangan bulat dari tanda yang sama hanya jika hasilnya berupa tanda yang berbeda:
sumber
char result = (char)127 + (char)3;
akan menjadi -126; lebih kecil dari kedua operan.Saya perlu menjawab pertanyaan yang sama untuk angka floating point, di mana bit masking dan shifting tidak terlihat menjanjikan. Pendekatan yang saya tetapkan pada karya untuk angka-angka titik yang ditandatangani dan tidak ditandatangani, bilangan bulat dan mengambang. Ini berfungsi bahkan jika tidak ada tipe data yang lebih besar untuk dipromosikan ke untuk perhitungan menengah. Ini bukan yang paling efisien untuk semua jenis ini, tetapi karena itu bekerja untuk mereka semua, itu layak digunakan.
Tes Overflow, Penambahan, dan Pengurangan yang ditandatangani:
Dapatkan konstanta yang mewakili nilai terbesar dan terkecil yang mungkin untuk tipe, MAXVALUE dan MINVALUE.
Hitung dan bandingkan tanda-tanda operan.
Sebuah. Jika salah satu nilai nol, maka penambahan atau pengurangan tidak bisa meluap. Lewati tes yang tersisa.
b. Jika tanda-tandanya berlawanan, maka penambahan tidak bisa meluap. Lewati tes yang tersisa.
c. Jika tanda-tandanya sama, maka pengurangan tidak bisa meluap. Lewati tes yang tersisa.
Tes untuk aliran MAXVALUE positif.
Sebuah. Jika kedua tanda positif dan MAXVALUE - A <B, maka penambahan akan melimpah.
b. Jika tanda B negatif dan MAXVALUE - A <-B, maka pengurangan akan melimpah.
Tes untuk luapan negatif MINVALUE.
Sebuah. Jika kedua tanda negatif dan MINVALUE - A> B, maka penambahan akan melimpah.
b. Jika tanda A negatif dan MINVALUE - A> B, maka pengurangan akan melimpah.
Kalau tidak, tidak ada luapan.
Tes Overflow, Multiplikasi dan Divisi yang ditandatangani:
Dapatkan konstanta yang mewakili nilai terbesar dan terkecil yang mungkin untuk tipe, MAXVALUE dan MINVALUE.
Hitung dan bandingkan besaran (nilai absolut) dari operan dengan satu. (Di bawah ini, anggap A dan B adalah magnitudo ini, bukan yang asli yang ditandatangani.)
Sebuah. Jika salah satu nilai adalah nol, perkalian tidak dapat meluap, dan pembagian akan menghasilkan nol atau tak terhingga.
b. Jika salah satu nilai adalah satu, multiplikasi dan pembagian tidak dapat meluap.
c. Jika besarnya satu operan di bawah satu dan yang lainnya lebih besar dari satu, multiplikasi tidak dapat meluap.
d. Jika besarnya keduanya kurang dari satu, pembagian tidak dapat meluap.
Tes untuk aliran MAXVALUE positif.
Sebuah. Jika kedua operan lebih besar dari satu dan MAXVALUE / A <B, maka multiplikasi akan melimpah.
b. Jika B kurang dari satu dan MAXVALUE * B <A, maka pembagian akan melimpah.
Kalau tidak, tidak ada luapan.
Catatan: Overflow minimum MINVALUE ditangani oleh 3, karena kami mengambil nilai absolut. Namun, jika ABS (MINVALUE)> MAXVALUE, maka kami akan memiliki beberapa false positive yang langka.
Tes untuk aliran bawah serupa, tetapi melibatkan EPSILON (angka positif terkecil yang lebih besar dari nol).
sumber
1.0e-200 / 1.0e200
akan menjadi contoh dari underflow yang sebenarnya, dengan asumsi IEEE berlipat ganda. Sebaliknya, istilah yang benar di sini adalah luapan negatif. </pedantic>1/INT_MAX
bisa juga dianggap underflow, tetapi bahasa hanya memerintahkan pemotongan ke nol.CERT telah mengembangkan pendekatan baru untuk mendeteksi dan melaporkan limpasan bilangan bulat bertanda tangan, pembungkus bilangan bulat tak bertanda, dan pemotongan bilangan bulat menggunakan model bilangan bulat "seolah-olah" tak berhingga (AIR). CERT telah menerbitkan laporan teknis yang menggambarkan model dan menghasilkan prototipe kerja berdasarkan GCC 4.4.0 dan GCC 4.5.0.
Model integer AIR baik menghasilkan nilai yang setara dengan yang akan diperoleh dengan menggunakan bilangan bulat tak terhingga atau hasil dalam pelanggaran kendala runtime. Tidak seperti model integer sebelumnya, integer AIR tidak memerlukan jebakan yang tepat, dan akibatnya tidak merusak atau menghambat sebagian besar optimasi yang ada.
sumber
Alat lain yang menarik adalah IOC: An Integer Overflow Checker untuk C / C ++ .
Ini adalah kompilasi Dentang tambalan , yang menambahkan pemeriksaan ke kode pada waktu kompilasi.
Anda mendapatkan hasil seperti ini:
sumber
Varian lain dari solusi, menggunakan bahasa assembly, adalah prosedur eksternal. Contoh ini untuk perkalian integer tak bertanda menggunakan g ++ dan fasm di Linux x64.
Prosedur ini mengalikan dua argumen integer yang tidak ditandatangani (32 bit) (sesuai dengan spesifikasi untuk amd64 (bagian 3.2.3 Parameter Passing ).
(edi dan esi mendaftar dalam kode saya)) dan mengembalikan hasilnya atau 0 jika terjadi overflow.
Uji:
Tautkan program dengan file objek asm. Dalam kasus saya, di Qt Creator , tambahkan ke
LIBS
dalam file .pro.sumber
Hitung hasilnya dengan ganda. Mereka memiliki 15 digit signifikan. Persyaratan Anda memiliki batas atas yang keras pada c dari 10 8 - ia dapat memiliki paling banyak 8 digit. Oleh karena itu, hasilnya akan tepat jika berada dalam jangkauan, dan tidak akan meluap sebaliknya.
sumber
Coba makro ini untuk menguji bit overflow dari mesin 32-bit (mengadaptasi solusi Angel Sinigersky)
Saya mendefinisikannya sebagai makro karena kalau tidak bit overflow akan ditimpa.
Berikutnya adalah aplikasi kecil dengan kode segmen di atas:
sumber
_MSC_VER
meskipun kompilasi MS semua akan menolak kode).Menangkap Integer Overflows di C menunjukkan solusi yang lebih umum daripada yang dibahas oleh CERT (ini lebih umum dalam hal jenis yang ditangani), bahkan jika itu memerlukan beberapa ekstensi GCC (saya tidak tahu seberapa luas mereka didukung).
sumber
Saya tidak setuju dengan ini. Anda bisa menulis beberapa bahasa rakitan inline dan menggunakan
jo
instruksi (lompatan lompatan) dengan asumsi Anda berada di x86 untuk menjebak overflow. Tentu saja, kode Anda tidak lagi portabel untuk arsitektur lain.Lihatlah
info as
daninfo gcc
.sumber
Untuk memperluas jawaban Kepala Geek, ada cara yang lebih cepat untuk melakukan
addition_is_safe
;Ini menggunakan arsitektur mesin aman, dalam bahwa integer 64-bit dan 32-bit masih akan bekerja dengan baik. Pada dasarnya, saya membuat topeng yang akan menutupi semua kecuali bagian yang paling signifikan. Kemudian, saya menutupi kedua bilangan bulat, dan jika salah satu dari mereka tidak memiliki set bit, maka penambahan aman.
Ini akan lebih cepat jika Anda melakukan inisialisasi topeng di beberapa konstruktor, karena itu tidak pernah berubah.
sumber
UINT_MAX + 1
. Setelah masking,a
akan memiliki bit set yang tinggi, tetapi1
akan menjadi nol dan karena itu fungsinya akan kembalitrue
, penambahan aman - namun Anda langsung menuju overflow.mozilla::CheckedInt<T>
menyediakan matematika integer berlebih yang diperiksa untuk tipe integerT
(menggunakan intrinsik kompiler pada dentang dan gcc jika tersedia). Kode ini berada di bawah MPL 2.0 dan tergantung pada tiga (IntegerTypeTraits.h
,Attributes.h
danCompiler.h
) header perpustakaan non-standar hanya header lainnya ditambah mesin pernyataan spesifik Mozilla . Anda mungkin ingin mengganti mesin asersi jika Anda mengimpor kode.sumber
Jawaban MSalter adalah ide yang bagus.
Jika perhitungan integer diperlukan (untuk presisi), tetapi floating point tersedia, Anda bisa melakukan sesuatu seperti:
sumber
(c * log(a) < max_log)
, di manaconst double max_log = log(UINT_MAX)
Set instruksi x86 termasuk instruksi multiplikasi yang tidak ditandatangani yang menyimpan hasilnya ke dua register. Untuk menggunakan instruksi dari C, seseorang dapat menulis kode berikut dalam program 64-bit (GCC):
Untuk program 32-bit, kita perlu membuat hasilnya 64 bit dan parameter 32 bit.
Alternatifnya adalah menggunakan intrinsik yang bergantung pada kompiler untuk memeriksa register flag. Dokumentasi GCC untuk intrinsik overflow dapat ditemukan dari 6.56 Fungsi Bawaan untuk Melakukan Aritmatika dengan Memeriksa Overflow .
sumber
__uint128
tidak ditandatangani untuk menghindari overflow yang ditandatangani dan menggeser nilai negatif ke kanan.sumber
Cara yang bersih untuk melakukannya adalah dengan menimpa semua operator (+ dan * khususnya) dan memeriksa overflow sebelum melakukan operasi.
sumber
Tergantung untuk apa Anda menggunakannya. Melakukan penambahan atau perkalian unsigned long (DWORD), solusi terbaik adalah dengan menggunakan ULARGE_INTEGER.
ULARGE_INTEGER adalah struktur dua DWORD. Nilai penuh dapat diakses sebagai "QuadPart" sementara DWORD tinggi diakses sebagai "HighPart" dan DWORD rendah diakses sebagai "LowPart".
Sebagai contoh:
sumber
ULARGE_INTEGER
.Untuk melakukan perkalian tanpa tanda tangan tanpa meluap dengan cara portabel berikut ini dapat digunakan:
sumber
Cara sederhana untuk menguji overflow adalah dengan melakukan validasi dengan memeriksa apakah nilai saat ini kurang dari nilai sebelumnya. Misalnya, misalkan Anda memiliki loop untuk mencetak kekuatan 2:
Menambahkan limpahan memeriksa cara saya menggambarkan hasil dalam ini:
Ini berfungsi untuk nilai yang tidak ditandatangani serta nilai yang ditandatangani positif dan negatif.
Tentu saja, jika Anda ingin melakukan sesuatu yang serupa untuk menurunkan nilai alih-alih meningkatkan nilai, Anda akan membalik
<=
tanda untuk membuatnya>=
, dengan asumsi perilaku underflow sama dengan perilaku overflow. Dalam semua kejujuran, itu tentang portabel karena Anda akan mendapatkan tanpa akses ke flag melimpah CPU (dan itu akan membutuhkan kode perakitan inline, tetap membuat kode Anda non-portabel di seluruh implementasi).sumber