के साथ uint64_t पूर्णांक ओवरफ़्लो के गुणा का पता लगाने के लिए क्या कोई कुशल और पोर्टेबल तरीका है जब यह जांचने के लिए कोई कुशल और पोर्टेबल तरीका है कि int64_t या uint64_t के साथ गुणात्मक संचालन सी में ऑपरेशन ओवरफ़्लो होता है?सी
उदाहरण के लिए, uint64_t के अलावा के लिए मैं कर सकते हैं:
if (UINT64_MAX - a < b) overflow_detected();
else sum = a + b;
लेकिन मैं गुणन के लिए एक समान सरल अभिव्यक्ति के लिए नहीं मिल सकता है।
मेरे साथ जो कुछ भी होता है वह ऑपरेशन को उच्च और निम्न uint32_t भागों में तोड़ रहा है और ओवरफ्लो की जांच करते समय उन हिस्सों के गुणा को निष्पादित कर रहा है, कुछ वास्तव में बदसूरत और शायद अक्षम भी है।
अद्यतन 1: जेन्स Gustedt विधि जोड़ा
बेंच मार्किंग कार्यक्रम:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define N 100000000
int d = 2;
#define POW_2_64 ((double)(1 << 31) * (double)(1 << 31) * 4)
#define calc_b (a + c)
// #define calc_b (a + d)
int main(int argc, char *argv[]) {
uint64_t a;
uint64_t c = 0;
int o = 0;
int opt;
if (argc != 2) exit(1);
opt = atoi(argv[1]);
switch (opt) {
case 1: /* faked check, just for timing */
for (a = 0; a < N; a++) {
uint64_t b = a + c;
if (c > a) o++;
c += b * a;
}
break;
case 2: /* using division */
for (a = 0; a < N; a++) {
uint64_t b = a + c;
if (b && (a > UINT64_MAX/b)) o++;
c += b * a;
}
break;
case 3: /* using floating point, unreliable */
for (a = 0; a < N; a++) {
uint64_t b = a + c;
if ((double)UINT64_MAX < (double)a * (double)b) o++;
c += b * a;
}
break;
case 4: /* using floating point and division for difficult cases */
for (a = 0; a < N; a++) {
uint64_t b = a + c;
double m = (double)a * (double)b;
if (((double)(~(uint64_t)(0xffffffff)) < m) &&
((POW_2_64 < m) ||
(b &&
(a > UINT64_MAX/b)))) o++;
c += b * a;
}
break;
case 5: /* Jens Gustedt method */
for (a = 0; a < N; a++) {
uint64_t b = a + c;
uint64_t a1, b1;
if (a > b) { a1 = a; b1 = b; }
else { a1 = b; b1 = a; }
if (b1 > 0xffffffff) o++;
else {
uint64_t a1l = (a1 & 0xffffffff) * b1;
uint64_t a1h = (a1 >> 32) * b1 + (a1l >> 32);
if (a1h >> 32) o++;
}
c += b1 * a1;
}
break;
default:
exit(2);
}
printf("c: %lu, o: %u\n", c, o);
}
अब तक मामले में 4 का उपयोग करता है कुछ बेंचमार्क कोड कई दृष्टिकोण को लागू करने
अद्यतन 2 जोड़ा अधिकांश मामलों को फ़िल्टर करने के लिए फ़्लोटिंग पॉइंट सबसे तेज़ होता है जब यह माना जाता है कि ओवरफ्लो बहुत असामान्य हैं, कम से कम मेरे कंप्यूटर पर जहां यह केवल दो टी है कुछ भी मामला से धीमी गति से imes।
प्रकरण 5, 30% 4 की तुलना में धीमी है, लेकिन यह हमेशा एक ही करता है, वहाँ किसी भी विशेष मामला संख्या कि धीमी संसाधन की आवश्यकता होती साथ 4.
फ्लोटिंग-पॉइंट का उपयोग करने के बारे में और यदि परिणाम 2^64 के बहुत करीब है, तो पूर्णांक गुणा कर रहा है? यदि फ़्लोटिंग-पॉइंट परिणाम 9.223370 ई + 18 से ऊपर है तो सटीक उत्पाद निश्चित रूप से 2^63 से अधिक होगा, और यदि फ़्लोटिंग-पॉइंट परिणाम 9.223374 ई + 18 से कम है तो सटीक उत्पाद निश्चित रूप से 3^63 से कम होगा। तो यदि फ़्लोटिंग-पॉइंट परिणाम निकट है और हस्ताक्षरित पूर्णांक 1ULL से अधिक उत्पन्न होता है << 63, पूर्णांक परिणाम एक ओवरफ़्लो का प्रतिनिधित्व नहीं करेगा। – supercat
@supercat: यह ज्यादातर मामला 4 करता है। – salva
केस चार यह जांचने के लिए प्रभाग का उपयोग करता है कि परिणाम फिट होगा या नहीं। कई प्रोसेसर पर, हस्ताक्षरित पूर्णांक को स्वयं गुणा करना बहुत तेज़ होगा (पूर्णांक विभाजन अक्सर सबसे धीमे निर्देशों में से एक होता है)। – supercat