1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *    http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package org.apache.arrow.vector.compare.util;
19 
20 import org.apache.arrow.vector.Float4Vector;
21 import org.apache.arrow.vector.Float8Vector;
22 import org.apache.arrow.vector.FloatingPointVector;
23 import org.apache.arrow.vector.compare.VectorValueEqualizer;
24 
25 /**
26  * Vector value equalizers that regard values as equal if their difference
27  * is within a small threshold (epsilon).
28  */
29 public class ValueEpsilonEqualizers {
30 
ValueEpsilonEqualizers()31   private ValueEpsilonEqualizers() {
32 
33   }
34 
35   /**
36    * Difference function for floating point values.
37    */
38   public static class FloatingPointEpsilonEqualizer implements VectorValueEqualizer<FloatingPointVector> {
39     private final double epsilon;
40 
FloatingPointEpsilonEqualizer(double epsilon)41     public FloatingPointEpsilonEqualizer(double epsilon) {
42       this.epsilon = epsilon;
43     }
44 
45     @Override
valuesEqual( FloatingPointVector vector1, int index1, FloatingPointVector vector2, int index2)46     public final boolean valuesEqual(
47             FloatingPointVector vector1, int index1, FloatingPointVector vector2, int index2) {
48       boolean isNull1 = vector1.isNull(index1);
49       boolean isNull2 = vector2.isNull(index2);
50 
51       if (isNull1 || isNull2) {
52         return isNull1 == isNull2;
53       }
54 
55       double d1 = vector1.getValueAsDouble(index1);
56       double d2 = vector2.getValueAsDouble(index2);
57 
58       if (Double.isNaN(d1)) {
59         return Double.isNaN(d2);
60       }
61       if (Double.isInfinite(d1)) {
62         return Double.isInfinite(d2) && Math.signum(d1) == Math.signum(d2);
63       }
64 
65       return Math.abs(d1 - d2) <= epsilon;
66     }
67 
68     @Override
clone()69     public VectorValueEqualizer<FloatingPointVector> clone() {
70       return new FloatingPointEpsilonEqualizer(epsilon);
71     }
72   }
73 
74   /**
75    * Difference function for float values.
76    */
77   public static class Float4EpsilonEqualizer implements VectorValueEqualizer<Float4Vector> {
78     private final float epsilon;
79 
Float4EpsilonEqualizer(float epsilon)80     public Float4EpsilonEqualizer(float epsilon) {
81       this.epsilon = epsilon;
82     }
83 
84     @Override
valuesEqual(Float4Vector vector1, int index1, Float4Vector vector2, int index2)85     public final boolean valuesEqual(Float4Vector vector1, int index1, Float4Vector vector2, int index2) {
86       boolean isNull1 = vector1.isNull(index1);
87       boolean isNull2 = vector2.isNull(index2);
88 
89       if (isNull1 || isNull2) {
90         return isNull1 == isNull2;
91       }
92 
93       float f1 = vector1.get(index1);
94       float f2 = vector2.get(index2);
95 
96       if (Float.isNaN(f1)) {
97         return Float.isNaN(f2);
98       }
99       if (Float.isInfinite(f1)) {
100         return Float.isInfinite(f2) && Math.signum(f1) == Math.signum(f2);
101       }
102 
103       return Math.abs(f1 - f2) <= epsilon;
104     }
105 
106     @Override
clone()107     public VectorValueEqualizer<Float4Vector> clone() {
108       return new Float4EpsilonEqualizer(epsilon);
109     }
110   }
111 
112   /**
113    * Difference function for double values.
114    */
115   public static class Float8EpsilonEqualizer implements VectorValueEqualizer<Float8Vector> {
116     private final double epsilon;
117 
Float8EpsilonEqualizer(double epsilon)118     public Float8EpsilonEqualizer(double epsilon) {
119       this.epsilon = epsilon;
120     }
121 
122     @Override
valuesEqual(Float8Vector vector1, int index1, Float8Vector vector2, int index2)123     public final boolean valuesEqual(Float8Vector vector1, int index1, Float8Vector vector2, int index2) {
124       boolean isNull1 = vector1.isNull(index1);
125       boolean isNull2 = vector2.isNull(index2);
126 
127       if (isNull1 || isNull2) {
128         return isNull1 == isNull2;
129       }
130 
131       double d1 = vector1.get(index1);
132       double d2 = vector2.get(index2);
133 
134       if (Double.isNaN(d1)) {
135         return Double.isNaN(d2);
136       }
137       if (Double.isInfinite(d1)) {
138         return Double.isInfinite(d2) && Math.signum(d1) == Math.signum(d2);
139       }
140 
141       return Math.abs(d1 - d2) <= epsilon;
142     }
143 
144     @Override
clone()145     public VectorValueEqualizer<Float8Vector> clone() {
146       return new Float8EpsilonEqualizer(epsilon);
147     }
148   }
149 }
150