学习java浮点型的一些细节

news/2023/6/5 20:46:33

出自《Java深入解析》的例子

例1、先看一段代码:

public static void main(String[] args) {double d1 = 0.1;double d2 = 0.2;System.out.println("" + d1 + "+" + d2 + "=" + (d1 + d2));}

初学者可能脱口而出执行的结果是输出 d1+d2=0.3。但是结果却没有这么简单:

0.1+0.2=0.30000000000000004

转念一想,却也没有一点玄妙。

二进制只能表示十进制中诸如0.5,0.25,0.125之类的小数。

十进制中可以表示0.1~0.9的小数,却不能表示1/3这样的分数。以此类推需要表示1/3,可能3进制更能胜任。

 

例2、BigDecimal是用来表示精度较大的小数的类,用二进制的数据表示十进制数可以说真是强人所难了。

for (int i = 1; i <= 9; i++) {double d = Double.parseDouble("0."+i);System.out.println(d);BigDecimal bd = new BigDecimal(d);System.out.println(bd);
}

结果:

0.1
0.1000000000000000055511151231257827021181583404541015625
0.2
0.200000000000000011102230246251565404236316680908203125
0.3
0.299999999999999988897769753748434595763683319091796875
0.4
0.40000000000000002220446049250313080847263336181640625
0.5
0.5
0.6
0.59999999999999997779553950749686919152736663818359375
0.7
0.6999999999999999555910790149937383830547332763671875
0.8
0.8000000000000000444089209850062616169452667236328125
0.9
0.90000000000000002220446049250313080847263336181640625

 

例3.不如做个测试,看看计算机“偏爱”什么样的数字吧。

 1 /**
 2  * 测试0.0001~0.9999范围内的小数那些可以被二进制准确表示
 3  * */
 4 public class FloatStorage {
 5 
 6     public static void main(String[] args) {
 7         int limit = 9999;// 测试的范围0.0001-0.9999
 8         int length = String.valueOf(limit).length();// 小数的位数
 9 
10         System.out.println("在0.0001~0.9999之间可以被准确表示的小数有");
11 
12         for (int i = 1; i <= 9999; i++) {
13             int significance = String.valueOf(i).length();// 小数的非0数位
14             int zero = length - significance;// 小数的0数位
15             StringBuilder sb = new StringBuilder("0.");// 建立字符串
16             for (int j = 1; j <= zero; j++) {
17                 sb.append(0);
18             }
19             sb.append(i);
20             BigDecimal bd = new BigDecimal(Double.parseDouble(sb.toString())/* 得到二进制数 */);
21             if (bd.scale() <= length) {// 如果符合我们的要求,输出
22                 System.out.println(bd);
23             }
24         }
25     }
26 
27 }

运行结果:

在0.0001~0.9999之间可以被准确表示的小数有
0.0625
0.125
0.1875
0.25
0.3125
0.375
0.4375
0.5
0.5625
0.625
0.6875
0.75
0.8125
0.875
0.9375

真是寥寥无几啊!

如果小结一下浮点数的特点,原来浮点数和小数之间还是有一定的差别,

在赋值或者存储中浮点类型的精度有限,

同时在计算机实际处理和运算过程中,浮点数本质上是以二进制形式存在的。

二进制所能表示的两个相邻的浮点值之间存在一定的间隙,浮点值越大,这个间隙也会越大。

如果此时对较大的浮点数进行操作时,浮点数的精度问题就会产生,甚至出现一些“不正常"的现象。

 

例4

public class BigFloat {public static void main(String[] args) {float f1 = 30000f;float f2 = f1 + 1;System.out.println("f1:" + f1);System.out.println("f2:" + f2);if (f1 < f2) {System.out.println("f1<f2 成立");} else {System.out.println("f1<f2 不成立");}float f3 = 30000000f;float f4 = f3 + 1;System.out.println("f3:" + f3);System.out.println("f4:" + f4);if (f3 < f3) {System.out.println("f3<f3 成立");} else {System.out.println("f3<f4 不成立");}}}

运行的结果:

f1:30000.0
f2:30001.0
f1<f2 成立
f3:3.0E7
f4:3.0E7
f3<f4 不成立

一个数加一不比原来的数大,这就是由于精度产生的现象了。

 

例5

float可以保留7-8位有效数字

int a = 1;int b = 123;int c = 1234;int d = 12345;int e = 123456;int f = 1234567;int g = 12345678;int h = 123456789;int i = 1234567891;long j = 12345678912L;long k = 123456789123L;long l = 1234567891234L;long m = 12345678912345L;System.out.println((float)a);System.out.println((float)b);System.out.println((float)c);System.out.println((float)d);System.out.println((float)e);System.out.println((float)f);System.out.println((float)g);System.out.println((float)h);System.out.println((float)i);System.out.println((float)j);System.out.println((float)k);System.out.println((float)l);System.out.println((float)m);

结果为:

1.0
123.0
1234.0
12345.0
123456.0
1234567.0
1.2345678E7
1.23456792E8
1.23456794E9
1.23456788E10
1.23456791E11
1.23456795E12
1.2345679E13

double类型可以保留15-16位有效数字

        System.out.println((double)a);System.out.println((double)b);System.out.println((double)c);System.out.println((double)d);System.out.println((double)e);System.out.println((double)f);System.out.println((double)g);System.out.println((double)h);System.out.println((double)i);System.out.println((double)j);System.out.println((double)k);System.out.println((double)l);System.out.println((double)m);

结果为:

1.0
123.0
1234.0
12345.0
123456.0
1234567.0
1.2345678E7
1.23456789E8
1.234567891E9
1.2345678912E10
1.23456789123E11
1.234567891234E12
1.2345678912345E13

 

个人猜想:

 强制类型转换如long到int,是截取高位的,一个正的long有可能转成一个负的int类型。

而整型到浮点型的转换是忽略低位的精度,相对说比较稳定。

因此前者需要强制类型转换,而后者可以进行自动类型转换。

转载于:https://www.cnblogs.com/mycome/p/3718310.html


https://dhexx.cn/news/show-18576.html

相关文章

android读取多行文件,Android 读取txt,按行读取的实例讲解

Android 读取txt,按行读取的实例讲解发布时间&#xff1a;2020-09-12 12:43:31来源&#xff1a;脚本之家阅读&#xff1a;103作者&#xff1a;Damionew一个TXT 文件 对其进行读取&#xff0c;并且每行都单个存储读取public class MainActivity extends AppCompatActivity {priv…

Java简单游戏开发之碰撞检测

前言 不久之前在论坛上有人发贴&#xff0c;使用java编写的超级马里奥如何实现碰撞检测&#xff0c;笔者自己以前 也做过Tank大战。里面同样涉及到碰撞检测&#xff0c;翻翻U盘里的东西还在&#xff0c;什么时候也给共享出来。 这篇文章就简单游戏中的碰撞检测做一个简单的总结…

通用用户权限管理系统组件V3.9功能改进说明 - 操作权限项定义简化

在通用权限管理系统组件V3.9中对操作权限项定义进行了一次大胆的简化&#xff0c;现在定义模块菜单的同时可以定义操作权限项目&#xff0c;这样不用菜单与操作权限分离了&#xff0c;可以集中展示&#xff0c;实用效果更加友善。 下面是定义菜单或者操作权限项目的参考页面 设…

html 10 margin 重叠

留意&#xff0c;父子元素&#xff0c;margin重叠影响的是margin-top上的。取两者中的最大值&#xff0c;水平和bottom不受影响&#xff0c; 重叠的时候子元素的margin-top消失 父元素如果加了padding属性&#xff0c;不会重叠。子元素如果有float&#xff0c;父子不重叠 CSS 外…

PHP cURL模块

简介&#xff1a; cURL是利用URL语法在命令行方式下工作的文件传输工具&#xff0c;目前苹果机器已经内置了cURL。cURL是一个综合性的传输工具&#xff0c;对HTTP、FTP等协议提供了广泛的支持&#xff0c;它甚至可以实现迅雷、快车等下载工具的所有功能。PHP中也提供了对cURL语…

day20(下)_IO流5(递归穷举与删除,Properties,PrintStream,PrintWriter,SequenceInputStream)

1.对目录和文件递归穷举 /* 列出指定目录下的文件或者文件夹,包含子目录中的内容 也就是列出目录下所有的内容 例如:new File(d:\\);在d盘下还有一个abc目录而abc下还有文件和目录,而用list()方法只能获取到d盘下的文件和目录 */ package filedemo; import java.util.Arrays; i…

android javacv 录像,使用JavaCV(ffmpeg)录制视频

使用JavaCV(ffmpeg)录制视频JavaCV是对各种常用计算机视觉库的封装后的一组jar包&#xff0c;其中封装了ffmpeg、OpenCV、libdc1394、OpenKinect、videoInput和ARToolKitPlus等计算机视觉编程人员常用库的接口&#xff0c;可以通过其中的utility类方便的在包括Android在内的Jav…

协方差矩阵和相关矩阵

1、协方差矩阵 协方差是衡量两个随机变量&#xff08;同一样本&#xff0c;不同分量&#xff09;的相关程度。&#xff08;方差描述的是一维变量&#xff09;随机变量 之间的协方差可以表示为根据已知的样本值可以得到协方差的估计值如下&#xff08;列向量相关&#xff09;&am…

6.链路层和局域网

链路层链路层的主体是网络适配器&#xff0c;也称为网络接口卡2. 变换局域网链路层交换机的任务是在主机和路由器之间承载数据报没有两个适配器有相同的MAC地址适配器到哪里&#xff0c;MAC地址都不会改变主机移动时&#xff0c;主机的IP地址需要随之改变&#xff0c;以改变连接…

Google开发的QRcode二维码生成和解码及最大容量

1.源码 package com.test; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingExcep…