cdm/src/main/java/ucar/ma2/MAMath.java
public static boolean nearlyEquals(Array data1, Array data2) {
    if (data1 == data2) {  // Covers case when both are null.
      return true;
    } else if (data1 == null || data2 == null) {
      return false;
    }

    if (data1.getSize() != data2.getSize()) return false;
    if (data1.isUnsigned() != data2.isUnsigned()) return false;
    DataType dt = DataType.getType(data1);

    IndexIterator iter1 = data1.getIndexIterator();
    IndexIterator iter2 = data2.getIndexIterator();

    if (dt == DataType.DOUBLE) {
      while (iter1.hasNext() && iter2.hasNext()) {
        double v1 = iter1.getDoubleNext();
        double v2 = iter2.getDoubleNext();
        if (!Misc.nearlyEquals(v1, v2, Misc.defaultMaxRelativeDiffDouble))
          return false;
      }
    } else if (dt == DataType.FLOAT) {
      while (iter1.hasNext() && iter2.hasNext()) {
        float v1 = iter1.getFloatNext();
        float v2 = iter2.getFloatNext();
        if (!Misc.nearlyEquals(v1, v2, Misc.defaultMaxRelativeDiffFloat))
          return false;
      }
    } else if (dt.getPrimitiveClassType() == int.class) {
      while (iter1.hasNext() && iter2.hasNext()) {
        int v1 = iter1.getIntNext();
        int v2 = iter2.getIntNext();
        if (v1 != v2) return false;
      }
    } else if (dt.getPrimitiveClassType() == byte.class) {
      while (iter1.hasNext() && iter2.hasNext()) {
        short v1 = iter1.getShortNext();
        short v2 = iter2.getShortNext();
        if (v1 != v2) return false;
      }
    } else if (dt.getPrimitiveClassType() == short.class) {
      while (iter1.hasNext() && iter2.hasNext()) {
        byte v1 = iter1.getByteNext();
        byte v2 = iter2.getByteNext();
        if (v1 != v2) return false;
      }
    } else if (dt.getPrimitiveClassType() == long.class) {
      while (iter1.hasNext() && iter2.hasNext()) {
        long v1 = iter1.getLongNext();
        long v2 = iter2.getLongNext();
        if (v1 != v2) return false;
      }
    } else {
      while (iter1.hasNext() && iter2.hasNext()) {
        if (!Objects.equals(iter1.next(), iter2.next())) {
          return false;
        }
      }
    }

    return true;
  }
public static boolean nearlyEquals(Array data1, Array data2) {
    if (data1 == data2) {  // Covers case when both are null.
      return true;
    } else if (data1 == null || data2 == null) {
      return false;
    }

    if (data1.getSize() != data2.getSize()) return false;
    if (data1.isUnsigned() != data2.isUnsigned()) return false;
    DataType dt = DataType.getType(data1);

    IndexIterator iter1 = data1.getIndexIterator();
    IndexIterator iter2 = data2.getIndexIterator();

    if (dt == DataType.DOUBLE) {
      while (iter1.hasNext() && iter2.hasNext()) {
        double v1 = iter1.getDoubleNext();
        double v2 = iter2.getDoubleNext();
        if (!Misc.nearlyEquals(v1, v2, Misc.defaultMaxRelativeDiffDouble))
          return false;
      }
    } else if (dt == DataType.FLOAT) {
      while (iter1.hasNext() && iter2.hasNext()) {
        float v1 = iter1.getFloatNext();
        float v2 = iter2.getFloatNext();
        if (!Misc.nearlyEquals(v1, v2, Misc.defaultMaxRelativeDiffFloat))
          return false;
      }
    } else if (dt.getPrimitiveClassType() == int.class) {
      while (iter1.hasNext() && iter2.hasNext()) {
        int v1 = iter1.getIntNext();
        int v2 = iter2.getIntNext();
        if (v1 != v2) return false;
      }
    } else if (dt.getPrimitiveClassType() == byte.class) {
      while (iter1.hasNext() && iter2.hasNext()) {
        short v1 = iter1.getShortNext();
        short v2 = iter2.getShortNext();
        if (v1 != v2) return false;
      }
    } else if (dt.getPrimitiveClassType() == short.class) {
      while (iter1.hasNext() && iter2.hasNext()) {
        byte v1 = iter1.getByteNext();
        byte v2 = iter2.getByteNext();
        if (v1 != v2) return false;
      }
    } else if (dt.getPrimitiveClassType() == long.class) {
      while (iter1.hasNext() && iter2.hasNext()) {
        long v1 = iter1.getLongNext();
        long v2 = iter2.getLongNext();
        if (v1 != v2) return false;
      }
    } else {
      while (iter1.hasNext() && iter2.hasNext()) {
        if (!Objects.equals(iter1.next(), iter2.next())) {
          return false;
        }
      }
    }

    return true;
  }
public static boolean nearlyEquals ( Array data1 , Array data2 ) { if ( data1 == data2 ) { // Covers case when both are null.
 return true ; } else if ( data1 == null || data2 == null ) { return false ; } if ( data1 . getSize ( ) != data2 . getSize ( ) ) return false ; if ( data1 . isUnsigned ( ) != data2 . isUnsigned ( ) ) return false ; DataType dt = DataType . getType ( data1 ) ; IndexIterator iter1 = data1 . getIndexIterator ( ) ; IndexIterator iter2 = data2 . getIndexIterator ( ) ; if ( dt == DataType . DOUBLE ) { while ( iter1 . hasNext ( ) && iter2 . hasNext ( ) ) { double v1 = iter1 . getDoubleNext ( ) ; double v2 = iter2 . getDoubleNext ( ) ; if ( ! Misc . nearlyEquals ( v1 , v2 , Misc . defaultMaxRelativeDiffDouble ) ) return false ; } } else if ( dt == DataType . FLOAT ) { while ( iter1 . hasNext ( ) && iter2 . hasNext ( ) ) { float v1 = iter1 . getFloatNext ( ) ; float v2 = iter2 . getFloatNext ( ) ; if ( ! Misc . nearlyEquals ( v1 , v2 , Misc . defaultMaxRelativeDiffFloat ) ) return false ; } } else if ( dt . getPrimitiveClassType ( ) == int . class ) { while ( iter1 . hasNext ( ) && iter2 . hasNext ( ) ) { int v1 = iter1 . getIntNext ( ) ; int v2 = iter2 . getIntNext ( ) ; if ( v1 != v2 ) return false ; } } else if ( dt . getPrimitiveClassType ( ) == byte . class ) { while ( iter1 . hasNext ( ) && iter2 . hasNext ( ) ) { short v1 = iter1 . getShortNext ( ) ; short v2 = iter2 . getShortNext ( ) ; if ( v1 != v2 ) return false ; } } else if ( dt . getPrimitiveClassType ( ) == short . class ) { while ( iter1 . hasNext ( ) && iter2 . hasNext ( ) ) { byte v1 = iter1 . getByteNext ( ) ; byte v2 = iter2 . getByteNext ( ) ; if ( v1 != v2 ) return false ; } } else if ( dt . getPrimitiveClassType ( ) == long . class ) { while ( iter1 . hasNext ( ) && iter2 . hasNext ( ) ) { long v1 = iter1 . getLongNext ( ) ; long v2 = iter2 . getLongNext ( ) ; if ( v1 != v2 ) return false ; } } else { while ( iter1 . hasNext ( ) && iter2 . hasNext ( ) ) { if ( ! Objects . equals ( iter1 . next ( ) , iter2 . next ( ) ) ) { return false ; } } } return true ; }
Returns true if the specified arrays have the same size, signedness, and <b>approximately</b> equal corresponding
elements. {@code float} elements must be within {@link Misc#defaultMaxRelativeDiffFloat} of each other, as
determined by {@link Misc#nearlyEquals(double, double, double)}. Similarly, {@code double} elements must be within
{@link Misc#defaultMaxRelativeDiffDouble} of each other.
<p>
{@link #equals(Array, Array)} is an alternative to this method that requires that corresponding elements be
<b>exactly</b> equal. It is suitable for use in {@link Object#equals} implementations, whereas this method isn't.

@param data1  one array to be tested for equality.
@param data2  the other array to be tested for equality.
@return true if the specified arrays have the same size, signedness, and approximately equal corresponding elems.
Returns true if the specified arrays have the same size signedness and <b > approximately< / b > equal corresponding elements . { @code float } elements must be within { @link Misc#defaultMaxRelativeDiffFloat } of each other as determined by { @link Misc#nearlyEquals ( double double double ) } . Similarly { @code double } elements must be within { @link Misc#defaultMaxRelativeDiffDouble } of each other . <p > { @link #equals ( Array Array ) } is an alternative to this method that requires that corresponding elements be <b > exactly< / b > equal . It is suitable for use in { @link Object#equals } implementations whereas this method isn t .