示例:
float timeRemaining = 0.58f;
为什么数字末尾需要f
?
答案 0 :(得分:82)
您对浮动的声明包含两部分:
timeRemaining
的类型为float
。0.58
分配给此变量。问题出现在第2部分。
右侧是自行评估的。根据C#规范,包含没有后缀的小数点的数字被解释为double
。
因此,我们现在要将double
值分配给float
类型的变量。为此,必须进行从double
到float
的隐式转换。没有这样的转换,因为您可能(在这种情况下)会在转换中丢失信息。
原因是编译器使用的值实际上不是0.58,而是最接近0.58的浮点值,对于double
来说是0.57999999999999978655962351581366 ...而对于float
来说恰好是0.579999946057796478271484375
严格来说,f
不是必需的。您可以通过将值转换为f
来避免使用float
后缀:
float timeRemaining = (float)0.58;
答案 1 :(得分:35)
因为有几种数字类型,编译器可以使用它们来表示值0.58
:float
,double
和decimal
。除非你对编译器选择一个你没问题,否则你必须消除歧义。
double
的文档指出,如果您没有自己指定类型,编译器总是选择double
作为任何实际数字文字的类型:
默认情况下,分配右侧的实际数字文字 运算符被视为double。但是,如果你想要一个整数 要被视为double,请使用后缀d或D.
附加后缀f
会创建float
;后缀d
会创建double
;后缀m
会创建decimal
。所有这些也都是大写的。
然而,这还不足以解释为什么不能编译:
float timeRemaining = 0.58;
答案中缺少的一半是从double
0.58
到float
timeRemaining
的转换可能会丢失信息,因此编译器拒绝隐式应用它。如果添加显式强制转换,则执行转换;如果添加f
后缀,则不需要转换。在这两种情况下,代码都会编译。
答案 2 :(得分:2)
问题在于.NET,为了允许执行涉及float
和double
的某些类型的隐式操作,需要明确指定在涉及混合操作数的所有场景中应该发生什么或者只允许在一个方向上执行类型之间的隐式转换;微软选择遵循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
表示更高的值。
唉,转换规则就是它们,所以在转换“安全”方向的值时,必须使用愚蠢的类型转换和后缀,并注意在危险方向上的隐式类型转换,这往往会产生虚假的结果