如果我正在使用 a double
,并将其转换为 a float
,这究竟是如何工作的?该值是否被截断以适合浮点数?或者值是否以不同的方式四舍五入?对不起,如果这听起来有点补救,但我试图掌握float
和double
转换的概念。
2 回答
从 double 到 float 的窄化原语转换受 IEEE 754 舍入规则 (§4.2.4) 的约束。这种转换可能会丢失精度,但也会丢失范围,从而导致非零双精度浮点数为零和有限双精度浮点数无穷大。双精度 NaN 转换为浮点 NaN,双无穷大转换为同符号浮点无穷大。
第4.2.4 节说:
Java 编程语言要求浮点算术表现得好像每个浮点运算符都将其浮点结果四舍五入到结果精度。不精确的结果必须四舍五入到最接近无限精确结果的可表示值;如果两个最接近的可表示值同样接近,则选择其最低有效位为零的值。这是 IEEE 754 标准的默认舍入模式,称为“四舍五入”。
I would suggest that floating-point types are most usefully regarded as representing ranges of values. The reason that 0.1f displays as 0.1 rather than as 0.100000001490116119384765625 is that it really represents the range of numbers from 13421772.5/134217728 to 13421773.5/134217728 (i.e. from 0.0999999977648258209228515625 to 0.1000000052154064178466796875); it wouldn't make sense to add extra digits indicating the number is greater than 0.100 when it might be less, nor to use a string of nines indicating the number is less than 0.100 when it might be greater.
Casting a double to a float will select the float whose range of values includes the range of doubles represented by the double. Note that while this operation is non-reversible, the result of the operation will generally be arithmetically correct; the only time it would not be 100% arithmetically correct would be if one were casting to float a double whose range was precisely centered on the boundary between two floats. In that situation, the system would select the float on one side or the other of the double's range; if the double in fact represented a number on the wrong side of the range, the resulting conversion would be slightly inaccurate.
In practice, the tiny imprecision mentioned above is almost never relevant, because the "range of values" represented by a floating-point type is in practice a little larger than indicated above. Performing a calculation (such as addition) on two numbers that have a certain amount of uncertainty will yield a result with more uncertainty, but the system won't keep track of how much uncertainty exists. Nonetheless, unless one performs dozens of operations on a float, or thousands of operations on a double, the amount of uncertainty will usually be small enough not to worry about.
It's important to note that casting a float to a double is actually far more dangerous operation than casting double to float, even though Java allows the former implicitly without a warning but squawks at the latter. Casting a float to a double causes the system to select the double whose range is centered about the center of the float's range. This will almost always result in a value whose actual uncertainty is far greater than would be typical of double-precision numbers. For example, if one casts 0.1f to double, the resulting double will represent a number in the range 0.10000000149011611 to 0.10000000149011613, even though the number it's supposed to be representing (one tenth) is, relatively speaking, nowhere near that range.