std::scalbn...d::scalblnl(3)

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

πŸ’… std::scalbn...d::scalblnl(3) β€” C++ Standard Library, bestie edition

okay so first things first: this whole page lives in the C++ Standard Library manual (third section, (3), iykyk), and it's about a whole family of functions: std::scalbn, std::scalbnf, std::scalbnl, std::scalbln, std::scalblnf, std::scalblnl. Yes, six of them. They're all the same vibe, just different types. Let's get into it 🫢


✨ NAME ✨

std::scalbn, std::scalbnf, std::scalbnl, std::scalbln, std::scalblnf, std::scalblnl β€” the whole squad. That's the name, that's the list, we're not skipping anyone πŸ’…


🌸 SYNOPSIS 🌸

Defined in header <cmath> β€” go include it, bestie, no cap.

the int exponent era:

int exponent

float       scalbn ( float num, int exp );
double      scalbn ( double num, int exp );            (since C++11)
                                                       (until C++23)
long double scalbn ( long double num, int exp );
constexpr /* floating-point-type */ scalbn ( /* floating-point-type */ num, int exp );  (since C++23)
                                                       (since C++11)
float       scalbnf( float num, int exp );             (2) (constexpr since C++23)
long double scalbnl( long double num, int exp );       (3) (since C++11) (constexpr since C++23)

and now the long exponent era:

long exponent

float       scalbln ( float num, long exp );
double      scalbln ( double num, long exp );          (1) (since C++11) (until C++23)
long double scalbln ( long double num, long exp );
constexpr /* floating-point-type */ scalbln ( /* floating-point-type */ num, long exp );  (since C++23)
float       scalblnf( float num, long exp );           (4) (5) (since C++11) (constexpr since C++23)
long double scalblnl( long double num, long exp );     (6) (since C++11) (constexpr since C++23)

πŸ’– Additional overloads

Defined in header <cmath> (again, yes, same header, calm down):

template< class Integer > double scalbn( Integer num, int exp );    (A) (since C++11) (constexpr since C++23)
template< class Integer > double scalbln( Integer num, long exp );  (B) (since C++11) (constexpr since C++23)

so what do overloads 1-6 actually do? They multiply a floating point value num by FLT_RADIX raised to power exp. That's it. That's the whole function. Literal main character energy ✨

and the tea on the type support: the library provides overloads of std::scalbn and std::scalbln for all cv-unqualified floating-point types as the type of the parameter num. (since C++23) β€” slay.

A and B are the glow-up overloads: additional overloads are provided for all integer types, which are treated as double. πŸŽ€


πŸ¦‹ PARAMETERS πŸ¦‹

  • num β€” a floating-point or integer value. the one getting scaled, okurrr πŸ’–
  • exp β€” an integer value. the power. the oomph. πŸ’…

πŸ”₯ RETURN VALUE πŸ”₯

If no errors occur, you get num multiplied by FLT_RADIX to the power of exp (numΓ—FLT_RADIXexp) returned to you. iconic.

If a range error due to overflow occurs, you get ±HUGE_VAL, ±HUGE_VALF, or ±HUGE_VALL handed back. 😭

If a range error due to underflow occurs, the correct result (after rounding) is returned. no drama. πŸ’œ


🌈 ERROR HANDLING 🌈

Errors are reported as specified in math_errhandling. periodt.

If the implementation supports IEEE floating-point arithmetic (IEC 60559), then buckle up, bestie:

  • Unless a range error occurs, FE_INEXACT is never raised (the result is exact). ✨
  • Unless a range error occurs, the current rounding mode is ignored. πŸ™ˆ
  • If num is Β±0, it is returned, unmodified. zero stays zero, no notes.
  • If num is ±∞, it is returned, unmodified. infinity's not going anywhere.
  • If exp is 0, then num is returned, unmodified. big "we did nothing and that's fine" energy.
  • If num is NaN, NaN is returned. of course it is. πŸ’€

πŸ‘‘ NOTES πŸ‘‘

okay this is the lore section, pay attention:

On binary systems (where FLT_RADIX is 2), std::scalbn is equivalent to std::ldexp. twin behavior fr fr.

Although std::scalbn and std::scalbln are specified to perform the operation efficiently β€” no cap, that's what the spec says β€” on many implementations they are less efficient than multiplication or division by a power of two using arithmetic operators. 🫠 the way that specs promise efficiency and the compilers simply do not... anyway.

The function name stands for "new scalb", where scalb was an older non-standard function whose second argument had floating-point type. history lesson, with receipts. πŸŽ€

The std::scalbln function is provided because the factor required to scale from the smallest positive floating-point value to the largest finite one may be greater than 32767, the standard-guaranteed INT_MAX. πŸ’€ In particular, for the 80-bit long double, the factor is 32828. yes, an actual number. that's why long exists, bestie.

The GNU implementation does not set errno regardless of math_errhandling. 😭 noted. do not come for errno on GNU, it simply won't be there.

The additional overloads are not required to be provided exactly as (A,B). They only need to be sufficient to ensure that for their argument num of integer type:

  • std::scalbn(num, exp) has the same effect as std::scalbn(static_cast<double>(num), exp).
  • std::scalbln(num, exp) has the same effect as std::scalbln(static_cast<double>(num), exp).

so the vibe is "make it behave like double" and the implementation details are left as an exercise πŸ’œ


⭐ EXAMPLE ⭐

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

int main()
{
    std::cout << "scalbn(7, -4) = " << std::scalbn(7, -4) << '\n'
              << "scalbn(1, -1074) = " << std::scalbn(1, -1074)
              << " (minimum positive subnormal double)\n"
              << "scalbn(nextafter(1,0), 1024) = "
              << std::scalbn(std::nextafter(1,0), 1024)
              << " (largest finite double)\n";

    // special values
    std::cout << "scalbn(-0, 10) = " << std::scalbn(-0.0, 10) << '\n'
              << "scalbn(-Inf, -1) = " << std::scalbn(-INFINITY, -1) << '\n';

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

    std::cout << "scalbn(1, 1024) = " << std::scalbn(1, 1024) << '\n';

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

πŸŽ€ Possible output

scalbn(7, -4) = 0.4375
scalbn(1, -1074) = 4.94066e-324 (minimum positive subnormal double)
scalbn(nextafter(1,0), 1024) = 1.79769e+308 (largest finite double)
scalbn(-0, 10) = -0
scalbn(-Inf, -1) = -inf
scalbn(1, 1024) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

ate. no crumbs. πŸ”₯


🧚 SEE ALSO 🧚

  • frexp, frexpf, frexpl β€” decomposes a number into significand and base-2 exponent (function) (C++11) (C++11)
  • ldexp, ldexpf, ldexpl β€” multiplies a number by 2 raised to an integral power (function) (C++11) (C++11)
  • C documentation for scalbn

ok bestie that's the whole page. every overload, every since C++11, every until C++23, every bullet, the 32828, the GNU errno situation, all of it. nothing dropped, nothing invented. that's the assignment and we ate it πŸ’…βœ¨

source/version: cppreference.com β€” dated 2024.06.10 β€” mwah, catch you in the next manpage πŸ«ΆπŸ’–πŸŽ€

πŸ“¦ where this page comes from