Skip to content

Commit 20a7bab

Browse files
authored
[refactor](exec) Refactor BE floating-point comparisons. (apache#55421)
before ``` mysql> select * from sort_float order by d; +------+-----------+ | id | d | +------+-----------+ | 8 | NaN | | 9 | NaN | | 5 | -Infinity | | 2 | -123 | | 6 | -0 | | 7 | 0 | | 1 | 123 | | 3 | 114514 | | 4 | Infinity | +------+-----------+ ``` now ``` mysql> select * from sort_float order by d; +------+-----------+ | id | d | +------+-----------+ | 5 | -Infinity | | 2 | -123 | | 6 | -0 | | 7 | 0 | | 1 | 123 | | 3 | 114514 | | 4 | Infinity | | 8 | NaN | | 9 | NaN | +------+-----------+ ```
1 parent 7dda320 commit 20a7bab

File tree

11 files changed

+1449
-1253
lines changed

11 files changed

+1449
-1253
lines changed

be/src/common/compare.h

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with 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,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
#include <cmath>
19+
20+
#include "common/compiler_util.h"
21+
#include "runtime/type_limit.h"
22+
23+
#pragma once
24+
namespace doris {
25+
#include "common/compile_check_begin.h"
26+
struct Compare {
27+
template <typename T>
28+
static bool less(const T& a, const T& b) {
29+
return a < b;
30+
}
31+
template <typename T>
32+
static bool greater(const T& a, const T& b) {
33+
return a > b;
34+
}
35+
36+
template <typename T>
37+
static bool less_equal(const T& a, const T& b) {
38+
return a <= b;
39+
}
40+
template <typename T>
41+
static bool greater_equal(const T& a, const T& b) {
42+
return a >= b;
43+
}
44+
template <typename T>
45+
static bool equal(const T& a, const T& b) {
46+
return a == b;
47+
}
48+
template <typename T>
49+
static bool not_equal(const T& a, const T& b) {
50+
return a != b;
51+
}
52+
53+
template <typename T>
54+
static int compare(const T& a, const T& b) {
55+
return a > b ? 1 : (a < b ? -1 : 0);
56+
}
57+
58+
template <typename T>
59+
static T min(const T& a, const T& b) {
60+
return less(a, b) ? a : b;
61+
}
62+
63+
template <typename T>
64+
static T max(const T& a, const T& b) {
65+
return greater(a, b) ? a : b;
66+
}
67+
68+
template <typename T>
69+
static T min_value() {
70+
return type_limit<T>::min();
71+
}
72+
73+
template <typename T>
74+
static T max_value() {
75+
return type_limit<T>::max();
76+
}
77+
};
78+
79+
template <typename T>
80+
bool EqualsFloat(T left, T right) {
81+
if (UNLIKELY(std::isnan(left) && std::isnan(right))) {
82+
return true;
83+
}
84+
return left == right;
85+
}
86+
87+
template <typename T>
88+
bool GreaterThanFloat(T left, T right) {
89+
// nan is always bigger than everything else
90+
bool left_is_nan = std::isnan(left);
91+
bool right_is_nan = std::isnan(right);
92+
if (UNLIKELY(right_is_nan)) {
93+
return false;
94+
}
95+
if (UNLIKELY(left_is_nan)) {
96+
return true;
97+
}
98+
return left > right;
99+
}
100+
101+
template <typename T>
102+
bool GreaterThanEqualsFloat(T left, T right) {
103+
// nan is always bigger than everything else
104+
bool left_is_nan = std::isnan(left);
105+
bool right_is_nan = std::isnan(right);
106+
if (UNLIKELY(right_is_nan)) {
107+
return left_is_nan;
108+
}
109+
if (UNLIKELY(left_is_nan)) {
110+
return true;
111+
}
112+
return left >= right;
113+
}
114+
115+
template <typename T>
116+
int CompareFloat(T left, T right) {
117+
// nan is always bigger than everything else
118+
bool left_is_nan = std::isnan(left);
119+
bool right_is_nan = std::isnan(right);
120+
if (UNLIKELY(left_is_nan || right_is_nan)) {
121+
if (left_is_nan && right_is_nan) {
122+
return 0;
123+
}
124+
if (left_is_nan) {
125+
return 1;
126+
} else {
127+
return -1;
128+
}
129+
}
130+
return left > right ? 1 : (left < right ? -1 : 0);
131+
};
132+
133+
// float
134+
template <>
135+
inline bool Compare::less(const float& a, const float& b) {
136+
return GreaterThanFloat(b, a);
137+
}
138+
template <>
139+
inline bool Compare::greater(const float& a, const float& b) {
140+
return GreaterThanFloat(a, b);
141+
}
142+
template <>
143+
inline bool Compare::less_equal(const float& a, const float& b) {
144+
return GreaterThanEqualsFloat(b, a);
145+
}
146+
template <>
147+
inline bool Compare::greater_equal(const float& a, const float& b) {
148+
return GreaterThanEqualsFloat(a, b);
149+
}
150+
template <>
151+
inline bool Compare::equal(const float& a, const float& b) {
152+
return EqualsFloat(a, b);
153+
}
154+
template <>
155+
inline bool Compare::not_equal(const float& a, const float& b) {
156+
return !EqualsFloat(a, b);
157+
}
158+
template <>
159+
inline int Compare::compare(const float& a, const float& b) {
160+
return CompareFloat(a, b);
161+
}
162+
template <>
163+
inline float Compare::max_value<float>() {
164+
return std::numeric_limits<float>::quiet_NaN();
165+
}
166+
167+
// double
168+
template <>
169+
inline bool Compare::less(const double& a, const double& b) {
170+
return GreaterThanFloat(b, a);
171+
}
172+
template <>
173+
inline bool Compare::greater(const double& a, const double& b) {
174+
return GreaterThanFloat(a, b);
175+
}
176+
template <>
177+
inline bool Compare::less_equal(const double& a, const double& b) {
178+
return GreaterThanEqualsFloat(b, a);
179+
}
180+
template <>
181+
inline bool Compare::greater_equal(const double& a, const double& b) {
182+
return GreaterThanEqualsFloat(a, b);
183+
}
184+
template <>
185+
inline bool Compare::equal(const double& a, const double& b) {
186+
return EqualsFloat(a, b);
187+
}
188+
template <>
189+
inline bool Compare::not_equal(const double& a, const double& b) {
190+
return !EqualsFloat(a, b);
191+
}
192+
template <>
193+
inline int Compare::compare(const double& a, const double& b) {
194+
return CompareFloat(a, b);
195+
}
196+
template <>
197+
inline double Compare::max_value<double>() {
198+
return std::numeric_limits<double>::quiet_NaN();
199+
}
200+
} // namespace doris
201+
202+
#include "common/compile_check_end.h"

be/src/vec/aggregate_functions/aggregate_function_min_max.h

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <vector>
3131

3232
#include "common/cast_set.h"
33+
#include "common/compare.h"
3334
#include "common/logging.h"
3435
#include "runtime/primitive_type.h"
3536
#include "runtime/type_limit.h"
@@ -78,20 +79,20 @@ struct SingleValueDataFixed {
7879
constexpr static bool IsFixedLength = true;
7980

8081
void set_to_min_max(bool max) {
81-
value = max ? type_limit<typename PrimitiveTypeTraits<T>::ColumnItemType>::max()
82-
: type_limit<typename PrimitiveTypeTraits<T>::ColumnItemType>::min();
82+
value = max ? Compare::max_value<typename PrimitiveTypeTraits<T>::ColumnItemType>()
83+
: Compare::min_value<typename PrimitiveTypeTraits<T>::ColumnItemType>();
8384
}
8485

8586
void change_if(const IColumn& column, size_t row_num, bool less) {
8687
has_value = true;
87-
value = less ? std::min(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
88-
TypeCheckOnRelease::DISABLE>(column)
89-
.get_data()[row_num],
90-
value)
91-
: std::max(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
92-
TypeCheckOnRelease::DISABLE>(column)
93-
.get_data()[row_num],
94-
value);
88+
value = less ? Compare::min(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
89+
TypeCheckOnRelease::DISABLE>(column)
90+
.get_data()[row_num],
91+
value)
92+
: Compare::max(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
93+
TypeCheckOnRelease::DISABLE>(column)
94+
.get_data()[row_num],
95+
value);
9596
}
9697

9798
void insert_result_into(IColumn& to) const {
@@ -137,9 +138,10 @@ struct SingleValueDataFixed {
137138
}
138139

139140
bool change_if_less(const IColumn& column, size_t row_num, Arena& arena) {
140-
if (!has() || assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
141-
TypeCheckOnRelease::DISABLE>(column)
142-
.get_data()[row_num] < value) {
141+
if (!has() || Compare::less(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
142+
TypeCheckOnRelease::DISABLE>(column)
143+
.get_data()[row_num],
144+
value)) {
143145
change(column, row_num, arena);
144146
return true;
145147
} else {
@@ -148,7 +150,7 @@ struct SingleValueDataFixed {
148150
}
149151

150152
bool change_if_less(const Self& to, Arena& arena) {
151-
if (to.has() && (!has() || to.value < value)) {
153+
if (to.has() && (!has() || Compare::less(to.value, value))) {
152154
change(to, arena);
153155
return true;
154156
} else {
@@ -157,9 +159,11 @@ struct SingleValueDataFixed {
157159
}
158160

159161
bool change_if_greater(const IColumn& column, size_t row_num, Arena& arena) {
160-
if (!has() || assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
161-
TypeCheckOnRelease::DISABLE>(column)
162-
.get_data()[row_num] > value) {
162+
if (!has() ||
163+
Compare::greater(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
164+
TypeCheckOnRelease::DISABLE>(column)
165+
.get_data()[row_num],
166+
value)) {
163167
change(column, row_num, arena);
164168
return true;
165169
} else {
@@ -171,13 +175,14 @@ struct SingleValueDataFixed {
171175
if (!has()) {
172176
return false;
173177
}
174-
return assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
175-
TypeCheckOnRelease::DISABLE>(column)
176-
.get_data()[row_num] == value;
178+
return Compare::equal(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
179+
TypeCheckOnRelease::DISABLE>(column)
180+
.get_data()[row_num],
181+
value);
177182
}
178183

179184
bool change_if_greater(const Self& to, Arena& arena) {
180-
if (to.has() && (!has() || to.value > value)) {
185+
if (to.has() && (!has() || Compare::greater(to.value, value))) {
181186
change(to, arena);
182187
return true;
183188
} else {
@@ -217,20 +222,20 @@ struct SingleValueDataDecimal {
217222
constexpr static bool IsFixedLength = true;
218223

219224
void set_to_min_max(bool max) {
220-
value = max ? type_limit<typename PrimitiveTypeTraits<T>::ColumnItemType>::max()
221-
: type_limit<typename PrimitiveTypeTraits<T>::ColumnItemType>::min();
225+
value = max ? Compare::max_value<typename PrimitiveTypeTraits<T>::ColumnItemType>()
226+
: Compare::min_value<typename PrimitiveTypeTraits<T>::ColumnItemType>();
222227
}
223228

224229
void change_if(const IColumn& column, size_t row_num, bool less) {
225230
has_value = true;
226-
value = less ? std::min(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
227-
TypeCheckOnRelease::DISABLE>(column)
228-
.get_data()[row_num],
229-
value)
230-
: std::max(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
231-
TypeCheckOnRelease::DISABLE>(column)
232-
.get_data()[row_num],
233-
value);
231+
value = less ? Compare::min(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
232+
TypeCheckOnRelease::DISABLE>(column)
233+
.get_data()[row_num],
234+
value)
235+
: Compare::max(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
236+
TypeCheckOnRelease::DISABLE>(column)
237+
.get_data()[row_num],
238+
value);
234239
}
235240

236241
void insert_result_into(IColumn& to) const {
@@ -276,9 +281,10 @@ struct SingleValueDataDecimal {
276281
}
277282

278283
bool change_if_less(const IColumn& column, size_t row_num, Arena& arena) {
279-
if (!has() || assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
280-
TypeCheckOnRelease::DISABLE>(column)
281-
.get_data()[row_num] < value) {
284+
if (!has() || Compare::less(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
285+
TypeCheckOnRelease::DISABLE>(column)
286+
.get_data()[row_num],
287+
value)) {
282288
change(column, row_num, arena);
283289
return true;
284290
} else {
@@ -287,7 +293,7 @@ struct SingleValueDataDecimal {
287293
}
288294

289295
bool change_if_less(const Self& to, Arena& arena) {
290-
if (to.has() && (!has() || to.value < value)) {
296+
if (to.has() && (!has() || Compare::less(to.value, value))) {
291297
change(to, arena);
292298
return true;
293299
} else {
@@ -296,9 +302,11 @@ struct SingleValueDataDecimal {
296302
}
297303

298304
bool change_if_greater(const IColumn& column, size_t row_num, Arena& arena) {
299-
if (!has() || assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
300-
TypeCheckOnRelease::DISABLE>(column)
301-
.get_data()[row_num] > value) {
305+
if (!has() ||
306+
Compare::greater(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
307+
TypeCheckOnRelease::DISABLE>(column)
308+
.get_data()[row_num],
309+
value)) {
302310
change(column, row_num, arena);
303311
return true;
304312
} else {
@@ -307,7 +315,7 @@ struct SingleValueDataDecimal {
307315
}
308316

309317
bool change_if_greater(const Self& to, Arena& arena) {
310-
if (to.has() && (!has() || to.value > value)) {
318+
if (to.has() && (!has() || Compare::greater(to.value, value))) {
311319
change(to, arena);
312320
return true;
313321
} else {
@@ -319,9 +327,10 @@ struct SingleValueDataDecimal {
319327
if (!has()) {
320328
return false;
321329
}
322-
return assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
323-
TypeCheckOnRelease::DISABLE>(column)
324-
.get_data()[row_num] == value;
330+
return Compare::equal(assert_cast<const typename PrimitiveTypeTraits<T>::ColumnType&,
331+
TypeCheckOnRelease::DISABLE>(column)
332+
.get_data()[row_num],
333+
value);
325334
}
326335

327336
void change_first_time(const IColumn& column, size_t row_num, Arena& arena) {

0 commit comments

Comments
 (0)