Fab i porównanie są bardzo szybkie dla IEEE float (na przykład, single-integer-op fast).
Jeśli kompilator nie obsługuje obu operacji, to albo przesuwaj go do tego czasu, albo znajdź implementację dla architektury i wstaw ją samodzielnie.
Możesz być może uzyskać coś z faktu, że pozytywne IEEE pływa w tej samej kolejności, co liczby całkowite z tymi samymi wzorami bitowymi. Oznacza to, że
f > g iff *(int*)&f > *(int*)&g
Więc kiedy już fabs'ed, myślę, że oddział wolne max dla int będzie również pracować dla pływaka (przy założeniu, że są tej samej wielkości, oczywiście). Istnieje wyjaśnienie, dlaczego to działa tutaj: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. Ale twój kompilator już to wszystko zna, podobnie jak twój procesor, więc nie ma to znaczenia.
Nie ma złożoności - szybszy sposób robienia tego. Twój algorytm jest już O (n), i nie możesz tego pokonać i wciąż patrzeć na każdą próbkę.
Domyślam się, że prawdopodobnie jest coś w SIMD twojego procesora (czyli SSE2 na Intel), które pomogłoby, przetwarzając więcej danych na cykl zegara niż twój kod. Ale nie wiem co. Jeśli tak, to prawdopodobnie będzie kilka razy szybciej.
Prawdopodobnie mógłbyś zrównoleglić na wielordzeniowym procesorze, zwłaszcza, że masz do czynienia z 40 niezależnymi strumieniami. To w najlepszym przypadku kilka czynników szybciej. "Wystarczy" wystartować odpowiednią liczbę dodatkowych wątków, podzielić pracę między nimi i użyć najjaśniejszego prymitywu, aby wskazać, kiedy są one kompletne (być może bariera wątku). Nie jestem całkiem pewien, czy wykreślasz maks. 40 strumieni, czy maksimum każdego osobno, więc może nie musisz synchronizować wątków roboczych, poza tym, że wyniki są dostarczane do następnego etapu bez uszkodzenia danych.
Prawdopodobnie warto rzucić okiem na demontaż, aby zobaczyć, ile kompilator rozwinął pętlę. Spróbuj rozwinąć nieco więcej, zobacz, czy to ma znaczenie.
Kolejną kwestią, którą należy przemyśleć, jest liczba braków w pamięci podręcznej, którą można uzyskać, oraz możliwość zmniejszenia liczby pamięci podręcznych dzięki kilku wskazówkom, dzięki czemu można wczytać odpowiednie strony z wyprzedzeniem. Ale nie mam z tym żadnego doświadczenia i nie pokładałabym nadziei. __builtin_prefetch jest magicznym zaklęciem na gcc i myślę, że pierwszym eksperymentem będzie coś w rodzaju "wstępnego pobrania następnego bloku przed wejściem do pętli dla tego bloku".
Jaki procent wymaganej prędkości aktualnie masz? Czy jest to przypadek "tak szybko jak to możliwe"?
Jaki kompilator? Jaka platforma? Jeśli korzystasz z gcc, możesz być zainteresowany takimi rzeczami jak __builtin_expect. –