Fixed extremes calculation in presense of NaNs [#METR-22882].

This commit is contained in:
Alexey Milovidov 2016-12-28 12:20:42 +03:00
parent 00176b9c5e
commit 9c39a324f2
3 changed files with 103 additions and 7 deletions

View File

@ -120,6 +120,27 @@ template <> inline UInt64 unionCastToUInt64(Float32 x)
} }
/// To be sure, that this function is zero-cost for non-floating point types.
template <typename T>
inline bool isNaN(T x)
{
return std::is_floating_point<T>::value ? isnan(x) : false;
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type NaNOrZero()
{
return std::numeric_limits<T>::quiet_NaN();
}
template <typename T>
typename std::enable_if<!std::is_floating_point<T>::value, T>::type NaNOrZero()
{
return 0;
}
/** Шаблон столбцов, которые используют для хранения простой массив. /** Шаблон столбцов, которые используют для хранения простой массив.
*/ */
template <typename T> template <typename T>
@ -435,16 +456,35 @@ public:
return; return;
} }
T cur_min = data[0]; bool has_value = false;
T cur_max = data[0];
for (size_t i = 1; i < size; ++i) /** Skip all NaNs in extremes calculation.
* If all values are NaNs, then return NaN.
* NOTE: There exist many different NaNs.
* Different NaN could be returned: not bit-exact value as one of NaNs from column.
*/
T cur_min = NaNOrZero<T>();
T cur_max = NaNOrZero<T>();
for (const T x : data)
{ {
if (data[i] < cur_min) if (isNaN(x))
cur_min = data[i]; continue;
if (data[i] > cur_max) if (!has_value)
cur_max = data[i]; {
cur_min = x;
cur_max = x;
has_value = true;
continue;
}
if (x < cur_min)
cur_min = x;
if (x > cur_max)
cur_max = x;
} }
min = typename NearestFieldType<T>::Type(cur_min); min = typename NearestFieldType<T>::Type(cur_min);

View File

@ -0,0 +1,48 @@
3
1
2
1
3
nan
1
2
1
2
3
nan
2
2
3
3
1
nan
1
3
nan
nan
2
2
2
nan
1
nan
1
1
3
nan
nan
3
3
nan
nan
nan
nan
nan

View File

@ -0,0 +1,8 @@
SELECT arrayJoin([3, 1, 2]) SETTINGS extremes = 1;
SELECT arrayJoin([nan, 1, 2]) SETTINGS extremes = 1;
SELECT arrayJoin([3, nan, 2]) SETTINGS extremes = 1;
SELECT arrayJoin([3, 1, nan]) SETTINGS extremes = 1;
SELECT arrayJoin([nan, nan, 2]) SETTINGS extremes = 1;
SELECT arrayJoin([nan, 1, nan]) SETTINGS extremes = 1;
SELECT arrayJoin([3, nan, nan]) SETTINGS extremes = 1;
SELECT arrayJoin([nan, nan, nan]) SETTINGS extremes = 1;