ClickHouse server version 20.8.9 revision 54438

Let's imagine some simple table structure:

```
CREATE TABLE users (
    `user_id` Int32
)
```

Modulo operator on **Int32** field with **150** argument returns negative result. This could have happened due to wrong type casting - result should be casted to **Int16** or **UInt8** instead of **Int8**.

```
SELECT 
    user_id % 150, 
    441746 % 150,
    toTypeName(user_id % 150),
    toTypeName(441746 % 150)
FROM users 
WHERE user_id = 441746
LIMIT 1
```

```
┌─modulo(user_id, 150)─┬─modulo(441746, 150)─┬─toTypeName(modulo(user_id, 150))─┬─toTypeName(modulo(441746, 150))─┐
│                -110  │                 146 │ Int8                             │ UInt8                           │
└──────────────────────┴─────────────────────┴──────────────────────────────────┴─────────────────────────────────┘
```
template <> struct Construct<false, false, 8> { using Type = UInt64; };
template <> struct Construct<false, false, 16> { using Type = UInt256; }; 
template <> struct Construct<false, false, 32> { using Type = UInt256; };
template <> struct Construct<false, true, 1> { using Type = Float32; };
template <> struct Construct<false, true, 2> { using Type = Float32; };
template <> struct Construct<false, true, 4> { using Type = Float32; };
template <> struct Construct<false, true, 8> { using Type = Float64; };
template <> struct Construct<true, false, 1> { using Type = Int8; };
template <> struct Construct<true, false, 2> { using Type = Int16; };
template <> struct Construct<true, false, 4> { using Type = Int32; };
template <> struct Construct<true, false, 8> { using Type = Int64; };
template <> struct Construct<true, false, 16> { using Type = Int128; };
template <> struct Construct<true, false, 32> { using Type = Int256; };
template <> struct Construct<true, true, 1> { using Type = Float32; };
template <> struct Construct<true, true, 2> { using Type = Float32; };
template <> struct Construct<true, true, 4> { using Type = Float32; };
template <> struct Construct<true, true, 8> { using Type = Float64; };
/** The result of addition or multiplication is calculated according to the following rules:
    * - if one of the arguments is floating-point, the result is a floating point, otherwise - the whole;
    * - if one of the arguments is signed, the result is signed, otherwise it is unsigned;
    * - the result contains more bits (not only meaningful) than the maximum in the arguments
    *   (for example, UInt8 + Int32 = Int64).
    */
template <typename A, typename B> struct ResultOfAdditionMultiplication
{
    using Type = typename Construct<
        is_signed_v<A> || is_signed_v<B>,
        std::is_floating_point_v<A> || std::is_floating_point_v<B>,
        nextSize(max(sizeof(A), sizeof(B)))>::Type;
};