加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 如何“混合”两个值而不溢出?

发布时间:2020-12-16 09:22:49 所属栏目:百科 来源:网络整理
导读:考虑以下功能: // Return a blended value of x and y:// blend(100,200,1,1) - 150// blend(100,2,1) - 133uint8_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; retu
考虑以下功能:

// 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节规定:

The following may be used in an expression wherever an int or unsigned
int
may be used:

  • An object or expression with an integer type (other than int or unsigned int ) whose integer conversion rank is less than
    or equal to the rank of int and unsigned int .
  • A bit-field of type
    _Bool,int,signed int,or unsigned int .

If an int can represent all values of the original type (as
restricted by the width,for a bit-field),the value is
converted to an int ; otherwise,it is converted to an unsigned
int
. These are called the integer promotions. All other
types are unchanged by the integer promotions.

第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节中规定的通常算术转换:

the integer promotions are performed on both operands. Then the
following rules are applied to the promoted operands:

  • If both operands have the same type,then no further conversion is needed.
  • Otherwise,if both operands have signed integer types or both have unsigned integer types,the operand with the type of lesser
    integer conversion rank is converted to the type of the operand
    with greater rank.
  • Otherwise,if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the
    other operand,then the operand with signed integer type is
    converted to the type of the operand with unsigned integer
    type.

另请注意,我们将每个部分分别除以总和.如果我们在分割之前首先添加两个部分,则分子可能超过65535.通过首先进行除法,这会使每个子表达式回到uint8_t的范围内.然后我们可以添加两个部分,它们将再次位于uint8_t的范围内.

因此,上述表达式保证在符合C标准的编译器上返回正确的精确答案.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读