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;
  }
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.