在嵌入式上下文中缩放值的高效程序

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.

时不声明