价格联动计算精度异常求助:输入零售价后数值偏差
问题分析与解决方案
问题根源
精度偏差的核心原因是多次链式调用Math.Round导致误差累积:
- 从零售价反向计算时,先将批发价四舍五入到两位小数,再用这个已丢失精度的批发价计算成本价并再次四舍五入,两次舍入的微小误差叠加后,最终结果偏离了原始值。
- 部分计算中使用整数运算(如
100+15),触发隐式类型转换,也会引入额外精度风险。
修复方案
核心思路:仅在最终赋值给实体字段时进行一次四舍五入,中间计算保留完整的decimal精度,避免链式舍入的误差累积。同时统一使用decimal类型字面量(加m后缀),消除整数运算的隐式转换问题。
修改后的代码示例
private decimal CostPrice { get => SelectedItem.Cost; set { SelectedItem.Cost = value; // 先计算高精度批发价,不提前round decimal wholesalePrice = (((SelectedItem.Cost + SelectedItem.Transport + SelectedItem.RoyaltyMarket + SelectedItem.DelStrand) / (1 - SelectedItem.Margin) * (1 + SelectedItem.AdjPercentage)) + SelectedItem.Levy); SelectedItem.WholesalePrice = Math.Round(wholesalePrice, 2); // 用高精度批发价计算零售价,最后统一round decimal retailPrice = ((wholesalePrice / (1m - 0.23m)) * (100m + 15m) / 100m) / SelectedItem.StockUom; SelectedItem.RecRetailPrice = Math.Round(retailPrice, 2); } } private decimal WholesalePrice { get => SelectedItem.WholesalePrice; set { SelectedItem.WholesalePrice = value; decimal retailPrice = ((value / (1m - 0.23m)) * (100m + 15m) / 100m) / SelectedItem.StockUom; SelectedItem.RecRetailPrice = Math.Round(retailPrice, 2); // 用原始输入的批发价直接计算成本,中间不做round decimal costPrice = (((value - SelectedItem.Levy) / (1m + SelectedItem.AdjPercentage)) * (1m - SelectedItem.Margin) - SelectedItem.Transport - SelectedItem.RoyaltyMarket - SelectedItem.DelStrand); SelectedItem.Cost = Math.Round(costPrice, 2); } } private decimal RecRetailPrice { get => SelectedItem.RecRetailPrice; set { SelectedItem.RecRetailPrice = value; // 计算高精度批发价,不提前round decimal wholesalePrice = ((value * (1m - 0.23m)) / (100m + 15m) * 100m) * SelectedItem.StockUom; SelectedItem.WholesalePrice = Math.Round(wholesalePrice, 2); // 直接用高精度批发价计算成本,避免依赖已round的中间值 decimal costPrice = (((wholesalePrice - SelectedItem.Levy) / (1m + SelectedItem.AdjPercentage)) * (1m - SelectedItem.Margin) - SelectedItem.Transport - SelectedItem.RoyaltyMarket - SelectedItem.DelStrand); SelectedItem.Cost = Math.Round(costPrice, 2); } }
额外优化建议
- 将重复的计算逻辑(如成本转批发价、批发价转成本价等)提取为独立私有方法,减少代码冗余,方便后续维护。
- 确认
SelectedItem中的所有价格相关字段均为decimal类型,避免使用float/double这类浮点类型带来的精度损失。
内容的提问来源于stack exchange,提问作者xotokai
相关产品推荐
相关产品推荐

