在不损失精度的情况下安全地将 `float` 转换为 `double`

Safely convert `float` to `double` without loss of precision

我有以下令人头疼的东西,在 jshell 11.0.1217.0.1 此处演示

jshell> 13.9f
 ==> 13.9

jshell> 13.9
 ==> 13.9

jshell> (double) 13.9f
 ==> 13.899999618530273

在两个版本

中的简单编译class中发生了同样的事情
strictfp public class Test {

    public strictfp static void main(String[] args) {
        System.out.format("%s%n", (double) 13.9f);
        System.out.format("%s%n", 13.9f);
    }

}
╰─➤  java Test      
13.899999618530273
13.9

尽管 17 警告不再需要 strictfp

warning: [strictfp] as of release 17, all floating-point expressions are evaluated strictly and 'strictfp' is not required

JLS 在第 5.1.2 节中这样说

A widening primitive conversion does not lose information about the overall
magnitude of a numeric value in the following cases, where the numeric value is
preserved exactly:
• from an integral type to another integral type
• from byte, short, or char to a floating-point type
• from int to double
• from float to double

在 14 中,项目符号列表后包含以下内容

A widening primitive conversion from float to double that is not strictfp may
lose information about the overall magnitude of the converted value.

根据我的阅读,这是实现中的错误?我发现执行此转换的唯一可靠方法是 Double.parseDouble(Float.toString(13.9f)).

Based on my reading this is a bug in the implementation?

没有。这是您期望中的错误。您看到的 double 值与 float 值完全相同。精确值为13.8999996185302734375.

与“最接近 13.9 的 double 值”相同,即 13.9000000000000003552713678800500929355621337890625。

您将值 13.8999996185302734375 分配给 double 值,然后打印字符串表示形式 - 即 13.899999618530273,因为它的精度足以将其与其他 double 值完全区分开来。如果要打印 13.9,那 是一个错误,因为有一个 double 值更接近 13.9,即 13.9000000000000003552713678800500929355621337890625.