首页 > 解决方案 > 匹配优于 C# 应用程序中的舍入

问题描述

我目前正在将用于计算科学值的相当高的 Excel 工作表转换为 C# 应用程序。但是,我在四舍五入方面遇到了一些问题。

我所有的值都存储为双精度值,当您对它们执行少量操作时,它们在可接受的精度(5 或 6 个小数位)内匹配 excel 表。当他们通过除法,乘法,平方根进行相当大的运算时。他们开始以相当大的幅度漂移。我在另一个点将整个代码库切换为小数,以测试它是否解决了这个问题,它缩小了差距,但问题仍然存在。

我知道这是由于软件开发中十进制数的性质,但我必须尽可能匹配 excel 的舍入。对这个主题的研究将我指向 excel 用于舍入的标准,而且 C# 默认情况下使用的标准似乎略有不同。尽管了解了这一点,但我仍然不确定如何继续复制 excels 舍入。我想知道是否有人对此主题有任何建议或以前的经验?

任何帮助将不胜感激。

编辑:我只想澄清一下,我并没有四舍五入我的数字。工作表和我的代码上的舍入都被隐式应用。我在一个完全不同的软件包(一个名为 K2 的表单生成器)中测试了相同的公式。结果数字与我的 c# 应用程序匹配,因此它似乎擅长隐式舍入在某些方面有所不同。

有问题的公式之一:

(8.04 * Math.Pow(10, -5)) *
(Math.Pow(preTestTestingDetails.PitotCp, 2)) * (DeltaH) *
(tempDGMAverage + 273.0) / 
(StackTemp + 273) * 
((preTestTestingDetails.BarometricPressure / 0.133322 + 
((preTestTestingDetails.StackStaticPressure / 9.80665) / 13.6)) /
(preTestTestingDetails.BarometricPressure / 0.133322)) * 
(preTestTestingDetails.EstimatedMolWeight / 
((preTestTestingDetails.EstimatedMolWeight * (1 - (EstimatedMoisture / 100))) +
(18 * (EstimatedMoisture / 100)))) *
Math.Pow((1 - (EstimatedMoisture / 100)), 2) * 
(Math.Pow(preTestTestingDetails.NozzleMean, 4));

标签: c#excelwpfmath

解决方案


在 C# 中的结果

int x = 5;
var result = x / 2; // result is 2 and of type int

...因为执行整数除法。因此,如果涉及整数(不是double没有小数的 a,而是intor类型的值long),请确保double在除法之前转换为。

int x = 5;
double result = x / 2; // result is 2.0 because conversion to double is made after division

这有效:

int x = 5;
var result = (double)x / 2; // result is 2.5 and of type double
int x = 5;
var result = x / 2.0; // result is 2.5 and of type double
int x = 5;
var result = 0.5 * x; // result is 2.5 and of type double

公式中唯一可能发生这种情况的地方是EstimatedMoisture / 100,如果EstimatedMoisture是类型int。如果是这种情况,请使用 修复它EstimatedMoisture / 100.0

代替8.04 * Math.Pow(10, -5),你可以写8.04e-5。这避免了Math.Pow!的舍入效应

我不知道如何Math.Pow(a, b)工作,但一般公式是a^b=exp(b*ln(a)). 所以与其写Math.Pow(something, 2),不如写something * something。这既更快又更准确。

对幻数使用常量可以增加清晰度。对常见的子表达式使用 temps 可使公式更具可读性。

const double mmHg_to_kPa = 0.133322;
const double g0 = 9.80665;

var p = preTestTestingDetails;
double moisture = EstimatedMoisture / 100.0;
double dryness = 1.0 - moisture;
double pressure_mmHg = p.BarometricPressure / mmHg_to_kPa;
double nozzleMean2 = p.NozzleMean * p.NozzleMean;
double nozzleMean4 = nozzleMean2 * nozzleMean2;

double result = 8.04E-05 *
    p.PitotCp * p.PitotCp * DeltaH * (tempDGMAverage + 273.0) / (StackTemp + 273.0) *
    ((pressure_mmHg + p.StackStaticPressure / g0 / 13.6) / pressure_mmHg) *
    (p.EstimatedMolWeight / (p.EstimatedMolWeight * dryness + 18.0 * moisture)) *
    dryness * dryness * nozzleMean4;

如果需要考虑精度,为什么不使用 273.15 而不是 273.0?


推荐阅读