std::log1p,...std::log1pl(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’– std::log1p, std::log1p f, std::log1pl β€” NAME

okay bestie, so this is std::log1p, std::log1pf, std::log1pl β€” from the C++ Standard Libary (yes the manual really spells it like that, we love her anyway 🫢). tldr: they compute the natural log of 1 + num without losing precision when num is tiny. iconic behaviour honestly.


✨ Synopsis ✨

Defined in header <cmath>

float       log1p ( float num );
double      log1p ( double num );                            (until C++23)

long double log1p ( long double num );
/* floating-point-type */                                    (since C++23)
                log1p ( /* floating-point-type */ num );
                                                             (constexpr since C++26)

float       log1pf( float num );                             (1) (2) (since C++11)
                                                             (constexpr since C++26)

long double log1pl( long double num );                       (3) (since C++11)
                                                             (constexpr since C++26)

Additional overloads (since C++11)
Defined in header <cmath>

template< class Integer >                                    (A)
                                                             (constexpr since C++26)

double      log1p ( Integer num );

so like, breaking it down for you:

  1. 1-3) computes the natural (base e) logarithm of 1 + num. the whole point? it's more precise than just writing the expression std::log(1 + num) when num is close to zero. literally that's her whole personality πŸ’…
  2. the library provides overloads of std::log1p for all cv-unqualified floating-point types as the type of the parameter. (since C++23)
  3. A) additional overloads are provided for all integer types, which are treated as double. (since C++11)

🌸 Parameters 🌸

  • num β€” floating-point or integer value. that's it. that's the whole vibe check.

πŸŽ€ Return value πŸŽ€

  • if no errors occur, ln(1+num) is returned. slay. ✨
  • if a domain error occurs, an implementation-defined value is returned (NaN where supported).
  • if a pole error occurs, -HUGE_VAL, -HUGE_VALF, or -HUGE_VALL is returned.
  • if a range error occurs due to underflow, the correct result (after rounding) is returned.

πŸ’€ Error handling πŸ’€

errors are reported as specified in math_errhandling. no cap.

  • Domain error occurs if num is less than -1.
  • Pole error may occur if num is -1.

if the implementation supports IEEE floating-point arithmetic (IEC 60559), then:

  • if the argument is Β±0, it is returned unmodified.
  • if the argument is -1, -∞ is returned and FE_DIVBYZERO is raised.
  • if the argument is less than -1, NaN is returned and FE_INVALID is raised.
  • if the argument is +∞, +∞ is returned.
  • if the argument is NaN, NaN is returned.

πŸ¦‹ Notes πŸ¦‹

the functions std::expm1 and std::log1p are useful for financial calculations, for example when calculating small daily interest rates: (1 + x)n - 1 can be expressed as std::expm1(n * std::log1p(x)). these functions also simplify writing accurate inverse hyperbolic functions. iykyk β€” this is the good stuff 🧚

the additional overloads are not required to be provided exactly as (A). they only need to be sufficient to ensure that for their first argument num1 and second argument num2:

  • If num1 or num2 has type long double, then std::log1p(num1, num2) has the same effect as std::log1p(static_cast<long double>(num1), static_cast<long double>(num2)).
  • Otherwise, if num1 and/or num2 has type double or an integer type, then std::log1p(num1, num2) has the same effect as std::log1p(static_cast<double>(num1), static_cast<double>(num2)). (until C++23)
  • Otherwise, if num1 or num2 has type float, then std::log1p(num1, num2) has the same effect as std::log1p(static_cast<float>(num1), static_cast<float>(num2)).

if num1 and num2 have arithmetic types, then std::log1p(num1, num2) has the same effect as std::log1p(static_cast</* common-floating-point-type */>(num1), static_cast</* common-floating-point-type */>(num2)), where /* common-floating-point-type */ is the floating-point type with the greatest floating-point conversion rank and greatest floating-point conversion subrank between the types of num1 and num2; arguments of integer type are considered to have the same floating-point conversion rank as double. (since C++23)

if no such floating-point type with the greatest rank and subrank exists, then overload resolution does not result in a usable candidate from the overloads provided. (she said no πŸ’€)


πŸ”₯ Example πŸ”₯

// Run this code

#include <cerrno>
#include <cfenv>
#include <cmath>
#include <cstring>
#include <iostream>
// #pragma STDC FENV_ACCESS ON

int main()
{
    std::cout << "log1p(0) = " << log1p(0) << '\n'
              << "Interest earned in 2 days on $100, compounded daily at 1%\n"
              << "    on a 30/360 calendar = "
              << 100 * expm1(2 * log1p(0.01 / 360)) << '\n'
              << "log(1+1e-16) = " << std::log(1 + 1e-16)
              << ", but log1p(1e-16) = " << std::log1p(1e-16) << '\n';

    // special values
    std::cout << "log1p(-0) = " << std::log1p(-0.0) << '\n'
              << "log1p(+Inf) = " << std::log1p(INFINITY) << '\n';

    // error handling
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);

    std::cout << "log1p(-1) = " << std::log1p(-1) << '\n';

    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_DIVBYZERO))
        std::cout << "    FE_DIVBYZERO raised\n";
}

⭐ Possible output ⭐

log1p(0) = 0
Interest earned in 2 days on $100, compounded daily at 1%
    on a 30/360 calendar = 0.00555563
log(1+1e-16) = 0, but log1p(1e-16) = 1e-16
log1p(-0) = -0
log1p(+Inf) = inf
log1p(-1) = -inf
    errno == ERANGE: Result too large
    FE_DIVBYZERO raised
ngl that log(1+1e-16) = 0 vs log1p(1e-16) = 1e-16 line is the entire reason she exists. main character energy. πŸ‘‘

πŸ’œ See also πŸ’œ

  • log, logf, logl β€” computes natural (base e) logarithm (ln(x)) (function) (C++11) (C++11)
  • log10, log10f, log10l β€” computes common (base 10) logarithm (log10(x)) (function) (C++11) (C++11)
  • log2, log2f, log2l β€” base 2 logarithm of the given number (log2(x)) (function) (C++11) (C++11) (C++11)
  • expm1, expm1f, expm1l β€” returns e raised to the given power, minus one (e^xβˆ’1) (function) (C++11) (C++11) (C++11)
  • C documentation for log1p

and that's the whole page bestie, go forth and compute precisely πŸŒˆπŸ’–

πŸŽ€ sourced straight from http://cppreference.com, version 2024.06.10, for std::log1p,...std::log1pl(3) β€” mwah, talk later! πŸŽ€
πŸ“¦ where this page comes from