diff --git a/velox/docs/functions/presto/binary.rst b/velox/docs/functions/presto/binary.rst index d5a9ad3a1dec3..b86ee14011677 100644 --- a/velox/docs/functions/presto/binary.rst +++ b/velox/docs/functions/presto/binary.rst @@ -26,6 +26,15 @@ Binary Functions Decodes binary data from the hex encoded ``string``. +.. function:: from_ieee754_32(binary) -> real + + Decodes the 32-bit big-endian ``binary`` in IEEE 754 single-precision floating-point format. + Throws a VeloxException if input size is shorter / longer than 32 bits. + +.. function:: from_ieee754_64(binary) -> double + + Decodes the 64-bit big-endian ``binary`` in IEEE 754 double-precision floating-point format. + .. function:: hmac_md5(binary, key) -> varbinary Computes the HMAC with md5 of ``binary`` with the given ``key``. @@ -98,10 +107,6 @@ Binary Functions Encodes ``double`` in a 64-bit big-endian binary according to IEEE 754 double-precision floating-point format. -.. function:: from_ieee754_64(binary) -> double - - Decodes the 64-bit big-endian ``binary`` in IEEE 754 double-precision floating-point format. - .. function:: xxhash64(binary) -> varbinary Computes the xxhash64 hash of ``binary``. diff --git a/velox/functions/prestosql/BinaryFunctions.h b/velox/functions/prestosql/BinaryFunctions.h index 5c8d4bff0636d..c3a3b96a1190c 100644 --- a/velox/functions/prestosql/BinaryFunctions.h +++ b/velox/functions/prestosql/BinaryFunctions.h @@ -424,4 +424,21 @@ struct ToIEEE754Bits32 { } }; +template +struct FromIEEE754Bits32 { + VELOX_DEFINE_FUNCTION_TYPES(T); + + FOLLY_ALWAYS_INLINE void call( + out_type& result, + const arg_type& input) { + static constexpr auto kTypeLength = sizeof(int32_t); + VELOX_USER_CHECK_EQ( + input.size(), + kTypeLength, + "Input floating-point value must be exactly 4 bytes long"); + memcpy(&result, input.data(), kTypeLength); + result = folly::Endian::big(result); + } +}; + } // namespace facebook::velox::functions diff --git a/velox/functions/prestosql/registration/BinaryFunctionsRegistration.cpp b/velox/functions/prestosql/registration/BinaryFunctionsRegistration.cpp index b9201cf22db15..3004e2c451594 100644 --- a/velox/functions/prestosql/registration/BinaryFunctionsRegistration.cpp +++ b/velox/functions/prestosql/registration/BinaryFunctionsRegistration.cpp @@ -66,6 +66,8 @@ void registerSimpleFunctions(const std::string& prefix) { {prefix + "from_ieee754_64"}); registerFunction( {prefix + "to_ieee754_32"}); + registerFunction( + {prefix + "from_ieee754_32"}); } } // namespace diff --git a/velox/functions/prestosql/tests/BinaryFunctionsTest.cpp b/velox/functions/prestosql/tests/BinaryFunctionsTest.cpp index 0a647d2ecf520..e690674ba431b 100644 --- a/velox/functions/prestosql/tests/BinaryFunctionsTest.cpp +++ b/velox/functions/prestosql/tests/BinaryFunctionsTest.cpp @@ -18,6 +18,7 @@ #include #include #include "velox/common/base/VeloxException.h" +#include "velox/common/base/tests/GTestUtils.h" #include "velox/expression/Expr.h" #include "velox/functions/prestosql/tests/utils/FunctionBaseTest.h" @@ -697,4 +698,61 @@ TEST_F(BinaryFunctionsTest, toIEEE754Bits32) { hexToDec("FF7FFFFF"), toIEEE754Bits32(std::numeric_limits::lowest())); } + +TEST_F(BinaryFunctionsTest, fromIEEE754Bits32) { + const auto fromIEEE754Bits32 = [&](const std::optional& arg) { + return evaluateOnce( + "from_ieee754_32(c0)", {arg}, {VARBINARY()}); + }; + + const auto toIEEE754Bits32 = [&](std::optional arg) { + return evaluateOnce("to_ieee754_32(c0)", arg); + }; + + EXPECT_EQ(std::nullopt, fromIEEE754Bits32(std::nullopt)); + EXPECT_EQ(1.0f, fromIEEE754Bits32(hexToDec("3F800000"))); + EXPECT_EQ(3.14f, fromIEEE754Bits32(hexToDec("4048F5C3"))); + EXPECT_EQ(3.4028235E38f, fromIEEE754Bits32(hexToDec("7f7fffff"))); + EXPECT_EQ(-3.4028235E38f, fromIEEE754Bits32(hexToDec("ff7fffff"))); + EXPECT_EQ(1.4E-45f, fromIEEE754Bits32(hexToDec("00000001"))); + EXPECT_EQ(-1.4E-45f, fromIEEE754Bits32(hexToDec("80000001"))); + EXPECT_EQ( + std::numeric_limits::infinity(), + fromIEEE754Bits32(hexToDec("7f800000"))); + EXPECT_EQ( + -std::numeric_limits::infinity(), + fromIEEE754Bits32(hexToDec("ff800000"))); + EXPECT_THROW(fromIEEE754Bits32("YQ"), VeloxUserError); + EXPECT_EQ(3.4028235E38f, fromIEEE754Bits32(toIEEE754Bits32(3.4028235E38f))); + EXPECT_EQ(-3.4028235E38f, fromIEEE754Bits32(toIEEE754Bits32(-3.4028235E38f))); + EXPECT_EQ(1.4E-45f, fromIEEE754Bits32(toIEEE754Bits32(1.4E-45f))); + EXPECT_EQ(-1.4E-45f, fromIEEE754Bits32(toIEEE754Bits32(-1.4E-45f))); + EXPECT_EQ( + std::numeric_limits::infinity(), + fromIEEE754Bits32( + toIEEE754Bits32(std::numeric_limits::infinity()))); + EXPECT_EQ( + -std::numeric_limits::infinity(), + fromIEEE754Bits32( + toIEEE754Bits32(-std::numeric_limits::infinity()))); + EXPECT_EQ( + std::numeric_limits::max(), + fromIEEE754Bits32(toIEEE754Bits32(std::numeric_limits::max()))); + EXPECT_EQ( + std::numeric_limits::min(), + fromIEEE754Bits32(toIEEE754Bits32(std::numeric_limits::min()))); + EXPECT_TRUE( + std::isnan(fromIEEE754Bits32( + toIEEE754Bits32(std::numeric_limits::quiet_NaN())) + .value())); + EXPECT_TRUE(std::isnan( + fromIEEE754Bits32( + toIEEE754Bits32(std::numeric_limits::signaling_NaN())) + .value())); + EXPECT_TRUE( + std::isnan(fromIEEE754Bits32(toIEEE754Bits32(std::nan("nan"))).value())); + VELOX_ASSERT_THROW( + fromIEEE754Bits32(hexToDec("0000000000000001")), + "Input floating-point value must be exactly 4 bytes long"); +} } // namespace