@@ -53,11 +53,11 @@ template <typename T>
5353using is_signed_integer =
5454 std::integral_constant<bool , std::is_integral<T>::value && std::is_signed<T>::value>;
5555
56- template <typename T>
57- using enable_if_signed_integer = enable_if_t <is_signed_integer<T>::value, T >;
56+ template <typename T, typename R = T >
57+ using enable_if_signed_integer = enable_if_t <is_signed_integer<T>::value, R >;
5858
59- template <typename T>
60- using enable_if_unsigned_integer = enable_if_t <is_unsigned_integer<T>::value, T >;
59+ template <typename T, typename R = T >
60+ using enable_if_unsigned_integer = enable_if_t <is_unsigned_integer<T>::value, R >;
6161
6262template <typename T, typename R = T>
6363using enable_if_integer =
@@ -686,6 +686,118 @@ struct Atan2 {
686686 }
687687};
688688
689+ struct LogNatural {
690+ template <typename T, typename Arg>
691+ static enable_if_floating_point<Arg, T> Call (KernelContext*, Arg arg, Status*) {
692+ static_assert (std::is_same<T, Arg>::value, " " );
693+ if (arg == 0.0 ) {
694+ return -std::numeric_limits<T>::infinity ();
695+ } else if (arg < 0.0 ) {
696+ return std::numeric_limits<T>::quiet_NaN ();
697+ }
698+ return std::log (arg);
699+ }
700+ };
701+
702+ struct LogNaturalChecked {
703+ template <typename T, typename Arg>
704+ static enable_if_floating_point<Arg, T> Call (KernelContext*, Arg arg, Status* st) {
705+ static_assert (std::is_same<T, Arg>::value, " " );
706+ if (arg == 0.0 ) {
707+ *st = Status::Invalid (" logarithm of zero" );
708+ return arg;
709+ } else if (arg < 0.0 ) {
710+ *st = Status::Invalid (" logarithm of negative number" );
711+ return arg;
712+ }
713+ return std::log (arg);
714+ }
715+ };
716+
717+ struct Log10 {
718+ template <typename T, typename Arg>
719+ static enable_if_floating_point<Arg, T> Call (KernelContext*, Arg arg, Status*) {
720+ static_assert (std::is_same<T, Arg>::value, " " );
721+ if (arg == 0.0 ) {
722+ return -std::numeric_limits<T>::infinity ();
723+ } else if (arg < 0.0 ) {
724+ return std::numeric_limits<T>::quiet_NaN ();
725+ }
726+ return std::log10 (arg);
727+ }
728+ };
729+
730+ struct Log10Checked {
731+ template <typename T, typename Arg>
732+ static enable_if_floating_point<Arg, T> Call (KernelContext*, Arg arg, Status* st) {
733+ static_assert (std::is_same<T, Arg>::value, " " );
734+ if (arg == 0 ) {
735+ *st = Status::Invalid (" logarithm of zero" );
736+ return arg;
737+ } else if (arg < 0 ) {
738+ *st = Status::Invalid (" logarithm of negative number" );
739+ return arg;
740+ }
741+ return std::log10 (arg);
742+ }
743+ };
744+
745+ struct Log2 {
746+ template <typename T, typename Arg>
747+ static enable_if_floating_point<Arg, T> Call (KernelContext*, Arg arg, Status*) {
748+ static_assert (std::is_same<T, Arg>::value, " " );
749+ if (arg == 0.0 ) {
750+ return -std::numeric_limits<T>::infinity ();
751+ } else if (arg < 0.0 ) {
752+ return std::numeric_limits<T>::quiet_NaN ();
753+ }
754+ return std::log2 (arg);
755+ }
756+ };
757+
758+ struct Log2Checked {
759+ template <typename T, typename Arg>
760+ static enable_if_floating_point<Arg, T> Call (KernelContext*, Arg arg, Status* st) {
761+ static_assert (std::is_same<T, Arg>::value, " " );
762+ if (arg == 0.0 ) {
763+ *st = Status::Invalid (" logarithm of zero" );
764+ return arg;
765+ } else if (arg < 0.0 ) {
766+ *st = Status::Invalid (" logarithm of negative number" );
767+ return arg;
768+ }
769+ return std::log2 (arg);
770+ }
771+ };
772+
773+ struct Log1p {
774+ template <typename T, typename Arg>
775+ static enable_if_floating_point<Arg, T> Call (KernelContext*, Arg arg, Status*) {
776+ static_assert (std::is_same<T, Arg>::value, " " );
777+ if (arg == -1 ) {
778+ return -std::numeric_limits<T>::infinity ();
779+ } else if (arg < -1 ) {
780+ return std::numeric_limits<T>::quiet_NaN ();
781+ }
782+ return std::log1p (arg);
783+ }
784+ };
785+
786+ struct Log1pChecked {
787+ template <typename T, typename Arg>
788+ static enable_if_floating_point<Arg, T> Call (KernelContext*, Arg arg, Status* st) {
789+ static_assert (std::is_same<T, Arg>::value, " " );
790+ if (arg == -1 ) {
791+ *st = Status::Invalid (" logarithm of zero" );
792+ return arg;
793+ } else if (arg < -1 ) {
794+ *st = Status::Invalid (" logarithm of negative number" );
795+ return arg;
796+ }
797+ return std::log1p (arg);
798+ }
799+ };
800+
689801// Generate a kernel given an arithmetic functor
690802template <template <typename ... Args> class KernelGenerator , typename Op>
691803ArrayKernelExec ArithmeticExecFromOp (detail::GetTypeId get_id) {
@@ -1295,6 +1407,60 @@ const FunctionDoc atan2_doc{
12951407 " Compute the inverse tangent using argument signs to determine the quadrant" ,
12961408 (" Integer arguments return double values." ),
12971409 {" y" , " x" }};
1410+
1411+ const FunctionDoc ln_doc{
1412+ " Compute natural log of arguments element-wise" ,
1413+ (" Non-positive values return -inf or NaN. Null values return null.\n "
1414+ " Use function \" ln_checked\" if you want non-positive values to raise an error." ),
1415+ {" x" }};
1416+
1417+ const FunctionDoc ln_checked_doc{
1418+ " Compute natural log of arguments element-wise" ,
1419+ (" Non-positive values return -inf or NaN. Null values return null.\n "
1420+ " Use function \" ln\" if you want non-positive values to return "
1421+ " -inf or NaN." ),
1422+ {" x" }};
1423+
1424+ const FunctionDoc log10_doc{
1425+ " Compute log base 10 of arguments element-wise" ,
1426+ (" Non-positive values return -inf or NaN. Null values return null.\n "
1427+ " Use function \" log10_checked\" if you want non-positive values to raise an error." ),
1428+ {" x" }};
1429+
1430+ const FunctionDoc log10_checked_doc{
1431+ " Compute log base 10 of arguments element-wise" ,
1432+ (" Non-positive values return -inf or NaN. Null values return null.\n "
1433+ " Use function \" log10\" if you want non-positive values to return "
1434+ " -inf or NaN." ),
1435+ {" x" }};
1436+
1437+ const FunctionDoc log2_doc{
1438+ " Compute log base 2 of arguments element-wise" ,
1439+ (" Non-positive values return -inf or NaN. Null values return null.\n "
1440+ " Use function \" log2_checked\" if you want non-positive values to raise an error." ),
1441+ {" x" }};
1442+
1443+ const FunctionDoc log2_checked_doc{
1444+ " Compute log base 2 of arguments element-wise" ,
1445+ (" Non-positive values return -inf or NaN. Null values return null.\n "
1446+ " Use function \" log2\" if you want non-positive values to return "
1447+ " -inf or NaN." ),
1448+ {" x" }};
1449+
1450+ const FunctionDoc log1p_doc{
1451+ " Compute natural log of (1+x) element-wise" ,
1452+ (" Values <= -1 return -inf or NaN. Null values return null.\n "
1453+ " This function may be more precise than log(1 + x) for x close to zero."
1454+ " Use function \" log1p_checked\" if you want non-positive values to raise an error." ),
1455+ {" x" }};
1456+
1457+ const FunctionDoc log1p_checked_doc{
1458+ " Compute natural log of (1+x) element-wise" ,
1459+ (" Values <= -1 return -inf or NaN. Null values return null.\n "
1460+ " This function may be more precise than log(1 + x) for x close to zero."
1461+ " Use function \" log1p\" if you want non-positive values to return "
1462+ " -inf or NaN." ),
1463+ {" x" }};
12981464} // namespace
12991465
13001466void RegisterScalarArithmetic (FunctionRegistry* registry) {
@@ -1460,6 +1626,36 @@ void RegisterScalarArithmetic(FunctionRegistry* registry) {
14601626
14611627 auto atan2 = MakeArithmeticFunctionFloatingPoint<Atan2>(" atan2" , &atan2_doc);
14621628 DCHECK_OK (registry->AddFunction (std::move (atan2)));
1629+
1630+ // ----------------------------------------------------------------------
1631+ // Logarithms
1632+ auto ln = MakeUnaryArithmeticFunctionFloatingPoint<LogNatural>(" ln" , &ln_doc);
1633+ DCHECK_OK (registry->AddFunction (std::move (ln)));
1634+
1635+ auto ln_checked = MakeUnaryArithmeticFunctionFloatingPointNotNull<LogNaturalChecked>(
1636+ " ln_checked" , &ln_checked_doc);
1637+ DCHECK_OK (registry->AddFunction (std::move (ln_checked)));
1638+
1639+ auto log10 = MakeUnaryArithmeticFunctionFloatingPoint<Log10>(" log10" , &log10_doc);
1640+ DCHECK_OK (registry->AddFunction (std::move (log10)));
1641+
1642+ auto log10_checked = MakeUnaryArithmeticFunctionFloatingPointNotNull<Log10Checked>(
1643+ " log10_checked" , &log10_checked_doc);
1644+ DCHECK_OK (registry->AddFunction (std::move (log10_checked)));
1645+
1646+ auto log2 = MakeUnaryArithmeticFunctionFloatingPoint<Log2>(" log2" , &log2_doc);
1647+ DCHECK_OK (registry->AddFunction (std::move (log2)));
1648+
1649+ auto log2_checked = MakeUnaryArithmeticFunctionFloatingPointNotNull<Log2Checked>(
1650+ " log2_checked" , &log2_checked_doc);
1651+ DCHECK_OK (registry->AddFunction (std::move (log2_checked)));
1652+
1653+ auto log1p = MakeUnaryArithmeticFunctionFloatingPoint<Log1p>(" log1p" , &log1p_doc);
1654+ DCHECK_OK (registry->AddFunction (std::move (log1p)));
1655+
1656+ auto log1p_checked = MakeUnaryArithmeticFunctionFloatingPointNotNull<Log1pChecked>(
1657+ " log1p_checked" , &log1p_checked_doc);
1658+ DCHECK_OK (registry->AddFunction (std::move (log1p_checked)));
14631659}
14641660
14651661} // namespace internal
0 commit comments