2012-10-16 13 views
5

Jestem świadomy błędów, które mogą wystąpić podczas wykonywania konwersji liczb zmiennoprzecinkowych i liczb całkowitych, ale co z wydajnością (proszę pomijać problemy z dokładnością)?Konwersje i liczba zmiennoprzecinkowa

wydajność całego ogólnie cierpią jeśli do działania N-ary na operandach różnych typów arytmetycznych, czyli na różnych pływających rodzajów punktów (np float i double) i zmiennej połączenia typu punkt/liczba całkowita (np float i int)? Czy istnieją zasady, takie jak, aby wszystkie operandy były tego samego typu?

P.S .: Pytam, ponieważ piszę bibliotekę szablonów ekspresji i chciałbym wiedzieć, czy dopuszczać operacje binarne na wektorach zawierających wartości różnych typów arytmetycznych.

+1

Tak, istnieją koszty konwersji między różnymi typami. Mogę dać dogłębną odpowiedź, jeśli nikt nie zrobi, zanim wrócę z mojej śródokresu. – Mysticial

+0

Ponieważ operacje zmiennoprzecinkowe nie są trywialne w kategoriach arytmetyki base-2, kompilatory często emitują funkcje pomocnicze (zobacz, dlaczego potrzebne jest użycie libgcc?) I które mogą poważnie wpłynąć na wydajność. –

+0

Chodzi o to, że twój program wykonuje ** nie ** i wykonuje operacje na operandach różnych typów. Promuje argumenty według np. C99's 6.3.1.8 Zwykłe konwersje arytmetyczne, a następnie odbywa się operacja n-ary, zwykle z argumentami tego samego typu (jest kilka wyjątków, ale żaden nie dotyczy typów zmiennoprzecinkowych). –

Odpowiedz

5

Podejrzewam, że odpowiedź na to pytanie będzie różnić się w zależności od architektury docelowej, ponieważ konwersje mogą (ale nie muszą) wystąpić w sprzęcie. Na przykład, rozważmy następujący kod, który powoduje pewne wzajemne przekształcenia między int i float:

int main (int argc, char** argv) 
{ 
    int precoarced = 35; 
    // precoarced gets forced to float 
    float result = 0.5 + precoarced; 

    // and now we force it back to int 
    return (int)result; 

    // I wonder what the disassembly looks like in different environments? 
} 

Kiedy próbowałem skompilować to z g ++ (jestem na Ubuntu, x86) z ustawieniami domyślnymi i używane gdb rozbierać :

0x00000000004004b4 <+0>: push %rbp 
    0x00000000004004b5 <+1>: mov %rsp,%rbp 
    0x00000000004004b8 <+4>: mov %edi,-0x14(%rbp) 
    0x00000000004004bb <+7>: mov %rsi,-0x20(%rbp) 
    0x00000000004004bf <+11>: movl $0x23,-0x8(%rbp) 
    0x00000000004004c6 <+18>: cvtsi2sdl -0x8(%rbp),%xmm0 
    0x00000000004004cb <+23>: movsd 0x10d(%rip),%xmm1  # 0x4005e0 
    0x00000000004004d3 <+31>: addsd %xmm1,%xmm0 
    0x00000000004004d7 <+35>: unpcklpd %xmm0,%xmm0 
    0x00000000004004db <+39>: cvtpd2ps %xmm0,%xmm0 
    0x00000000004004df <+43>: movss %xmm0,-0x4(%rbp) 
    0x00000000004004e4 <+48>: movss -0x4(%rbp),%xmm0 
    0x00000000004004e9 <+53>: cvttss2si %xmm0,%eax 
    0x00000000004004ed <+57>: pop %rbp 
    0x00000000004004ee <+58>: retq 

Uwaga instrukcje z CVT-prefiksem mnemoników. Są to instrukcje konwersji. Tak więc w tym przypadku konwersja odbywa się w sprzęcie za pomocą kilku instrukcji. Tak więc, w zależności od tego, ile cykli kosztują te instrukcje, może być dość szybki. Ale znowu, inna architektura (lub inny kompilator) może zmienić historię.

Edycja: W zabawnej notatce bocznej istnieje dodatkowa konwersja dzięki temu, że przypadkowo podałem 0.5 zamiast 0.5f. Właśnie dlatego jest tam cvtpd2ps op.

Edycja: x86 ma wsparcie FP przez długi czas (od lat 80.), więc kompilatory C++ kierujące się do x86 będą na ogół korzystały ze sprzętu (chyba że kompilator jest poważnie za czasami). Dzięki Hot Licks za wskazanie tego.

+0

kompilator mógł być na tyle sprytny, że wykonał konwersję w czasie kompilacji, ale nie było to ... – user1095108

+0

@ user1095108 Rzeczywiście. Nie za bardzo mnie to jednak dziwi; Byłem w ustawieniach domyślnych, dla jednego. Posiadanie takiego float nie jest typowym "praktycznym" przypadkiem użycia. Również twórcy kompilatorów prawdopodobnie boją się wszelkich optymalizacji związanych z float, ponieważ muszą być * bardzo * ostrożni. Na przykład możesz pomyśleć, że komutacja dodawania (A + B = B + A) byłaby ważną podstawą dla optymalizacji dodatków typu "float", ale z powodu niedokładności fp nie jest; może potwornie złamać precyzję niektórych algorytmów FP. – WeirdlyCheezy

+0

Należy zauważyć, że instrukcje konwersji były tam, w takiej czy innej formie, od oryginalnego koprocesora 8087. Dlatego praktycznie wszystkie systemy ze zmiennoprzecinkowym sprzętem będą miały konwersję sprzętową. –

2

Na większości komputerów konwersje między formatami float i int są dość szybkie, wspomagane przez funkcje sprzętu zmiennoprzecinkowego.

Należy jednak, oczywiście, podjąć pewne wysiłki w celu wyrażenia literałów w "poprawnym" formacie, choćby w celach dokumentacyjnych. I nie zaszkodzi również używać jawnych rzutów, do dokumentacji.

2

Zazwyczaj są pewne kary za wyniki, choć nieistotne w porównaniu do innych rzeczy. Jest to spowodowane migracją danych pomiędzy rejestrami całkowitymi i zmiennoprzecinkowymi oraz innymi możliwymi problemami ABI.

Odpowiedź na takie pytania jest zawsze taka sama. Wątpliwości? Benchmark to. Wydajność nie jest teoretycznie przewidywalna.

+2

nie zapomnij, że zapytałem o zasady. Znam regułę bench. – user1095108

Powiązane problemy