为什么在宣布花车时需要“f”?

时间:2012-07-17 09:33:30

标签: c# floating-point

示例:

float timeRemaining = 0.58f;

为什么数字末尾需要f

3 个答案:

答案 0 :(得分:82)

您对浮动的声明包含两部分:

  1. 它声明变量timeRemaining的类型为float
  2. 它将值0.58分配给此变量。
  3. 问题出现在第2部分。

    右侧是自行评估的。根据C#规范,包含没有后缀的小数点的数字被解释为double

    因此,我们现在要将double值分配给float类型的变量。为此,必须进行从doublefloat的隐式转换。没有这样的转换,因为您可能(在这种情况下)会在转换中丢失信息。

    原因是编译器使用的值实际上不是0.58,而是最接近0.58的浮点值,对于double来说是0.57999999999999978655962351581366 ...而对于float来说恰好是0.579999946057796478271484375

    严格来说,f不是必需的。您可以通过将值转换为f来避免使用float后缀:

    float timeRemaining = (float)0.58;
    

答案 1 :(得分:35)

因为有几种数字类型,编译器可以使用它们来表示值0.58floatdoubledecimal。除非你对编译器选择一个你没问题,否则你必须消除歧义。

double的文档指出,如果您没有自己指定类型,编译器总是选择double作为任何实际数字文字的类型:

  

默认情况下,分配右侧的实际数字文字   运算符被视为double。但是,如果你想要一个整数   要被视为double,请使用后缀d或D.

附加后缀f会创建float;后缀d会创建double;后缀m会创建decimal。所有这些也都是大写的。

然而,这还不足以解释为什么不能编译:

float timeRemaining = 0.58;

答案中缺少的一半是从double 0.58float timeRemaining的转换可能会丢失信息,因此编译器拒绝隐式应用它。如果添加显式强制转换,则执行转换;如果添加f后缀,则不需要转换。在这两种情况下,代码都会编译。

答案 2 :(得分:2)

问题在于.NET,为了允许执行涉及floatdouble的某些类型的隐式操作,需要明确指定在涉及混合操作数的所有场景中应该发生什么或者只允许在一个方向上执行类型之间的隐式转换;微软选择遵循Java的主导,允许偶尔有利于精确度的方向,但经常牺牲正确性并且通常会造成麻烦。

在几乎所有情况下,获取最接近特定数字数量的double值并将其分配给float将产生最接近同一数量的float值。有一些极端情况,例如价值9,007,199,791,611,905;最好的float代表是9,007,200,328,482,816(减去536,870,911),但是向double投出最佳float代表(即9,007,199,791,611,904),收益率为9,007,199,254,740,992(减去536,870,913)。但是,一般情况下,将某些数量的最佳double表示转换为float会产生最佳的float表示形式,或者两种表示形式基本相同的表示形式之一。

请注意,这种理想的行为即使在极端情况下也适用;例如,数量10 ^ 308的最佳float表示与通过转换该数量的最佳float表示获得的double表示相匹配。同样,10 ^ 309的最佳float表示形式与通过转换该数量的最佳float表示形式所获得的double表示形式相匹配。

不幸的是,在不需要明确演员的方向上的转换很少接近准确。将值的最佳float表示转换为double很少会产生任何特别接近该值的最佳double表示的内容,并且在某些情况下,结果可能会被数百个订单所取消数量级(例如,将10 ^ 40的最佳float表示转换为double将产生一个比10 ^ 300的最佳double表示更高的值。

唉,转换规则就是它们,所以在转换“安全”方向的值时,必须使用愚蠢的类型转换和后缀,并注意在危险方向上的隐式类型转换,这往往会产生虚假的结果