Skip to content

Commit

Permalink
Add truncate(x,n) Presto function (facebookincubator#2892)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebookincubator#2892

Adding truncate(x,n) Presto function

Differential Revision: D40516665

fbshipit-source-id: 1d3eeb2587f32a437cd093351d444911a8e5fcd3
  • Loading branch information
Gosh Arzumanyan authored and facebook-github-bot committed Nov 28, 2022
1 parent 7c2879e commit b0f16b1
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 5 deletions.
4 changes: 4 additions & 0 deletions velox/docs/functions/math.rst
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ Mathematical Functions

Returns x rounded to integer by dropping digits after decimal point.

.. function:: truncate(x, n) -> double

Returns x truncated to n decimal places. n can be negative to truncate n digits left of the decimal point.

.. function:: width_bucket(x, bound1, bound2, n) -> bigint

Returns the bin number of ``x`` in an equi-width histogram with the
Expand Down
7 changes: 5 additions & 2 deletions velox/functions/prestosql/Arithmetic.h
Original file line number Diff line number Diff line change
Expand Up @@ -486,10 +486,13 @@ struct EulerConstantFunction {

template <typename T>
struct TruncateFunction {
template <typename TInput>
FOLLY_ALWAYS_INLINE void call(TInput& result, TInput a) {
FOLLY_ALWAYS_INLINE void call(double& result, double a) {
result = std::trunc(a);
}

FOLLY_ALWAYS_INLINE void call(double& result, double a, int32_t n) {
result = truncate(a, n);
}
};

} // namespace
Expand Down
26 changes: 26 additions & 0 deletions velox/functions/prestosql/ArithmeticImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <cmath>
#include <type_traits>
#include "folly/CPortability.h"
#include "velox/type/DoubleUtil.h"

namespace facebook::velox::functions {

Expand Down Expand Up @@ -132,4 +133,29 @@ T ceil(const T& arg) {
return results;
}

FOLLY_ALWAYS_INLINE double truncate(
const double& number,
const int32_t& decimals = 0) {
const bool dec_negative = (decimals < 0);
const auto log_10_size = DoubleUtil::kPowersOfTen.size(); // 309
if (dec_negative && decimals <= -log_10_size)
return 0.0;

const uint64_t abs_dec = dec_negative ? -decimals : decimals;
const double tmp = (abs_dec < log_10_size) ? DoubleUtil::kPowersOfTen[abs_dec]
: std::pow(10.0, (double)abs_dec);

const double value_mul_tmp = number * tmp;
if (!dec_negative && !std::isfinite(value_mul_tmp))
return number;

const double value_div_tmp = number / tmp;
if (number >= 0.0)
return decimals < 0 ? std::floor(value_div_tmp) * tmp
: std::floor(value_mul_tmp) / tmp;
else
return decimals < 0 ? std::ceil(value_div_tmp) * tmp
: std::ceil(value_mul_tmp) / tmp;
}

} // namespace facebook::velox::functions
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ void registerSimpleFunctions() {
registerFunction<ToBaseFunction, Varchar, int64_t, int64_t>({"to_base"});
registerFunction<PiFunction, double>({"pi"});
registerFunction<EulerConstantFunction, double>({"e"});
registerUnaryNumeric<TruncateFunction>({"truncate"});
registerFunction<TruncateFunction, double, double>({"truncate"});
registerFunction<TruncateFunction, double, double, int32_t>({"truncate"});
}

} // namespace
Expand Down
43 changes: 41 additions & 2 deletions velox/functions/prestosql/tests/ArithmeticTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cmath>
#include <optional>

#include <gmock/gmock.h>
Expand All @@ -33,6 +34,10 @@ MATCHER(IsNan, "is NaN") {
return arg && std::isnan(*arg);
}

MATCHER(IsInf, "is Infinity") {
return arg && std::isinf(*arg);
}

class ArithmeticTest : public functions::test::FunctionBaseTest {
protected:
template <typename T, typename TExpected = T>
Expand Down Expand Up @@ -631,15 +636,49 @@ TEST_F(ArithmeticTest, clamp) {
}

TEST_F(ArithmeticTest, truncate) {
const auto truncate = [&](std::optional<double> a) {
return evaluateOnce<double>("truncate(c0)", a);
const auto truncate = [&](std::optional<double> a,
std::optional<int32_t> n = 0) {
return evaluateOnce<double>("truncate(c0,c1)", a, n);
};

EXPECT_EQ(truncate(0), 0);
EXPECT_EQ(truncate(1.5), 1);
EXPECT_EQ(truncate(-1.5), -1);
EXPECT_EQ(truncate(std::nullopt), std::nullopt);
EXPECT_THAT(truncate(kNan), IsNan());
EXPECT_THAT(truncate(kInf), IsInf());

EXPECT_EQ(truncate(0, 0), 0);
EXPECT_EQ(truncate(1.5, 0), 1);
EXPECT_EQ(truncate(-1.5, 0), -1);
EXPECT_EQ(truncate(std::nullopt, 0), std::nullopt);
EXPECT_EQ(truncate(1.5, std::nullopt), std::nullopt);
EXPECT_THAT(truncate(kNan, 0), IsNan());
EXPECT_THAT(truncate(kNan, 1), IsNan());
EXPECT_THAT(truncate(kInf, 0), IsInf());
EXPECT_THAT(truncate(kInf, 1), IsInf());

EXPECT_DOUBLE_EQ(truncate(1.5678, 2).value(), 1.56);
EXPECT_DOUBLE_EQ(truncate(-1.5678, 2).value(), -1.56);
EXPECT_DOUBLE_EQ(truncate(1.333, -1).value(), 0);
EXPECT_DOUBLE_EQ(truncate(3.54555, 2).value(), 3.54);
EXPECT_DOUBLE_EQ(truncate(1234, 1).value(), 1234);
EXPECT_DOUBLE_EQ(truncate(1234, -1).value(), 1230);
EXPECT_DOUBLE_EQ(truncate(1234.56, 1).value(), 1234.5);
EXPECT_DOUBLE_EQ(truncate(1234.56, -1).value(), 1230.0);
EXPECT_DOUBLE_EQ(truncate(1239.999, 2).value(), 1239.99);
EXPECT_DOUBLE_EQ(truncate(1239.999, -2).value(), 1200.0);
EXPECT_DOUBLE_EQ(
truncate(123456789012345678901.23, 3).value(), 123456789012345678901.23);
EXPECT_DOUBLE_EQ(
truncate(-123456789012345678901.23, 3).value(),
-123456789012345678901.23);
EXPECT_DOUBLE_EQ(
truncate(123456789123456.999, 2).value(), 123456789123456.99);
EXPECT_DOUBLE_EQ(truncate(123456789012345678901.0, -21).value(), 0.0);
EXPECT_DOUBLE_EQ(truncate(123456789012345678901.23, -21).value(), 0.0);
EXPECT_DOUBLE_EQ(truncate(123456789012345678901.0, -21).value(), 0.0);
EXPECT_DOUBLE_EQ(truncate(123456789012345678901.23, -21).value(), 0.0);
}

} // namespace
Expand Down
52 changes: 52 additions & 0 deletions velox/type/DoubleUtil.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "velox/type/DoubleUtil.h"
#include <array>

namespace facebook::velox {

const std::array<double, 309> DoubleUtil::kPowersOfTen = {
1e000, 1e001, 1e002, 1e003, 1e004, 1e005, 1e006, 1e007, 1e008, 1e009, 1e010,
1e011, 1e012, 1e013, 1e014, 1e015, 1e016, 1e017, 1e018, 1e019, 1e020, 1e021,
1e022, 1e023, 1e024, 1e025, 1e026, 1e027, 1e028, 1e029, 1e030, 1e031, 1e032,
1e033, 1e034, 1e035, 1e036, 1e037, 1e038, 1e039, 1e040, 1e041, 1e042, 1e043,
1e044, 1e045, 1e046, 1e047, 1e048, 1e049, 1e050, 1e051, 1e052, 1e053, 1e054,
1e055, 1e056, 1e057, 1e058, 1e059, 1e060, 1e061, 1e062, 1e063, 1e064, 1e065,
1e066, 1e067, 1e068, 1e069, 1e070, 1e071, 1e072, 1e073, 1e074, 1e075, 1e076,
1e077, 1e078, 1e079, 1e080, 1e081, 1e082, 1e083, 1e084, 1e085, 1e086, 1e087,
1e088, 1e089, 1e090, 1e091, 1e092, 1e093, 1e094, 1e095, 1e096, 1e097, 1e098,
1e099, 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119, 1e120,
1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129, 1e130, 1e131,
1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139, 1e140, 1e141, 1e142,
1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, 1e150, 1e151, 1e152, 1e153,
1e154, 1e155, 1e156, 1e157, 1e158, 1e159, 1e160, 1e161, 1e162, 1e163, 1e164,
1e165, 1e166, 1e167, 1e168, 1e169, 1e170, 1e171, 1e172, 1e173, 1e174, 1e175,
1e176, 1e177, 1e178, 1e179, 1e180, 1e181, 1e182, 1e183, 1e184, 1e185, 1e186,
1e187, 1e188, 1e189, 1e190, 1e191, 1e192, 1e193, 1e194, 1e195, 1e196, 1e197,
1e198, 1e199, 1e200, 1e201, 1e202, 1e203, 1e204, 1e205, 1e206, 1e207, 1e208,
1e209, 1e210, 1e211, 1e212, 1e213, 1e214, 1e215, 1e216, 1e217, 1e218, 1e219,
1e220, 1e221, 1e222, 1e223, 1e224, 1e225, 1e226, 1e227, 1e228, 1e229, 1e230,
1e231, 1e232, 1e233, 1e234, 1e235, 1e236, 1e237, 1e238, 1e239, 1e240, 1e241,
1e242, 1e243, 1e244, 1e245, 1e246, 1e247, 1e248, 1e249, 1e250, 1e251, 1e252,
1e253, 1e254, 1e255, 1e256, 1e257, 1e258, 1e259, 1e260, 1e261, 1e262, 1e263,
1e264, 1e265, 1e266, 1e267, 1e268, 1e269, 1e270, 1e271, 1e272, 1e273, 1e274,
1e275, 1e276, 1e277, 1e278, 1e279, 1e280, 1e281, 1e282, 1e283, 1e284, 1e285,
1e286, 1e287, 1e288, 1e289, 1e290, 1e291, 1e292, 1e293, 1e294, 1e295, 1e296,
1e297, 1e298, 1e299, 1e300, 1e301, 1e302, 1e303, 1e304, 1e305, 1e306, 1e307,
1e308};
} // namespace facebook::velox
29 changes: 29 additions & 0 deletions velox/type/DoubleUtil.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <array>

namespace facebook::velox {

/// A static class that holds helper functions for DOUBLE type.
class DoubleUtil {
public:
static const std::array<double, 309> kPowersOfTen;

}; // DoubleUtil
} // namespace facebook::velox

0 comments on commit b0f16b1

Please sign in to comment.