java基础之float、double底层运算
2016-09-21 10:46
246 查看
目前java遵照IEEE制定的浮点数表示法来进行float,double运算。这种结构是一种科学计数法,用符号、指数和尾数来表示,底数定为2——即把一个浮点数表示为尾数乘以2的指数次方再添上符号。 我们来看一段java代码:
IEEE浮点数表示标准:V = (-1)s×M×2E E = e-Bias其中Bias表示偏移量,float的偏移量为Bias=2k-1-1=28-1-1=127,double的偏移量为Bias=210-1=1023浮点数在计算机中存储时,按照二进制科学计数法拆分为三个部分:符号位、指数部分和尾数部分。如下图所示:
存储时,按照最高位存储符号位,次高位存储指数部分,低位存储尾数部分的次序存储。存储时的排列示意图如下:
float类型的内存分布如下图所示:
double类型的内存分布如下图所示:
编码规则在实际存储时要对使用二进制科学计数法表示的浮点数值的符号位、指数部分和尾数部分进行编码处理。一般需要分为规约形式的浮点数、非规约形式的浮点数和特殊值三种类型进行编码。其编码前后处理如下图所示:
注:非规约浮点数主要用于扩大0值附近的浮点数表示范围,非规约浮点数的绝对值均小于规约浮点数的绝对值,即前者在实数轴上更靠近0,这样可以提高0附近的计算精度;一般C、C++中float和double的取值范围都是按照规约浮点数定义的,MSDN文档和相关教材也是这么说的,但部分编译器按照ANSI/IEEE Std 754-1985标准实现了非规约浮点数,本文末尾留有程序示例说明。符号位:0表示正数,1表示负数;指数部分: float的偏移量为2^8 - 1,double的偏移量为2^11 - 1;尾数部分:实际尾数部分中的小数点后的数值,规约浮点数使用标准的二进制科学计数法表示,其尾数范围在 [1,2),非规约浮点数的尾数部分范围在(0,1)。上面的理论在哪里都能看到,这只是IEEE754的定义而已,我们来实际用一下它是怎么表达小数的:
①求单精度8.5f 的二进制 过程。首先8.5是正数所以符号位为0;然后化为二进制,1*2^3+0*2^2+0*2^1+0*2^0 (整数部分) . (小数点) 1*2^-1小数部分简化为1000.1要把二进制数变成(1.f)*2^(exponent)的形式,其中exponent是指数即1.0001*2^3.然后我们得到阶码为e=3+127=130 即阶码表示二进制为10000010.
余下小数0001,我们补齐至23位即00010000000000000000000。
这样符合结构 符号位 0 阶码 10000010 尾数00010000000000000000000
然后我们来看一下8.5存储在内存中01000001000010000000000000000000
因为java.lang.Integer.toBinaryString() 方法返回一个字符串表示的整数参数,以2为底的无符号整数,所以在开始的程序打印结果我们添加一个0,与我们算出的结果就相同了。
网上有很多关于float、double的转换解说,这里只是我涉及到了这块,然后自己去学习了一下,其实刚开始我看理论知识比较晕,后来看到别人以列子详细解说,然后再回头看理论,就发现也没那么难了。
public class FloatToBinary { public static void main(String[] args) { float f1=8.5f; System.out.println("f1底层数据(十进制):"+Float.floatToIntBits(f1)); int int1=Float.floatToIntBits(f1); System.out.println("f1底层数据(二进制):"+Integer.toBinaryString(int1)); } } 打印结果: f1底层数据(十进制):1091043328 f1底层数据(二进制):1000001000010000000000000000000我们知道float与double分别在内存中占有32位和64位,见下:
符号位 | 阶码 | 尾数 | 长度 | |
float | 1 | 8 | 23 | 32 |
double | 1 | 11 | 52 | 64 |
存储时,按照最高位存储符号位,次高位存储指数部分,低位存储尾数部分的次序存储。存储时的排列示意图如下:
float类型的内存分布如下图所示:
double类型的内存分布如下图所示:
编码规则在实际存储时要对使用二进制科学计数法表示的浮点数值的符号位、指数部分和尾数部分进行编码处理。一般需要分为规约形式的浮点数、非规约形式的浮点数和特殊值三种类型进行编码。其编码前后处理如下图所示:
注:非规约浮点数主要用于扩大0值附近的浮点数表示范围,非规约浮点数的绝对值均小于规约浮点数的绝对值,即前者在实数轴上更靠近0,这样可以提高0附近的计算精度;一般C、C++中float和double的取值范围都是按照规约浮点数定义的,MSDN文档和相关教材也是这么说的,但部分编译器按照ANSI/IEEE Std 754-1985标准实现了非规约浮点数,本文末尾留有程序示例说明。符号位:0表示正数,1表示负数;指数部分: float的偏移量为2^8 - 1,double的偏移量为2^11 - 1;尾数部分:实际尾数部分中的小数点后的数值,规约浮点数使用标准的二进制科学计数法表示,其尾数范围在 [1,2),非规约浮点数的尾数部分范围在(0,1)。上面的理论在哪里都能看到,这只是IEEE754的定义而已,我们来实际用一下它是怎么表达小数的:
①求单精度8.5f 的二进制 过程。首先8.5是正数所以符号位为0;然后化为二进制,1*2^3+0*2^2+0*2^1+0*2^0 (整数部分) . (小数点) 1*2^-1小数部分简化为1000.1要把二进制数变成(1.f)*2^(exponent)的形式,其中exponent是指数即1.0001*2^3.然后我们得到阶码为e=3+127=130 即阶码表示二进制为10000010.
余下小数0001,我们补齐至23位即00010000000000000000000。
这样符合结构 符号位 0 阶码 10000010 尾数00010000000000000000000
然后我们来看一下8.5存储在内存中01000001000010000000000000000000
因为java.lang.Integer.toBinaryString() 方法返回一个字符串表示的整数参数,以2为底的无符号整数,所以在开始的程序打印结果我们添加一个0,与我们算出的结果就相同了。
网上有很多关于float、double的转换解说,这里只是我涉及到了这块,然后自己去学习了一下,其实刚开始我看理论知识比较晕,后来看到别人以列子详细解说,然后再回头看理论,就发现也没那么难了。
相关文章推荐
- java中float,double利用BigDecimal运算
- Java基础:如何解决double和float精度不准的问题
- java基础之面试篇三---int,float,long,double取值范围,内存泄露
- Java基础-数据类型int,short,char,long,float,double,boolean,byte
- (转) java double、float 运算
- Java使用BigDecimal保留double、float运算精度、保留指定位数有效数字、四舍五入
- java中float,double利用BigDecimal运算
- 神奇:java中float,double,int的值比较运算
- Java浮点类型(Double/Float)运算精度问题
- 09.java语言基础-小数类型(float-double)
- java基础之面试篇三---int,float,long,double取值范围,内存泄露
- Java使用BigDecimal保留double、float运算精度、保留指定位数有效数字、四舍五入
- java float double类型做小数点加减运算不准确
- java float double类型做小数点加减运算不准确
- 第2章 Java编程基础——FAQ2.10 如何解决double和float精度不准的问题?
- java中float,double利用BigDecimal运算
- java中float,double类型运算的处理
- JAVA对double或者 float的浮点数精度计算控制方法
- 关于java中Double类型的运算精度问题
- java float double精度为什么会丢失?浅谈java的浮点数精度问题