2013-12-23 1 views
15

Рассмотрим следующий код для добавления всех элементов vector:Почему функция std :: accumulate показывает неправильную сумму вектора <double>?

#include<iostream> 
#include<algorithm> 
#include<numeric> 
#include<vector> 
using namespace std; 
int main(void) 
{ 

    std::vector<double> V; 
    V.push_back(1.2); 
    V.push_back(3.6); 
    V.push_back(5.6); 
    double sum = accumulate(V.begin(),V.end(),0); 

    cout << "The sum of the elements of the vector V is " << sum << endl; 
    return 0; 
} 

Когда я компилирую это на Cygwin на Windows, и запустить его, я получаю выход на терминале в

Сумма элементов вектора V равна 9

Функция accumulate, кажется, округляет все цифры и добавляет их, что объясняет ответ.

Это что-то не так с компилятором Cygwin g ++ или с неправильной интерпретацией функции accumulate для добавления vector из double s?

ответ

28

std::accumulate объявлен как таковой:

template <typename InputIt, typename T> 
T accumulate(InputIt first, InputIt last, T init); 

Второй аргумент шаблона к std::accumulate выводится в int, потому что 0 имеет тип int. Пропустите двойной вместо этого, например 0.0.

+3

О, дорогая! Мне это кажется нецензурной.Не логичнее ли выводить тип из взгляда на природу элементов вектора? Существует ли какое-либо использование этого способа определения накопления? – smilingbuddha

+1

@smilingbuddha Можно написать оболочку, которая выбирает тип 'init', используя' typename std :: iterator_traits :: value_type' вместо параметра шаблона. Я считаю, что это не сделано, потому что это будет менее гибким, хотя я не уверен. – rightfold

+0

@rightfold Почему бы просто не преобразовать значение в значение 'value_type контейнера'? –

5

Изменить 00.0. Затем он получает 10.4. В то время как контейнер является двойным, вывод типа int из-за начального аргумента, переданного в std::accumulate. Поэтому для контейнера назначаются значения int.

+0

Вы можете использовать 'decltype (* first)' for 'vt'. – Jarod42

+1

Обратите внимание, что с вашей 'accumulate' вы можете иметь противоположную проблему:' accumulate 'где результат стоит в' int', но не в 'uint8_t'. И использование 'accumulate' для смещения указателя не возможно (' accumulate ') с вашей версией (или любым другим использованием, где' T' и 'decltype (* first)' не связаны). – Jarod42

+1

@ Jarod42: Да - возможно, нужно сделать что-то вроде 'decltype (std :: declval (vt) + std :: declval (T))', чтобы получить результат как любой тип, который добавит/даст. Это позволит пользователю продвигать продвижение по более широкому типу, но не (возможно, случайно) усекать до более узкого типа. –

2

Последний аргумент вызова std::accumulate определяет тип внутренней суммы, а также тип возврата. Поскольку 0 - это int, все округляется во время добавления, а результат также является целым числом.

4

значения возвращается из функции станд :: накопления является целым числом, а не двойное из-за этого:

double sum = accumulate(V.begin(), V.end(), 0); 
//           ^-- Integer! 

Вывод параметров шаблона выполняется компилятором C++ делает тип возвращаемой функции accumulate то же, что и параметр init, который в вашем случае является целым числом. Поэтому возвращаемое значение округляется до ближайшего целого числа. Возвращаемое значение затем неявно возвращается обратно в double, когда оно назначается в sum.

Чтобы исправить это, вы можете просто передать нуль как двойной (то есть 0.0).

 Смежные вопросы

  • Нет связанных вопросов^_^