【问题标题】:As operation 'decimal' * 'decimal' result in a loss of precision but is authorized, why is the operation 'decimal' * 'double' forbidden?由于操作 'decimal' * 'decimal' 会导致精度损失但被授权,为什么禁止操作 'decimal' * 'double'?
【发布时间】:2015-02-11 00:47:41
【问题描述】:

我了解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' 是否有原因?

【问题讨论】:

    标签: c# floating-point


    【解决方案1】:

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

    技术上,从 decimaldouble 没有隐式转换(反之亦然,因此编译器无法为您转换;您需要显式转换操作数之一.

    逻辑上,您需要对最后一个进行强制转换,因为编译器需要知道 result 的类型。对于前三个,类型是明确的——它们都导致 decimal,因为从 intdecimal 的隐式转换。

    但是decimal * double 的结果应该是什么?根据您的需要,它可以是 decimaldouble。如果您将它分配给一个变量,那么编译器可以推断,但如果它是内联完成的呢? m * a + 1 的类型是什么?

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

    在处理利率、增值税率或一般利率时,对我来说,使用双精度值来存储这些值似乎更合乎逻辑

    为什么?为什么要将 0.10 的利率存储在一个不能准确存储 0.10 的类型中?

    decimal 应用于财务计算和其他需要保留小数表示的计算。

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

    【讨论】:

    • 嗯,其实这个var s = (double)(12.4m * 23.3d);也是被禁止的,虽然给出了结果。我认为这是关于告诉编译器如何进行计算。
    • @TaW 这更有可能是由于子表达式 (12.4m * 23.3d) 由于此答案中给出的原因而失败
    • 感谢您的详细回答。关于我想存储的费率,它可以是像 '1/3 = 0.3333...' 这样的东西,既不能用小数精确存储,也不能用双精度存储。
    • @TaW:作为设计理念,C# 不允许使用表达式的方式影响对其求值的方式。例如,给定Int32 Million = 1000000; Int64 Trillion = Million * Million;,在未检查的上下文中,结果将是 -727379968,在检查的上下文中将是溢出异常,但在任何情况下都不会是算术正确的 1000000000000,即使编译器并不难认识到该产品被立即用作Int64 值。
    猜你喜欢
    • 2017-03-18
    • 2023-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 2017-02-12
    • 2012-09-10
    • 1970-01-01
    相关资源
    最近更新 更多