Dlaczego std :: zmniejszyć potrzebę przemienności

głosy
5

https://en.cppreference.com/w/cpp/algorithm/reduce

Mówi ona, że ​​zachowanie operacji nie jest określona, ​​jeśli operacja nie jest przemienne, ale dlaczego? Po prostu dzielimy tablicę na bloki, a następnie scalić wynik, jest to konieczne tylko do skojarzeń?

Utwórz 13/02/2020 o 21:51
źródło użytkownik
W innych językach...                            


3 odpowiedzi

głosy
1

Zachowanie jest rzeczywiście niedeterministyczne jeśli operacja między argumentów nie jest przemienne. „non-deterministyczne” to nie to samo co „nieokreślone”. Zmiennoprzecinkowych matematyki nie jest przemienne, np. Jest to jeden z powodów, dlaczego wywołanie std::reducenie może być deterministyczny, ponieważ funkcja binarna jest stosowana w nieokreślonym celu.

Odnoszą się do niniejszej noty w standardzie:

Uwaga: Różnica pomiędzy reducea accumulatejest to, że zmniejsza zastosowanie binary_opw nieokreślonym porządku, co daje w wyniku niedeterministycznych dla nie-asocjatywnym lub nie przemiennego binary_op takie jak zmiennoprzecinkowej dodawania. -End uwaga]

Odpowiedział 13/02/2020 o 22:02
źródło użytkownik

głosy
1

Standard definiuje uogólnić w następujący sposób: suma numeric.defns

Definiowanie GENERALIZED_NONCOMMUTATIVE_SUM (op, a1, ..., an) w następujący sposób:

  • A1, gdy n oznacza 1, inaczej

  • op (GENERALIZED_NONCOMMUTATIVE_SUM (op, a1, ..., ak) op (GENERALIZED_NONCOMMUTATIVE_SUM (op, jestem, ..., an)) dla dowolnego k gdzie 1

Określić GENERALIZED_SUM (PO, A1 ... An), jak GENERALIZED_NONCOMMUTATIVE_SUM (OP, B1 ... Bn), gdzie B1, ..., bn mogą być dowolnego permutacji A1 ... An.

Tak, kolejność sumowania jak również kolejność argumentów jest nieokreślona. Więc jeśli operacja binarna nie jest przemienne lub nie asocjacyjne, wynik jest nieokreślony.

Który jest również wyraźnie zaznaczyć tutaj .

Jeśli chodzi dlaczego: Daje biblioteki producentów większą swobodę, dzięki czemu może lub nie może realizować to lepiej. Jako przykład, gdzie realizacja może korzystać z przemienności. Rozważmy sumę a+b+c+d+e, musimy najpierw obliczyć a+bi c+drównolegle. Teraz a+bpowraca przed c+drobi (co może się zdarzyć, ponieważ odbywa się równolegle). Zamiast czekać na wartości zwracanej c+dmożemy teraz bezpośrednio obliczyć (a+b)+e, a następnie dodać ten wynik do wyniku c+d. Więc w końcu, obliczony ((a+b)+e)+(c+d), który jest przegrupowanie a+b+c+d+e.

Odpowiedział 13/02/2020 o 22:07
źródło użytkownik

głosy
6

std::reducewymaga zarówno asocjatywność i przemienności. Łączność jest to bezwzględnie konieczne dla algorytmu równoległego, ponieważ chcesz wykonać obliczenia na oddzielne porcje, a następnie połączyć je.

Jeśli chodzi o przemienności: Według post reddit przez MSVC STL dewelopera Billy O'Neal, jest to konieczne w celu umożliwienia wektoryzacji instrukcji SIMD:

Przemienność jest również niezbędne, aby umożliwić wektoryzacji, ponieważ kod chcesz do zmniejszenia wyjdzie jak coś takiego:

vecRegister = load_contiguous(first);
while (a vector register sized chunk is left) {
    first += packSize;
    vecRegister = add_packed(load_contiguous(first), vecRegister);
}
// combine vecRegister's packed components

itd., które ze względu typu int i rejestry SSE i a * b * C * D * E * * F G * H zapewnia coś podobnego (a *), e * (b * F) * (g) * C * (d * H ).

Większość innych językach nie robią wyraźne rzeczy, aby umożliwić ich Wektoryzacja redukcja. I nic nie mówi, że nie można dodać noncommutative_reduce czy coś takiego w przyszłości, jeśli ktoś pojawia się z atrakcyjną przypadku użycia.

Odpowiedział 13/02/2020 o 22:13
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more