如何将小数标准化为范围内的值的数字

How to normalise a decimal into a number that is a value within a range

如何将 [0.0, 1.0] 范围内的浮点小数 归一化为设置在最大值和最小值范围之间的数字?规范化是正确的词吗?按照我想做的去做。

如果我输入0.5,范围是010,那么输出应该是5.

如果我输入0.799999,范围是010,那么输出应该是8.

如果我输入0.345,范围是010,那么输出应该是3.

如果我输入0.555,范围是020,那么输出应该是11.

unsigned int Normalise(float value, unsigned int min, unsigned int max) {
    // Return value normalised between min and max
}

我不太确定 normalise 在算术上下文中是否是正确的词。

您要找的词是“插值法”a.k.a“线性插值法”a.k.alerp:

您可以轻松创建一个模板来满足您的需求:

template<typename T>
[[nodiscard]] T lerp(const T& a, const T& b, float t) {
    return ((1.0f - t) * a) + (t * b);
}

你的问题有 c++11 标签,但值得一提的是,如果你在 c++20 中编译,std::lerp() 会让你完成一半。

提供您自己的 lerp() 相当简单。这是@Casey 提出的功能的更完整实现:​​

#include <cassert>
#include <type_traits>

template<typename Ta, typename Tb, typename Tt>
constexpr auto lerp(const Ta& a, const Tb& b, const Tt& t) {
    static_assert(std::is_floating_point_v<Tt>);
    assert(t >= Tt{0} && t <= Tt{1});
    
    return a + t * (b - a);
}

// c++11 version:

template<typename Ta, typename Tb, typename Tt>
constexpr auto lerp(const Ta& a, const Tb& b, const Tt& t) -> decltype(a + t * (b - a)) {
    static_assert(std::is_floating_point<Tt>::value, "Tt must be a floating point type");
    // assert(t >= Tt{0} && t <= Tt{1}); //can't assert in constexpr code in C++11 :(

    return a + t * (b - a);
}


但是,lerp() 并不能完全满足您的需求。

If I input 0.799999 and the range is 0 to 10, then the output should be 8.

您最终会得到 7,因为 C++ 默认将所有内容四舍五入为 0。因此,您还必须手动将该值四舍五入为最接近的整数。您 可以 作为 lerp 的一部分执行此操作,但是 lerp() 具有相当明确的 expected 行为。弄乱它可能会带来惊喜。

最好为此创建一个单独的方法,在后台使用 lerp()

template<typename IntT, typename Tt>
constexpr IntT interpolateToNearest(const IntT& a, const IntT& b, const Tt& t) {
  static_assert(std::is_integral_v<IntT>);

  // There's a hidden implicit cast to IntT here.
  return std::round(lerp(a, b, t));
}

// c++11 version:

template<typename IntT, typename Tt>
constexpr IntT interpolateToNearest(const IntT& a, const IntT& b, const Tt& t) {
  static_assert(std::is_integral<IntT>::value, "IntT must be an integer type");
  return std::round(lerp(a, b, t));
}

请注意,这会强制 ab 和 return 类型都是同一类型。这是一个有点武断的决定,您可以根据自己的需要更改或不更改。

用法:

int x = interpolateToNearest(0, 10, 0.5);