2010-08-30 9 views
27
double numbers[ ] = { 1, 0.5 ,0.333333 ,0.25 ,0.2, 0.166667, 0.142857, 0.125, 
         0.111111, 0.1 } ; 
std::vector<double> doublenumbers (numbers , numbers + 10) ; 
std::cout << std::accumulate (doublenumbers.begin() , doublenumbers.end() , 0) ; 

To daje 1, co jest ewidentnie błędne. Jakieś wyjaśnienia?C++ std :: accumulate nie daje oczekiwanej sumy

+2

+1, jest to ważny haczyka, który jest ugryziony mnie kilka razy. –

+2

również wektor nie jest konieczny; możesz używać wskaźników jako iteratorów: 'std :: accumulate (liczby, liczby + sizeof liczby/sizeof * liczby, 0.0);'. [W prawdziwym kodzie prawdopodobnie miałbyś stałą lub zmienną 'num_numbers' zamiast' sizeof numbers/sizeof * numbers'] –

+0

Zapoznaj się z moją odpowiedzią, aby w łatwy sposób zapobiec temu bólowi głowy w przyszłości. –

Odpowiedz

50

Należy napisać następujące:

std::cout << 
std::accumulate (doublenumbers.begin() , doublenumbers.end() , 0.0) ; 

Ponieważ typ 0 jest int.

Po utworzeniu instancji std::accumulate z typem trzeciego argumentu to int, wówczas konwertuje prawą stronę sumy. np .:

result += *iter; 
// int += double 

Byłoby to wymusić konwersję double do int, zamiast tego, co pan myśli, które jest przeciwieństwem.

+3

Co zabawne, nawet przy użyciu "0.0" nadal mogą występować pewne rozbieżności (w przypadku dużych sum) ze względu na przybliżoną reprezentację liczb zmiennoprzecinkowych. 'std :: vector v (1000, 1000.1f); std :: cout << std :: accumulate (v.begin(), v.end(), 0.0f); 'daje' 1.00011e + 06', ponieważ wartość float ma tylko 5/6 cyfr wartości precyzji na moim komputerze. –

+1

Po prostu miałem ten sam problem. Teraz zastanawiam się, jak należy to wiedzieć z dokumentacji (np. Http://pl.cppreference.com/w/cpp/algorithm/accumulate)? To poważne pytanie, a nie skarga. Naprawdę chciałbym bardziej przyzwyczaić się do C++. – user463035818

+0

@MatthieuM. Nie jest to szczególny problem z 'std :: accumulate', prawda? – Isaac

5
std::accumulate (doublenumbers.begin() , doublenumbers.end() , .0) ; 

lub

std::accumulate (doublenumbers.begin() , doublenumbers.end() , (double) 0) ; 

Typ "akumulatora" zmienna jest typu ostatniego argumentu std::accumulate. Jako argument podano 0 - oznacza to, że akumulator będzie miał typ: int. "Kumulacja" jest dokonywana w akumulatorze int (to jest zaokrąglone do int po każdym pojedynczym podsumowaniu) i daje wynik int. W tym przypadku jest to, podobno, 1.

8

Nazywasz accumulate z 0 jako argumentem init, więc będzie się on kumulował przy użyciu liczb całkowitych. Zamiast tego użyj 0.0.

1
std::accumulate<double> (doublenumbers.begin(), doublenumbers.end(), 0); // also works 
+1

Podejrzewam, że niektóre parametry szablonu zostały pożarte. Załącz swój kod w tikki ('), aby tak się nie stało. –

+1

Witamy w przepełnieniu stosu. Byłoby to lepszą odpowiedzią, gdybyś wspomniał o * dlaczego * to działa, a także gdybyś zwrócił uwagę na to, co dokładnie zmieniłeś. To różnica między dawaniem człowiekowi ryby a uczeniem go łowienia ryb. –

+0

Ahh, jeśli to jest to, co zamierzałeś, to nie jestem pewien, czy to zadziała. 'std :: accumulate' pobiera w tym przypadku dwa parametry szablonu. Jeden do zdefiniowania typu iteratora, a drugi do zdefiniowania typu zwracanego. Jeśli podasz tylko jeden, dopasuje się do pierwszego parametru i nadal będzie odgadywany drugi. –

2

std::accumulate zacznie Podsumowując typ, który jest przekazywany jako 3rd argumentu, jeśli przejdą liczbę całkowitą, typ zwracany będzie int. I w tym przypadku niejawnie przekonwertowane na double.

w C++ 11 i C++ 14, jeśli chcesz, aby zapobiec zwężenie konwersji, można utworzyć obiekt przy bezpośredni wykazie inicjalizację:

double sum { std::accumulate(doublenumbers.begin(), doublenumbers.end(), 0) }; 

Kompilator będzie następnie daje ostrzeżenie mówiące, że próbujesz przekonwertować z int na podwójne, a także na której linii. Pozwoli to zaoszczędzić czas debugowania. I można łatwo naprawić, tak że staje się poprawne:

double sum { std::accumulate(doublenumbers.begin(), doublenumbers.end(), 0.0) }; 
+0

Dla wyjścia pofałdowanego możemy użyć 0.0f. – user1436187

Powiązane problemy