故事背景

《搜神记》:

楚干将、莫邪为楚王作剑,三年乃成。王怒,欲杀之。剑有雌雄。其妻重身当产。夫语妻曰:“吾为王作剑,三年乃成。王怒,往必杀我。汝若生子是男,大,告之曰:‘出户望南山,松生石上,剑在其背。’”于是即将雌剑往见楚王。王大怒,使相之:“剑有二,一雄一雌,雌来雄不来。”王怒,即杀之。

莫邪子名赤,比后壮,乃问其母曰:“吾父所在?”母曰:“汝父为楚王作剑,三年乃成。王怒杀之。去时嘱我:‘语汝子,出户望南山,松生石上,剑在其背。’”于是子出户南望,不见有山,但睹(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比较操作注意要点的更多相关文章

  1. 一个故事搞懂Java并发编程

    最近在给别人讲解Java并发编程面试考点时,为了解释锁对象这个概念,想了一个形象的故事.后来慢慢发现这个故事似乎能讲解Java并发编程中好多核心概念,于是完善起来形成了了这篇文章.大家先忘记并发编程, ...

  2. Java实现操作dos命令

    java实现操作dos命令的两种方式 1.读取文件中的命令 package com; import java.io.InputStream; public class cmd { public sta ...

  3. JAVA 链表操作:循环链表

    主要分析示例: 一.循环链表简述 二.单链表循环链表 三.双链表循环链表 一.循环链表简述 循环链表即链表形成了一个循环的结构,尾节点不再指向NULL,而是指向头节点HEAD,此时判定链表的结束是尾节 ...

  4. java日期操作大全

    摘自(http://www.blogjava.net/i369/articles/83483.html) java日期操作 大全 先来一个:  取得指定月份的第一天与取得指定月份的最后一天  http ...

  5. Java CSV操作(导出和导入)

    Java CSV操作(导出和导入)  CSV是逗号分隔文件(Comma Separated Values)的首字母英文缩写,是一种用来存储数据的纯文本格式,通常用于电子表格或数据库软件.在 CSV文件 ...

  6. Java开发--操作MongoDB

    http://www.cnblogs.com/hoojo/archive/2011/06/01/2066426.html介绍到了在MongoDB的控制台完成MongoDB的数据操作,通过前一篇文章我们 ...

  7. hive-通过Java API操作

    通过Java API操作hive,算是测试hive第三种对外接口 测试hive 服务启动 package org.admln.hive; import java.sql.SQLException; i ...

  8. HDFS的Java客户端操作代码(HDFS的查看、创建)

    1.HDFS的put上传文件操作的java代码: package Hdfs; import java.io.FileInputStream; import java.io.FileNotFoundEx ...

  9. Java文件操作源码大全

    Java文件操作源码大全 1.创建文件夹 52.创建文件 53.删除文件 54.删除文件夹 65.删除一个文件下夹所有的文件夹 76.清空文件夹 87.读取文件 88.写入文件 99.写入随机文件 9 ...

随机推荐

  1. js中的所有兼容问题总结

    js兼容问题总结 ​ 在学习js过程中很多人都遇到过兼容问题,这些兼容问题是因为各版本浏览器不同导致的,为了解决这些兼容问题,js给我们提供了解决这些兼容问题的方案,对此,我个人进行了汇集以及总结. ...

  2. 反序列化JSON

    本人编程生涯刚刚起步,以下是个人理解,如果有些不对的地方,请各位在评论区指出,如果有更详细的博客也可以推荐给我. 首先要根据JSON创建一个实体类,并且要实现Serializable接口,再创建一个J ...

  3. XSS漏洞之加载远程js文件

    这次在对一个系统渗透测试过程中,发现一个XSS漏洞,可弹窗,并且没有httponly 但是在尝试加载远程js文件的时候发现,script标签被过滤掉了,准确的说应该是服务器后端在识别到输入内容有< ...

  4. (转)java程序调用内存变化过程分析(详细)

    原博地址: https://blog.csdn.net/Myuhua/article/details/81385609 (一)不含静态变量的java程序运行时内存变化过程分析 代码: package ...

  5. vue2.0 创建项目

    准备 安装淘宝 npm镜像 npm install -g cnpm --registry=https://registry.npm.taobao.org 添加系统变量path的内容 因为cnpm会被安 ...

  6. mybatis拦截器实现通用权限字段添加

    实现效果 日常sql中直接使用权限字段实现权限内数据筛选,无需入参,直接使用,使用形式为:select * from crh_snp.channelinfo where short_code in ( ...

  7. d010:盈数、亏数和完全数

    题目: 对一个正整数N而言,将它除了本身以外所有的因子加起来的总和为S,如果S>N,则N为盈数,如果S<N,则N为亏数,而如果S=N,则N为完全数(Perfect Number).例如10 ...

  8. WeakMap 本身释放,而 keyObject 没有释放的情况下,value 会释放吗?

    const keyObject = ['keyObject']; new WeakMap().set(keyObject, ['value']); 问题:现在 ['value'] 会被释放吗? 听说W ...

  9. 37 (OC)* 类别的作用

    问题: OC中类别(Category)是什么?Category类别是Objective-C语言中提供的一个灵活的类扩展机制.类别用于在不获悉.不改变原来代码的情况下往一个已经存在的类中添加新的方法,只 ...

  10. Django-官网查询部分翻译(1.11版本文档)-QuerySet-字段查找-06

    目录 Making queries 进行查询 创建一个对象(一条数据记录) 保存修改的表对象 保存外键字段或多对多字段(ForeignKey or ManyToManyField fields) Re ...