从干将莫邪的故事说起--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 ...
随机推荐
- 【Offer】[59-1] 【滑动窗口的最大值】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值.例如,如果输入数组{2,3,4,2,6,2, 5,1}及滑动窗口的大小3,那 ...
- SIA-GateWay之API网关安装部署指南
SIA-GATEWAY是基于SpringCloud微服务生态体系下开发的一个分布式微服务网关系统.具备简单易用.可视化.高可扩展.高可用性等特征,提供云原生.完整及成熟的接入服务解决方案.本文介绍AP ...
- 全网最实用的 Debug调试技巧汇总-Python大佬偷偷使用的神技
一.思考❓❔ 1.什么是debug? 找茬 找软件的茬 发现程序的缺陷 2.为什么需要debug? 谁都不敢保证,写的代码没有任何问题 高效查找软件异常 一位优秀的开发工程师 20%的时间写代码 80 ...
- 2019CSP初赛基础知识整理
一.硬件 计算机发展: 年代 元件 第一代 1946~1958 电子管 第二代 1959~1964 晶体管 第三代 1965~1970 集成电路 第四代 1971~? 大规模集成电路 世界上第一台 ...
- 每天学会一点点(spring-mvc.xml与web.xml配置文件)
1.spring-mvc.xml中拦截器的使用 首先在springMVC.xml配置如下代码: <!-- 拦截器 --> <mvc:interceptors> <bean ...
- FreeSql (二十三)分组、聚合
IFreeSql fsql = new FreeSql.FreeSqlBuilder() .UseConnectionString(FreeSql.DataType.MySql, "Data ...
- 谈谈你对HTML语义化的理解。
1.什么是HTML语义化? 基本上都是围绕着几个主要的标签,像标题(h1-h6),列表(li),强调(strong em)等. 根据内容的语义化(内容结构化),选择合适的标签(代码语义化),便于开发者 ...
- 【干货推荐】Android开发该学习哪些东西?
开篇: 本人也是众多Android开发道路上行走的一员,听了不少大神的知乎live,自己也看了不少书,也和不少前辈交流过,所以在这里分享一下Android开发应该学习的书籍以及知识,当然,也包括一些方 ...
- Elastic Stack 笔记(一)CentOS7.5 搭建 Elasticsearch5.6 集群
博客地址:http://www.moonxy.com 一.前言 Elasticsearch 是一个基于 Lucene 的分布式搜索引擎服务,采用 Java 语言编写,使用 Lucene 构建索引.提供 ...
- 谈谈HTTPS安全认证,抓包与反抓包策略
文章原创于公众号:程序猿周先森.本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号. 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信 ...