例子:
float timeRemaining = 0.58f;
为什么f
在这个数字的末尾是必需的?
Your declaration of a float contains two parts:
timeRemaining
is of type float
.0.58
to this variable.The problem occurs in part 2.
The right-hand side is evaluated on its own. According to the C# specification, a number containing a decimal point that doesn't have a suffix is interpreted as a double
.
So we now have a double
value that we want to assign to a variable of type float
. In order to do this, there must be an implicit conversion from double
to float
. There is no such conversion, because you may (and in this case do) lose information in the conversion.
The reason is that the value used by the compiler isn't really 0.58, but the floating-point value closest to 0.58, which is 0.57999999999999978655962351581366... for double
and exactly 0.579999946057796478271484375 for float
.
Strictly speaking, the f
is not required. You can avoid having to use the f
suffix by casting the value to a float
:
float timeRemaining = (float)0.58;
因为编译器可以使用几种数字类型来表示值0.58
:float
和. 除非您对编译器为您选择一个没问题,否则您必须消除歧义。double
decimal
的文档double
指出,如果您自己不指定类型,编译器总是选择double
任何实数值文字的类型:
默认情况下,赋值运算符右侧的实数文字被视为双精度值。但是,如果您希望将整数视为双精度数,请使用后缀 d 或 D。
附加后缀f
会创建一个float
; 后缀d
创建一个double
; 后缀m
创建一个decimal
. 所有这些也都以大写形式工作。
但是,这仍然不足以解释为什么它不能编译:
float timeRemaining = 0.58;
答案中缺少的一半是从double
0.58
到的转换float
timeRemaining
可能会丢失信息,因此编译器拒绝隐式应用它。如果添加显式转换,则会执行转换;如果添加f
后缀,则无需转换。在这两种情况下,代码都会编译。
问题是.NET,为了允许执行某些类型的隐式操作,涉及float
和double
,需要明确指定在涉及混合操作数的所有场景中应该发生什么,或者允许在一个类型之间执行隐式转换只有方向;微软选择跟随 Java 的领导,允许偶尔偏爱精确但经常牺牲正确性并且通常会产生麻烦的方向。
在几乎所有情况下,取double
最接近特定数字量的值并将其分配给 afloat
将产生float
最接近该相同量的值。有一些极端情况,例如值 9,007,199,791,611,905;最佳float
表示将是 9,007,200,328,482,816(相差 536,870,911),但将最佳double
表示(即 9,007,199,791,611,904)转换为float
9,007,199,254,740,992(相差 536,870,913)。但是,一般而言,将double
某个数量的最佳表示转换为float
将产生可能的最佳float
表示,或者是本质上同样好的两种表示之一。
请注意,这种理想的行为即使在极端情况下也适用;例如,float
数量 10^308的最佳表示与float
通过转换该double
数量的最佳表示所获得的表示相匹配。同样,float
10^309 的最佳表示与float
通过转换该double
数量的最佳表示所获得的表示相匹配。
不幸的是,在不需要显式转换的方向上的转换很少能接近准确。float
将一个值的最佳表示转换为double
很少会产生特别接近double
该值的最佳表示的任何东西,并且在某些情况下,结果可能会相差数百个数量级(例如,将float
10^40 的最佳表示转换为double
将产生比较大于double
10^300 的最佳表示的值。
唉,转换规则就是这样,所以在“安全”方向转换值时,必须忍受使用愚蠢的类型转换和后缀,并小心在危险方向上的隐式类型转换,这会经常产生虚假结果。