summaryrefslogtreecommitdiffstats
path: root/yql/essentials/udfs/common/math/lib/round.h
diff options
context:
space:
mode:
authorimunkin <[email protected]>2024-11-08 10:00:23 +0300
committerimunkin <[email protected]>2024-11-08 10:12:13 +0300
commita784a2f943d6e15caa6241e2e96d80aac6dbf375 (patch)
tree05f1e5366c916b988a8afb75bdab8ddeee0f6e6d /yql/essentials/udfs/common/math/lib/round.h
parentd70137a7b530ccaa52834274913bbb5a3d1ca06e (diff)
Move yql/udfs/common/ to /yql/essentials YQL-19206
Except the following directories: * clickhouse/client * datetime * knn * roaring commit_hash:c7da95636144d28db109d6b17ddc762e9bacb59f
Diffstat (limited to 'yql/essentials/udfs/common/math/lib/round.h')
-rw-r--r--yql/essentials/udfs/common/math/lib/round.h77
1 files changed, 77 insertions, 0 deletions
diff --git a/yql/essentials/udfs/common/math/lib/round.h b/yql/essentials/udfs/common/math/lib/round.h
new file mode 100644
index 00000000000..f59700da88f
--- /dev/null
+++ b/yql/essentials/udfs/common/math/lib/round.h
@@ -0,0 +1,77 @@
+#pragma once
+
+#include <util/system/types.h>
+#include <cmath>
+#include <optional>
+#include <fenv.h>
+
+namespace NMathUdf {
+
+template <class T>
+inline T RoundToDecimal(T v, int decShift) {
+ T div = std::pow(T(10), decShift);
+ return std::floor(v / div + T(0.5)) * div;
+}
+
+inline std::optional<i64> Mod(i64 value, i64 m) {
+ if (!m) {
+ return {};
+ }
+
+ const i64 result = value % m;
+ if ((result < 0 && m > 0) || (result > 0 && m < 0)) {
+ return result + m;
+ }
+ return result;
+}
+
+inline std::optional<i64> Rem(i64 value, i64 m) {
+ if (!m) {
+ return {};
+ }
+
+ const i64 result = value % m;
+ if (result < 0 && value > 0) {
+ return result + m;
+ }
+
+ if (result > 0 && value < 0) {
+ return result - m;
+ }
+ return result;
+}
+
+inline std::optional<i64> NearbyIntImpl(double value, decltype(FE_DOWNWARD) mode) {
+ if (!::isfinite(value)) {
+ return {};
+ }
+
+ auto prevMode = ::fegetround();
+ ::fesetround(mode);
+ auto res = ::nearbyint(value);
+ ::fesetround(prevMode);
+ // cast to i64 gives wrong sign above 9223372036854774784
+ // lower bound is adjusted to -9223372036854774784 as well
+ if (res < double(std::numeric_limits<i64>::min() + 513) || res > double(std::numeric_limits<i64>::max() - 512)) {
+ return {};
+ }
+
+ return static_cast<i64>(res);
+}
+
+inline std::optional<i64> NearbyInt(double value, ui32 mode) {
+ switch (mode) {
+ case 0:
+ return NearbyIntImpl(value, FE_DOWNWARD);
+ case 1:
+ return NearbyIntImpl(value, FE_TONEAREST);
+ case 2:
+ return NearbyIntImpl(value, FE_TOWARDZERO);
+ case 3:
+ return NearbyIntImpl(value, FE_UPWARD);
+ default:
+ return {};
+ }
+}
+
+}