Spec-Zone.ru › C++

std::lerp

Определён в заголовочном файле <cmath>
constexpr float       lerp( float a, float b, float t ) noexcept;
constexpr double      lerp( double a, double b, double t ) noexcept;
constexpr long double lerp( long double a, long double b,
                            long double t ) noexcept;
(1) (начиная с C++20)
(до C++23)
constexpr /* floating-point-type */
    lerp( /* floating-point-type */ a,
          /* floating-point-type */ b,
          /* floating-point-type */ t ) noexcept;
(начиная с C++23)
Дополнительные перегрузки
Определён в заголовочном файле <cmath>
template< class Arithmetic1, class Arithmetic2, class Arithmetic3 >
constexpr /* common-floating-point-type */
    lerp( Arithmetic1 a, Arithmetic2 b, Arithmetic3 t ) noexcept;
(A) (начиная с C++20)
1) Вычисляет линейную интерполяцию между a и b, если параметр t находится внутри [0, 1) (в противном случае выполняется линейная экстраполяция), то есть результат вычисления \(a+t(b−a)\)a+t(b−a) с учётом погрешностей вычислений с плавающей точкой. Библиотека предоставляет перегрузки для всех типов с плавающей точкой без квалификаторов cv в качестве типов параметров a, b и t.(начиная с C++23)
A) Для всех остальных сочетаний арифметических типов предоставляются дополнительные перегрузки.

Параметры

a, b, t - значения с плавающей точкой или целочисленные значения

Возвращаемое значение

\(a + t(b − a)\)a + t(b − a)

Если std::isfinite(a) && std::isfinite(b) равно true, гарантируются следующие свойства:

  • Если t == 0, результат равен a.
  • Если t == 1, результат равен b.
  • Если t >= 0 && t <= 1, результат является конечным.
  • Если std::isfinite(t) && a == b, результат равен a.
  • Если std::isfinite(t) || (b - a != 0 && std::isinf(t)), результат не является NaN.

Пусть CMP(x, y) равно 1, если x > y, -1, если x < y, и 0 в остальных случаях. Для любых t1 и t2 произведение

  • CMP(std::lerp(a, b, t2), std::lerp(a, b, t1)),
  • CMP(t2, t1) и
  • CMP(b, a)

неотрицательно. (То есть std::lerp является монотонной.)

Примечания

Дополнительные перегрузки не обязательно должны быть предоставлены в точности в виде (A). Они должны лишь обеспечивать, чтобы для первого аргумента num1, второго аргумента num2 и третьего аргумента num3:

  • Если num1, num2 или num3 имеет тип longdouble, то std::lerp(num1, num2, num3) действует так же, как std::lerp(static_cast<long double>(num1),static_cast<long double>(num2),static_cast<long double>(num3)).
  • В противном случае, если num1, num2 и/или num3 имеет тип double или целочисленный тип, то std::lerp(num1, num2, num3) действует так же, как std::lerp(static_cast<double>(num1),static_cast<double>(num2),static_cast<double>(num3)).
  • В противном случае, если num1, num2 или num3 имеет тип float, то std::lerp(num1, num2, num3) действует так же, как std::lerp(static_cast<float>(num1),static_cast<float>(num2),static_cast<float>(num3)).
(до C++23)

Если num1, num2 и num3 имеют арифметические типы, то std::lerp(num1, num2, num3) действует так же, как std::lerp(static_cast</*common-floating-point-type*/>(num1),static_cast</*common-floating-point-type*/>(num2),static_cast</*common-floating-point-type*/>(num3)), где /*common-floating-point-type*/ — тип с плавающей точкой с наибольшим рангом преобразования типов с плавающей точкой и наибольшим подрангом преобразования типов с плавающей точкой среди типов num1, num2 и num3; считается, что аргументы целочисленного типа имеют такой же ранг преобразования типов с плавающей точкой, как double.

Если не существует такого типа с плавающей точкой с наибольшими рангом и подрангом, то разрешение перегрузки не приводит к выбору подходящего кандидата среди предоставленных перегрузок.

(начиная с C++23)
Макрос проверки поддержки функции Значение Стандарт Функция
__cpp_lib_interpolate 201902L (C++20) std::lerp, std::midpoint

Пример

#include <cassert>
#include <cmath>
#include <iostream>

float naive_lerp(float a, float b, float t)
{
    return a + t * (b - a);
}

int main()
{
    std::cout << std::boolalpha;
    
    const float a = 1e8f, b = 1.0f;
    const float midpoint = std::lerp(a, b, 0.5f);
    
    std::cout << "a = " << a << ", " << "b = " << b << '\n'
              << "midpoint = " << midpoint << '\n';
    
    std::cout << "std::lerp is exact: "
              << (a == std::lerp(a, b, 0.0f)) << ' '
              << (b == std::lerp(a, b, 1.0f)) << '\n';
    
    std::cout << "naive_lerp is exact: "
              << (a == naive_lerp(a, b, 0.0f)) << ' '
              << (b == naive_lerp(a, b, 1.0f)) << '\n';
    
    std::cout << "std::lerp(a, b, 1.0f) = " << std::lerp(a, b, 1.0f) << '\n'
              << "naive_lerp(a, b, 1.0f) = " << naive_lerp(a, b, 1.0f) << '\n';
    
    assert(not std::isnan(std::lerp(a, b, INFINITY))); // lerp here can be -inf
    
    std::cout << "Extrapolation demo, given std::lerp(5, 10, t):\n";
    for (auto t{-2.0}; t <= 2.0; t += 0.5)
        std::cout << std::lerp(5.0, 10.0, t) << ' ';
    std::cout << '\n';
}

Возможный вывод:

a = 1e+08, b = 1
midpoint = 5e+07
std::lerp is exact?: true true
naive_lerp is exact?: true false
std::lerp(a, b, 1.0f) = 1
naive_lerp(a, b, 1.0f) = 0
Extrapolation demo, given std::lerp(5, 10, t):
-5 -2.5 0 2.5 5 7.5 10 12.5 15

См. также

midpoint
(C++20)
середина между двумя числами или указателями
(шаблон функции)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/numeric/lerp

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API