1#pragma once
2
3#include <type_traits>
4#include <common/likely.h>
5#include <Common/Exception.h>
6#include <Common/config.h>
7#include <DataTypes/NumberTraits.h>
8
9
10namespace DB
11{
12
13namespace ErrorCodes
14{
15 extern const int ILLEGAL_DIVISION;
16}
17
18#pragma GCC diagnostic push
19#pragma GCC diagnostic ignored "-Wsign-compare"
20
21template <typename A, typename B>
22inline void throwIfDivisionLeadsToFPE(A a, B b)
23{
24 /// Is it better to use siglongjmp instead of checks?
25
26 if (unlikely(b == 0))
27 throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION);
28
29 /// http://avva.livejournal.com/2548306.html
30 if (unlikely(is_signed_v<A> && is_signed_v<B> && a == std::numeric_limits<A>::min() && b == -1))
31 throw Exception("Division of minimal signed number by minus one", ErrorCodes::ILLEGAL_DIVISION);
32}
33
34template <typename A, typename B>
35inline bool divisionLeadsToFPE(A a, B b)
36{
37 if (unlikely(b == 0))
38 return true;
39
40 if (unlikely(is_signed_v<A> && is_signed_v<B> && a == std::numeric_limits<A>::min() && b == -1))
41 return true;
42
43 return false;
44}
45
46
47#pragma GCC diagnostic pop
48
49template <typename A, typename B>
50struct DivideIntegralImpl
51{
52 using ResultType = typename NumberTraits::ResultOfIntegerDivision<A, B>::Type;
53
54 template <typename Result = ResultType>
55 static inline Result apply(A a, B b)
56 {
57 throwIfDivisionLeadsToFPE(a, b);
58
59 /// Otherwise overflow may occur due to integer promotion. Example: int8_t(-1) / uint64_t(2).
60 /// NOTE: overflow is still possible when dividing large signed number to large unsigned number or vice-versa. But it's less harmful.
61 if constexpr (is_integral_v<A> && is_integral_v<B> && (is_signed_v<A> || is_signed_v<B>))
62 return std::make_signed_t<A>(a) / std::make_signed_t<B>(b);
63 else
64 return a / b;
65 }
66
67#if USE_EMBEDDED_COMPILER
68 static constexpr bool compilable = false; /// don't know how to throw from LLVM IR
69#endif
70};
71
72}
73