Fix nulls/infinities

This commit is contained in:
Michael Kolupaev 2024-11-09 00:00:42 +00:00
parent 9ae02bf9c7
commit 539b17c693

View File

@ -39,22 +39,40 @@ template <> struct FunctionUnaryArithmeticMonotonicity<NameNegate>
/// * then jumps up from -2^63 to 2^63-1, then /// * then jumps up from -2^63 to 2^63-1, then
/// * monotonically decreases on [2^63+1, 2^64-1] (with overflow). /// * monotonically decreases on [2^63+1, 2^64-1] (with overflow).
/// Similarly for UInt128 and UInt256. /// Similarly for UInt128 and UInt256.
bool is_monotonic = true; /// Note: we currently don't handle the corner case -UINT64_MIN == UINT64_MIN, and similar for floats and wide signed ints.
switch (left.getType()) /// (This implementation seems overcomplicated and not very correct, maybe there's a better way to do it,
{ /// maybe by using the actual IDataType instead of two field types.)
case Field::Types::UInt64:
is_monotonic = (left.safeGet<UInt64>() > 1ul << 63) == (right.safeGet<UInt64>() > 1ul << 63);
break;
case Field::Types::UInt128:
is_monotonic = (left.safeGet<UInt128>() > UInt128(1) << 127) == (right.safeGet<UInt128>() > UInt128(1) << 127);
break;
case Field::Types::UInt256:
is_monotonic = (left.safeGet<UInt256>() > UInt256(1) << 255) == (right.safeGet<UInt256>() > UInt256(1) << 255);
break;
default:
break;
}
/// We don't know the data type, assume nonmonotonic.
if (left.isNull() && right.isNull())
return { .is_monotonic = false, .is_positive = false, .is_strict = true };
auto which_half_if_unsigned_or_infinity = [](const Field & f, int half_if_null, bool & is_unsigned) -> int
{
is_unsigned = true;
switch (f.getType())
{
case Field::Types::UInt64: return (f.safeGet<UInt64>() > 1ul << 63) ? +1 : -1;
case Field::Types::UInt128: return (f.safeGet<UInt128>() > UInt128(1) << 127) ? +1 : -1;
case Field::Types::UInt256: return (f.safeGet<UInt256>() > UInt256(1) << 255) ? +1 : -1;
default: break;
}
is_unsigned = false;
if (f.isPositiveInfinity())
return +1;
if (f.isNegativeInfinity())
return -1;
if (f.isNull())
return half_if_null;
return 0;
};
bool left_is_unsigned, right_is_unsigned;
int left_half = which_half_if_unsigned_or_infinity(left, -1, left_is_unsigned);
int right_half = which_half_if_unsigned_or_infinity(right, +1, right_is_unsigned);
bool is_monotonic = true;
if (left_is_unsigned || right_is_unsigned)
is_monotonic = left_half * right_half >= 0; /// either both values in the same half or unexpected signed-unsigned mix
return { .is_monotonic = is_monotonic, .is_positive = false, .is_strict = true }; return { .is_monotonic = is_monotonic, .is_positive = false, .is_strict = true };
} }
}; };