从干将莫邪的故事说起--java比较操作注意要点
故事背景
《搜神记》:
楚干将、莫邪为楚王作剑,三年乃成。王怒,欲杀之。剑有雌雄。其妻重身当产。夫语妻曰:“吾为王作剑,三年乃成。王怒,往必杀我。汝若生子是男,大,告之曰:‘出户望南山,松生石上,剑在其背。’”于是即将雌剑往见楚王。王大怒,使相之:“剑有二,一雄一雌,雌来雄不来。”王怒,即杀之。
莫邪子名赤,比后壮,乃问其母曰:“吾父所在?”母曰:“汝父为楚王作剑,三年乃成。王怒杀之。去时嘱我:‘语汝子,出户望南山,松生石上,剑在其背。’”于是子出户南望,不见有山,但睹(dû)堂前松柱下石低之上。即以斧破其背,得剑,日夜思欲报楚王。
王梦见一儿,眉间广尺,言欲报仇。王即购之千金。儿闻之,亡去,入山行歌。客有逢者,谓:“子年少,何哭之甚悲耶(yé)?”曰:“吾干将、莫邪子也,楚王杀吾父,吾欲报之!”客曰:“闻王购子头千金,将子头与剑来,为子报之。”儿曰:“幸甚!”即自刎(wên),两手捧头及剑奉之,立僵。客曰:“不负子也。”于是尸乃仆。
客持头往见楚王,王大喜。客曰:“此乃勇士头也,当于汤镬(huò)煮之。”王如其言。煮头三日三夕,不烂,头踔出汤中,瞋目大怒。客曰:“此儿头不烂,愿王自往临视之,是必烂也。”王即临之。客以剑拟王,王头随坠汤中,客亦自拟己头,头复坠汤中。三首俱烂,不可识辨。乃分其汤肉葬之,故通名“三王墓”,今在汝南北宜春县界。
java中的雌雄双剑0与-0
0与-0按理说都是一样的,但在程序中不一定就相等哦。请看下面的程序:
- public static void main(String[] args) {
- System.out.println(Float.compare(-0.0f, 0.0f));
- System.out.println(Math.max(-0.0f, 0.0f));
- System.out.println(Math.min(-0.0f, 0.0));
- System.out.println(-0.0f<0.0f);
- System.out.println(-0.0f<=0.0f);
- }
上面的结果可能让你大吃一惊。
- -1
0.0
-0.0
false
true
让我们看看JSL上怎么说吧
- 15.20.1. Numerical Comparison Operators <, <=, >, and >=
The type of each of the operands of a numerical comparison operator must be a type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs.
Binary numeric promotion is performed on the operands (§5.6.2).
Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).
If the promoted type of the operands is int or long, then signed integer comparison is performed.
If the promoted type is float or double, then floating-point comparison is performed.
Comparison is carried out accurately on floating-point values, no matter what value sets their representing values were drawn from.
The result of a floating-point comparison, as determined by the specification of the IEEE 754 standard, is:
If either operand is NaN, then the result is false.
All values other than NaN are ordered, with negative infinity less than all finite values, and positive infinity greater than all finite values.
Positive zero and negative zero are considered equal.
For example, -0.0<0.0 is false, but -0.0<=0.0 is true.
Note, however, that the methods Math.min and Math.max treat negative zero as being strictly smaller than positive zero.
Subject to these considerations for floating-point numbers, the following rules then hold for integer operands or for floating-point operands other than NaN:
The value produced by the < operator is true if the value of the left-hand operand is less than the value of the right-hand operand, and otherwise is false.
The value produced by the <= operator is true if the value of the left-hand operand is less than or equal to the value of the right-hand operand, and otherwise is false.
The value produced by the > operator is true if the value of the left-hand operand is greater than the value of the right-hand operand, and otherwise is false.
The value produced by the >= operator is true if the value of the left-hand operand is greater than or equal to the value of the right-hand operand, and otherwise is false.
Positive zero and negative zero are considered equal.(浮点数中0.0和-0.0进行关系比较是相等的)
For example, -0.0<0.0 is false, but -0.0<=0.0 is true.(例如:-0.0<0.0是false,但-0.0<=0.0 是true)
Note, however, that the methods Math.min and Math.max treat negative zero as being strictly smaller than positive zero.(主意:然而,使用Math.min和Math.max进行浮点数比较时,-0.0时小于0.0的)
java中浮点数在循环中使用要慎重
- public static void main(String[] args) {
- final int START = 2000000000;
- int count = 0;
- for (float f = START; f < START + 50; f++)
- count++;
- System.out.println(count);
- }
f的初始值接近于Integer.MAX_VALUE,因此它需要用31 位来精确表示,而float 类型只能提供24 位的精度。对如此巨大的一个float 数值进行增量操作将不会改变其值。因此,这个程序看起来应该无限地循环下去,因为f 永远也不可能解决其终止值。但是,如果你运行该程序,就会发现它并没有无限循环下去,事实上,它立即就终止了,并打印出0。怎么回事呢?
问题在于终止条件测试失败了,其方式与增量操作失败的方式非常相似。这个循环只有在循环索引f 比(float)(START + 50)小的情况下才运行。在将一个int与一个float 进行比较时,会自动执行从int 到float 的提升[JLS 15.20.1]。遗憾的是,这种提升是会导致精度丢失的三种拓宽原始类型转换的一种[JLS5.1.2]。(另外两个是从long 到float 和从long 到double。)
f 的初始值太大了,以至于在对其加上50,然后将结果转型为float 时,所产生的数值等于直接将f 转换成float 的数值。换句话说,(float)2000000000 ==2000000050,因此表达式f < START + 50 即使是在循环体第一次执行之前就是false,所以,循环体也就永远的不到机会去运行。
总结
数据比较的时候,尽量避开浮点数,使用int,long等。
参考资料
【1】https://baike.baidu.com/item/%E5%B9%B2%E5%B0%86%E8%8E%AB%E9%82%AA/550371?fr=aladdin
【2】https://docs.oracle.com/javase/specs/jls/se12/html/jls-15.html#jls-15.20.1
从干将莫邪的故事说起--java比较操作注意要点的更多相关文章
- 一个故事搞懂Java并发编程
最近在给别人讲解Java并发编程面试考点时,为了解释锁对象这个概念,想了一个形象的故事.后来慢慢发现这个故事似乎能讲解Java并发编程中好多核心概念,于是完善起来形成了了这篇文章.大家先忘记并发编程, ...
- Java实现操作dos命令
java实现操作dos命令的两种方式 1.读取文件中的命令 package com; import java.io.InputStream; public class cmd { public sta ...
- JAVA 链表操作:循环链表
主要分析示例: 一.循环链表简述 二.单链表循环链表 三.双链表循环链表 一.循环链表简述 循环链表即链表形成了一个循环的结构,尾节点不再指向NULL,而是指向头节点HEAD,此时判定链表的结束是尾节 ...
- java日期操作大全
摘自(http://www.blogjava.net/i369/articles/83483.html) java日期操作 大全 先来一个: 取得指定月份的第一天与取得指定月份的最后一天 http ...
- Java CSV操作(导出和导入)
Java CSV操作(导出和导入) CSV是逗号分隔文件(Comma Separated Values)的首字母英文缩写,是一种用来存储数据的纯文本格式,通常用于电子表格或数据库软件.在 CSV文件 ...
- Java开发--操作MongoDB
http://www.cnblogs.com/hoojo/archive/2011/06/01/2066426.html介绍到了在MongoDB的控制台完成MongoDB的数据操作,通过前一篇文章我们 ...
- hive-通过Java API操作
通过Java API操作hive,算是测试hive第三种对外接口 测试hive 服务启动 package org.admln.hive; import java.sql.SQLException; i ...
- HDFS的Java客户端操作代码(HDFS的查看、创建)
1.HDFS的put上传文件操作的java代码: package Hdfs; import java.io.FileInputStream; import java.io.FileNotFoundEx ...
- Java文件操作源码大全
Java文件操作源码大全 1.创建文件夹 52.创建文件 53.删除文件 54.删除文件夹 65.删除一个文件下夹所有的文件夹 76.清空文件夹 87.读取文件 88.写入文件 99.写入随机文件 9 ...
随机推荐
- EditPlus5.0破解激活
永久激活用户名激活码: 用户名:Vovan注册码:3AG46-JJ48E-CEACC-8E6EW-ECUAW 然后重启软件即可
- ConcurrentHashMap 的工作原理及代码实现
ConcurrentHashMap采用了非常精妙的"分段锁"策略,ConcurrentHashMap的主干是个Segment数组.Segment继承了ReentrantLock,所 ...
- CSAPP DataLab
注意不同版本的题目可能会有所不同,搜了很多他们的题目和现在官网给的实验题都不一样,自己独立思考完整做一遍顺便记录一下. PS:这些难度为1的题有的说实话我都做了挺久的,不过完整做一遍感觉很有意思,这些 ...
- Http 协议简略
用户在浏览器中输入一个网址并回车,浏览器会向服务器发送一个http请求,服务器端程序会接受这个请求,并对请求进行相应的处理,然后发送一个回应,浏览器收到回应,再把回应的内容显示到页面,这种请求—相应的 ...
- python中os模块再回顾
先看下我的文件目录结构 F:\PYTHON项目\ATM购物车\7月28 在此目录下的文件如下: 封装.py 模块os.sys复习.py 运行当前的文件是模块os.sys复习.py 1.获取当前文件所在 ...
- log4j日志不输出的问题
今天服务器上报错,想先去看一下日志进行排查,结果发现日志很久都没有输出过了.从上午排查到下午,刚刚解决,因此记录一下,但现在也只是知其然,并不知其所以然,所以如果大家有什么想法请在下方评论. 先说一下 ...
- hadoop生态系列
1.hadoop高可用安装和原理详解 2.hadoop2.7+spark2.2+zookeeper3.4.简单安装 3.windows下通过idea连接hadoop和spark集群 4.hadoop2 ...
- RDD基本操作之Action
Action介绍 在RDD上计算出来一个结果 把结果返回给driver program或保存在文件系统,count(),save 常用的Action reduce() 接收一个函数,作用在RDD两个类 ...
- 苹果系统IOS第三方管理工具——imazing 优秀
iMazing 是一款 Windows.macOS 平台的 iPhone.iPad 管理工具,可以进行文件.音乐.视频传输,备份与还原数据,并且可以管理已安装应用,比如重新安装那些已下架的应用,是「史 ...
- Windows(Win7)搭建RabbitMQ服务器
首先安装Erlang环境,RabbitMQ的运行依赖于Erlang.可以在官网链接http://www.erlang.org/downloads 页面找到对应的开发环境安装包.例如64位Windows ...