Proč std :: snížit potřebu vyměnitelnost

hlasů
5

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

To říká, že chování operace není definována, pokud operace není komutativní, ale proč? Právě jsme se rozdělit pole do bloků a pak sloučit výsledek, je to jen nutné asociativní?

Položena 13/02/2020 v 23:51
zdroj uživatelem
V jiných jazycích...                            


3 odpovědí

hlasů
1

Chování je vlastně non-deterministický , pokud operace mezi operandy není komutativní. „non-deterministický“ není totéž jako „nedefinováno“. Plovoucí čárkou není komutativní, například. To je jeden z důvodů, proč volání std::reducenemusí být deterministický, protože binární funkce je použita v nespecifikovaném pořadí.

Odkazovat na tuto poznámku v normě:

Poznámka: Rozdíl mezi reducea accumulateje to, že snižuje se použije binary_opv blíže neurčené pořadí, která poskytuje nedeterministického výsledek pro ne-asociativní nebo nekomutativní binary_op, jako je kromě s pohyblivou řádovou čárkou. -End poznámka]

Odpovězeno 14/02/2020 v 00:02
zdroj uživatelem

hlasů
1

Standard definuje zobecněný součet takto: numeric.defns

Definovat GENERALIZED_NONCOMMUTATIVE_SUM (op, a1, ..., an) takto:

  • a1, když n je 1, v opačném případě

  • op (GENERALIZED_NONCOMMUTATIVE_SUM (OP, a1, ..., ak), op (GENERALIZED_NONCOMMUTATIVE_SUM (OP, aM, ..., an)) pro všechny k, kde 1

Definovat GENERALIZED_SUM (op, a1, ..., an), jak je GENERALIZED_NONCOMMUTATIVE_SUM (OP, B1, ..., Bn), kde B1, ..., Bn mohou být jakékoli permutace a1, ..., an.

Takže pořadí sčítání, jakož i pořadí operandů NS. Takže pokud je binární operace není komutativní nebo ne asociativní, výsledek není specifikován.

Který je také výslovně uvedeno zde .

Pokud jde o důvod, proč: Dává knihovna prodejci větší volnost, takže se mohou, ale nemusí to lépe provádět. Jako příklad, pokud provádění může těžit z commutativity. Vezměme si částku a+b+c+d+e, nejprve spočítat a+ba c+dparalelně. Nyní a+bse vrací před c+ddělá (jak se to může stát, protože je provedeno současně). Namísto čekání na návratovou hodnotu c+dmůžeme nyní přímo vypočítat (a+b)+ea pak přidejte tento výsledek do výsledku c+d. Takže nakonec jsme počítán ((a+b)+e)+(c+d), což je přeskupení a+b+c+d+e.

Odpovězeno 14/02/2020 v 00:07
zdroj uživatelem

hlasů
6

std::reducevyžaduje jak asociativitu a commutativity. Asociativita je to nezbytně nutné pro paralelní algoritmus, protože chcete provést výpočet na samostatné kusy a pak sloučí.

Co se týče commutativity: Podle s Reddit příspěvek od MSVC STL vývojáře Billy O'Neal, je to vyžadováno, aby se umožnilo, aby vektorizaci SIMD instrukcí:

Commutativity je rovněž nezbytné k tomu, vektorizace, protože kód, který chcete pro snížení vyjít něco jako:

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

atd., které vzhledem k ints a SSE registry a * b * c * d * e * f * g * h dává něco jako (a * e) * (b * f) * (c * g) * (d * h ).

Většina ostatních jazyků nedělají explicitní věci, aby se vektorizace jejich redukce je to možné. A nic říká, že nemůžeme přidat noncommutative_reduce nebo něco podobného v budoucnu, pokud někdo přijde s přesvědčivé případu užití.

Odpovězeno 14/02/2020 v 00:13
zdroj uživatelem

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