2013-04-10 28 views
22

Tôi có 2 số: AB. Tôi cần tính A+B ở đâu đó trong mã của tôi. Cả hai số AB đều là long long và có thể là số dương hoặc âm.Làm cách nào để kiểm tra xem A + B có dài quá lâu không? (cả A và B dài)

Mã của tôi chạy sai và tôi nghi ngờ sự cố xảy ra khi tính toán A+B. Tôi chỉ muốn kiểm tra xem nếu A+B vượt quá phạm vi long long. Vì vậy, bất kỳ phương pháp nào cũng được chấp nhận, vì tôi chỉ sử dụng nó để gỡ lỗi.

+0

'nếu ((A <0 && B <0 && A+B> 0) || (A> 0 && B> 0 && A + B <0)) {/ * Overflow * /} 'Bạn chỉ có thể tràn nếu cả A và B có cùng dấu.Nếu họ làm, và A + B không có dấu hiệu giống nhau, thì bạn có vấn đề tràn. Trong các tin tức khác, đây là phương pháp cơ bản nhanh nhất xung quanh, vì nó thực hiện trong thời gian không đổi, và chỉ thực hiện việc bổ sung một lần. – FrankieTheKneeMan

+2

Bạn nên đăng nó như một câu trả lời. Nhân tiện, có một trường hợp góc khi 'A = B = 0x8000000000000000', sau đó 'A + B = 0' và mã của bạn không hoạt động: p – riv

+1

@FrankieTheKneeMan Lỗi tràn là hành vi không xác định. – john

Trả lời

31

Chỉ có thể tràn khi cả hai con số có cùng một dấu. Nếu cả hai đều dương, thì bạn có tràn nếu toán học A + B > LLONG_MAX hoặc tương đương B > LLONG_MAX - A. Vì phía bên phải là không âm, điều kiện sau đã ngụ ý B > 0. Các đối số tương tự cho thấy rằng đối với trường hợp tiêu cực, chúng tôi cũng không cần phải kiểm tra các dấu hiệu của B (nhờ Ben Voigt cho chỉ ra rằng kiểm tra dấu hiệu trên B là không cần thiết). Sau đó, bạn có thể kiểm tra

if (A > 0) { 
    return B > (LLONG_MAX - A); 
} 
if (A < 0) { 
    return B < (LLONG_MIN - A); 
} 
return false; 

để phát hiện tràn. Các tính toán này không thể tràn do kiểm tra ban đầu.

Kiểm tra ký hiệu của kết quả là A + B sẽ hoạt động với ngữ nghĩa quấn quanh được bảo đảm của tính toán số nguyên tràn. Nhưng tràn các số nguyên đã ký là hành vi không xác định, và thậm chí trên các CPU nơi xung quanh là hành vi được thực hiện, trình biên dịch có thể giả định rằng không có hành vi không xác định nào xảy ra và loại bỏ hoàn toàn kiểm tra tràn khi thực hiện như vậy. Vì vậy, kiểm tra đề xuất trong các ý kiến ​​cho câu hỏi là rất không đáng tin cậy.

+4

Không chỉ kiểm tra các dấu hiệu không được đảm bảo để làm việc, nhưng tối ưu hóa đang sử dụng mà không có bảo lãnh (ví dụ tôi chỉ kiểm tra gcc tối ưu hóa 'a + 42> a' đến' true'). – AProgrammer

+0

Điều này sẽ dễ đọc hơn nếu bạn gói nó trong một biểu thức duy nhất, thay vì vứt bỏ 'return' sang phải và trái. Một cái gì đó như 'trả về một <0! = B <0 || (ví dụ: < 0 ? b > LLONG_MIN - a: b

+16

@JamesKanze Tôi tìm thấy nó dễ đọc hơn được chia thành các trường hợp riêng biệt, nhưng đó là tất nhiên chỉ là sở thích của tôi. –

7

Something như sau:

long long max = std::numeric_limits<long long>::max(); 
long long min = std::numeric_limits<long long>::min(); 

if(A < 0 && B < 0) 
    return B < min - A; 
if(A > 0 && B > 0) 
    return B > max - A; 

return false; 

Chúng ta có thể suy luận về vấn đề này như sau:

  • Nếu AB là dấu hiệu ngược lại, họ không thể tràn - một trong những lớn hơn không cần lớn hơn max hoặc số nhỏ hơn 0 sẽ cần phải nhỏ hơn min.

  • Trong các trường hợp khác, đại số đơn giản là đủ. A + B > max => B > max - A sẽ tràn nếu cả hai đều dương. Nếu không, cả hai đều là số âm, A + B < min => B < min - A.

+0

Các thử nghiệm 'B> 0' và' B <0' không cần thiết. –

2

Ngoài ra, nếu bạn chỉ sử dụng nó để gỡ lỗi, bạn có thể sử dụng sau 'hack' để đọc các bit tràn từ các hoạt động cuối cùng trực tiếp (giả sử biên dịch của bạn/CPU hỗ trợ này):

int flags; 
_asm { 
    pushf  // push flag register on the stack 
    pop flags // read the value from the stack 
} 
if (flags & 0x0800) // bit 11 - overflow 
    ... 
+0

Cờ mang theo rất thú vị đối với các số chưa ký. Đối với các số đã ký, bạn phải kiểm tra cờ tràn. – fredoverflow

2

Mặt nạ các biển báo, truyền tới giá trị chưa ký và thực hiện bổ sung. Nếu nó ở trên 1 << (sizeof(int) * 8 - 1) thì bạn bị tràn.

int x, y; 
if (sign(x) == sign(y)){ 
    unsigned int ux = abs(x), uy = abs(y);  
    overflow = ux + uy >= (1 << (sizeof(int) * 8 - 1)); 
} 

Hơn thế nữa, chúng ta hãy viết một mẫu:

template <typename T> 
bool overflow(signed T x, signed T y){ 
    unsigned T ux = x, uy = y; 
    return (sign(x) == sign(y) && (ux + uy >= (1 << (sizeof(T) * 8 - 1))); 
} 
Các vấn đề liên quan