在嵌入式上下文中缩放值的高效程序
Efficient program to scale values in embedded context
我想在 0 到 32767 之间缩放我的输入值。就上下文而言,此程序是 运行 在 ARM M0 上,我想避免任何浮点运算。我的输入类型是 u32,输出类型是 u16。到目前为止,我有这个,我在进行大乘法时明确检查溢出。如果不是,我只是继续将数字相乘。这种检查溢出的方法是实现所需缩放的有效方法吗?
uint16_t scaling(uint32_t in, uint32_t base)
{
uint32_t new_base = INT16_MAX; // 32767
if (in >= base) {
return (uint16_t)new_base;
}
if (in != ((in * new_base) / new_base) ) {
// overflow, increase bit width!
uint64_t tmp = in * (uint64_t)new_base;
tmp /= base;
return (uint16_t)(tmp);
}
// simply multiply
uint32_t tmp = (in * new_base) / base;
if (tmp > new_base) {
tmp = new_base; // clamp
}
return (uint16_t)tmp;
}
例如,对于 (in=200000, base=860000) 的样本“大”输入,预期输出为 7620(此程序确实返回)
OP 代码的以下变体预先计算了 in * new_base
溢出到 64 位的阈值,并保存了最后一次检查 if (tmp > new_base)
,它是冗余的一次 in < base
。
uint16_t scaling(uint32_t in, uint32_t base)
{
static const uint32_t new_base = INT16_MAX; // 2^15 - 1 = 32767
static const uint32_t in32 = (uint32_t)(((uint64_t)UINT32_MAX + 1) / INT16_MAX); // 2^32 / (2^15 - 1) = 131076
if (in >= base) {
return (uint16_t)new_base;
}
if(in < in32) {
return (uint16_t)((in * new_base) / base);
}
return (uint16_t)(((uint64_t)in * new_base) / base);
}
作为旁注,至少 one compiler(运行 默认优化)将在 new_base = INT16_MAX
时用更便宜的 (in << 15) - in
替换乘法 in * new_base
声明为 const uint32_t
但声明为 uint32_t
.
时不声明
我想在 0 到 32767 之间缩放我的输入值。就上下文而言,此程序是 运行 在 ARM M0 上,我想避免任何浮点运算。我的输入类型是 u32,输出类型是 u16。到目前为止,我有这个,我在进行大乘法时明确检查溢出。如果不是,我只是继续将数字相乘。这种检查溢出的方法是实现所需缩放的有效方法吗?
uint16_t scaling(uint32_t in, uint32_t base)
{
uint32_t new_base = INT16_MAX; // 32767
if (in >= base) {
return (uint16_t)new_base;
}
if (in != ((in * new_base) / new_base) ) {
// overflow, increase bit width!
uint64_t tmp = in * (uint64_t)new_base;
tmp /= base;
return (uint16_t)(tmp);
}
// simply multiply
uint32_t tmp = (in * new_base) / base;
if (tmp > new_base) {
tmp = new_base; // clamp
}
return (uint16_t)tmp;
}
例如,对于 (in=200000, base=860000) 的样本“大”输入,预期输出为 7620(此程序确实返回)
OP 代码的以下变体预先计算了 in * new_base
溢出到 64 位的阈值,并保存了最后一次检查 if (tmp > new_base)
,它是冗余的一次 in < base
。
uint16_t scaling(uint32_t in, uint32_t base)
{
static const uint32_t new_base = INT16_MAX; // 2^15 - 1 = 32767
static const uint32_t in32 = (uint32_t)(((uint64_t)UINT32_MAX + 1) / INT16_MAX); // 2^32 / (2^15 - 1) = 131076
if (in >= base) {
return (uint16_t)new_base;
}
if(in < in32) {
return (uint16_t)((in * new_base) / base);
}
return (uint16_t)(((uint64_t)in * new_base) / base);
}
作为旁注,至少 one compiler(运行 默认优化)将在 new_base = INT16_MAX
时用更便宜的 (in << 15) - in
替换乘法 in * new_base
声明为 const uint32_t
但声明为 uint32_t
.