1d08a801bSTue Ly //===-- Single-precision log(x) function ----------------------------------===// 2d08a801bSTue Ly // 3d08a801bSTue Ly // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4d08a801bSTue Ly // See https://llvm.org/LICENSE.txt for license information. 5d08a801bSTue Ly // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6d08a801bSTue Ly // 7d08a801bSTue Ly //===----------------------------------------------------------------------===// 8d08a801bSTue Ly 9d08a801bSTue Ly #include "src/math/logf.h" 109e7688c7STue Ly #include "common_constants.h" // Lookup table for (1/f) and log(f) 11d08a801bSTue Ly #include "src/__support/FPUtil/BasicOperations.h" 1282df72ccSTue Ly #include "src/__support/FPUtil/FEnvImpl.h" 13d08a801bSTue Ly #include "src/__support/FPUtil/FMA.h" 14d08a801bSTue Ly #include "src/__support/FPUtil/FPBits.h" 15d08a801bSTue Ly #include "src/__support/FPUtil/PolyEval.h" 16d08a801bSTue Ly #include "src/__support/common.h" 17d08a801bSTue Ly 1882df72ccSTue Ly // This is an algorithm for log(x) in single precision which is correctly 1982df72ccSTue Ly // rounded for all rounding modes, based on the implementation of log(x) from 2082df72ccSTue Ly // the RLIBM project at: 21d08a801bSTue Ly // https://people.cs.rutgers.edu/~sn349/rlibm 22d08a801bSTue Ly 23d08a801bSTue Ly // Step 1 - Range reduction: 24d08a801bSTue Ly // For x = 2^m * 1.mant, log(x) = m * log(2) + log(1.m) 25d08a801bSTue Ly // If x is denormal, we normalize it by multiplying x by 2^23 and subtracting 26d08a801bSTue Ly // m by 23. 27d08a801bSTue Ly 28d08a801bSTue Ly // Step 2 - Another range reduction: 29d08a801bSTue Ly // To compute log(1.mant), let f be the highest 8 bits including the hidden 30d08a801bSTue Ly // bit, and d be the difference (1.mant - f), i.e. the remaining 16 bits of the 31d08a801bSTue Ly // mantissa. Then we have the following approximation formula: 32d08a801bSTue Ly // log(1.mant) = log(f) + log(1.mant / f) 33d08a801bSTue Ly // = log(f) + log(1 + d/f) 34d08a801bSTue Ly // ~ log(f) + P(d/f) 35d08a801bSTue Ly // since d/f is sufficiently small. 36d08a801bSTue Ly // log(f) and 1/f are then stored in two 2^7 = 128 entries look-up tables. 37d08a801bSTue Ly 38d08a801bSTue Ly // Step 3 - Polynomial approximation: 39d08a801bSTue Ly // To compute P(d/f), we use a single degree-5 polynomial in double precision 40d08a801bSTue Ly // which provides correct rounding for all but few exception values. 41d08a801bSTue Ly // For more detail about how this polynomial is obtained, please refer to the 42d08a801bSTue Ly // paper: 43d08a801bSTue Ly // Lim, J. and Nagarakatte, S., "One Polynomial Approximation to Produce 44d08a801bSTue Ly // Correctly Rounded Results of an Elementary Function for Multiple 45d08a801bSTue Ly // Representations and Rounding Modes", Proceedings of the 49th ACM SIGPLAN 46d08a801bSTue Ly // Symposium on Principles of Programming Languages (POPL-2022), Philadelphia, 47d08a801bSTue Ly // USA, January 16-22, 2022. 48d08a801bSTue Ly // https://people.cs.rutgers.edu/~sn349/papers/rlibmall-popl-2022.pdf 49d08a801bSTue Ly 50d08a801bSTue Ly namespace __llvm_libc { 51d08a801bSTue Ly 52d08a801bSTue Ly LLVM_LIBC_FUNCTION(float, logf, (float x)) { 53d08a801bSTue Ly constexpr double LOG_2 = 0x1.62e42fefa39efp-1; 54d08a801bSTue Ly using FPBits = typename fputil::FPBits<float>; 55d08a801bSTue Ly FPBits xbits(x); 5682df72ccSTue Ly 5782df72ccSTue Ly switch (FPBits(x).uintval()) { 5882df72ccSTue Ly case 0x41178febU: // x = 0x1.2f1fd6p+3f 5982df72ccSTue Ly if (fputil::get_round() == FE_TONEAREST) 6082df72ccSTue Ly return 0x1.1fcbcep+1f; 6182df72ccSTue Ly break; 6282df72ccSTue Ly case 0x4c5d65a5U: // x = 0x1.bacb4ap+25f 6382df72ccSTue Ly if (fputil::get_round() == FE_TONEAREST) 6482df72ccSTue Ly return 0x1.1e0696p+4f; 6582df72ccSTue Ly break; 6682df72ccSTue Ly case 0x65d890d3U: // x = 0x1.b121a6p+76f 6782df72ccSTue Ly if (fputil::get_round() == FE_TONEAREST) 6882df72ccSTue Ly return 0x1.a9a3f2p+5f; 6982df72ccSTue Ly break; 7082df72ccSTue Ly case 0x6f31a8ecU: // x = 0x1.6351d8p+95f 7182df72ccSTue Ly if (fputil::get_round() == FE_TONEAREST) 7282df72ccSTue Ly return 0x1.08b512p+6f; 7382df72ccSTue Ly break; 7482df72ccSTue Ly case 0x3f800001U: // x = 0x1.000002p+0f 7582df72ccSTue Ly if (fputil::get_round() == FE_UPWARD) 7682df72ccSTue Ly return 0x1p-23f; 7782df72ccSTue Ly return 0x1.fffffep-24f; 7882df72ccSTue Ly case 0x500ffb03U: // x = 0x1.1ff606p+33f 7982df72ccSTue Ly if (fputil::get_round() != FE_UPWARD) 8082df72ccSTue Ly return 0x1.6fdd34p+4f; 8182df72ccSTue Ly break; 8282df72ccSTue Ly case 0x7a17f30aU: // x = 0x1.2fe614p+117f 8382df72ccSTue Ly if (fputil::get_round() != FE_UPWARD) 8482df72ccSTue Ly return 0x1.451436p+6f; 8582df72ccSTue Ly break; 8682df72ccSTue Ly case 0x5cd69e88U: // x = 0x1.ad3d1p+58f 8782df72ccSTue Ly if (fputil::get_round() != FE_UPWARD) 8882df72ccSTue Ly return 0x1.45c146p+5f; 8982df72ccSTue Ly break; 9082df72ccSTue Ly } 9182df72ccSTue Ly 92d08a801bSTue Ly int m = 0; 93d08a801bSTue Ly 94d08a801bSTue Ly if (xbits.uintval() < FPBits::MIN_NORMAL || 95d08a801bSTue Ly xbits.uintval() > FPBits::MAX_NORMAL) { 96d08a801bSTue Ly if (xbits.is_zero()) { 97d08a801bSTue Ly return static_cast<float>(FPBits::neg_inf()); 98d08a801bSTue Ly } 99d08a801bSTue Ly if (xbits.get_sign() && !xbits.is_nan()) { 100d08a801bSTue Ly return FPBits::build_nan(1 << (fputil::MantissaWidth<float>::VALUE - 1)); 101d08a801bSTue Ly } 102d08a801bSTue Ly if (xbits.is_inf_or_nan()) { 103d08a801bSTue Ly return x; 104d08a801bSTue Ly } 105d08a801bSTue Ly // Normalize denormal inputs. 1067e7ecef9SGuillaume Chatelet xbits.set_val(xbits.get_val() * 0x1.0p23f); 107d08a801bSTue Ly m = -23; 108d08a801bSTue Ly } 109d08a801bSTue Ly 110d08a801bSTue Ly m += xbits.get_exponent(); 111d08a801bSTue Ly // Set bits to 1.m 112d08a801bSTue Ly xbits.set_unbiased_exponent(0x7F); 1133e520968SMichael Jones int f_index = xbits.get_mantissa() >> 16; 114d08a801bSTue Ly 1157e7ecef9SGuillaume Chatelet FPBits f = xbits; 116d08a801bSTue Ly f.bits &= ~0x0000'FFFF; 117d08a801bSTue Ly 118d08a801bSTue Ly double d = static_cast<float>(xbits) - static_cast<float>(f); 1193e520968SMichael Jones d *= ONE_OVER_F[f_index]; 120d08a801bSTue Ly 121d08a801bSTue Ly double extra_factor = 122*c5f8a0a1STue Ly fputil::multiply_add(static_cast<double>(m), LOG_2, LOG_F[f_index]); 12382df72ccSTue Ly 12482df72ccSTue Ly double r = __llvm_libc::fputil::polyeval( 12582df72ccSTue Ly d, extra_factor, 0x1.fffffffffffacp-1, -0x1.fffffffef9cb2p-2, 12682df72ccSTue Ly 0x1.5555513bc679ap-2, -0x1.fff4805ea441p-3, 0x1.930180dbde91ap-3); 12782df72ccSTue Ly 12882df72ccSTue Ly return static_cast<float>(r); 129d08a801bSTue Ly } 130d08a801bSTue Ly 131d08a801bSTue Ly } // namespace __llvm_libc 132