• Jobs
  • About Us
  • professionals
    • Home
    • Jobs
    • Courses and challenges
  • business
    • Home
    • Post vacancy
    • Our process
    • Pricing
    • Assessments
    • Payroll
    • Blog
    • Sales
    • Salary Calculator

0

417
Views
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 3 years ago · Santiago Trujillo
2 answers
Answer question

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 3 years ago · Santiago Trujillo Report

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 3 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Our process Sales
Legal
Terms and conditions Privacy policy
© 2025 PeakU Inc. All Rights Reserved.

Andres GPT

Recommend me some offers
I have an error