0votos

Calcular la Media sin tener los numeros anteriores en JavaScript

por josejuan hace 6 años

Recuperar el sumatorio a partir de la media y la cuenta es el paso obvio (y que estrictamente pide el enunciado luego es correcto). Sin embargo, es mejor no hacer caso al enunciado y resolver el problema que describe guardando el sumatorio y no la media. Los dos beneficios directos son: no hay pérdida de datos por error de precisión (aun usando double) y se ahorra una multiplicación en cada paso.

Solo conociendo la Media anterior, la cuenta de números procesados y el siguiente numero. Sacar la Media.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function MediaAcumulada() { 
    this.s = this.c = 0; 
    this.Push = function(valor) {this.s += valor; this.c++}; 
    this.Media = function() {return this.s / this.c}; 
 
 
 
 
// ejemplo 
var ma = new MediaAcumulada(); 
for(var n = 1; n <= 5; n++) { 
    ma.Push(n); 
    console.log(ma.Media()); 
8 comentarios
0votos

Escrito por Fernando Pelliccioni hace 5 años

La desventaja es que podes obtener un overflow en la sumatoria en caso de que el tipo de datos sea Entero. En caso de tipos Floating Point (IEEE 754) podrías obtener Infinito.
0votos

Escrito por josejuan hace 5 años

Fernando, esa interpretación es incorrecta.

De hecho, con el mismo número de bits, obtendrás overflow antes con el float que con un entero (pues la mantisa tendrá menos bits que en la versión entera).

Fíjate que, para 32, 64, ... bits, 1e200 == (1e200 + 1).
0votos

Escrito por Fernando Pelliccioni hace 5 años

JoseJuan, quizás me he expresado mal.
Mi punto no está en la comparación entre usar tipos Enteros o FloatingPoints, sino en que estás almacenando la sumatoria y cada valor de la serie es cercano a la capacidad máxima del Tipo de dato ( INTMAX, DBLMAX, o lo que fuere ) vas a tener Overflow ( o el valor especial Infinito en caso de IEEE 754 ).
Creo que lo mejor es almacenar el promedio por más que sea menos eficiente.
Aquí mi versión que es un poquito más eficiente que la solución más obvia (aunque tiene un error en las Constraints)
http://www.solveet.com/exercises/Calcular-la-Media-sin-tener-los-numeros-anteriores/115/solution-1614
0votos

Escrito por josejuan hace 5 años

Creo haberte entendido :D y el problema sigue siendo el mismo. Si usas coma flotante, 1e200+1 es, en la máquina, exactamente el mismo valor que 1e200 (por lo que tu media no será actualizada). Si usas enteros... mira mi último desafío propuesto "Media progresiva en máquina limitada". ¡Feliz 2014!
0votos

Escrito por Fernando Pelliccioni hace 5 años

Lo que decís es cierto, en una máquina limitada los puntos flotantes IEEE 754 de 64 bits pierden precision antes (aprox 2^53) de que un entero de 64bits llegue a Overflow...
Pero, yo me refiero al algoritmo, sin enfocarme en los tipos de datos.
El desafío habla de que la serie a promediar es de "numeros", pero no especifica que tienen que estar restringidos a enteros (mas allá del ejemplo, que no debería ser normativo), por lo tanto, un algoritmo Genérico para calcular la media (aritmética o lo que fuere) no debería guardar la sumatoria como Entero.
Si guardamos la sumatoria como un entero, entonces, restringimos el algoritmo a enteros, por consiguiente, no es un algoritmo genérico.
No conozco Javascript en detalle, pero creo que tu solución tambien podria perder precisión.
¿Cuáles son los tipos de datos de this.s y this.c ?
¿Cómo esta definido el operador de division / para esos tipos de datos?
/ : int / int -> double (¿?)

Abrazo!
0votos

Escrito por josejuan hace 5 años

Fernando que te lías XD XD

No perdamos la línea argumental, que luego no sabemos qué es lo que discutimos (yo el primero).

[1] el desafío no impone restricciones en la cantidad de datos ni en la capacidad de cómputo.

[2] por [1], una solución posible es la que yo he dado, que requiere una suma y un incremento por cada dato de entrada y una división cada vez que se desee recuperar la media. El algoritmo sirve para cualquier tipo de dato (entero, flotante, complejo, matricial, precisión fija, arbitraria, ...) Y NO PIERDE PRECISIÓN por acumulación de error.

[3] tú argumentas que el algoritmo falla por un posible overflow (que únicamente puede darse en la suma acumulada) y sugieres acumular el valor medio.

[4] yo respondo que, no fijando restricción, almacenar el valor medio es peor solución (en general), porque se va a acumular un error (por residuo perdido en enteros o por pérdida de decimales en la mantisa de un flotante).

[5] para fijar y concretar un contexto sin ambigüedades del problema que creo entender tú has planteado, he propuesto un nuevo desafío que he intentado condense y fuerce a solucionar tu cuestión.

[6] en tu último comentario, dices no enfocarte en los tipos de datos, sino en el algoritmo, pero ya he mostrado en [2] que MI ALGORITMO es uno de los mejores posibles (puedes usar un tipo de dato de mayor capacidad, pero el algoritmo no cambia y además funciona con cualquier grupo aditivo [cuerpo si queremos sacar explícitamente la media])

Por supuesto, quizás hay algo que no termino de ver.

¡Saludos!
0votos

Escrito por Fernando Pelliccioni hace 5 años

Se volvió un poco confuso el tema.
Te he respondido en mi solución.
0votos

Escrito por Fernando Pelliccioni hace 5 años

Aclaro, en las demás soluciones también ya que ( old_avg * count ) recupera la sumatoria. Estamos ante el mismo problema. Luego postro mi solución.

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.