2010-07-23 8 views
3

Supposons que je veuille calculer la valeur moyenne d'un tel queempêche la moyenne longue durée de débordement?

class Averager { 
    float total; 
    size_t count; 
    float addData (float value) { 
     this->total += value; 
     return this->total/++this->count; 
    } 
} 

tôt ou tard, la valeur total ou count série de données débordera, donc je le faire ne se rappelle pas la valeur totale par:

class Averager { 
    float currentAverage; 
    size_t count; 
    float addData (float value) { 
     this->currentAverage = (this->currentAverage*count + value)/++count; 
     return this->currentAverage; 
    } 
} 

il semble qu'ils déborderont plus, mais la multiplication entre average et count problème conduit à débordement, donc la prochaine solution est:

class Averager { 
    float currentAverage; 
    size_t count; 
    float addData (float value) { 
     this->currentAverage += (value - this->currentAverage)/++count; 
     return this->currentAverage; 
    } 
} 

semble mieux, le prochain problème est comment empêcher count de débordement?

+5

Je pense que le problème de l'imprécision numérique est plus important que le débordement. – kennytm

+0

Il est très peu probable que 'total' déborde. Il perdra de la précision s'il devient beaucoup plus grand que la moyenne. –

+0

@kenny: il y aura une certaine perte de précision, mais à mesure que le nombre augmente, toute valeur ajoutée est moins sensible à la moyenne, elle pourrait être résolue statistiquement. – uray

Répondre

6

Seaux agrégés.

Nous choisissons une taille de seau qui est confortablement inférieure à squareRoot (MAXINT). Pour rester simple, choisissons 10.

Chaque nouvelle valeur est ajoutée au compartiment en cours, et la moyenne mobile peut être calculée comme vous le décrivez.

Lorsque le godet est plein, démarrez un nouveau compartiment en vous souvenant de la moyenne du godet complet. Nous pouvons calculer en toute sécurité la moyenne globale en combinant les moyennes des godets complets et du godet partiel actuel. Lorsque nous arrivons à 10 seaux complets, nous créons un plus grand seau, la capacité 100.

Pour calculer la moyenne totale, nous calculons d'abord la moyenne des «10», puis les combinons avec les «100». Ce modèle se répète pour "1000" "10 000" et ainsi de suite. A chaque étape, nous avons seulement besoin de considérer deux niveaux 10 x plus grands que le précédent.

+0

Je pense que ce que vous décrivez est la "moyenne mobile" (http://en.wikipedia.org/wiki/Moving_average) –

+1

@DR Je pense que c'est un peu plus que cela - moyenne mobile classique doit maintenir un nombre de combien articles que nous avons vu, et finalement cela peut déborder. La technique que je décris évite ce problème. – djna

+0

Ah, d'accord, vous avez raison. –

2

Utilisez double total; unsigned long long count;. Vous devriez toujours vous soucier de la précision, mais ce sera beaucoup moins un problème qu'avec float.

+0

J'ai besoin d'une approche statistique de ce problème, peu importe la taille du type de données de 'counter' tôt ou tard, il débordera – uray

+1

big int :) –

+4

@uray: Es-tu sérieux? Un compteur de 64 bits prendra 70 ans pour être bouclé même si vous l'incrémentez 4 milliards de fois par seconde. Attendez-vous une disponibilité de 70 ans pour votre programme? Vous attendez-vous à avoir en moyenne plus de 18 quintillions? –

0

Vous pouvez utiliser ces types de données spéciaux où les nombres entiers peuvent croître indéfiniment jusqu'à ce que votre RAM soit pleine. Qu'en est-il de l'utilisation de l'arithmétique de précision arbitraire?

1

Il y a une liste des bibliothèques que vous pouvez utiliser sur Wikipédia: http://en.wikipedia.org/wiki/Bignum#Libraries

La plupart des bibliothèques arithmétiques arbitraires précision ne débordera pas jusqu'à ce que le nombre de chiffres mémorisés remplir la mémoire disponible (ce qui est assez peu probable).

Questions connexes