当前位置: 首页 > 后端技术 > Java

为什么不能用实数作为HashMap的key?

时间:2023-04-01 18:35:07 Java

1。之所以关注这一点,是因为一个问题:牛客网上的max-points-on-a-line题目是这样描述的:给定一个二维平面上的n个点,求位于该线上的最大点数同一条直线。大意是给我一些点的X和Y坐标,找到点数最多的直线,输出这条直线上的点数。所以我输入了以下代码:importjava.util.HashMap;importjava.util.Map;//classPoint{//intx;//inty;//Point(inta,intb){x=A;y=b;}//}publicclassSolution{publicintmaxPoints(Point[]points){if(points.length<=2){returnpoints.length;}最大整数=2;for(inti=0;imap=newHashMap<>(16);//记录垂直点数;Points[i]线上的当前最大点数;垂直于Points[i]的点intver=0,cur,dup=0;对于(intj=i+1;j>>16);}接下来这里就是比较h和key的hashCode对不对,再来看hashCode()函数publicnativeinthashCode();这是本地的方法,源码看不到,好吧,那我就用它看看,测试一下,是不是很好?我写了下面的测试代码:publicstaticvoidmain(String[]args){System.out.println(0.0==-0.0);System.out.println(newFloat(0.0).hashCode()==newFloat(-0.0).hashCode());}?结果竟然是True和False!!!终于找到源头了,0.0和-0.0的hashCode值不一样!修改了一下,通过了这道题(其实精度会有问题,应该用BigDecimal,但是牛客网要求没那么高,后来想了想,精度问题可以完全避免了只能将一次方程写成Ax+By+C=0的形式。)接下来讨论实数的hashCode()函数是什么情况:2.程序执行过程中,只要equals方法的比较操作中使用的信息没有被修改,必须为同一个对象多次调用hashCode方法。始终返回相同的整数。如果两个对象根据equals方法比较相等,则对两个对象调用hashCode方法必须返回相同的整数结果。如果根据equals方法两个对象不相等,则hashCode方法不必返回不同的整数。——《effective java》然后我们看看0.0和-0.0调用的equals方法是否相等:System.out.println(newFloat(0.0).equals(0.0f));System.out.println(newFloat(0.0).equals((float)-0.0));输出的是True和False嘛,这两个调用equals()方法不相等,好像符合书上说的逻辑,那我们来看看Float写的底层equals函数:publicbooleanequals(Objectobj){return(objinstanceofFloat)&&(floatToIntBits(((Float)obj).value)==floatToIntBits(value));}哦,原来在将Float转换为Bits时发生了奇怪的事情,我找到了源头ofitall:/***根据IEEE754浮点“单一格式”位*布局返回指定浮点值*的表示形式。**

第31位(由mask*{@code0x80000000})表示浮点数*的符号。*Bits30-23(由mask*{@code0x7f800000}选择的位)表示指数。*Bits22-0(由掩码*{@code0x007fffff})选择的位表示浮点数的重要性和(有时称为*尾数)。**

如果参数是正无穷大,结果是*{@code0x7f800000}。**

如果参数是负无穷大,结果是*{@code0xff800000}。**

如果参数是NaN,结果是{@code0x7fc00000}.**

在所有情况下,结果都是一个整数,当将其提供给*{@link#intBitsToFloat(int)}方法时,将产生一个与{@codefloatToIntBits}*的参数(除了所有NaN值都折叠为单个*“规范”NaN值)。**@paramvalue一个浮点数。*@return表示浮点数的位。*/publicstaticintfloatToIntBits(floatvalue){intresult=floatToRawIntBits(value);//根据位字段的值、最大值//指数和非零尾数检查NaN。如果(((结果&FloatConsts.EXP_BIT_MASK)==FloatConsts.EXP_BIT_MASK)&&(结果&FloatConsts.SIGNIF_BIT_MASK)!=0)结果=0x7fc00000;returnresult;}这个文档比较长,我也查了其他资料。无穷大、负零和NaN(不是数字)的定义。在使用Java的过程中,通常会遇到一些特殊的浮点数让大家感到困惑。当浮点运算产生一个非常接近0的负浮点数时,就会产生“-0.0”,这个浮点数不能正常。我们可以输出一个Wave0.0和-0.0的数据:System.out.println(Float.floatToIntBits((float)0.0));System.out.println(Float.floatToIntBits((float)-0.0));System.out。println(Float.floatToRawIntBits(0.0f));System.out.println(Float.floatToRawIntBits((float)-0.0));Result:0-21474836480-2147483648也就是说存储-0.0其实就是0x80000000,我们熟悉Integer.MIN\_VALUE3。综上所述,java中浮点数的表示比较复杂,尤其是涉及到-0.0、NaN、正负无穷大的时候,不适合作为Map的key,因为可能不是符合我们的预期