【发布时间】:2012-04-09 14:53:22
【问题描述】:
如果我正在使用double,并将其转换为float,这究竟是如何工作的?该值是否被截断以适合浮点数?或者值是否以不同的方式四舍五入?抱歉,如果这听起来有点补救,但我正在尝试掌握 float 和 double 转换的概念。
【问题讨论】:
标签: java floating-point double type-conversion
如果我正在使用double,并将其转换为float,这究竟是如何工作的?该值是否被截断以适合浮点数?或者值是否以不同的方式四舍五入?抱歉,如果这听起来有点补救,但我正在尝试掌握 float 和 double 转换的概念。
【问题讨论】:
标签: java floating-point double type-conversion
我建议将浮点类型最有用地视为表示值的范围。 0.1F显示为0.1而不是0.100000001490116119384765625,它确实代表了13421772.5/134217728到134217728到134217728到134217773.5/1342177728(I.00217728)在可能小于 0.100 时添加额外的数字表示该数字大于 0.100 是没有意义的,当它可能更大时使用表示该数字小于 0.100 的九进制字符串也是没有意义的。
将 double 转换为 float 将选择值范围包括 double 表示的 double 范围的 float。请注意,虽然此操作是不可逆的,但操作的结果通常在算术上是正确的;唯一一次不是 100% 算术正确的情况是,如果一个人正在铸造一个双精度浮点数,其范围恰好位于两个浮点数之间的边界上。在这种情况下,系统会选择双精度范围的一侧或另一侧的浮点数;如果双精度值实际上代表了范围错误一侧的数字,则生成的转换会稍微不准确。
实际上,上面提到的微小的不精确性几乎从不相关,因为浮点类型表示的“值范围”实际上比上面指出的要大一些。对具有一定不确定性的两个数字执行计算(例如加法)将产生具有更多不确定性的结果,但系统不会跟踪存在多少不确定性。尽管如此,除非对浮点数执行数十次操作,或对双精度数执行数千次操作,否则不确定性通常会小到不必担心。
重要的是要注意,将浮点数转换为双精度实际上比将双精度转换为浮点数更危险,尽管 Java 允许前者在没有警告的情况下隐含但对后者大喊大叫。将浮点数转换为双精度数会导致系统选择其范围以浮点数范围的中心为中心的双精度数。这几乎总是会导致一个值的实际不确定性远大于双精度数字的典型值。例如,如果将 0.1f 转换为 double,则生成的 double 将代表 0.10000000149011611 到 0.10000000149011613 范围内的数字,即使它应该代表的数字(十分之一)相对而言远不接近该范围。
【讨论】:
来自Java Language Specification, section 5.1.3:
从 double 到 float 的窄化原语转换受 IEEE 754 舍入规则 (§4.2.4) 的约束。这种转换可能会丢失精度,但也会丢失范围,从而导致非零双精度浮点数为零和有限双精度浮点数无穷大。双精度 NaN 转换为浮点 NaN,双无穷大转换为同符号浮点无穷大。
和section 4.2.4 说:
Java 编程语言要求浮点算术表现得好像每个浮点运算符都将其浮点结果四舍五入到结果精度。不精确的结果必须四舍五入到最接近无限精确结果的可表示值;如果两个最接近的可表示值同样接近,则选择其最低有效位为 0 的值。这是 IEEE 754 标准的默认舍入模式,称为“四舍五入”。
【讨论】:
RoundingMode 类,但我认为这只适用于BigDecimal 和BigInteger 操作,不适用于对原语的操作。但我对此不是 100% 有信心。