如何解决如何将小数标准化为一个范围内的数值
如何将范围 [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 在算术上下文中是否是正确的词。
解决方法
您要查找的术语是“插值”,也就是“线性插值”,也就是 lerp
:
您可以轻松创建一个模板来满足您的需求:
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,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()
并不能完全满足您的需求。
如果我输入 0.799999 并且范围是 0 到 10,那么输出应该是 8。
您最终会得到 7,因为默认情况下 C++ 会将所有内容都四舍五入到 0。因此,您还必须手动将该值四舍五入为最接近的整数。您可以将其作为 lerp 的一部分来执行,但是 lerp()
具有相当明确的预期行为。搞砸了可能会带来惊喜。
最好为此创建一个单独的方法,在后台使用 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,const Tt& t) {
static_assert(std::is_integral<IntT>::value,"IntT must be an integer type");
return std::round(lerp(a,t));
}
请注意,这会强制 a
、b
和返回类型都为相同类型。这是一个有点武断的决定,您可能希望也可能不想根据自己的需要进行更改。
用法:
int x = interpolateToNearest(0,10,0.5);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。