欢迎来到“Under The Hood”第四期。上期我们讨论了JVM的字节码指令集,本期我们继续这个话题。本文我们来看看JVM中的浮点运算。
JVM支持IEEE-754浮点数标准(1985)。该标准定义了32位和64位浮点数的格式,以及在此之上的各种运算。在JVM中,浮点运算是基于32位float数和64位double数的。对每个操作float数的字节码,都有一个对应的操作double数的版本。
浮点数由4部分组成:数符(sign),尾数(mantissa),基数(radix)和阶码(exponent)。数符取1或-1。尾数是一个正数,它持有浮点数的有效位。阶码是尾数和符号位应该乘以的基数的正(负)幂数。这4个部分用下面的公式得到浮点数的值:
sign * mantissa * radixexponent |
浮点数有很多种表现形式,因为你总是可以把浮点数的尾数乘以基数的某次幂,然后通过改变阶码的方式获得原先的值。例如,-5可以写成如下以10为基数的形式:
Sign | Mantissa | Radix | Exponent |
-1 | 50 | 10 | -1 |
-1 | 5 | 10 | 0 |
-1 | 0.5 | 10 | 1 |
-1 | 0.05 | 10 | 2 |
每个浮点数都有一个规范化的表示形式。如果浮点数的尾数符合下面的公式,我们就说这个浮点数是规范化的。
1/radix <= mantissa < 1 |
规范化的以10为基数的浮点数,尾数的小数点出现在第一个非0的有效位前面。-5的规范化形式是-1*0.5*10 1。也就是说,规范化的浮点数中,小数点的左边是0,右边第一位不是0。其他不是这种形式的浮点数都是非规范化数。注意,0没有规范化的形式,因为它没有非0数放在小数点后面。数字0们总是感叹“为什么要规范化我们呢?”。
JVM中的浮点数以2为基数,所以JVM中的浮点数值用下面的公式获得:
sign * mantissa * 2exponent |
JVM中的浮点数的尾数用2进制数表示。规范化的二进制数小数点出现在非0最高有效位前面。由于二进制数系统只有2个数字,1和0,所以最高有效位上的数字总是1。
float和double数的最高有效位是它的符号位,float的最后23位是尾数位,而double则为最后52位。阶码处在符号位和尾数中间,float为8位,double为11位。float的完整2进制形式如下,s表示符号位,e表示阶码,m表示尾数。
s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm |
正数的符号位为0,负数的符号位为1。尾数总是一个正的二进制数,但不是二进制补码数。如果符号位为1,浮点数的值是负的,但尾数仍然是正的。
阶码有3种解释方式。如果阶码位全是1,意味着这是一个特殊的浮点数,表示正无穷或负无穷,或者不是一个数(NaN)。NaN是特定运算的结果,比如除法的除数是0。阶码的所有位为0,表示这是一个非规范化的浮点数。除上面2种情况之外的阶码,都是规范化浮点数的一部分。
尾数部分其实隐式包含了一个额外的精度位。float数的尾数占23位,却有24个精度位;同一样的,double数的尾数占52位,却有53个精度位。因为尾数部分的最高有效位是可以被预测的,所以并没有包含在尾数中。JVM中,浮点数的阶码可以指明该数是不是一个规范化浮点数。如果阶码位全0,则为非规范化数,且最高有效位肯定是0。其他情况下,则为规范化浮点数,且最高有效位肯定是1。
在JVM中,任何浮点运算都不会抛出异常。类似除数为0的问题操作,JVM会返回一些特殊值,比如正/负无穷,或NaN。尾数位全是0的情况下,如果阶码位全是1,符号位是0,则表示正无穷;如果阶码位全是1,符号位是1,则表示负无穷。如果阶码位全是1,尾数位不全是0,则表示NaN。JVM总是为NaN使用相同的尾数:最高有效位是1,其他全为0。下表列出了上面提到的3中特殊值:
Special float values | Float bits (sign exponent mantissa) |
+Infinity | 0 11111111 00000000000000000000000 |
-Infinity | 1 11111111 00000000000000000000000 |
NaN | 1 11111111 10000000000000000000000 |
非全0和非全1的阶码表示规范化尾数要乘以的2的幂数。可以把阶码当做一个正数,然后减去一个偏移量,这样就能得到实际的幂数。对float数来说,偏移量是126;而double数,则为1023。例如,一个float数的阶码为00000001,则幂数为-125(1 – 126),这是float中最小的幂数。再看一个例子,如果阶码是11111110,则幂数为128(254 – 126),这是float中最大的幂数。下表列出了一些正规化的浮点数:
Normalized float values | Float bits (sign exponent mantissa) | Unbiased exponent |
Largest positive (finite) float | 0 11111110 11111111111111111111111 | 128 |
Largest negative (finite) float | 1 11111110 11111111111111111111111 | 128 |
Smallest normalized float | 1 00000001 00000000000000000000000 | -125 |
Pi | 0 10000000 10010010000111111011011 | 2 |
阶码位全0,说明尾数没有规范化,也隐含说明了最高有效为是0,而不是1。这种情况下,幂数为浮点数的最小幂数。对float来说,是-125。这意味着,规范化尾数乘以2 -125的浮点数,它的阶码为00000001,而非规范化尾数乘以2 -125的浮点数,它的阶码为00000000。阶码范围底端的非规范化数修正值,使得下溢出较为平缓。如果最小阶码用来表示规范化数,下溢成0的最小数值会更大一些。 换句话说,让最小阶码表示非规范化数,可以使浮点数能表示更小的数值。虽然非规范化数的精度没有规范化数高,但是,这相对于阶码一旦达到最小规范化数值,浮点数就会下溢成0来说,非规范化数更好一些。
Denormalized float values | Float bits (sign exponent mantissa) |
Smallest positive (non-zero) float | 0 00000000 00000000000000000000001 |
Smallest negative (non-zero) float | 1 00000000 00000000000000000000001 |
Largest denormalized float | 1 00000000 11111111111111111111111 |
Positive zero | 0 00000000 00000000000000000000000 |
Negative zero | 1 00000000 00000000000000000000000 |
相关推荐
标题中提到了JVM原理、JVM调优、JVM内存模型和JAVA并发,这些都是Java虚拟机(JVM)相关的核心概念。JVM是运行Java字节码的虚拟计算机,为Java提供了一个跨平台的环境,确保Java程序可以在不同的操作系统上运行而...
Java虚拟机(JVM)是Java程序运行的核心,它负责解释和执行字节码,为Java应用程序提供了一个跨平台的运行环境。JDK(Java Development Kit)包含了开发和运行Java程序所需的所有工具,包括JVM。当我们谈论"jdk,jvm...
JVM指令码表,JVM运行原理学习的必备工具。常量入栈指令、局部变量值转载到栈中指令、将栈顶值保存到局部变量中指令、wide指令、通用(无类型)栈操作指令、类型转换指令、整数运算、浮点运算等指令。
- JVM指令是字节码,每条指令对应一个特定的操作,如加载和存储变量、算术运算、控制流程、对象创建和方法调用等。 - 指令手册会列出所有这些指令,比如`iconst_5`表示将整数5压入操作数栈,`aload_0`用于将局部...
Java虚拟机(JVM)是Java程序运行的基础,它是一个抽象的计算机系统,负责执行Java字节码。本文将深入探讨JVM的启动过程及其基本原理。 首先,我们需要理解JVM的基本概念。JVM是Java Virtual Machine的缩写,它是...
### JVM 详细介绍:掌握 JVM 的各个组成部分与功能 #### 一、Java 源文件编译及执行 Java 应用程序的核心在于源文件的编译与执行。不同于 C/C++ 这类需要针对不同平台进行编译的语言,Java 采用了一种更为灵活的...
SAP JVM 8.1 64位是一个专为SAP系统设计的Java虚拟机,它基于Oracle的Java Development Kit (JDK) 进行优化,以满足SAP应用程序的特定需求。SAP JVM旨在提高性能、可靠性和安全性,同时确保与SAP产品的无缝集成。...
JVM(Java Virtual Machine,Java虚拟机)是运行所有Java程序的假想计算机,是Java程序的运行环境,负责执行指令、管理数据、内存、寄存器等,是实现Java跨平台特性的关键部分。JVM指令手册详细记录了JVM的所有操作...
【狂神说JVM探究】是一份集合了多种格式的学习资料,主要涵盖了Java虚拟机(JVM)的基础知识。这份资料出自B站上的【狂神说Java】系列教程,为快速入门JVM提供了详实的笔记。以下是根据这些资源可能包含的一些关键...
Java虚拟机(JVM)是Java程序运行的核心组件,它负责解释和执行字节码,为开发者提供了跨平台的运行环境。"jvm视频及笔记"这个资源显然是一份全面学习JVM的材料,结合了视频教程和书面笔记,帮助学习者深入理解JVM的...
### JVM必知必会知识点梳理 #### 1. JVM的定义与层次 Java虚拟机(JVM)具有多重含义: - **一套规范**:即Java虚拟机规范,定义了Java虚拟机应该具有的行为。 - **一种实现**:例如HotSpot、J9、JRockit,它们都是...
【jvm-mon基于控制台的JVM监视】 `jvm-mon`是一款实用的工具,它允许开发者通过控制台界面实时监控Java虚拟机(JVM)的状态。在Java开发过程中,性能分析是至关重要的,因为良好的性能能提升用户体验,降低服务器...
JVM 输出 GC 日志导致 JVM 卡住 JVM 输出 GC 日志导致 JVM 卡住是一个常见的问题,尤其是在高并发和高性能应用中。这个问题的根源在于 JVM 的垃圾回收机制(Garbage Collection,GC),它会在 JVM 运行时周期性地...
46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT...
在Java开发领域,JVM(Java Virtual Machine)是运行所有Java程序的核心,它负责解析字节码并执行程序。深入理解JVM的内核原理、诊断技巧以及优化方法对于提升应用性能至关重要。本教程——“深入JVM内核—原理、...
- **数据操作指令**:包括加载(如`iload`、`fload`用于加载局部变量表中的整型和浮点型数据)、存储(如`istore`、`fstore`用于存储数据回局部变量表)、算术运算(如`iadd`、`imul`执行加法和乘法)和类型转换...
### 深入解析JVM:Java虚拟机的精髓与挑战 #### JVM概览与重要性 JVM,即Java Virtual Machine(Java虚拟机),是Java程序员必须掌握的核心技术之一。初学者通常从简单的“HelloWorld”程序开始,逐渐接触更复杂的...
JVM(Java虚拟机)是Java语言运行的基础,它负责执行Java字节码,并且是Java跨平台特性的关键实现。JVM的主要职责包括加载Java程序、验证字节码、将字节码转换成机器码执行、内存管理、垃圾回收和提供安全机制等。...
3. **算术运算指令**:包括加减乘除等基本数学运算,如`iadd`表示整数加法,`imul`表示整数乘法,这些指令在执行计算时会使用操作数栈。 4. **类型转换指令**:Java是一种强类型语言,不同数据类型的转换需要特定...
JVM指令集分为五大类:整数运算指令、浮点运算指令、对象处理指令、控制转移指令和本地变量操作指令。每条指令都有其特定的功能,它们共同构成了Java程序在JVM上运行的基石。 1. **整数运算指令**:这类指令主要...