C++ 如何将十进制标准化为一个范围内的数值

C++ 如何将十进制标准化为一个范围内的数值,c++,c++11,math,integer-arithmetic,C++,C++11,Math,Integer Arithmetic,如何将[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) {

如何将[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:

您可以轻松创建一个模板,该模板将执行您想要的操作:

模板
[[nodiscard]]T lerp(常数T&a、常数T&b、浮动T){
返回值((1.0f-t)*a)+(t*b);
}

您的问题带有
c++11
标签,但值得一提的是,如果您使用c++20进行编译,这会让您半途而废

提供自己的
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);
}


请注意,这强制要求
a
b
和返回类型都是相同的类型。这是一个有点武断的决定,根据你的需要,你可能想改变,也可能不想改变

用法:

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

看起来你想要的是value*max的绝对值,我称之为逆操作归一化。(一个(数学)向量的标准化结果是一个长度为1的向量。)尽管
(max-min)*值+min
和一些强制转换/舍入应该足够,但这个操作应该不会太难。
0.05
应该是0,因为它不高于
0.5
@fabian
(max-min)*value+min
似乎能起作用。很好@杰米特:谢谢你指出这一点。我编辑这个问题是为了指出十进制浮点必须在[0.0,1.0]范围内,或者等待平台实现。出于好奇,为什么要在这里使用
[[nodiscard]]
?我真的想不出这可能捕捉到任何错误。@Frank这是一个警告,它告诉编译器它应该警告您,您没有以某种方式捕捉返回值。“这是一个能捕捉虫子的功能。”凯利斯说。使用提供的STL特性总是比编写自己的STL特性更可取。在2016年10月之前,
std::clamp
不存在,因此开发人员编写自己的代码是很常见的。现在没有理由了。@Casey我知道它是什么,只是看起来没用。你能分享一个特定函数的bug例子吗?我很想知道那会是什么样子,因为我什么都想不出来。从我的观点来看,这只是增加了对C++14的依赖,因为我觉得这不是一个好的理由。这不会产生与asker预期不同的结果吗?他们需要目标范围内的整数值,而不是浮点值。例如,他们期望
lerp(0,10,0.79999f)
8
,而不是
7.99999
@NathanPierson
(int)ceil(lerp(0,10,0.79999f))
起作用。
ceil()
是OP别无选择,只能做的事情。我认为它实际上是
圆形的
而不是
ceil
,因为他们想要
(0,10,0.345)
转到
3
而不是
4
。我只是想指出,仍然需要一点按摩,才能让输出准确地达到asker想要的位置。@NathanPierson很好。更新了答案。@TheWaterProgrammer我已经用c++11下编译的代码版本更新了答案。
int x = interpolateToNearest(0, 10, 0.5);