8

Piszę w czasie rzeczywistym oprogramowanie numeryczne, w C++, obecnie kompilując je z Visual-C++ 2008. Teraz używając "szybkiego" modelu zmiennoprzecinkowego (/fp:fast), różne optymalizacje większość z nich użyteczne moja sprawa, ale konkretnie:Pływające opcje kompilatora C++ | Zapobieganie a/b -> a * (1/b)

a/b -> a*(1/b) Division by multiplicative inverse 

jest zbyt niestabilne numerycznie do-wielu moich obliczeń.

(patrz: Microsoft Visual C++ Floating-Point Optimization)

Przełączanie /fp:precise sprawia, że ​​moja aplikacja uruchomić więcej niż dwa razy powoli. Czy możliwe jest precyzyjne dostrojenie optymalizatora (tj. Wyłączenie tej konkretnej optymalizacji), lub w jakiś sposób ręcznie ominąć go?

- rzeczywisty przykład minimalny Kod: -

void test(float a, float b, float c, 
    float &ret0, float &ret1) { 
    ret0 = b/a; 
    ret1 = c/a; 
} 

[My rzeczywisty kod jest najczęściej związane z macierzą algorytmy]

wyjściowy VC (Cl, wersja 15 0x86) wynosi:

divss  xmm0,xmm1 
mulss  xmm2,xmm0 
mulss  xmm1,xmm0 

Posiadanie jednego diva, zamiast dwóch, jest dużym problemem numerycznym, (xmm0, jest wstępnie załadowany z 1.0f z pamięci RAM), zależnie od wartości xmm1,2 (które mogą być w różnych r anges) możesz stracić dużo precyzji (Kompilacja bez SSE, daje podobny kod stack-x87-FPU).

Owijanie funkcję z

#pragma float_control(precise, on, push) 
... 
#pragma float_control(pop) 

nie rozwiązuje problem dokładności, ale po pierwsze, jest ona dostępna tylko w funkcji poziomu (global-zakres), a po drugie, zapobiega inline funkcji (tj kary prędkości są zbyt wysokie)

„precyzyjny” wyjście jest rzutowane na „podwójne” tam iz powrotem jak-dobrze:

divsd  xmm1,xmm2 
cvtsd2ss xmm1,xmm1 
divsd  xmm1,xmm0 
cvtpd2ps xmm0,xmm1 
+2

Każda zmiennoprzecinkowa matematyka, która opiera się na równości, będzie niestabilna. –

+1

@Hans: OP nie szuka równości; on/ona mówi, że kompilator dokonuje powyższej zmiany jako optymalizacji i że jest to nieprzydatne w jego/jej aplikacji. –

+0

@Oli: wciąż nie wiemy, czy wymagania dokładności OP są osiągalne, czy nie z tego świata. – peterchen

Odpowiedz

0

rozwiązanie (dziwne), które znalazłem: ilekroć dzieląc przez tę samą wartość w funkcji - dodać trochę epsilon:

a/b; c/b 

->

a/(b+esp1); c/(b+esp2) 

oszczędza także z okazjonalnym div przez zero

2

dokument ten stanowi, że można kontrolować Optymalizacje typu "float-pointing" na zasadzie line-by-line za pomocą pragmy.

0

Czy można umieścić funkcje zawierające te obliczenia w oddzielnym pliku kodu źródłowego i skompilować tylko ten plik z różnymi ustawieniami?

Nie wiem, czy to jest bezpieczne, musisz sprawdzić!

3

Dodaj

#pragma float_control(precise, on)

przed obliczeń i

#pragma float_control(precise,off)

po tym. Myślę, że powinno to zrobić.

+0

tak, że to, co obecnie używam: #pragma float_control (precyzyjny, na, naciśnięciem) ... #pragma float_control (POP) niestety, wydaje się działać tylko na poziomie całego funkcji, plus uniemożliwić inline. Dodam komentarz z moimi aktualnymi ustaleniami. To by było naprawdę rockowe, gdyby była lepiej dostrojona opcja optymalizacji float – oyd11

1

Istnieje również __assume. Możesz użyć __assume (a/b! = (A * (1/b))). Nigdy nie używałem __assume, ale teoretycznie istnieje dokładnie, aby dostroić optymalizator.

+0

Dobrze wiedzieć o __assume(), inne kompilatory, których użyłem wcześniej miały podobne opcje (NASSERT w kompilatorach TI), spróbują to jednak , Myślę, że kompilator już przyjmuje (a/b! = (A * (1/b))) – oyd11

Powiązane problemy