Предотвращение переполнения / переполнения с помощью двойного «простого суммирования»;

Я борюсь с проблемой суммирования, которая терпит неудачу с недостаточным или переполнением.

У меня более 8271571 двойных значений, из которых мне нужно среднее арифметическое.

Но главная проблема в том, что я не настолько умен, чтобы это делать.

В настоящее время я просто суммирую их и делю на размеры.
В большинстве случаев это не удается при недостаточном или переполнении, что дает мне -1. ​​# INF или 1. # INF.

for(size_t j = 0; j < 12; j++)
{
double a = 0.0;

for(size_t i=0; i < Features->size(); i++)
{
a += Features->at(i)->at(j);
}
meanVector[j] = a / Features->size();
}

Однако нет возможности сказать, что это просто положительное или отрицательное значение, поэтому я не могу установить тип данных для подписи.

Я также пытался использовать константу деления в суммировании или делении на размер уже при их сложении, но это тоже не помогает.

Значения могут варьироваться, от того, что я видел на беглом взгляде, от -20 до +30, но точно сказать не могу.

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

Редактировать:

Размер никогда не равен 0, проверка выполняется перед подразделением.
Далее ни одно из значений не является недействительным ни в коем случае. При их извлечении я уже проверяю #IND и NaN.

Если я делю уже на суммирование, я думаю, это тоже не правильный результат?

a+= Features->at(i)->at(j) / Features->size()

результат -3,7964983860343639e + 305

но для каждой итерации. Это не может быть правильно и выглядит как граница

Изменить 2:

Так что некоторые из вас, ребята, были совершенно правы. Там много мусора …

0: размер: 8327571, мин .: -2,24712e + 307, макс: 3362,12 1: размер: 8327571,
мин: -2,24712e + 307, макс: 142181 2: размер: 8327571, мин: -2,24712e + 307,
макс: 59537,8 3: размер: 8327571, мин: -2,24712e + 307, макс: 236815 4:
размер: 8327571, мин .: -2.24712e + 307, макс .: 353488 5: размер: 8327571, мин:
-2.24712e + 307, макс .: 139960 6: размер: 8327571, мин: 0, макс: 0 7: размер: 8327571, мин: 0, макс: 0 8: размер: 8327571, мин: 0, макс: 0 9: размер:
8327571, мин: 0, макс: 0 10: размер: 8327571, мин: 0, макс: 0 11: размер:
8327571, мин: 0, макс: 0

4

Решение

  • У меня более 8271571 двойных значений, из которых мне нужно среднее арифметическое.
  • Значения могут варьироваться, от того, что я видел на беглом взгляде, от -20 до
    +30, но точно сказать не могу.
  • Размер никогда не равен 0, проверка выполняется перед подразделением.

Это не складывается. Сумма должна соответствовать double без труда. Там должно быть что-то не так с данными. Вы можете сделать быструю проверку ваших ценностей следующим образом:

for (size_t j = 0; j < 12; ++j)
{
std::vector<double> values;

values.reserve(Features->size());
for (size_t i = 0; i < Features->size(); ++i)
{
values.push_back(Features->at(i)->at(j));
}

// Find extreme values, including infinity
std::cout << j << ": "<< "size: " << values.size()
<< ", min: " << *std::min_element(values.begin(), values.end())
<< ", max: " << *std::max_element(values.begin(), values.end())
<< std::endl;

// Find NaNs
for (size_t i = 0; i < Features->size(); ++i)
{
// Choose one of the following ifs

// For C++11 (isnan is a standard thing now)
if (std::isnan(Features->at(i)->at(j))

// Or for Visual Studio
if (_isnan(Features->at(i)->at(j))

// Or for GCC prior to C++11
if (__builtin_isnan(Features->at(i)->at(j))

{
std::cout << "NaN at [" << i << ", " << j << "]" << std::endl;
}
}
}

Вы должны быть в состоянии быстро определить, есть ли что-то странное с вводом.

4

Другие решения

Вы можете вычислить среднее значение с помощью онлайн-алгоритма, что означает, что вам не нужно добавлять все значения перед делением. Вот:

template< typename NumberType >
class ProgressiveMean{
NumberType  m_Mean;
NumberType  m_MeanKMinus1;
long        m_K;
public:
ProgressiveMean();
void Seed( NumberType seed );
void AddValue( NumberType newVal );
NumberType getMean() const;
};

template< typename NumberType >
ProgressiveMean<NumberType>::ProgressiveMean():
m_Mean( 0 ),
m_MeanKMinus1( 0 ),
m_K( 0 ){
}

template< typename NumberType >
void ProgressiveMean<NumberType>::Seed( NumberType seed ){
m_MeanKMinus1 = seed
m_K = 2;  //Start from K = 1, so next one is 2
}

template< typename NumberType >
void ProgressiveMean<NumberType>::AddValue( NumberType newVal ){
m_Mean = m_MeanKMinus1 + (newVal - m_MeanKMinus1) / m_K;
m_MeanKMinus1 = m_Mean;
m_K++;
}

template< typename NumberType >
NumberType ProgressiveMean<NumberType>::getMean() const{
return m_Mean;
}

Чтобы использовать это, позвоните Seed с начальным значением, вызовом цикла AddValue для остальных, и когда вы закончите, позвоните getMean,

Эта идея от Кнута, и я получил ее от Вот.

Вы также можете рассмотреть возможность использования библиотеки больших чисел.

0

По вопросам рекламы [email protected]