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

为什么不推荐使用实数作为HashMap的key?

时间:2023-04-01 23:50:39 Java

1。引起我注意这一点的原因是一个问题,描述如下:给定二维平面上的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){返回点。长度;}最大整数=2;for(inti=0;imap=newHashMap<>(16);//记录垂直点数;Points[i]直线上的当前最大点数;垂直于Points[i]的点数intver=0,cur,dup=0;对于(intj=i+1;je;返回(e=getNode(哈希(键),键))==空?null:e.value;}嗯,先获取hash(),对吧,然后找到了哈希函数:staticfinalinthash(Objectkey){inth;返回(键==空)?0:(h=key.hashCode())^(h>>>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.实数的hashCode()在程序执行期间,只要equals方法的比较操作使用的信息没有被修改,调用同一个对象时hashCode方法必须一致返回相同的整数多次。如果两个对象根据equals方法比较相等,则对两个对象调用hashCode方法必须返回相同的整数结果。如果根据equals方法两个对象不相等,则hashCode方法不必返回不同的整数。——♂然后我们看看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位(由掩码*{@code0x80000000}选择的位)表示浮点数的符号*。*位30-23(由掩码选择的位*{@code0x7f800000})表示指数。*位22-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)&&(结果t&FloatConsts.SIGNIF_BIT_MASK)!=0)结果=0x7fc00000;returnresult;}这个文档比较长,我也查了其他资料。点算术标准IEEE754标准提供了浮点无穷大、负无穷大、负零和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,因为可能和我们的不一致期望。