Spec-Zone.ru › C++

std::lerp

Определено в заголовке <cmath>
(1)
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;
(с 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 имеет тип long double, то 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/w/cpp/numeric/lerp

Spec-Zone.ru

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