Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

455
Vistas
C # / LINQ Tomando la suma de decimales muestra diferentes resultados

Tengo una lista de objetos de los que intento sumar después de múltiples 3 de los campos entre sí. El problema es que el resultado final NO coincide cuando ejecuto el cálculo en los siguientes 2 casos:

1 - purchasesDeserialized.Sum(reference => reference.Price * reference.Box * reference.Qty)

2 - purchasesDeserialized.OrderBy(r => r.Box).Sum(reference => reference.Price * reference.Box * reference.Qty);

Los datos son idénticos en dos casos, la diferencia es que en el caso n. ° 1 hago el cálculo sin ordenar primero frente al caso n. ° 2, primero ordeno y luego calculo. (Esperaba que el resultado fuera el mismo, ya que la clasificación no debería cambiar ningún dato subyacente, sino simplemente reordenarlos).

No estoy seguro de si LINQ está afectando el cálculo después de OrderBy o si el problema aterriza en el lado del redondeo decimal de C#.

Código de replicación completo:

 using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; namespace ConsoleApp1 { public class Purchase { public decimal Price { get; set; } public decimal Box { get; set; } public decimal Qty { get; set; } } class Program { static void Main(string[] args) { string purchases = "[{\"Box\":10.0,\"Qty\":206.000000,\"Price\":8.323300970873786407766990292},{\"Box\":10.0,\"Qty\":108.000000,\"Price\":8.333333333333333333333333333},{\"Box\":10.0,\"Qty\":46.000000,\"Price\":8.695652173913043478260869565},{\"Box\":10.0,\"Qty\":18.000000,\"Price\":24.833333333333333333333333333},{\"Box\":1.0,\"Qty\":566.000000,\"Price\":80.87985865724381625441696112},{\"Box\":1.0,\"Qty\":12.000000,\"Price\":97.46666666666666666666666667},{\"Box\":1.0,\"Qty\":72.000000,\"Price\":103.06805555555555555555555556},{\"Box\":1.0,\"Qty\":246.000000,\"Price\":81.2906504065040650406504065},{\"Box\":1.0,\"Qty\":78.000000,\"Price\":80.08333333333333333333333333},{\"Box\":10.0,\"Qty\":146.000000,\"Price\":8.030821917808219178082191782},{\"Box\":10.0,\"Qty\":178.000000,\"Price\":8.326404494382022471910112359},{\"Box\":10.0,\"Qty\":364.000000,\"Price\":8.324175824175824175824175825},{\"Box\":10.0,\"Qty\":30.000000,\"Price\":8.666666666666666666666666667},{\"Box\":10.0,\"Qty\":36.000000,\"Price\":24.5000000000000000000},{\"Box\":1.0,\"Qty\":120.000000,\"Price\":83.662500000000000000},{\"Box\":1.0,\"Qty\":332.000000,\"Price\":80.74698795180722891566265061},{\"Box\":1.0,\"Qty\":36.000000,\"Price\":78.833333333333333333333333333},{\"Box\":1.0,\"Qty\":22.000000,\"Price\":96.35909090909090909090909091},{\"Box\":1.0,\"Qty\":134.000000,\"Price\":78.149253731343283582089552239},{\"Box\":10.0,\"Qty\":26.000000,\"Price\":24.346153846153846153846153846},{\"Box\":1.0,\"Qty\":298.000000,\"Price\":97.06644295302013422818791947},{\"Box\":1.0,\"Qty\":18.000000,\"Price\":95.22777777777777777777777778},{\"Box\":10.0,\"Qty\":6.000000,\"Price\":24.166666666666666666666666667},{\"Box\":1.0,\"Qty\":82.000000,\"Price\":96.42195121951219512195121951},{\"Box\":10.0,\"Qty\":154.000000,\"Price\":8.149350649350649350649350649}]"; var purchasesDeserialized = JsonConvert.DeserializeObject<List<Purchase>>(purchases); var sumRes1 = purchasesDeserialized .Sum(reference => reference.Price * reference.Box * reference.Qty); Console.WriteLine("Sum:" + sumRes1); //returns 294648.40000000000000000000000M var sumRes2 = purchasesDeserialized .OrderBy(r => r.Box) .Sum(reference => reference.Price * reference.Box * reference.Qty); Console.WriteLine("Sum after sort:" + sumRes2); //returns 294648.39999999999999999999999M } } }

Y la salida:

 Sum:294648.40000000000000000000000 Sum after sort:294648.39999999999999999999999
over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

Creo que el problema es que está aumentando el valor de la cantidad total (durante la operación Sum) al mismo tiempo que está disminuyendo la precisión máxima decimal.

En este caso, el orden de los elementos en la colección es importante porque afectará en qué punto se excede la precisión decimal. Los elementos restantes luego se agregarán, pero no precisamente, lo que al final da como resultado diferentes totales.

Para dar un ejemplo, digamos que mi tipo de datos puede contener hasta 4 lugares:

 var x = 4.998; var y = 0.002; var z = 10.00; x + y + z = 4.998 + 0.002 + 10.00 => 15.00; z + x + y = 10.00 + 4.998 + 0.002 => 14.99; //(because 10.00 + 4.998 = 14.99 and there is no precision left for remaining decimal place, so its stripped)
over 4 years ago · Santiago Trujillo Denunciar

0

Considere, por ejemplo, los términos indexados desde su json 0 y 22

 decimal d00 = 10M * 206.000000M * 8.323300970873786407766990292M; decimal d22 = 10.0M * 6.000000M * 24.166666666666666666666666667M; decimal sum = d00 + d22;

Los resultados reales son (encontrados usando una calculadora de precisión completa )

 d00 = 17146.00000000000000000000000152 // 31 d22 = 1450.00000000000000000000000002 // 30 sum = 18596.00000000000000000000000154 // 31

pero perderá precisión al ver que d00 debe tener 31 dígitos en total, etc., y al estar limitado a la precisión decimal , los resultados en C# son

 d00 = 17146.000000000000000000000002 // 29 d22 = 1450.0000000000000000000000000 // 29 sum = 18596.000000000000000000000002 // 29

entonces el error en esta suma arbitraria es 0.000000000000000000000000046. Con la forma en que se realiza el redondeo, los errores se redondearán hacia arriba o hacia abajo, según el orden en que se realicen las operaciones de suma (50% de probabilidad de redondear de una forma u otra en cada paso), por lo que lo más probable es que termine con resultados diferentes de órdenes diferentes.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda