从干将莫邪的故事说起--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 ...
随机推荐
- input上传按钮的优化
在使用input标签按钮的时候,<input type="file" value="" /> 显示很难看,怎么办? 使用label <li c ...
- docker java环境 直接做成镜像 跑自己的java包
yum install docker #基于阿里源 可以直接下载 systemctl restart docker ifconfig #出现 docker0 说明环境部署成功 docker ver ...
- Apache RocketMQ 消息队列部署与可视化界面安装
一.介绍 Apache RocketMQ是一个分布式.队列模型的消息中间件,具有低延迟.高性能和高可靠.万亿级容量和灵活的可扩展性.核心组件由四部分组成:Name Servers,Brokers,Pr ...
- 14个Linux系统安全小妙招,总有一招用的上!
对于互联网IT从业人员来说,越来越多的工作会逐渐转移到Linux系统之上,这一点,无论是开发.运维.测试都应该是深有体会.曾有技术调查网站W3Techs于2018年11月就发布一个调查报告,报告显示L ...
- VMware 虚拟机三种网络模式详解
一.前言 Vmware 为我们提供了三种网络工作模式,分别是:Bridged(桥接模式).NAT(网络地址转换模式).Host-only(仅主机模式). 二.VMware 的几个常见虚拟设备 打开 V ...
- Cabloy全栈JS框架微创新之一:不一样的“移动优先 PC适配”
前言 目前流行的前端UI组件库都支持移动设备优先的响应式布局特性.但基于Mobile和PC两个场景的不同用户体验,也往往会实现Mobile和PC两个版本. PC场景下的Web工程,如大量的后台前端管理 ...
- TestNG(三) 基本注解BeforeMethod和AfterMethod
package com.course.testng; import org.testng.annotations.*; public class BasicAnnotation { @Test //最 ...
- 07 (OC)* XIB原理和Xib、storyBoard、代码的优缺点
1:可读性 2:可视化界面.立马看到 3:开发速度. 4:复用性 5:维护性差 本质 编译时对xml文件做了如下操作1,读取xml文件,生成所有界面对象,生成所有object(即自定义的control ...
- Kubernetes学习之应用部署变迁
从物理单机.虚拟化(容器化)到云原生 历史 云原生 ---初期 总结
- [Algorithm] Hashing for search
Hashing Process 关于hash本身,解决冲突是一个小重点,如下图. 代码实现分析 —— 定义HashTable类 一.数据结构 def __init__(self): self.size ...