由于操作'十进制'*'十进制'导致精度损失但被授权,为什么禁止操作'十进制'*'双'?

时间:2015-02-10 16:06:37

标签: c# floating-point

我理解decimal是一种适用于金融和金钱的数字格式,因为它具有固定的精确度。

因此,当加入或减去两个decimals时,永远不会有精度损失。

考虑到这一点,我可以理解编译器必须禁止操作'decimal'+'double',因为可能会丢失精度。

但是当你乘以(或除以)两个decimals时会发生什么?

让我们考虑一个简单的十进制类型,总共只有4位数,小数点后的精度为2位数(从00.00到99.99)。

您可以定义a = 0.01

然后m = a * a = 0.0001,被截断为0.00,因此精度会下降。

尽管精度不高,但编译器认为此操作是合法的。

所以我们在C#中有以下案例:

  • decimal / int:尽管精度不合法仍然合法
  • decimal / decimal:尽管精度不合法仍然合法
  • decimal * decimal:尽管精度不合法仍然合法
  • decimal * double:非法

(当然,您总是可以使用强制转换覆盖,但此解决方案对我来说并不令人满意。)

还有其他原因我不知道要解释吗?

在处理利率,增值税税率或一般税率时,使用双倍来存储这些值似乎更合乎逻辑,然后能够使用小数。 但我必须在两者之间做出选择:

  • 使用decimal(过度杀伤)存储费率。
  • 使用double然后投射(丑陋)来存储费率。

考虑到所有这些,我的问题是:

有没有理由为C#编译器禁止'decimal'*'double'?

1 个答案:

答案 0 :(得分:1)

decimal multiplication (*) operator 采用decimal类型的操作数。但是,存在从intdecimal的隐式转换,因此编译器会为您int投射decimal

技术上,没有从decimaldouble的隐式演员(反之亦然,所以编译器不能为你演员;你需要明确演员其中一个操作数。

逻辑,您需要在最后一个上进行强制转换,因为编译器需要知道结果的类型。对于前三个类型,类型很明确 - 由于decimalint的隐式转换,它们都会产生decimal

decimal * double的结果应该是什么?它可以是decimaldouble,具体取决于您的需求。如果你将它分配给一个变量,那么编译器可以推断出来,但如果它是内联的呢? m * a + 1的类型是什么?

所以你需要一个强制转换来告诉编译器结果类型是什么。

  

在处理利率,增值税率或一般税率时,使用双倍来存储这些值似乎更合乎逻辑

为什么呢?为什么在无法正确存储0.10 的类型中存储0.10的利率?

decimal应该用于财务计算和其他需要保留十进制再次激活的计算。

double应该用于不精确的科学测量(温度,距离)和其他计算,其中速度比十进制表示的准确性更重要。