<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          同事把實數(shù)作為 HashMap 的key,領導發(fā)飆了...

          共 12063字,需瀏覽 25分鐘

           ·

          2021-12-29 00:48

          上一篇:GET 和 POST請求的本質區(qū)別是什么?看完覺得自己太無知了...

          來源:blog.csdn.net/qq_30219017/article/details/79689492

          1.起因

          讓我關注到這一點的起因是一道題:??途W(wǎng)上的max-points-on-a-line

          題目是這么描述的:

          Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.

          大意就是給我一些點的X,Y坐標,找到過這些點最多的直線,輸出這條線上的點數(shù)量

          于是我就敲出了以下的代碼:

          import java.util.HashMap;
          import java.util.Map;

          //class Point {
          //    int x;
          //    int y;
          //    Point(int a, int b) { x = a; y = b; }
          //}

          public class Solution {
              public int maxPoints(Point[] points) {
                  if (points.length <= 2) {
                      return points.length;
                  }

                  int max = 2;
                  for (int i = 0; i < points.length - 1; i++) {
                      Map<Float, Integer> map = new HashMap<>(16);
                      // 記錄垂直點數(shù); 當前和Points[i]在一條線上的最大點數(shù); 和Points[i]垂直的點數(shù)
                      int ver = 0, cur, dup = 0;
                      for (int j = i + 1; j < points.length; j++) {
                          if (points[j].x == points[i].x) {
                              if (points[j].y != points[i].y) {
                                  ver++;
                              } else {
                                  dup++;
                              }
                          } else {
                              float d = (float)((points[j].y - points[i].y) / (double) (points[j].x - points[i].x));
                              map.put(d, map.get(d) == null ? 1 : map.get(d) + 1);
                          }
                      }

                      cur = ver;
                      for (int v : map.values()) {
                          cur = Math.max(v, cur);
                      }

                      max = Math.max(max, cur + dup + 1);
                  }
                  return max;
              }
          }
          這段代碼在天真的我看來是沒啥問題的,可就是沒辦法過,經過長久的排查錯誤,我寫了以下代碼加在上面的代碼里運行,搜索公眾號互聯(lián)網(wǎng)架構師復“2T”,送你一份驚喜禮包。
          public static void main(String[] args) {
              int[][] vals = {{2,3},{3,3},{-5,3}};
              Point[] points = new Point[3];

              for (int i=0; i<vals.length; i++){
                  points[i] = new Point(vals[i][0], vals[i][1]);
              }

              Solution solution = new Solution();

              System.out.println(solution.maxPoints(points));
          }

          它輸出的,竟然是2

          也就是說,它認為(3-3) / (3-2) 和 (3-3) / (-5-2) 不同? 什么鬼…
          經過debug,發(fā)現(xiàn)上述結果分別是0.0和-0.0
          0.0 難道不等于 -0.0 ?

          這時我心里已經一陣臥槽了,不過我還是寫了驗證代碼:

          System.out.println(0.0 == -0.0);
          結果是True,沒問題啊,我凌亂了……

          一定是java底層代碼錯了! 我沒錯……

          又是一陣debug,我找到了這條語句:
          map.put(d, map.get(d) == null ? 1 : map.get(d) + 1);

          我覺得map.get()很有問題, 它的源代碼是這樣的:

          public V get(Object key) {
              Node<K,V> e;
              return (e = getNode(hash(key), key)) == null ? null : e.value;
          }

          唔,先獲得hash()是吧,那我找到了它的hash函數(shù):

          static final int hash(Object key) {
              int h;
              return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
          }

          再來,這里是要比較h 和key的hashCode是吧,那我們去看hashCode()函數(shù)

          public native int hashCode();

          這是一個本地方法,看不到源碼了,唔,,那我就使用它看看吧,測試一下不就好了嗎,我寫了以下的測試代碼:搜索公眾號互聯(lián)網(wǎng)架構師復“2T”,送你一份驚喜禮包。

              public static void main(String[] args) {
                  System.out.println(0.0 == -0.0);
                  System.out.println(new Float(0.0).hashCode() == 
                      new Float(-0.0).hashCode());
              }

          結果竟然是True和False !!!

          這個源頭終于找到了, 0.0 和 -0.0 的hashCode值是不同的 !
          經過一番修改,我通過了這道題(其實精度也會有問題,應該使用BigDecimal的,不過??途W(wǎng)要求沒那么高。后來我想了想只有把直線方程寫成Ax+By+C=0的形式才能完全避免精度問題)
          接下來,探討下實數(shù)的hashCode()函數(shù)是個啥情況:

          2.實數(shù)的hashCode()

          那么我們來看看,0.0和-0.0調用equals方法是否相等:
          System.out.println(new Float(0.0).equals(0.0f));
          System.out.println(new Float(0.0).equals((float) -0.0));

          輸出是True 和 False

          好吧,二者調用equals() 方法不相等,看來是滿足了書里說的邏輯的

          那我們看看Float底層equals函數(shù)咋寫的:

          public boolean equals(Object obj) {
              return (obj instanceof Float)
                     && (floatToIntBits(((Float)obj).value) == 
                             floatToIntBits(value));
          }

          哦,原來是把Float轉換成Bits的時候發(fā)生了點奇妙的事,于是我找到了一切的源頭:搜索公眾號互聯(lián)網(wǎng)架構師復“2T”,送你一份驚喜禮包。

              /**
               * Returns a representation of the specified floating-point value
               * according to the IEEE 754 floating-point "single format" bit
               * layout.
               *
               * <p>Bit 31 (the bit that is selected by the mask
               * {@code 0x80000000}) represents the sign of the floating-point
               * number.
               * Bits 30-23 (the bits that are selected by the mask
               * {@code 0x7f800000}) represent the exponent.
               * Bits 22-0 (the bits that are selected by the mask
               * {@code 0x007fffff}) represent the significand (sometimes called
               * the mantissa) of the floating-point number.
               *
               * <p>If the argument is positive infinity, the result is
               * {@code 0x7f800000}.
               *
               * <p>If the argument is negative infinity, the result is
               * {@code 0xff800000}.
               *
               * <p>If the argument is NaN, the result is {@code 0x7fc00000}.
               *
               * <p>In all cases, the result is an integer that, when given to the
               * {@link #intBitsToFloat(int)} method, will produce a floating-point
               * value the same as the argument to {@code floatToIntBits}
               * (except all NaN values are collapsed to a single
               * "canonical" NaN value).
               *
               * @param   value   a floating-point number.
               * @return the bits that represent the floating-point number.
               */

              public static int floatToIntBits(float value) {
                  int result = floatToRawIntBits(value);
                  // Check for NaN based on values of bit fields, maximum
                  // exponent and nonzero significand.
                  if (((result & FloatConsts.EXP_BIT_MASK) ==
                        FloatConsts.EXP_BIT_MASK) &&
                       (result & FloatConsts.SIGNIF_BIT_MASK) != 0)
                      result = 0x7fc00000;
                  return result;
              }

          這文檔挺長的,也查了其它資料,看了半天終于搞懂了

          就是說Java浮點數(shù)的語義一般遵循IEEE 754二進制浮點算術標準。IEEE 754標準提供了浮點無窮,負無窮,負零和NaN(非數(shù)字)的定義。在使用Java過程中,一些特殊的浮點數(shù)通常會讓大家很迷惑

          當浮點運算產生一個非常接近0的負浮點數(shù)時,會產生“-0.0”,而這個浮點數(shù)不能正常表示

          我們可以輸出一波0.0和-0.0的數(shù)據(jù):

          System.out.println(Float.floatToIntBits((float0.0));
          System.out.println(Float.floatToIntBits((float) -0.0));
          System.out.println(Float.floatToRawIntBits(0.0f));
          System.out.println(Float.floatToRawIntBits((float)-0.0));

          結果:

          0
          -2147483648
          0
          -2147483648

          就是說,存儲-0.0, 竟然用的是0x80000000

          這也是我們熟悉的Integer.MIN_VALUE

          3.總結

          java中浮點數(shù)的表示比較復雜,特別是牽涉到-0.0NaN, 正負無窮這種,所以不適宜用來作為Map的key, 因為可能跟我們預想的不一致



          1、2T架構師學習資料干貨分享

          2、985副教授工資曝光

          3、心態(tài)崩了!稅前2萬4,到手1萬4,年終獎扣稅方式1月1日起施行~

          4、雷軍做程序員時寫的博客,很強大!

          5、人臉識別的時候,一定要穿上衣服??!

          6、清華大學:2021 元宇宙研究報告!

          7、績效被打3.25B,員工將支付寶告上了法院,判了

          瀏覽 20
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  美女国产一区二区 | 国产欧美91av研究在线 | 99这里只有精品 | www.超碰在线 | 男女系列视频福利网站 |