2011-01-27 18 views
5

Chicos, Estoy escribiendo un método para redondear. La entrada es un tipo decimal (cuatro decimales garantizados). La regla de redondeo es que se ignora 0.005 o menos, es decir, mira el tercer lugar decimal - si es < = 5, redondee hacia abajo o redondee hacia arriba. Algunos casos de uso: 82.3657 -> 82.36, 82.3667 -> 82.37, 82.5967 -> 82.60, 82.9958 -> 82.99, 82.9968 -> 83.00 ¿Alguna buena idea? Lo he resuelto de la siguiente manera.Redondeo personalizado de tipo decimal en C#

private decimal CustomRound(decimal x) 
{ 
    decimal rX = Math.Truncate(x * 100)/100; 
    decimal x3DecPlaces = Math.Truncate(x * 1000)/1000; 
    decimal t = (x3DecPlaces * 1000) % 10; 
    if (t >= 6) 
     rX = rX + 0.01m; 
    return rX; 
} 

Respuesta

7

No creo que haya nada incorporado para eso, porque es un requisito bastante inusual (por ejemplo, la idea de que 1.3358 está más cerca de 1.33 que de 1.34 es impar). Tu código parece razonablemente apropiado.

EDIT: No se puede utilizar MidpointRounding para conseguir el efecto que usted quiere aquí, debido a que el punto en el que se inicia redondeo no es el punto medio - es (digamos) de 1,336 en lugar de la normal de 1.335. Solo 1.335 se trata como el punto medio entre 1.33 y 1.34, porque ese es el punto medio. Efectivamente has obtenido un redondeo sesgado aquí de una manera inusual.

Ni siquiera puede truncar a tres DP y luego usar MidpointRounding, ya que no hay modo "hacia cero".

Una opción poco extraño sería llevar a cabo con eficacia la tendencia a sí mismo:

private static decimal CustomRound(decimal x) 
{ 
    return decimal.Round(x - 0.001m, 2, MidpointRounding.AwayFromZero); 
} 

por lo que sería tratar 82.3657 82.3647 y tan redonda que a 82.36; trataría 82.3667 y 82.3657 y lo redondeará a 82.37, y trataría 82.5967 como 82.5957 y lo redondeará a 82.60 etc. I piensa que hace lo que quiere, pero solo para valores positivos. Tendría que averiguar exactamente qué comportamiento desea para los valores negativos.

Haga lo que haga, es necesario documentar muy claramente :)

Así como una cuestión de preferencia, me gustaría utilizar en lugar de decimal.TruncateMath.Truncate, sólo para hacerlo más claro que todo lo que realmente se hace con decimales.

+0

@Downvoter: ¿me gustaría comentar? –

+0

Sí, he tenido problemas para tratar de usar métodos integrados. Gracias. – redzon

-1

Quizás podría utilizar el método Math.Round (Double, Int32)?

+4

la conversión de decimal a duplicar y luego de vuelta es una idea terrible - que significa que es prácticamente inútil utilizar decimal a empezar. –

+0

@Jon: hay una [sobrecarga] (http://msdn.microsoft.com/en-us/library/ms131275.aspx) de 'Math.Round' que funciona con decimales. – Vlad

+0

@Vlad: Claro, pero esta respuesta específicamente llama a la sobrecarga usando el doble. –

0

¿Cómo se manejan los valores negativos? Supongo que querrías -13.999 redondear a -14 no a -13.99 ¿verdad?

En ese caso, su +/- 0.01m debe depender de si x es negativo o positivo.

Esta es una manera más fácil de hacerlo:

decimal CustomRound(decimal x) 
{ 
    var offset = x >= 0 ? -0.001m : 0.001m; 
    return Decimal.Round(x + offset, 2, MidpointRounding.AwayFromZero); 
}