1

我正在使用raylib,它使用 32 位 RGBA 颜色。我在备忘单中搜索,但找不到任何合适的例程。我想要做的是将两种颜色相乘,就好像它们vec4在 opengl 中一样(每个通道的范围从 0 到 1)。实际上,我已经成功地执行了乘法运算,但是对于如此简单的事情,它涉及大量浮点运算的操作相当慢:

uint8_t multiplyBytes(uint8_t a, uint8_t b) {
    const float invertedByte = 1/255.0;
    return (uint8_t)(((a * invertedByte) * (b * invertedByte)) * 255.0);
}

我的问题是是否有更好的方法来做到这一点?或者我应该坚持这个解决方案?

4

2 回答 2

2

我实际上已经成功地执行了乘法,但是对于如此简单的事情,它涉及大量浮点运算的操作相当慢:

改进 FP 数学的一个步骤是避免使用floatdouble类型。

// double to float
const float invertedByte = 1/255.0;  

// uint8_t to float (twice)
// float to double
// double to uint8_t
return (uint8_t)(((a * invertedByte) * (b * invertedByte)) * 255.0);
//                ^---- float product ------------------^    double

更好的 FP 解决方案将使用

const float invertedByte = 1.0f/255.0f;  
// unsigned to float (once)
// float to uint8_t
return (uint8_t)( ((unsigned)a * (unsigned)b) * invertedByte);

然而,一个全整数解决方案 - 类似于@Jakub Dóka

return (uint8_t) (((unsigned)a * (unsigned)b + 255u) >> 8);

或者按照@Paul Hankin的建议

return (uint8_t) ((unsigned)a * (unsigned)b + 127u) / 255u;

另请参阅@Ian Abbott好主意

return ((uint_fast32_t)a * (uint_fast32_t)b * 0x10101u + 0x800000u) >> 24;
于 2021-06-07T15:08:28.520 回答
1

经过一番搜索,我意识到,我可以将其升级为:

uint8_t multiplyBytes(uint8_t a, uint8_t b) {
    return (uint8_t)(((unsigned short)a * (unsigned short)b + 255) >> 8);
}

不确定这是否是最好的解决方案。

于 2021-06-07T14:17:25.757 回答