c – 如何“混合”两个值而不溢出?
考虑以下功能:
// Return a blended value of x and y: // blend(100,200,1,1) -> 150 // blend(100,2,1) -> 133 uint8_t blend(uint8_t x,uint8_t y,uint8_t parts_x,uint8_t parts_y) { uint32_t big_parts_x = parts_x; uint32_t big_parts_y = parts_y; return (uint8_t) ((big_parts_x * x + big_parts_y * y) / (big_parts_x + big_parts_y)); } 有没有办法接近适当的返回值而不需要任何大于uint8_t的分配?您可以通过执行两个分区轻松地将其分解(减少四舍五入)为两个uint16_t的添加.你能用uint8_t做到吗? 解决方法
符合标准的C实现保证执行至少16位的算术运算.
C standard第6.3.1.1p2节规定:
第E.1节还规定int必须能够支持至少在-32767到32767范围内的值,而unsigned int必须支持至少在0到65535范围内的值. 由于uint8_t的排名低于int,因此当前者成为大多数运算符的主题时,前者将始终被提升为后者,包括,–,*和/. 鉴于此,您可以通过以下轻微修改安全地计算该值: uint8_t blend(uint8_t x,uint8_t parts_y) { return ((1u*parts_x*x) / (parts_x + parts_y)) + ((1u*parts_y*y) / (parts_x + parts_y)); } 表达式parts_x * x和parts_y * y的最大值为65025.这对于16位int而言太大而不是16位无符号int,因此每个乘以1u以强制将值转换为unsigned int按照6.3.1.8节中规定的通常算术转换:
另请注意,我们将每个部分分别除以总和.如果我们在分割之前首先添加两个部分,则分子可能超过65535.通过首先进行除法,这会使每个子表达式回到uint8_t的范围内.然后我们可以添加两个部分,它们将再次位于uint8_t的范围内. 因此,上述表达式保证在符合C标准的编译器上返回正确的精确答案. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |