Make behaviour of remainder of division for floating point numbers compatible with most of DBMS #7323

This commit is contained in:
Alexey Milovidov 2020-07-20 04:03:46 +03:00
parent b8cc2bee53
commit 10355a2850
6 changed files with 33 additions and 9 deletions

View File

@ -100,10 +100,12 @@ template <typename A, typename B> struct ResultOfIntegerDivision
*/
template <typename A, typename B> struct ResultOfModulo
{
using Type = typename Construct<
is_signed_v<A> || is_signed_v<B>,
false,
sizeof(B)>::Type;
using Type = std::conditional_t<std::is_floating_point_v<A> || std::is_floating_point_v<B>,
Float64,
typename Construct<
is_signed_v<A> || is_signed_v<B>,
false,
sizeof(B)>::Type>;
};
template <typename A> struct ResultOfNegate

View File

@ -1,5 +1,6 @@
#pragma once
#include <cmath>
#include <type_traits>
#include <Common/Exception.h>
#include <DataTypes/NumberTraits.h>
@ -86,8 +87,15 @@ struct ModuloImpl
template <typename Result = ResultType>
static inline Result apply(A a, B b)
{
throwIfDivisionLeadsToFPE(typename NumberTraits::ToInteger<A>::Type(a), typename NumberTraits::ToInteger<B>::Type(b));
return typename NumberTraits::ToInteger<A>::Type(a) % typename NumberTraits::ToInteger<B>::Type(b);
if constexpr (std::is_floating_point_v<ResultType>)
{
return ResultType(a) - trunc(ResultType(a) / ResultType(b)) * ResultType(b);
}
else
{
throwIfDivisionLeadsToFPE(typename NumberTraits::ToInteger<A>::Type(a), typename NumberTraits::ToInteger<B>::Type(b));
return typename NumberTraits::ToInteger<A>::Type(a) % typename NumberTraits::ToInteger<B>::Type(b);
}
}
#if USE_EMBEDDED_COMPILER

View File

@ -102,6 +102,7 @@ using FunctionModulo = FunctionBinaryArithmetic<ModuloImpl, NameModulo, false>;
void registerFunctionModulo(FunctionFactory & factory)
{
factory.registerFunction<FunctionModulo>();
factory.registerAlias("mod", "modulo", FunctionFactory::CaseInsensitive);
}
}

View File

@ -14,10 +14,17 @@ struct ModuloOrZeroImpl
template <typename Result = ResultType>
static inline Result apply(A a, B b)
{
if (unlikely(divisionLeadsToFPE(a, b)))
return 0;
if constexpr (std::is_floating_point_v<ResultType>)
{
return ResultType(a) - floor(ResultType(a) / ResultType(b)) * ResultType(b);
}
else
{
if (unlikely(divisionLeadsToFPE(a, b)))
return 0;
return ModuloImpl<A, B>::template apply<Result>(a, b);
return ModuloImpl<A, B>::template apply<Result>(a, b);
}
}
#if USE_EMBEDDED_COMPILER

View File

@ -0,0 +1,3 @@
1 -1 1 -1
0.125 -0.125 0.125 -0.125
1 -1 1 -1

View File

@ -0,0 +1,3 @@
WITH 8.5 AS a, 2.5 AS b SELECT a % b, -a % b, a % -b, -a % -b;
WITH 10.125 AS a, 2.5 AS b SELECT a % b, -a % b, a % -b, -a % -b;
WITH 8.5 AS a, 2.5 AS b SELECT mod(a, b), MOD(-a, b), modulo(a, -b), moduloOrZero(-a, -b);