Skip to content

JEP 306: Restore Always-Strict Floating-Point Semantics | 恢复始终严格的浮点语义

摘要

使浮点运算始终保持严格,而不是既有严格浮点语义(strictfp)又有微妙不同的默认浮点语义。这将恢复语言和虚拟机中的原始浮点语义,与在 Java SE 1.2 中引入严格和默认浮点模式之前的语义相匹配。

目标

  • 简化对数值敏感的库的开发,包括 java.lang.Mathjava.lang.StrictMath

  • 在平台的棘手方面提供更多规律性。

非目标

定义任何形式的“快速浮点”或“宽松浮点”(参考 JSR 84: 浮点扩展)不是本项目的目标。

动机

上世纪 90 年代末,推动改变平台默认浮点语义的动因源于原始 Java 语言与 JVM 语义之间的不良交互,以及流行的 x86 架构中 x87 浮点协处理器指令集的一些不幸的特殊性。在所有情况下,包括次正规数和结果,匹配精确的浮点语义需要大量额外的指令开销。在没有溢出或下溢的情况下匹配结果可以以更小的开销实现,这大致就是 Java SE 1.2 中引入的修订后的默认浮点语义所允许的。

然而,从 2001 年左右开始,在奔腾 4 及后续处理器中推出的 SSE2(Streaming SIMD Extensions 2)扩展能够以直截了当的方式支持严格的 JVM 浮点运算,而不会造成不必要的开销。

由于英特尔和 AMD 都长期支持 SSE2 及后续扩展,这些扩展能够自然支持严格的浮点语义,因此,保留与严格浮点语义不同的默认浮点语义的技术动机已不复存在。

描述

本 JEP 将修改的接口包括 Java 语言规范中涉及的浮点表达式部分(请参阅 JLS 的第 4.2.3 节“浮点类型、格式和值”,第 5.1.13 节“值集转换”,第 15.4 节“FP-strict 表达式”,以及第 15 章后续部分中的许多小更新)和 Java 虚拟机规范 (JVMS 的类似部分,包括第 2.3.2 节“浮点类型、值集和值”,第 2.8.2 节“浮点模式”,第 2.8.3 节“值集转换”,以及对各个浮点指令的许多小更新)。将从 JLS 和 JVMS 中删除值集和值集转换的概念。JDK 中的实现更改将包括更新 HotSpot 虚拟机,以确保其永远不会在允许扩展指数值集的浮点模式下运行(此类模式对于 strictfp 操作是强制要求的),并更新 javac 以针对 strictfp 修饰符的不必要使用发出新的 lint 警告。

测试

由于此更改始终使用当前允许的操作模式之一,因此所有现有的数值测试都将保持有效。

现有的使用 strictfp 的 Java 源代码测试可以在不使用该修饰符的情况下进行复制。

风险与假设

所提议的规范变更风险较低,主要是删除文本并更新 JLS 和 JVMS 中的浮点概览。平台的原始语义得以恢复,且仅严格模式始终是允许的实现选项。因此,本 JEP 中的变更带来的行为兼容性风险可忽略不计。即使在可能出现非严格执行的平台上,也没有强制进行非严格评估的惯用方式。为了保持健壮性,代码必须能够在严格执行时正常工作,而这将再次成为唯一选项。