неявное продвижение, чтобы избежать переполнения в std :: частичный_сум - PullRequest
2 голосов
/ 03 февраля 2010

Этот код страдает от переполнения, потому что тип промежуточных результатов не зависит от типа назначения:

vector< uint8_t > increments;
…
vector< uint32_t > increasing( increments.size() );
partial_sum( increments.begin(), increments.end(), increasing.begin() );

Однако, это также (GCC 4.2):

partial_sum( increments.begin(), increments.end(), increasing.begin(),
             plus< uint32_t >() );

Разве plus< uint32_t > не должен продвигать свои операнды и избегать переполнения?

Редактировать: Я слишком зависимый. После небольшого перерыва я снова сел и проверил реализацию. Это делает это:

  /* input_iterator::value_type */ __value = __binary_op(__value, *__first);
  *++__result = __value;

Я не думаю, что это соответствует требованиям, поэтому я проверю последнюю версию и, возможно, сообщу об ошибке ...

1 Ответ

1 голос
/ 03 февраля 2010

Согласно http://www.open -std.org / jtc1 / sc22 / wg21 / docs / lwg-active.html # 539 , partial_sum полностью переопределено с n3000 (последний выпуск)

Эффекты: Пусть VT будет InputIterator's тип ценности. Для непустого диапазона, инициализирует аккумулятор в соответствии с типом VT с * first и выполняет * result = соотв. Для каждого итератора я в [first + 1, последний) по порядку изменено acc = acc + * i или acc = binary_op (acc, * i) и назначается * (результат + (я - первый)).

и

Тогда «расширяющее» поведение может быть получен путем написания собственного прокси итератор, который несколько вовлечен.

Я действительно не вижу преимущества такого поведения. Читая отчет о дефектах, я не вижу никакого оправдания, кроме

Целью алгоритмов является выполнение их расчетов с использованием тип входного итератора.

Arrrgh.

Редактировать: Я пошел дальше и реализовал расширяющийся входной итератор. Работает как рекламируется.

template< class Base, class Wider >
struct widen_iter : iterator< input_iterator_tag, Wider > {
    Base b;
    widen_iter( Base const &inb = Base() ) : b( inb ) {}
    Wider operator*() const { return Wider( *b ); }
    Wider const *operator->() const { Wider t( *b ), *ta = &t; return ta; }
    widen_iter &operator++() { ++ b; return *this; }
    widen_iter operator++(int) { widen_iter t = *this; ++ b; return t; }
    bool operator==( widen_iter const &r ) const { return b == r.b; }
    bool operator!=( widen_iter const &r ) const { return b != r.b; }
};
template< class Wider, class Base >
widen_iter< Base, Wider >
widener( Base b ) { return widen_iter< Base, Wider >( b ); }

Было бы намного короче, если бы существовал общий итератор ввода с фильтрами по функторам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...