我有一個物件串列,我試圖在多個 3 個欄位之后相互求和。問題是當我通過以下兩種情況運行計算時,最終結果不匹配:
1 -purchasesDeserialized.Sum(reference => reference.Price * reference.Box * reference.Qty)
2 -purchasesDeserialized.OrderBy(r => r.Box).Sum(reference => reference.Price * reference.Box * reference.Qty);
兩種情況下的資料是相同的,不同之處在于 #1 我在不先排序的情況下進行計算,而在 #2 我先排序然后計算的情況下進行計算。(我希望結果是一樣的,因為排序不應該改變任何基礎資料,而只是重新排序它們)。
不確定 LINQ 是否會影響 OrderBy 之后的計算,或者問題是否出現在 C# 十進制舍入方面。
完整復制代碼:
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
}
}
}
和輸出:
Sum:294648.40000000000000000000000
Sum after sort:294648.39999999999999999999999
uj5u.com熱心網友回復:
我認為問題在于您正在增加總量的值(在 Sum 操作期間),同時您正在降低十進制最大精度。
在這種情況下,集合中元素的順序很重要,因為它會影響您在哪一點超過小數精度。然后將添加剩余的元素,但不精確地最終導致不同的總數。
舉個例子,假設我的資料型別最多可以容納 4 個位置:
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)
uj5u.com熱心網友回復:
例如考慮從您的 json 0 和 22 索引的術語
decimal d00 = 10M * 206.000000M * 8.323300970873786407766990292M;
decimal d22 = 10.0M * 6.000000M * 24.166666666666666666666666667M;
decimal sum = d00 d22;
實際結果是(使用全精度計算器找到)
d00 = 17146.00000000000000000000000152 // 31
d22 = 1450.00000000000000000000000002 // 30
sum = 18596.00000000000000000000000154 // 31
但是你會失去精度,因為你看到d00應該有 31 個總數字等,并且僅限于decimal精度,c# 中的結果是
d00 = 17146.000000000000000000000002 // 29
d22 = 1450.0000000000000000000000000 // 29
sum = 18596.000000000000000000000002 // 29
所以這個任意和的誤差是0.000000000000000000000000046。隨著舍入的方式,錯誤將向上或向下舍入,具體取決于加法操作的順序(每一步舍入一種或另一種方式的可能性為 50%),因此您很可能最終得到不同的結果不同的訂單。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/422283.html
標籤:
上一篇:如何展開物件串列?
