Pregunta

Estoy intentando redondear un número a su primer decimal y, considerando las diferentes opciones de MidpointRounding, parece funcionar bien.Sin embargo, surge un problema cuando ese número tiene decimales posteriores que afectarían aritméticamente el redondeo.

Un ejemplo:

Con 0.1, 0.11..0.19 y 0.141..0.44 funciona:

Math.Round(0.1, 1) == 0.1
Math.Round(0.11, 1) == 0.1
Math.Round(0.14, 1) == 0.1
Math.Round(0.15, 1) == 0.2
Math.Round(0.141, 1) == 0.1

Pero con 0.141..0.149 siempre regresa 0.1, a pesar de 0.146..0.149 debe redondearse a 0.2:

Math.Round(0.145, 1, MidpointRounding.AwayFromZero) == 0.1
Math.Round(0.146, 1, MidpointRounding.AwayFromZero) == 0.1
Math.Round(0.146, 1, MidpointRounding.ToEven) == 0.1
Math.Round(0.146M, 1, MidpointRounding.ToEven) == 0.1M
Math.Round(0.146M, 1, MidpointRounding.AwayFromZero) == 0.1M

Intenté idear una función que solucione este problema y funciona bien para este caso, pero, por supuesto, falla glamurosamente si intentas redondear, es decir. 0.144449 a su primer dígito decimal (que debería ser 0.2, pero los resultados 0.1.) (Eso tampoco funciona con Math.Round()).

private double "round"(double value, int digit)
{
    // basically the old "add 0.5, then truncate to integer" trick
    double fix = 0.5D/( Math.Pow(10D, digit+1) )*( value >= 0 ? 1D : -1D );
    double fixedValue = value + fix;

    // 'truncate to integer' - shift left, round, shift right
    return Math.Round(fixedValue * Math.Pow(10D, digit)) / Math.Pow(10D, digit);
}

Supongo que una solución sería enumerar todos los dígitos, encontrar el primer valor mayor que 4 y luego redondear hacia arriba o hacia abajo.Problema 1:Eso parece una idiotez, Problema 2:No tengo idea de cómo enumerar los dígitos sin un millón de multiplicaciones y restas.

Larga historia corta:¿Cuál es la mejor manera de hacer eso?

¿Fue útil?

Solución

Math.Round() se está comportando correctamente.

Cuando se está realizando redondeo punto medio estándar, que nunca es necesario mirar más allá de dígitos decimales 1 más allá de donde redondear a. Si va a redondear a la décima más cercana, entonces nunca necesita mirar más allá del segundo dígito después del punto decimal.

La idea con redondeo punto medio es que la mitad de la en-entre los números deben redondear hacia arriba y la otra mitad se deben redondear hacia abajo. Así que para números entre 0,1 y 0,2, la mitad de ellos debe redondear a 0,1 y mitad debe ronda a 0,2. El punto medio entre estos dos números es de 0,15, por lo que es el umbral para el redondeo. 0,146 es menor que 0,15, por lo tanto debe redondear hacia abajo a 0,1.

                    Midpoint
0.10                  0.15                  0.20
 |----------------|----|---------------------|
                0.146
       <---- Rounds Down

Otros consejos

No obtiene lo que se está tratando de lograr aquí. 0,149 redondeado a un decimal es 0.1, no 0.2

El redondeo no es un proceso iterativo, que ronda sólo una vez.

Así 0,146 redondeado a 1 dígito decimal es 0.1.

No hace esto:

0.146 --> 0.15
0.15 -->  0.2

Sólo se hace esto:

0.146 --> 0.1

De lo contrario, la siguiente:

0.14444444444444446

También haría redonda a 0,2, pero no es así, y no debería.

No tratar de agravar los 'errores' de redondeo. Que es lo que estamos tratando de hacer.

0.146 debe abajo y vuelta a 0,1 si se va a colocar un decimal.

Por redondeo a 0.15 primero, y luego de nuevo a 0.2 sólo estás introduciendo más error de redondeo, no menos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top