有没有一种方法可以接近适当的返回值而不需要任何大于 uint8_t 的分配?
理论上是的:
uint8_t blend(uint8_t x, uint8_t y, uint8_t parts_x, uint8_t parts_y) {
return lookup_table[x][y][parts_x][parts_y];
}
实际上,查找表需要 4 GiB 的 RAM,所以这可能不是一个好主意。
除此之外,这取决于您所说的“接近”(“可接受的最坏情况错误”可以有多大)以及有效值的范围(尤其是对于parts_x 和parts_y)。
例如(如果 parts_x 和 parts_y 的范围仅为 1 到 15):
uint8_t blend(uint8_t x, uint8_t y, uint8_t parts_x, uint8_t parts_y) {
uint8_t scaleX = (parts_x << 4) / (parts_x + parts_y);
uint8_t scaleY = (parts_y << 4) / (parts_x + parts_y);
return (x >> 4) * scaleX + (y >> 4) * scaleY;
}
当然在这种情况下“关闭”意味着:
- 混合(100、200、1、1)= 6*8 + 12*8 = 144(不是 150)
- 混合(100、200、2、1)= 6*10 + 12*5 = 120(不是 133)
请注意,(通常)乘法是“扩展”的。我的意思是,如果a 有 M 位范围,b 有 N 位范围,那么 a*b 将有 M+N 位范围。换句话说(使用全范围)以避免溢出uint8_t * uint8_t = uint16_t。除法明显差很多(比如要避免精度损失,1/3需要无限位),有些精度损失是无法避免的,结果中的位数决定了精度损失多少,8位精度“不多” .
另外请注意,我上面展示的简单示例可以通过为这些情况添加额外代码来改进某些情况。例如:
uint8_t blend(uint8_t x, uint8_t y, uint8_t parts_x, uint8_t parts_y) {
if(parts_x < parts_y) {
return blend(y, x, parts_y, parts_x);
}
// parts_x <= parts_y now
if(parts_x == parts_y*2) {
return 2*(x/3) + y/3;
} else if(parts_x == parts_y*3) {
return 3*(x/4) + y/4;
} else if(parts_x == parts_y*4) {
return 4*(x/5) + y/5;
} else if(parts_x == parts_y*5) {
return 5*(x/6) + y/6;
} else if( (x > 16) && (y > 16) ){
uint8_t scaleX = (parts_x << 4) / (parts_x + parts_y);
uint8_t scaleY = (parts_y << 4) / (parts_x + parts_y);
return (x * scaleX + y * scaleY) >> 4;
} else {
uint8_t scaleX = (parts_x << 4) / (parts_x + parts_y);
uint8_t scaleY = (parts_y << 4) / (parts_x + parts_y);
return (x >> 4) * scaleX + (y >> 4) * scaleY;
}
}
当然,使用比uint8_t 更大的东西要容易得多,也快得多,所以...