c++ - 是否可以为 AVR 编写一个 constexpr 舍入函数?

标签 c++ rounding avr constexpr

我正在编写一个类来在 AVR 微 Controller 上设置串行端口。我有一个模板函数,它将 cpu 时钟值和所需的波特率作为参数,进行快速计算,使用静态断言验证实际值是否在所需值的 1.5% 范围内,然后返回实际值以在内部设置一个 8 位寄存器。我需要使用 std::round 并且它的返回值需要是 constexpr 才能在编译时评估所有内容。这是有问题的一点:

#include <cmath>

template<int c, int b>
constexpr int UBRRValue() {
   // return the value for UBRR register to get close to the desired baud rate
   // avoid integer division
    return std::round( static_cast<float>(c) / ( 16 * b ) - 1 );
}

int main() {
    constexpr auto val = UBRRValue<2000,25>();
    return val;
}

这在编译器资源管理器上适用于 x86,它返回 4。 在 AVR 上没有 cmath,float round(float) 在 math.h 中定义并在汇编中实现,因此可能不是 constexpr。快速搜索后,我发现了这个:https://stackoverflow.com/a/24348037/11221049 我做了一些调整,然后让 gcc 指出这个函数是非 constexpr。我将它设为 constexpr,但它的结果永远不会是 constexpr,因为它需要访问一个尚未初始化的 union 成员。 Union 技巧不是 constexpr。 那么...是否有可能制作一个 constexpr round 函数(知道 math.h 中的任何内容都是直接用汇编编写的)? 在 gnu libc++ 中是如何完成的?

最佳答案

您要计算的是 (c/(16 * b)) - 1 的正确舍入结果。您正在转换为 float 以避免整数除法,但如果您之后要四舍五入,这几乎毫无意义。

请注意,我们可以将 -1 安全地移动到舍入之外(只有当您因缺乏浮点精度而丢弃 -1 时才会更改结果,这你似乎不打算)。所以我们所需要的只是 c/(16*b) 的正确舍入结果。如果我们这样做作为整数除法,我们会得到向下舍入的结果。我们只需将除数的一半加到被除数上(假设两者均为正数),就可以得到一个中间舍入的结果:

template<int c, int b>
constexpr int UBRRValue() {
   // return the value for UBRR register to get close to the desired baud rate
    return (c + 8*b) / (16 * b) - 1;
}

这是它通过的一些测试用例:https://godbolt.org/z/Va6qDT

关于c++ - 是否可以为 AVR 编写一个 constexpr 舍入函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55382543/

相关文章:

c++ - Live555 RTSPServer 对象销毁不当或库错误?

c++ - 如何将 vector<int> 转换为 int*

c - 嵌套开关盒不起作用

eclipse - AVR - 无法在 Eclipse 上添加程序员

c++ - 使用 C++ 中的 prepare 语句在 SQLite 中批量插入数据

Python 总是向下舍入?

c++ - 在 C++ 中将数字显式舍入到小数点后 7 位以上

algorithm - 将数字四舍五入为不对称分辨率

c - 通过 UART 发送十六进制

c++ - 智能指针管理数组中的智能指针