Skip to content

Commit 907c17d

Browse files
committed
[ARROW-6458][Java] Remove value boxing/unboxing for ApproxEqualsVisitor
1 parent 934c18e commit 907c17d

File tree

2 files changed

+171
-22
lines changed

2 files changed

+171
-22
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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;
19+
20+
import java.util.concurrent.TimeUnit;
21+
22+
import org.apache.arrow.memory.BufferAllocator;
23+
import org.apache.arrow.memory.RootAllocator;
24+
import org.apache.arrow.vector.compare.ApproxEqualsVisitor;
25+
import org.apache.arrow.vector.compare.Range;
26+
import org.openjdk.jmh.annotations.Benchmark;
27+
import org.openjdk.jmh.annotations.BenchmarkMode;
28+
import org.openjdk.jmh.annotations.Mode;
29+
import org.openjdk.jmh.annotations.OutputTimeUnit;
30+
import org.openjdk.jmh.annotations.Scope;
31+
import org.openjdk.jmh.annotations.Setup;
32+
import org.openjdk.jmh.annotations.State;
33+
import org.openjdk.jmh.annotations.TearDown;
34+
import org.openjdk.jmh.runner.Runner;
35+
import org.openjdk.jmh.runner.RunnerException;
36+
import org.openjdk.jmh.runner.options.Options;
37+
import org.openjdk.jmh.runner.options.OptionsBuilder;
38+
39+
/**
40+
* Benchmarks for floating point vectors.
41+
*/
42+
@State(Scope.Benchmark)
43+
public class FloatingPointBenchmarks {
44+
45+
private static final int VECTOR_LENGTH = 1024;
46+
47+
private static final int ALLOCATOR_CAPACITY = 1024 * 1024;
48+
49+
private BufferAllocator allocator;
50+
51+
private Float4Vector floatVector1;
52+
53+
private Float4Vector floatVector2;
54+
55+
private Float8Vector doubleVector1;
56+
57+
private Float8Vector doubleVector2;
58+
59+
private ApproxEqualsVisitor floatVisitor;
60+
61+
private ApproxEqualsVisitor doubleVisitor;
62+
63+
private Range range;
64+
65+
/**
66+
* Setup benchmarks.
67+
*/
68+
@Setup
69+
public void prepare() {
70+
allocator = new RootAllocator(ALLOCATOR_CAPACITY);
71+
floatVector1 = new Float4Vector("vector", allocator);
72+
floatVector2 = new Float4Vector("vector", allocator);
73+
doubleVector1 = new Float8Vector("vector", allocator);
74+
doubleVector2 = new Float8Vector("vector", allocator);
75+
76+
floatVector1.allocateNew(VECTOR_LENGTH);
77+
floatVector2.allocateNew(VECTOR_LENGTH);
78+
doubleVector1.allocateNew(VECTOR_LENGTH);
79+
doubleVector2.allocateNew(VECTOR_LENGTH);
80+
81+
for (int i = 0; i < VECTOR_LENGTH; i++) {
82+
if (i % 3 == 0) {
83+
floatVector1.setNull(i);
84+
floatVector2.setNull(i);
85+
doubleVector1.setNull(i);
86+
doubleVector2.setNull(i);
87+
} else {
88+
floatVector1.set(i, i * i);
89+
floatVector2.set(i, i * i);
90+
doubleVector1.set(i, i * i);
91+
doubleVector2.set(i, i * i);
92+
}
93+
}
94+
floatVector1.setValueCount(VECTOR_LENGTH);
95+
floatVector2.setValueCount(VECTOR_LENGTH);
96+
doubleVector1.setValueCount(VECTOR_LENGTH);
97+
doubleVector2.setValueCount(VECTOR_LENGTH);
98+
99+
floatVisitor = new ApproxEqualsVisitor(floatVector1, floatVector2, 0.01f, 0.01);
100+
doubleVisitor = new ApproxEqualsVisitor(doubleVector1, doubleVector2, 0.01f, 0.01);
101+
range = new Range(0, 0, VECTOR_LENGTH);
102+
}
103+
104+
/**
105+
* Tear down benchmarks.
106+
*/
107+
@TearDown
108+
public void tearDown() {
109+
floatVector1.close();
110+
floatVector2.close();
111+
doubleVector1.close();
112+
doubleVector2.close();
113+
allocator.close();
114+
}
115+
116+
@Benchmark
117+
@BenchmarkMode(Mode.AverageTime)
118+
@OutputTimeUnit(TimeUnit.MICROSECONDS)
119+
public int approxEqualsBenchmark() {
120+
boolean floatResult = floatVisitor.visit(floatVector1, range);
121+
boolean doubleResult = doubleVisitor.visit(doubleVector1, range);
122+
return (floatResult ? 1 : 0) + (doubleResult ? 1 : 0);
123+
}
124+
125+
public static void main(String [] args) throws RunnerException {
126+
Options opt = new OptionsBuilder()
127+
.include(FloatingPointBenchmarks.class.getSimpleName())
128+
.forks(1)
129+
.build();
130+
131+
new Runner(opt).run();
132+
}
133+
}
134+

java/vector/src/main/java/org/apache/arrow/vector/compare/ApproxEqualsVisitor.java

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import org.apache.arrow.vector.ValueVector;
2424

2525
/**
26-
* Visitor to compare floating point.
26+
* Visitor to compare floating point vectors approximately.
2727
*/
2828
public class ApproxEqualsVisitor extends RangeEqualsVisitor {
2929

@@ -36,10 +36,8 @@ public class ApproxEqualsVisitor extends RangeEqualsVisitor {
3636
/**
3737
* Functions to calculate difference between float/double values.
3838
*/
39-
private DiffFunction<Float> floatDiffFunction =
40-
(Float value1, Float value2) -> Math.abs(value1 - value2);
41-
private DiffFunction<Double> doubleDiffFunction =
42-
(Double value1, Double value2) -> Math.abs(value1 - value2);
39+
private DiffFunctionFloat floatDiffFunction;
40+
private DiffFunctionDouble doubleDiffFunction;
4341

4442
/**
4543
* Constructs a new instance.
@@ -53,13 +51,18 @@ public ApproxEqualsVisitor(ValueVector left, ValueVector right, float floatEpsil
5351
super(left, right, true);
5452
this.floatEpsilon = floatEpsilon;
5553
this.doubleEpsilon = doubleEpsilon;
54+
55+
floatDiffFunction =
56+
(float value1, float value2) -> Math.abs(value1 - value2) <= floatEpsilon;
57+
doubleDiffFunction =
58+
(double value1, double value2) -> Math.abs(value1 - value2) <= doubleEpsilon;
5659
}
5760

58-
public void setFloatDiffFunction(DiffFunction<Float> floatDiffFunction) {
61+
public void setFloatDiffFunction(DiffFunctionFloat floatDiffFunction) {
5962
this.floatDiffFunction = floatDiffFunction;
6063
}
6164

62-
public void setDoubleDiffFunction(DiffFunction<Double> doubleDiffFunction) {
65+
public void setDoubleDiffFunction(DiffFunctionDouble doubleDiffFunction) {
6366
this.doubleDiffFunction = doubleDiffFunction;
6467
}
6568

@@ -94,15 +97,15 @@ private boolean float4ApproxEquals(Range range) {
9497
}
9598

9699
if (!isNull) {
97-
Float leftValue = leftVector.get(leftIndex);
98-
Float rightValue = rightVector.get(rightIndex);
99-
if (leftValue.isNaN()) {
100-
return rightValue.isNaN();
100+
float leftValue = leftVector.get(leftIndex);
101+
float rightValue = rightVector.get(rightIndex);
102+
if (Float.isNaN(leftValue)) {
103+
return Float.isNaN(rightValue);
101104
}
102-
if (leftValue.isInfinite()) {
103-
return rightValue.isInfinite() && Math.signum(leftValue) == Math.signum(rightValue);
105+
if (Float.isInfinite(leftValue)) {
106+
return Float.isInfinite(rightValue) && Math.signum(leftValue) == Math.signum(rightValue);
104107
}
105-
if (floatDiffFunction.apply(leftValue, rightValue) > floatEpsilon) {
108+
if (!floatDiffFunction.approxEquals(leftValue, rightValue)) {
106109
return false;
107110
}
108111
}
@@ -126,21 +129,33 @@ private boolean float8ApproxEquals(Range range) {
126129

127130
if (!isNull) {
128131

129-
Double leftValue = leftVector.get(leftIndex);
130-
Double rightValue = rightVector.get(rightIndex);
131-
if (leftValue.isNaN()) {
132-
return rightValue.isNaN();
132+
double leftValue = leftVector.get(leftIndex);
133+
double rightValue = rightVector.get(rightIndex);
134+
if (Double.isNaN(leftValue)) {
135+
return Double.isNaN(rightValue);
133136
}
134-
if (leftValue.isInfinite()) {
135-
return rightValue.isInfinite() && Math.signum(leftValue) == Math.signum(rightValue);
137+
if (Double.isInfinite(leftValue)) {
138+
return Double.isInfinite(rightValue) && Math.signum(leftValue) == Math.signum(rightValue);
136139
}
137-
if (doubleDiffFunction.apply(leftValue, rightValue) > doubleEpsilon) {
140+
if (!doubleDiffFunction.approxEquals(leftValue, rightValue)) {
138141
return false;
139142
}
140143
}
141144
}
142145
return true;
143146
}
144-
}
145147

148+
/**
149+
* Difference function for float values.
150+
*/
151+
public interface DiffFunctionFloat {
152+
boolean approxEquals(float v1, float v2);
153+
}
146154

155+
/**
156+
* Difference function for double values.
157+
*/
158+
public interface DiffFunctionDouble {
159+
boolean approxEquals(double v1, double v2);
160+
}
161+
}

0 commit comments

Comments
 (0)