Tìm hai số nguyên lớn nhất trong năm số nguyên càng nhanh càng tốt


9

Tôi sử dụng một biến thể của bộ lọc trung bình 5 chữ thập trên dữ liệu hình ảnh trên một hệ thống nhúng nhỏ, tức là

    x
  x x x
    x

Thuật toán thực sự đơn giản: đọc 5 giá trị nguyên không dấu, lấy 2 giá trị cao nhất, thực hiện một số phép tính trên các giá trị đó và ghi lại kết quả số nguyên không dấu.

Điều tuyệt vời là 5 giá trị đầu vào số nguyên đều nằm trong phạm vi 0-20. Giá trị nguyên được tính cũng nằm trong phạm vi 0-20!

Thông qua hồ sơ, tôi đã nhận ra rằng việc có được hai số lớn nhất là nút cổ chai nên tôi muốn tăng tốc phần này lên. Cách nhanh nhất để thực hiện lựa chọn này là gì?

Thuật toán hiện tại sử dụng mặt nạ 32 bit với 1 ở vị trí được cho bởi 5 số và hàm CLZ được CTNH hỗ trợ.
Tôi nên nói rằng CPU là độc quyền, không có sẵn bên ngoài công ty của tôi. Trình biên dịch của tôi là GCC nhưng được thiết kế riêng cho CPU này.

Tôi đã cố gắng tìm hiểu xem tôi có thể sử dụng bảng tra cứu hay không nhưng tôi đã thất bại trong việc tạo khóa mà tôi có thể sử dụng.

Tôi có kết hợp cho đầu vào nhưng thứ tự không quan trọng, nghĩa là giống như .215[5,0,0,0,5][5,5,0,0,0]

Nó xảy ra rằng hàm băm dưới đây tạo ra một hàm băm hoàn hảo mà không bị va chạm!

def hash(x):
    h = 0
    for i in x:
        h = 33*h+i
    return h

Nhưng hàm băm là rất lớn và đơn giản là không đủ bộ nhớ để sử dụng.

Có một thuật toán tốt hơn mà tôi có thể sử dụng? Có thể giải quyết vấn đề của tôi bằng cách sử dụng bảng tra cứu và tạo khóa không?


1
Bạn đang sử dụng thuật toán nào? Bảy so sánh số nguyên là đủ, điều đó có quá chậm không? Bạn hashđã thực hiện nhiều hoạt động hơn. Các cuộc gọi tiếp theo đến phương thức có liên quan không, ví dụ: trung tâm có xdi chuyển qua ma trận từng hàng không?
Raphael

Bộ lọc được tích hợp thông qua hàng hình ảnh theo hàng. Tức là lấy 5 giá trị và thực hiện các phép tính sau đó di chuyển mọi thứ một bước sang phải và lặp lại. Băm chỉ là một ví dụ. Tôi đã điểm chuẩn một số giải pháp cửa sổ trượt để giảm thiểu việc đọc dữ liệu nhưng tất cả đều tìm ra 2 giá trị cao nhất.
Fredrik Pihl

3
Rất có thể thuật toán của bạn, nếu được triển khai đúng cách, sẽ bị giới hạn bởi truy cập bộ nhớ chứ không phải bởi tính toán. Sử dụng hashtable sẽ chỉ làm tăng lượng truy cập bộ nhớ và làm chậm mọi thứ. Vui lòng gửi mã hiện tại của bạn để chúng tôi có thể thấy nó có thể được cải thiện như thế nào - tôi tin rằng chỉ có thể tối ưu hóa vi mô. Điều tôi có thể nghĩ nhiều nhất là: có lẽ chúng ta có thể tận dụng thực tế là 2 giá trị chung giữa các cửa sổ lân cận?
jkff

@jkff Tùy thuộc vào ma trận, kích thước bộ đệm và chức năng ánh xạ (bộ đệm), mọi giá trị có thể chỉ phải được tải một lần; Hầu hết các hoạt động nên chạy trên thanh ghi hoặc bộ đệm L1. Đường ống là một vấn đề khác, mặc dù.
Raphael

1
Nhân tiện, bạn đã làm điều này song song chưa? Điều này có vẻ đặc biệt phù hợp với song song hóa vector hoặc SIMD (ví dụ trên GPU). Tuyến đường đó sẽ giúp nhiều hơn là tiết kiệm một vài phần trăm cho mỗi tế bào.
Raphael

Câu trả lời:


11

Trong câu trả lời khác của tôi, tôi đề nghị rằng các bước nhảy có điều kiện có thể là trở ngại chính cho hiệu quả. Kết quả là, các mạng sắp xếp xuất hiện trong tâm trí: chúng là bất khả tri về dữ liệu, đó là cùng một chuỗi so sánh được thực hiện bất kể đầu vào, chỉ có các giao dịch hoán đổi là có điều kiện.

U^2(5)=6

Mạng mà anh ta đưa ra trong các giải pháp (được viết lại thành các mảng dựa trên zero) là

[0:4][1:4][0:3][1:3][0:2][1:2]

trong đó thực hiện - sau khi điều chỉnh hướng so sánh - trong mã giả như

def selMax2(a : int[])
  a.swap(0,4) if a[0] < a[4]
  a.swap(1,4) if a[1] < a[4]
  a.swap(0,3) if a[0] < a[3]
  a.swap(1,3) if a[1] < a[3]
  a.swap(0,2) if a[0] < a[2]
  a.swap(1,2) if a[1] < a[2]
  return (a[0], a[1])
end

Bây giờ, các triển khai ngây thơ vẫn có các bước nhảy có điều kiện (qua mã hoán đổi). Tuy nhiên, tùy thuộc vào máy của bạn, bạn có thể xác nhận chúng bằng các hướng dẫn có điều kiện. x86 dường như là bản thân bùn thông thường của nó; ARM có vẻ hứa hẹn hơn vì rõ ràng hầu hết các hoạt động đều có điều kiện . Nếu tôi hiểu các hướng dẫn chính xác, trao đổi đầu tiên sẽ chuyển sang điều này, giả sử các giá trị mảng của chúng tôi đã được tải vào các thanh ghi R0thông qua R4:

CMP     R0,R4
MOVLT   R5 = R0
MOVLT   R0 = R4
MOVLT   R4 = R6

Vâng, vâng, tất nhiên bạn có thể sử dụng trao đổi XOR với EOR .

Tôi chỉ hy vọng bộ xử lý của bạn có cái này, hoặc một cái gì đó tương tự. Tất nhiên, nếu bạn xây dựng thứ cho mục đích này, có lẽ bạn có thể có được mạng cứng trên mạng không?

Đây có lẽ là (có thể?) Là điều tốt nhất bạn có thể làm trong vương quốc cổ điển, tức là không sử dụng miền giới hạn và thực hiện các phép thuật nội từ độc ác.


  1. Sắp xếp và tìm kiếm bởi Donald E. Knuth; Nghệ thuật lập trình máy tính Vol. 3 (tái bản lần 2, 1998)
  2. W^2(5)=7

Tôi chấp nhận điều này. Tôi đã nhận được rất nhiều ý tưởng mới mà tôi cần phải điểm chuẩn trước khi tiếp tục. Nhắc đến Knuth luôn làm việc cho tôi :-) Cảm ơn nỗ lực và thời gian của bạn!
Fredrik Pihl

@FredrikPihl Thật tuyệt, xin vui lòng cho chúng tôi biết cuối cùng nó diễn ra như thế nào!
Raphael

Tôi sẽ! Đọc Chương 5.3.3 ngay bây giờ. Yêu sự khởi đầu của nó với các tham chiếu đến Lewis Carroll và giải đấu quần vợt :-)
Fredrik Pihl

2
Tùy thuộc vào tập lệnh, sử dụng 2 * max (a, b) = a + b + abs (ab) cùng với mạng lựa chọn có thể hữu ích; nó có thể ít tốn kém hơn so với các bước nhảy có điều kiện không dự đoán được (ngay cả khi không có động thái nội tại hoặc có điều kiện cho abs: gcc, ít nhất là đối với x86, tạo ra một chuỗi không lộn xộn dường như không phụ thuộc vào x86). Có một chuỗi không lộn xộn cũng hữu ích khi kết hợp với SIMD hoặc GPU.
AProgrammer 27/2/2015

4

Chỉ để nó trên bàn, đây là một thuật toán trực tiếp:

// Sort x1, x2
if x1 < x2
  M1 = x2
  m1 = x1
else
  M1 = x1
  m1 = x2
end

// Sort x3, x4
if x3 < x4
  M2 = x4
  m2 = x3
else
  M2 = x3
  m2 = x4
end

// Pick largest two
if M1 > M2
  M3 = M1
  if m1 > M2
    m3 = m1
  else
    m3 = M2
  end
else
  M3 = M2
  if m2 > M1
    m3 = m2
  else
    m3 = M1
  end
end

// Insert x4
if x4 > M3
  m3 = M3
  M3 = x4
else if x4 > m3
  m3 = x4
end

Bằng cách thực hiện thông minh if ... else, người ta có thể thoát khỏi một số bước nhảy vô điều kiện mà một bản dịch trực tiếp sẽ có.

Điều này là xấu nhưng chỉ mất

  • năm hoặc sáu so sánh (tức là nhảy có điều kiện),
  • chín đến mười bài tập (với 11 biến, tất cả trong sổ đăng ký) và
  • không có quyền truy cập bộ nhớ bổ sung.

W2(5)

Điều này không thể được dự kiến ​​là nhanh trên các máy có đường ống, mặc dù; với tỷ lệ cao của các bước nhảy có điều kiện, phần lớn thời gian có thể sẽ được sử dụng trong gian hàng.

Lưu ý rằng một biến thể đơn giản hơn - sắp xếp x1x2sau đó chèn các giá trị khác sau đó - mất bốn đến bảy so sánh và chỉ năm đến sáu bài tập. Vì tôi hy vọng các bước nhảy sẽ có chi phí cao hơn ở đây, tôi đã mắc kẹt với điều này.


  1. Sắp xếp và tìm kiếm bởi Donald E. Knuth; Nghệ thuật lập trình máy tính Vol. 3 (tái bản lần 2, 1998)

Tôi tự hỏi những gì một trình biên dịch tối ưu hóa có thể làm với những điều này.
Raphael

Tôi sẽ thực hiện điều này và đánh giá nó dựa trên giải pháp dựa trên CLZ hiện tại. Cảm ơn vì đã dành thời gian cho tôi!
Fredrik Pihl

1
@FredrikPihl Kết quả của điểm chuẩn của bạn là gì?
Raphael

1
Phương pháp tiếp cận dựa trên SWAP đánh bại CLZ! Trên di động bây giờ. Có thể đăng thêm dữ liệu vào lúc khác, trên điện thoại di động ngay bây giờ
Fredrik Pihl

@FredrikPihl Tuyệt! Tôi rất vui vì cách tiếp cận lý thuyết cũ tốt có thể (vẫn) được sử dụng thực tế. :)
Raphael

4

Đây có thể là một ứng dụng và trường hợp thử nghiệm tuyệt vời cho dự án Souper . Souper là một superoptimizer - một công cụ lấy một chuỗi mã ngắn làm đầu vào và cố gắng tối ưu hóa nó càng nhiều càng tốt (cố gắng tìm một chuỗi mã tương đương sẽ nhanh hơn).

Souper là nguồn mở. Bạn có thể thử chạy Souper trên đoạn mã của mình để xem liệu nó có thể làm tốt hơn không.

Xem thêm cuộc thi của John Regehr về cách viết mã nhanh để sắp xếp 16 giá trị 4 bit ; có thể một số kỹ thuật có thể hữu ích.


Tôi quan tâm đến những gì điều này có thể làm trên các chương trình mà OP đang cố gắng.
Raphael

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.