atanh(x) = 0.5 * log((1 + x) / (1 - x)) if abs(x) <= 1 atanh(x) = nan otherwise
| 1230 | // atanh(x) = 0.5 * log((1 + x) / (1 - x)) if abs(x) <= 1 |
| 1231 | // atanh(x) = nan otherwise |
| 1232 | XlaOp Atanh(XlaOp x) { |
| 1233 | XlaBuilder* b = x.builder(); |
| 1234 | auto do_it = [&](XlaOp x) -> StatusOr<XlaOp> { |
| 1235 | TF_ASSIGN_OR_RETURN(auto shape, b->GetShape(x)); |
| 1236 | auto naive_result = (Log1p(x) - Log1p(-x)) * ScalarLike(x, 0.5); |
| 1237 | |
| 1238 | // TODO(jlebar): For now, we ignore the nan edge case for complex inputs, |
| 1239 | // because we don't yet have exhaustive tests for complex trig functions. |
| 1240 | if (primitive_util::IsComplexType(shape.element_type())) { |
| 1241 | return naive_result; |
| 1242 | } |
| 1243 | |
| 1244 | auto nan = FullLike(x, std::numeric_limits<float>::quiet_NaN()); |
| 1245 | return Select(Gt(Abs(x), ScalarLike(x, 1)), nan, naive_result); |
| 1246 | }; |
| 1247 | return DoWithUpcastToF32(x, {BF16}, [&](XlaOp x) { // |
| 1248 | return b->ReportErrorOrReturn(do_it(x)); |
| 1249 | }); |
| 1250 | } |
| 1251 | |
| 1252 | // Cosh(x) = (e^x + e^-x) / 2 |
| 1253 | // = e^(x + log(1/2)) + e^(-x + log(1/2)). |