从干将莫邪的故事说起--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 ...
随机推荐
- yzoj P2344 斯卡布罗集市 题解
共t条街对于每一条街上有n个店铺(n可能不相同),每次只能选两端第一个营业的店铺采购,采购第i个店铺会获得幸福度ai,采购完后,这个店铺和它相邻的店铺便会关门,问最大幸福度? 考场想了一下dp,一开始 ...
- android日志搜集原理及方案比较
说明: 本文只讨论Log日志,而不是应用的埋点日志. Android 日志架构 用一张图来了解Android Log的架构: 这里涉及到三个进程: APP进程: 调用Log的接口打日志,最终通过soc ...
- win10 无法安装/启用 .net framework 3.5
有些程序依赖.net framework 3.5 win10可以在控制面板->程序和功能->启用或关闭windows功能 启用 但有时会报错 比如 0x800f0950 官方论坛的解决办法 ...
- 【Offer】[23] 【链表中环的入口结点】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 一个链表中包含环,如何找出环的入口结点?  思路分析 判断链表中是否有环:用快慢指针的方法,慢指针走一步,快指针走两步,如果快指针追上 ...
- day01小结
Java特点 1,面向对象的(write once,run anywhere) 2,跨平台的 ,,,,,, Java体系结构 JavaSE,JavaEE,JavaME,Java Card 对JDK,J ...
- Redis相关安装TCL
安装相关命令 wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gzsudo tar -xzvf tcl8.6.1-src.tar. ...
- 配置hibernate访问mysql
在之前搭建spring mvc项目这篇的基础上继续集成,引入hibernate支持 一.添加jar包引用 修改pom.xml文件,加入: <dependency> <groupId& ...
- [VB.NET Tips]再谈字符串连接之内置池
CLR自动维护一个称为"内置池"(暂存池)(intern pool)的表,在编译时此表包含程序中声明的每个唯一的字符串常量的单个实例,以及以编程方式创建的String类的任何唯一实 ...
- java处理emoji(转)
最近对接ios.安卓客户端,需要处理emoji等表情符号,网上总结: 1.过滤掉emoji表情符 2.修改数据库的编码格式等,让其支持存储emoji 以下分别对两种方案进行描述: 第一种:过滤掉emo ...
- AppScan工具介绍与安装
本文仅供个人参考学习,如做商业用途,请购买正版,谢谢! 介绍 AppScan是IBM公司出的一款Web应用安全测试工具,采用黑盒测试的方式,可以扫描常见的web应用安全漏洞.其工作原理,首先是根据起始 ...