2009-05-26 6 views
8

Có cách nào an toàn để thêm chữ số ở cuối số nguyên mà không chuyển đổi số thành một chuỗi và không sử dụng chuỗi ký tự không?Nối chữ số vào một int mà không chuyển đổi thành chuỗi?

Tôi đã cố gắng google câu trả lời cho điều này và hầu hết các giải pháp đều đề xuất chuyển đổi thành chuỗi và sử dụng chuỗi nhưng tôi muốn giữ nguyên làm số nguyên để đảm bảo tính toàn vẹn của dữ liệu và tránh chuyển đổi loại.
Tôi cũng đọc một giải pháp gợi ý nhân số int bằng 10 rồi thêm chữ số, tuy nhiên điều này có thể gây ra tràn số nguyên.
Điều này có an toàn để thực hiện hoặc có phương pháp tốt hơn để thực hiện việc này không? Và nếu tôi làm điều này nhân với 10 và thêm các giải pháp chữ số, tôi nên thực hiện biện pháp phòng ngừa nào?

Trả lời

25

Đặt cược tốt nhất của bạn là nhân với 10 và cộng thêm giá trị. Bạn có thể làm a naive check như vậy:

assert(digit >= 0 && digit < 10); 
newValue = (oldValue * 10) + digit; 
if (newValue < oldValue) 
{ 
    // overflow 
} 
+0

tuyệt vời! Cảm ơn nhiều! – nmuntz

+0

Kiểm tra tràn là sai. Ví dụ: 4772185889 - 2^32 = 477218593, lớn hơn 477218588. –

+0

Tôi đồng ý, tôi liên kết đến nơi bạn có thể thực hiện ít hơn ngây thơ. – user7116

3

Để ngăn chặn tràn:

if ((0 <= value) && (value <= ((MAX_INT - 9)/10))) { 
    return (value * 10) + digit; 
} 

Thay MAX_INT, bạn có thể sử dụng std::numeric_limits<typeof(value)>::max() hoặc tương tự, để hỗ trợ các loại khác hơn là int.

2
 
    assert(digit >= 0 && digit < 10); 
    newvalue = 10 * oldvalue; 
    if (oldvalue < 0) { 
    newvalue -= digit; 
    } else { 
    newvalue += digit; 
    } 

    // check for overflow SGN(oldvalue) == 0 || SGN(newvalue) == SGN(oldvalue) 
2

Đây là một thực hiện tốt hơn và chống đạn hơn một trong đó đã được chấp nhận như là một câu trả lời mà cũng nhanh:

#include <climits> 
#include <cassert> 

unsigned int add_digit(unsigned int val, unsigned int digit) 
{ 
    // These should be computed at compile time and never even be given a memory location 
    static const unsigned int max_no_overflow = (UINT_MAX - 9)/10U; 
    static const unsigned int max_maybe_overflow = UINT_MAX/10U; 
    static const unsigned int last_digit = UINT_MAX % 10; 

    assert(digit >= 0 && digit < 10); 
    if ((val > max_no_overflow) && ((val > max_maybe_overflow) || (digit > last_digit))) { 
     // handle overflow 
    } else { 
     return val * 10 + digit; 
    } 
    assert(false); 
} 

Bạn cũng sẽ có thể làm cho điều này trở thành một chức năng inline. Kiểm tra tràn sẽ hầu như luôn luôn ngắn mạch sau khi so sánh đầu tiên. Mệnh đề sau && đơn giản là bạn có thể (trong trường hợp số nguyên bổ sung 32 bit, số hai) cộng 5 vào cuối 429496729, nhưng không phải là 6.