归一化整数到/从浮点转换
Posted
技术标签:
【中文标题】归一化整数到/从浮点转换【英文标题】:Normalized Integer to/from Float Conversion 【发布时间】:2016-10-01 12:29:23 【问题描述】:我需要将归一化的整数值与实数浮点值相互转换。例如,对于 int16_t,值 1.0 由 32767 表示,-1.0 由 -32768 表示。尽管对每种整数类型(包括有符号和无符号)都执行此操作有点繁琐,但手动编写仍然很容易。
但是,我想尽可能使用标准方法,而不是重新发明***,所以我正在寻找标准 C 或 C++ 头文件、Boost 库或其他一些小型、可移植、已经执行这些转换的易于合并的源。
【问题讨论】:
我不确定是否需要库...double convert(int16_t x) return x < 0 ? x/double(32768) : x/double(32767);
。可以使用std::numeric_limits
轻松地将其模板化并推广到所有 int 类型。无论如何,它的制作时间很短,而且肯定不在 std 库中。也看这里:***.com/questions/929103/…
@coyotte508 虽然我还没有找到它,但我真的在寻找/希望已经模板化的东西,比如标准库中的 std::numeric_limits,因为我知道我已经这样做了不是唯一需要这个的。我在职业生涯中花了很多时间编写本来可以而且应该已经标准化的代码,但后来发现有人已经编写了这些代码,这些天我在自己编写之前尝试找到现有的标准化代码。顺便说一句,谢谢你的链接。
我通常会同意,但是当它是一行时,将它“内联”(在现场)比包裹在一个不起眼的想要标准的名称函数调用中更清楚。顺便说一句,与问题正交,您确定要使用浮点数吗?精度在 0 到 1 之间变化很大。
@v.oddou 这是一个很好的观点,即使是这样一个简单的问题,也可能会出现问题,具体取决于您的使用案例,例如***.com/questions/599976/…。顺便说一句,我正在使用双打(或我的代码中出现的 float64_t),但我想笼统地问这个问题,这样我就不会限制我得到的答案。我在 SO 上遇到了很多好的但晦涩难懂的链接,即使它不是您正在寻找的内容(例如,它使用浮点数而不是双精度数),您仍然可以经常找到一些非常好的东西。跨度>
这个问题没有完全说明。如果 -32768 和 32767 分别代表 -1 和 1,那么要么正负数的缩放比例不同,要么 0 不代表 0。在前一种情况下,相反符号的代表数字之间的加法和减法将得出错误的结果。在后一种情况下,代表的简单乘法会得出错误的结果。
【参考方案1】:
这是一个使用std::numeric_limits
的模板化解决方案:
#include <cstdint>
#include <limits>
template <typename T>
constexpr double normalize (T value)
return value < 0
? -static_cast<double>(value) / std::numeric_limits<T>::min()
: static_cast<double>(value) / std::numeric_limits<T>::max()
;
int main ()
// Test cases evaluated at compile time.
static_assert(normalize(int16_t(32767)) == 1, "");
static_assert(normalize(int16_t(0)) == 0, "");
static_assert(normalize(int16_t(-32768)) == -1, "");
static_assert(normalize(int16_t(-16384)) == -0.5, "");
static_assert(normalize(uint16_t(65535)) == 1, "");
static_assert(normalize(uint16_t(0)) == 0, "");
这处理有符号和无符号整数,0 确实归一化为 0。
View Successful Compilation Result
【讨论】:
这是非常好的代码,也是很好的用例测试。谢谢。 从整数转换为双精度很容易,但如果能看到从双精度转换为整数的正确解决方案(即0.99999999999 == 32767
而不是 0.99999999999 == 32766
由于 static_cast 截断而不是舍入的方式,在static_cast<uint16_t>(value * std::numeric_limits<uint16_t>::max()
的方向上使用类似的方法。【参考方案2】:
我会质疑您的意图是否正确(或者实际上大多数答案的意图)。
由于您可能只是处理诸如由 ADC 产生的“真实”值的整数表示之类的东西 - 我认为实际上是 +32767/32768 的浮点分数(不是 +1.0 ) 由整数 +32767 表示,因为使用了 2 的补码算法,+1.0 的值实际上不能以这种形式表示。
【讨论】:
您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。【参考方案3】:虽然对每个整数类型都这样做有点乏味,但两者都 签名和未签名,手写还是很容易的。
您当然不需要为每个整数类型都这样做!请改用<limits>
。
template<class T> double AsDouble(const T x)
const double valMin = std::numeric_limits<T>::min();
const double valMax = std::numeric_limits<T>::max();
return 2 * (x - valMin) / (valMax - valMin) - 1; // note: 0 does not become 0.
【讨论】:
以上是关于归一化整数到/从浮点转换的主要内容,如果未能解决你的问题,请参考以下文章