Nuestros programadores estrellas agotaron sus reservas de café, en su búsqueda a tiempo completo por la resolución, hasta que Gerardo halló el arreglo en Gitea y en este momento la comparte contigo.
Solución:
Hay muchas maneras de hacer precisamente esto, siempre que no le preocupe confiar en los datos decimales originales.
El primer método, y quizás el más popular, sería el método del resto más grande.
Que es básicamente:
- Redondeando todo hacia abajo
- Obteniendo la diferencia en suma y 100
- Distribuir la diferencia sumando 1 a los elementos en orden decreciente de sus partes decimales
En tu caso, sería así:
13.626332%
47.989636%
9.596008%
28.788024%
Si tomas las partes enteras, obtienes
13
47
9
28
que suma 97, y quieres sumar tres más. Ahora, observa las partes decimales, que son
.626332%
.989636%
.596008%
.788024%
y toma los más grandes hasta que el total llegue a 100. Entonces obtendrías:
14
48
9
29
Alternativamente, puede simplemente elegir mostrar un lugar decimal en lugar de valores enteros. Entonces, los números serían 48.3 y 23.9, etc. Esto reduciría mucho la varianza de 100.
Probablemente la “mejor” manera de hacer esto (citado ya que “mejor” es un término subjetivo) es mantener un registro continuo (no integral) de dónde se encuentra y redondear ese valor.
Luego, utilícelo junto con el historial para determinar qué valor se debe utilizar. Por ejemplo, usando los valores que diste:
Value CumulValue CumulRounded PrevBaseline Need
--------- ---------- ------------ ------------ ----
0
13.626332 13.626332 14 0 14 ( 14 - 0)
47.989636 61.615968 62 14 48 ( 62 - 14)
9.596008 71.211976 71 62 9 ( 71 - 62)
28.788024 100.000000 100 71 29 (100 - 71)
---
100
En cada etapa, no redondeas el número en sí. En cambio, redondeas el acumulado valor y calcule el mejor número entero que alcanza ese valor desde la línea base anterior; esa línea base es el valor acumulativo (redondeado) de la fila anterior.
Esto funciona porque eres no perder información en cada etapa, sino utilizar la información de manera más inteligente. Los valores redondeados “correctos” están en la columna final y puede ver que suman 100.
Puede ver la diferencia entre esto y el redondeo ciego de cada valor, en el tercer valor anterior. Mientras 9.596008
normalmente redondearía a 10
el acumulado 71.211976
redondea correctamente a 71
– esto significa que sólo 9
es necesario agregar a la línea de base anterior de 62
.
Esto también funciona para secuencias “problemáticas” como tres aproximadamente:1/3
valores, donde uno de ellos deben ser redondeados:
Value CumulValue CumulRounded PrevBaseline Need
--------- ---------- ------------ ------------ ----
0
33.333333 33.333333 33 0 33 ( 33 - 0)
33.333333 66.666666 67 33 34 ( 67 - 33)
33.333333 99.999999 100 67 33 (100 - 67)
---
100
Dado que ninguna de las respuestas aquí parece resolverlo correctamente, aquí está mi versión semi-ofuscada usando guiones bajos:
function foo(l, target)
var off = target - _.reduce(l, function(acc, x) return acc + Math.round(x) , 0);
return _.chain(l).
sortBy(function(x) return Math.round(x) - x ).
map(function(x, i) return Math.round(x) + (off > i) - (i >= (l.length + off)) ).
value();
foo([13.626332, 47.989636, 9.596008, 28.788024], 100) // => [48, 29, 14, 9]
foo([16.666, 16.666, 16.666, 16.666, 16.666, 16.666], 100) // => [17, 17, 17, 17, 16, 16]
foo([33.333, 33.333, 33.333], 100) // => [34, 33, 33]
foo([33.3, 33.3, 33.3, 0.1], 100) // => [34, 33, 33, 0]
valoraciones y comentarios
Recuerda algo, que te brindamos la opción de decir si te ayudó.