Sinh(x) = (e^x - e^-x) / 2 = e^(x + log(1/2)) - e^(-x + log(1/2)). The second formulation avoids overflowing when e^x = inf but (e^x)/2 is not inf. This incorrectly overflows to +/-inf for two f32 input values, namely +/-89.4159851, due to rounding error when computing x +/- log(1/2). The correct answer of 3.40281961e+38 (0x7f7fffec) is very close to max-float, so we deem this acceptable.
| 1277 | // correct answer of 3.40281961e+38 (0x7f7fffec) is very close to max-float, so |
| 1278 | // we deem this acceptable. |
| 1279 | XlaOp Sinh(XlaOp x) { |
| 1280 | XlaBuilder* b = x.builder(); |
| 1281 | auto do_it = [&](XlaOp x) -> StatusOr<XlaOp> { |
| 1282 | TF_ASSIGN_OR_RETURN(auto shape, b->GetShape(x)); |
| 1283 | auto one_half = ScalarLike(x, 0.5); |
| 1284 | auto log_one_half = Log(ScalarLike(x, 0.5)); |
| 1285 | auto large_sinh_result = Exp(x + log_one_half) - Exp(-x + log_one_half); |
| 1286 | |
| 1287 | if (primitive_util::IsComplexType(shape.element_type())) { |
| 1288 | return large_sinh_result; |
| 1289 | } |
| 1290 | |
| 1291 | // Here we use e^x = e^(x / 2) * e^(x / 2). This avoids overflow for large |
| 1292 | // values of x. |
| 1293 | |
| 1294 | // For smaller x, we get unwanted cancellations of e^x - e^-x, resulting in |
| 1295 | // 0. |
| 1296 | // Rewrite this to avoid that. We use expm1(x) because that preserves the |
| 1297 | // first order term of the taylor series of e^x. |
| 1298 | // (e^(x) - e^(-x)) / 2. = |
| 1299 | // (e^(x) - 1 + 1 - e^(-x)) / 2. |
| 1300 | // (expm1(x) + (e^(x) - 1) / e^x) / 2. |
| 1301 | // (expm1(x) + expm1(x) / (expm1(x) + 1)) / 2. |
| 1302 | auto expm1 = Expm1(x); |
| 1303 | auto one = ScalarLike(x, 1.); |
| 1304 | auto small_sinh_result = one_half * (expm1 + expm1 / (expm1 + one)); |
| 1305 | return Select(Lt(Abs(x), one), small_sinh_result, large_sinh_result); |
| 1306 | }; |
| 1307 | return DoWithUpcastToF32(x, {BF16, F16}, [&](XlaOp x) { |
| 1308 | return b->ReportErrorOrReturn(do_it(x)); |
| 1309 | }); |
| 1310 | } |
| 1311 | |
| 1312 | XlaOp MaybeConjugate(XlaOp x, bool conjugate) { |
| 1313 | XlaBuilder* builder = x.builder(); |