如何将小数标准化为范围内的值的数字
How to normalise a decimal into a number that is a value within a range
如何将 [0.0, 1.0] 范围内的浮点小数 归一化为设置在最大值和最小值范围之间的数字?规范化是正确的词吗?按照我想做的去做。
如果我输入0.5
,范围是0
到10
,那么输出应该是5
.
如果我输入0.799999
,范围是0
到10
,那么输出应该是8
.
如果我输入0.345
,范围是0
到10
,那么输出应该是3
.
如果我输入0.555
,范围是0
到20
,那么输出应该是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));
}
请注意,这会强制 a
、b
和 return 类型都是同一类型。这是一个有点武断的决定,您可以根据自己的需要更改或不更改。
用法:
int x = interpolateToNearest(0, 10, 0.5);
如何将 [0.0, 1.0] 范围内的浮点小数 归一化为设置在最大值和最小值范围之间的数字?规范化是正确的词吗?按照我想做的去做。
如果我输入0.5
,范围是0
到10
,那么输出应该是5
.
如果我输入0.799999
,范围是0
到10
,那么输出应该是8
.
如果我输入0.345
,范围是0
到10
,那么输出应该是3
.
如果我输入0.555
,范围是0
到20
,那么输出应该是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));
}
请注意,这会强制 a
、b
和 return 类型都是同一类型。这是一个有点武断的决定,您可以根据自己的需要更改或不更改。
用法:
int x = interpolateToNearest(0, 10, 0.5);