为什么乘以双精度时有不同的输出

本文关键字:输出 双精度 为什么 | 更新日期: 2023-09-27 18:32:08

假设我有以下内容:

double f;
double c = 5;
Console.WriteLine("{0} | {1}", c, f = 9 / 5 * c + 32);

这将给出输出:5 | 37

同时:

double f;
double c = 5;
Console.WriteLine("{0} | {1}", c, f = 9.0 / 5.0 * c + 32);

将给出正确的输出:5 | 41(表示 5 摄氏度是多少华氏度)

我知道我正在与双倍工作,但我缺乏洞察力,为什么两种结果彼此不等同?

为什么乘以双精度时有不同的输出

使用整数语法(9 而不是 9.0)时,每个操作都四舍五入,不带小数

因为 C 语言 [本质上] 被设计为一种与硬件无关的汇编语言。因此,除法,除非涉及浮点值是整数除法,否则CPU将在单个指令中完成。这意味着像这样的表达式:

int x = 9 ;
int y = 5 ;
int z = x / y ;

这通常会编译为单个机器指令(可能与其他机器指令一起将值加载/存储到寄存器/从寄存器加载/存储值,其最终结果是商和余数。因此,上述int z = x / y将解析为 1 ,将4的其余部分留在表中(请注意,如果需要余数,请使用 % 运算符:int z = x % y产生预期的4

如果其中一个操作数是浮点值,则使用浮点除法(从计算角度来说,成本很高)。

由于 C# 继承自该旧版,因此它的行为方式相同。因此,该标准的§14.7.2说

14.7.2 除法运算符

对于形式为 x / y 的操作,应用二进制运算符重载解析 (§14.2.4) 以选择特定的运算符实现。操作数将转换为参数类型 所选运算符,结果的类型是运算符的返回类型。

下面列出了预定义的除法运算符。 运算符都计算 xy 的商。

  • 整数除法:

    int   operator /( int   x, int   y );
    uint  operator /( uint  x, uint  y );
    long  operator /( long  x, long  y );
    ulong operator /( ulong x, ulong y );
    void  operator /( long  x, ulong y );
    void  operator /( ulong x, long  y );
    

具有返回类型的运算符void始终生成编译时错误。因此 一个操作数的类型为 long,另一个操作数的类型为 ulong 是错误的。

如果右操作数的值为零,则抛出System.DivideByZeroException

除法将结果四舍五入为零,结果的绝对值为 小于 的商的绝对值的最大可能整数 两个操作数。当两个操作数具有相同的操作数时,结果为零或正数 当两个操作数具有相反的符号时,符号和零或负数。

如果左操作数是最小的intlong值(−231 或 −263, 分别)并且右操作数–1,则发生溢出。在checked的背景下,这 导致抛出System.ArithmeticException(或其子类)。在unchecked 上下文,它是实现定义的,即System.ArithmeticException(或 其子类)被抛出或溢出未报告,结果值为 的左操作数。

[省略浮点和小数除法的讨论]

这就是原因。