2010-08-24 45 views
5

Có cách nào so sánh hai khối bộ nhớ và biết tại thời điểm nào chúng khác nhau (memcmp() không đáp ứng yêu cầu này)? Tôi sẽ không muốn thực hiện các vòng tốn kém. Cảm ơn trước.So sánh bộ nhớ (với vị trí khác biệt)

Kính trọng, Neo_b

+0

xem thêm http://stackoverflow.com/questions/855895/intrinsic-memcmp về triển khai memcmp tối ưu hóa cho mỗi CPU. Nếu bạn biết CPU, bạn có thể điều chỉnh một trong các hàm __builtin_memcmp() của gcc theo nhu cầu của bạn. – mvds

+1

Lưu ý rằng bất cứ điều gì bạn có ở đây sẽ được thực hiện như là một vòng lặp * một nơi nào đó * - không có cách kỳ diệu để làm những gì bạn muốn ở đây mà không có một. –

Trả lời

2

So với bất cứ điều gì khác mà bạn đang làm, một vòng khá rẻ: với chi phí lớn sẽ được lấy dữ liệu từ ram ở nơi đầu tiên (hoặc đĩa!).

2

Bạn không thể tránh lặp với bộ nhớ so sánh hơn một vài byte. Viết các thuật toán như bạn có thể tưởng tượng nó. Nó đủ đơn giản và bạn có thể ngạc nhiên khi trình biên dịch tối ưu hóa mã như thế này.

4

std::mismatch sẽ làm điều đó cho bạn cùng với std::distance.

+0

Bạn cho rằng anh ta đang sử dụng trình lặp STL, và hơn thế nữa anh ta cần phải biết bộ nhớ điểm nào khác. – Doomsday

+0

Tôi đã std :: bằng đầu tiên mà rõ ràng là sai vì vậy tôi đã sửa chữa nó. Thuật toán hoạt động rất tốt với các con trỏ cũng như với các trình vòng lặp (toàn diện). –

+3

@Doomsday: 'char *' * là * một loại trình lặp, và 'mismatch' trả về hai trình vòng lặp trỏ đến sự khác biệt. +1 – Potatoswatter

1

memcmp đơn giản thực hiện "vòng lặp tốn kém", byte cho byte. Ví dụ: đây là triển khai của Microsoft:

EXTERN_C int __cdecl memcmp(const void *Ptr1, const void *Ptr2, size_t Count) 
{ 
    INT v = 0; 
    BYTE *p1 = (BYTE *)Ptr1; 
    BYTE *p2 = (BYTE *)Ptr2; 

    while(Count-- > 0 && v == 0) { 
     v = *(p1++) - *(p2++); 
    } 

    return v; 
} 

Hầu hết các triển khai khác cũng thực hiện tương tự. Đối với nhu cầu của bạn, bạn có thể làm một cái gì đó như thế này:

long my_memcmp(const void *Ptr1, const void *Ptr2, size_t Count) 
{ 
    INT v = 0; 
    long pos = 0; 
    BYTE *p1 = (BYTE *)Ptr1; 
    BYTE *p2 = (BYTE *)Ptr2; 

    while(Count-- > 0 && v == 0) 
    { 
     v = *(p1++) - *(p2++); 
     if (v == 0) 
      pos++; 
     else 
      break; 
    } 

    return pos; 
} 
+0

byte-mỗi-byte thực sự là tốn kém. Các hoạt động 'int' 32 bit thậm chí có thể nhanh hơn các đối tác 8 bit của chúng. – mvds

+0

Tôi đã tạo bản triển khai của riêng mình (tôi nghĩ mình có thể thay thế nó bằng một thứ gì đó khác). Nhu cầu của tôi yêu cầu lên tới 10 000 000 lần lặp. Hệ thống đóng băng đôi khi, nhưng nó hoạt động. Nó cũng cho biết có bao nhiêu byte không phù hợp sau lần xuất hiện không khớp đầu tiên. –

+0

@Neo_b: 10 triệu lần lặp lại không nhiều - hầu hết mọi hệ thống sẽ thực hiện điều đó trong một phần tư giây trở xuống. Tôi sẽ xem xét sơ đồ đệm đầu vào của bạn hoặc xem xét lại cách bạn đang tấn công vấn đề này. Nếu bạn đang tìm kiếm các chuỗi, ví dụ, thuật toán Boyer Moore có thể sẽ làm bạn tốt hơn bất cứ điều gì ở đây. –

0

Bạn sẽ luôn cần một vòng lặp. Nhưng bạn có thể điểm chuẩn nếu looping bởi 4 byte (cast để int *) hoặc 8 byte (uint64_t hoặc long long int) là nhanh hơn so với các giải pháp ngây thơ mỗi byte.

Thậm chí tốt hơn, tùy thuộc vào độ dài (giả sử,> 1kb) bạn có thể hủy vòng lặp, nghĩa là bạn kiểm tra ví dụ: mỗi 8 int/uint64_t và trên một điểm không phù hợp, xác định byte khác nhau đầu tiên.

uint64_t *bigsteps1 = (uint64_t*)m1; 
uint64_t *bigsteps2 = (uint64_t*)m2; 
int steps = min(m1_len,m2_len)/sizeof(uint64_t); 
int i; 
for (i=0; i<steps; i+=8) 
{ 
    if (bigsteps1[i] != bigsteps2[i] 
     || bigsteps1[i+1] != bigsteps2[i+1] 
    /// .... 
     || bigsteps1[i+7] != bigsteps2[i+7]) break; 
} 

// i<steps tells if we found a difference 
// end game is trivial, left as an excercise to the reader. 

Các tháo vật cuộn tròn lại vòng lặp cũng có thể phản tác dụng, vì bạn có tất cả những điều + N trong đó và i + = 8 là tốt. Điểm chuẩn để chắc chắn.

ps cũng kiểm tra sự liên kết bộ nhớ: đây sẽ là nhanh nhất khi m1&0xff == m2&0xff == 0

+0

Cảm ơn lời khuyên, tôi chắc chắn sẽ thực hiện nó, mặc dù tôi không hoàn toàn chắc chắn những gì m1 & 0xff == m2 & 0xff == 0 là nghĩa vụ phải làm, từ những gì tôi biết m1 & 0xff == m1, không phải là chính xác? –

+0

Điều này sẽ nhanh hơn trong một số trường hợp, nhưng có thể dẫn đến một số vấn đề. Trước hết, nó dựa trên nền tảng của bạn có cùng một liên kết cho các số nguyên 64 bit như đối với các ký tự, thường không phải như vậy. (Không ai nói rằng cơ sở của mảng ký tự phải nằm trên một ranh giới 8 byte) Thứ hai, một nội tại hoặc lắp ráp nội tại có thể sẽ nhanh hơn. Trên x86, vấn đề liên kết bộ nhớ sẽ chỉ làm cho mọi thứ chậm hơn, và trên các kiến ​​trúc khác, nó sẽ làm cho bộ vi xử lý ngắt một ngắt. –

+0

@Neo_b: 'm1 & 0xff == 0' là một phép thử nếu địa chỉ' m1' kết thúc bằng '00'. @ Billy: Tất nhiên trong các loại tối ưu này, bạn phải fiddle một chút với ranh giới, vì vậy cho đến khi khối liên kết đầu tiên bạn kiểm tra chậm, sau đó kiểm tra càng nhiều khối càng tốt, và kiểm tra phần còn lại chậm. (như đã nói những điều này chỉ làm việc tích cực nếu các khối là đủ lớn) Một nội tại hoặc lắp ráp nội tại có thể sẽ nhanh hơn * nếu nó tồn tại * mà tôi nghĩ không phải là trường hợp cho vấn đề ở bàn tay. – mvds

1

Nếu có một cách tốt hơn để so sánh hai khối bộ nhớ, memcmp sẽ được thực hiện lại để làm điều đó.

Đã nói thường xuyên, memcmp có triển khai di động mặc định trong thư viện C chuẩn nhưng thường có trình biên dịch được thực hiện dưới dạng hàm dựng sẵn. Hàm dựng sẵn này nên được tối ưu hóa cao cho kiến ​​trúc đích. Do đó, hãy thực hiện thư viện với một nhúm muối.

Các vấn đề liên quan