Trang 1 trên tổng số 2 12 Cuối cùngCuối cùng
Từ 1 tới 10 trên tổng số 17 kết quả

Đề tài: Đổi giá trị 2 biến không dùng biến trung gian

  1. #1
    Ngày gia nhập
    01 2007
    Nơi ở
    Hải Phòng
    Bài viết
    210

    Mặc định Đổi giá trị 2 biến không dùng biến trung gian

    Mình biết được một thủ thuật đổi giá trị 2 biến mà không dùng biến trung gian như sau :
    Code:
    int a,b;
    
    a=a+b;
    b=a-b;
    a=a-b;
    Mình thấy mọi người bảo là cách này gây tràn bộ nhớ nếu như a, b lớn, và không nên dùng cách này. Qua kiểm chứng thì mình thấy cách làm trên luôn đưa ra kết quả chính xác. Vậy nhận xét của mọi người là sai và vẫn cứ sử dụng cách này phải không ?
    pEnGwINUS.

  2. #2
    Ngày gia nhập
    09 2006
    Nơi ở
    /usr/share/.hack@
    Bài viết
    1,433

    a = 99999999999999999999999
    b = 9999999999999999999999999999999999999

    Kiểu int.
    Test là biết thế nào là buffer overflow ^^

    Thưa anh, a và b mà anh đưa ra đã vượt quá giới hạn biến int rồi. (Posted by huynguyen)
    None!

  3. #3
    Ngày gia nhập
    06 2007
    Nơi ở
    Hà nội
    Bài viết
    77

    chắc chắn nếu a,b lớn sẽ tràn bộ nhớ rồi(vì có xử dùng phép cộng 2 số cùng kiểu),nhận xét đó ko có gì là sai,bạn cứ thử cho giá trị của a,b gần đến giớ hạn của kiểu int xem hoặc tổng (a+b) vượt ra giới hạn của kiểu int,sẽ xảy ra lỗi ngay
    tôi thì vẫn dùng biến trung gian để gán giá trị giữa các biến,vừa rõ ràng vừa đảm bảo ko xảy ra lỗi
    Sống ở trên đời cần có một TẤM LÒNG để lúc đói còn có chỗ mà nhét THỨC ĂN

  4. #4
    Ngày gia nhập
    10 2007
    Nơi ở
    HCMUNS
    Bài viết
    459

    Yeah, cách này thì thế nào hả mọi người :

    Code:
    void Swap(int &a, int &b)
    {
              a ^= b ^= a ^= b;
    }
    Keep moving forward!

    ... Retired ...

  5. #5
    Ngày gia nhập
    07 2006
    Nơi ở
    Hanoi, Vietnam
    Bài viết
    2,750

    Code:
    void Swap(int &a, int &b)
    {
              a ^= b ^= a ^= b;
    }
    Cái này sử dụng toán tử ^ (XOR) để đổi giá trị 2 biến. Khá hay! Dr nghĩ nên áp dụng cách này hoặc cách dùng biến temp thì hơn.
    Email: admin[@]congdongcviet.com | CC to: info[@]congdongcviet.com
    Phone: 0972 89 7667 (Office: 04 6329 2380)
    Yahoo & Skype: dreaminess_world (Vui lòng chỉ rõ mục đích ngay khi liên hệ, cảm ơn!)

    Một người nào đó coi thường ý thức kỷ luật cũng có nghĩa là người đó đã coi thường tương lai số phận của chính bản thân người đó. Những người coi thường ý thức kỷ luật sẽ không bao giờ có được sự thành công trong sự nghiệp!

  6. #6
    Ngày gia nhập
    01 2007
    Nơi ở
    Hải Phòng
    Bài viết
    210

    Mặc định Đổi giá trị 2 biến không dùng biến trung gian

    a = 99999999999999999999999
    b = 9999999999999999999999999999999999999

    Kiểu int.
    Test là biết thế nào là buffer overflow ^^
    Ông Pete này ăn nói..."ngầu" quá há. Thử hỏi ông làm cách gì để mà đổi chỗ 2 biến kiểu int này cơ chứ. Vốn 2 số đã tràn rồi, thì có đổi đàng trời. Ý của tui là 2 biến tuy lớn nhưng chưa tràn kiểu ( ví dụ 32000 và 20000 ấy cơ ( với sizeof(int) = 2 ) )

    chắc chắn nếu a,b lớn sẽ tràn bộ nhớ rồi(vì có xử dùng phép cộng 2 số cùng kiểu),nhận xét đó ko có gì là sai,bạn cứ thử cho giá trị của a,b gần đến giớ hạn của kiểu int xem hoặc tổng (a+b) vượt ra giới hạn của kiểu int,sẽ xảy ra lỗi ngay
    tôi thì vẫn dùng biến trung gian để gán giá trị giữa các biến,vừa rõ ràng vừa đảm bảo ko xảy ra lỗi
    Tất nhiên là mình thử với các số gần với giới hạn kiểu int rồi. Và tất nhiên là nó có tràn. Nhưng các bạn có biết nó tràn thế nào không ?

    Giả sử trường hợp max int là 32767, mình có biến là x = 32767, nếu mình dùng phép x=x+1, lúc này x == -32768. Nếu mình cho x=x-1 thì x == 32767. Các bạn có thể tạm hiểu là nó tràn theo kiểu vòng tròn, chính vì vậy mà dù phép cộng có gây tràn đi nhưng phép trừ b=a-b vẫn cho ra kết quả mong muốn.

    Yeah, cách này thì thế nào hả mọi người :
    Code:
    void Swap(int &a, int &b)
    {
              a ^= b ^= a ^= b;
    }
    Cảm ơn bạn ! Mình cũng biết cách này rồi. Nhưng ở đây mình muốn nói rằng việc hoán đổi số lớn theo phép cộng không hề xảy ra lỗi như mọi người vẫn thường nghĩ.

    Mình nghĩ đây là một vấn đề hay. Hóa ra việc hoán đổi số lớn bị tràn số mà mọi người e ngại trước đây đều không đúng. Các bạn không tin thì cứ thử xem, qua nó có thể giúp các bạn hiểu về việc tràn số hơn.
    pEnGwINUS.

  7. #7
    Ngày gia nhập
    06 2007
    Nơi ở
    Hà nội
    Bài viết
    77

    chính vì vậy mà dù phép cộng có gây tràn đi nhưng phép trừ b=a-b vẫn cho ra kết quả mong muốn.
    tôi ko hiểu ý này,nếu phép cộng đã sinh lỗi thì thủ tục bị dừng lại ngay,làm sao mà nó thực hiện tiếp được phép trừ phía dưới,hơn nữa trong 1 đoạn lệnh mà bạn ko khống chế được lỗi phát sinh thì tốt nhất là đừng dùng đoạn lệnh đó,tại sao cứ phải dùng cách phức tạp mà ko dùng những cách đơn giản và an toàn
    Sống ở trên đời cần có một TẤM LÒNG để lúc đói còn có chỗ mà nhét THỨC ĂN

  8. #8
    Ngày gia nhập
    10 2007
    Nơi ở
    HCMUNS
    Bài viết
    459

    Mình thì không thích tất cả các cách này. Nên code theo dạng biến temp để ko phụ thuộc kiểu dữ liệu:

    C++ Code:
    1.         public static void Swap<T> (ref T x, ref T y)
    2.         {
    3.             T temp = x;
    4.             x = y;
    5.             y = temp;
    6.         }
    Keep moving forward!

    ... Retired ...

  9. #9
    Ngày gia nhập
    07 2006
    Nơi ở
    Hanoi, Vietnam
    Bài viết
    2,750

    2 cách dùng sau đây:

    a ^= b ^= a ^= b;

    a=a+b; b=a-b; a=a-b;

    Có sự tương đồng với nhau.
    Có ai vạch ra được sự tương đồng trong 2 cách này không?
    Sự khác nhau giữa 2 cách trên là chỗ nào?
    Trong 2 cách trên, theo bạn nên dùng cách nào?
    Giải thích những câu trả lời của bạn?
    (Loại trừ TQN và rongchaua vì Dr đoán là 2 người này biết khá rõ vấn đề này)
    Email: admin[@]congdongcviet.com | CC to: info[@]congdongcviet.com
    Phone: 0972 89 7667 (Office: 04 6329 2380)
    Yahoo & Skype: dreaminess_world (Vui lòng chỉ rõ mục đích ngay khi liên hệ, cảm ơn!)

    Một người nào đó coi thường ý thức kỷ luật cũng có nghĩa là người đó đã coi thường tương lai số phận của chính bản thân người đó. Những người coi thường ý thức kỷ luật sẽ không bao giờ có được sự thành công trong sự nghiệp!

  10. #10
    Ngày gia nhập
    11 2006
    Bài viết
    633

    tôi ko hiểu ý này,nếu phép cộng đã sinh lỗi thì thủ tục bị dừng lại ngay,
    Tràn số ko phải là lỗi nhé, nó sẽ bị xoay vòng số.
    Ko tin cứ test thử đoạn code dưới đây:
    C++ Code:
    1. #include<iostream>
    2. using namespace std;                
    3. int main()
    4. {
    5.     int i = 2147483647;
    6.     ++i;
    7.     cout <<i <<endl;
    8.     system("pause");
    9.     return 0;
    10. }
    Trên môi trường Win kiểu int là 4 bit nên max là 2147483647, bảo đảm nó xuất ra số -2147483648.
    tại sao cứ phải dùng cách phức tạp mà ko dùng những cách đơn giản và an toàn
    Suốt đời cứ đơn giản và an toàn thì giống con ếch ngồi đáy giếng
    Nói như bạn thì công nghệ máy tính ko thể nào phát triển nổi vì ko suy nghĩ ra những thứ phức tạp thì làm sao có thể làm gọn nhẹ chương trình được.

    a ^= b ^= a ^= b;

    và a=a+b; b=a-b; a=a-b;
    Viết như trên nhiều bạn sẽ khó hiểu, viết lại thế này cho dễ hiểu nhé:
    Code:
    a = a ^ b; 
    b = b ^ a; 
    a = a ^ b;
    Bây giờ ta tạm thời chuyển sang học toán 1 chút về phép xor nhé:
    trên mỗi cặp bit tương ứng nhau của hai toán hạng, toán tử XOR sẽ trả về 1 nếu chỉ có một trong hai bit là 1 (và bit còn lại là 0), ngược lại, XOR trả về bit 0. Ví dụ:
    Code:
        0101
    XOR 0011
    ---------
        0110
    Đặt a = 0101, b = 0011
    a = a ^ b = 0110
    Lúc này a = 0110, b = 0011
    b = b ^ a = 0101 = a
    Lúc này a = 0110, b = 0101
    a = a ^ b = 0011 = b
    Xét về phép xử lý bằng thuật toán cộng trừ:
    Code:
    a=a+b; 
    b=a-b; 
    a=a-b;
    Cho a = 5, b = 3
    a = a + b = 8
    Lúc này a = 8, b = 3
    b = a - b = 5 = a
    Lúc này a = 8, b = 5
    a = a - b = 3 = b
    Trên phép tính số thập phân thì kết quả của phép tính cộng a và b khi trừ ngược lại cho a thì ra b, trừ ngược lại cho b thì ra a.
    Trên phép tính số nhị phân thì kết quả của phép xor a và b khi xor ngược lại cho a thì ra b và xor ngược lại cho b thì ra a.
    Dùng phép xor lợi thế hơn nhiều vì CPU xử lý nhanh hơn.
    Và tôi bảo đảm với các bạn rằng dùng thuật toán cộng trừ ko bao giờ sai cho dù tổng của nó bị vượt quá giới hạn. Bạn hãy thử chạy đoạn code dưới đây sẽ thấy rõ ràng:
    C++ Code:
    1. #include<iostream>
    2. using namespace std;                
    3. int main()
    4. {
    5.     int a = 2000000000;
    6.     int b = 147483650;
    7.     a += b;
    8.     b = a - b;
    9.     a -= b;
    10.     cout <<a <<endl <<b <<endl;
    11.     a ^= b;
    12.     b ^= a;
    13.     a ^= b;
    14.     cout <<a <<endl <<b <<endl;
    15.     system("pause");
    16.     return 0;
    17. }
    Để chứng minh điều này tôi giả sử ta có kiểu dữ liệu rất nhỏ với các giá trị đi từ -64 đến 63 (rất nhỏ để các bạn dễ nhẩm)
    Ta cho 2 số 50 và 40 hoán vị với nhau, tổng của 2 số này là 90 nhưng do kiểu dữ liệu của ta quá nhỏ nên nó sẽ bị xoay vòng.
    90 - 63 = 27 (tự chứng minh )
    -64 + 26 = -38 (cộng 27 là sai nhé, tự chứng minh nốt )
    Như vậy a = a + b = -38
    Bây giờ b = a - b = -38 - 40 = -78 (lại vượt quá giới hạn)
    -78 - (-64) = -14
    63 - 13 = 50 (ặc ặc ) (-(-14) là sai, -(-13) cũng sai)
    Bây giờ a = a - b = -38 - 50 = -88 (quá rồi)
    -88 - (-64) = -24
    63 - 23 = 40 (ô là la)
    Vì các kiểu dữ liệu số nguyên trong máy tính là bội số của kiểu dũ liệu mà ta chứng minh cho nên bài toán này đúng với mọi kiểu dữ liệu là số nguyên trong máy tính.
    Ta đã chứng minh thuật toán cộng trừ để hoán vị 2 biến là đúng bất chấp tổng 2 số vượt quá giới hạn của kiểu dữ liệu.
    Đã được chỉnh sửa lần cuối bởi huynguyen : 28-10-2007 lúc 03:48 AM.

Các đề tài tương tự

  1. Cách xác định ngày hết bảo hành biết ngày mua và thời gian bảo hành?
    Gửi bởi davidhuynhvan trong diễn đàn Thắc mắc lập trình C#
    Trả lời: 2
    Bài viết cuối: 11-07-2013, 11:26 AM
  2. Trả lời: 0
    Bài viết cuối: 04-11-2011, 03:38 PM
  3. Lập trình C Nếu muốn biết thời gian chạy của một chương trình trong c thì phải làm thế nào?
    Gửi bởi nguyenphuongcntv trong diễn đàn Nhập môn lập trình C/C++
    Trả lời: 1
    Bài viết cuối: 16-10-2011, 09:58 PM
  4. Dùng biến để biết hàng thứ mấy trong mảng
    Gửi bởi KFC trong diễn đàn Thắc mắc lập trình C/C++/C++0x
    Trả lời: 1
    Bài viết cuối: 21-05-2008, 05:31 PM

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn