具有不同宽度变量和铸造的数学
Math with different width variables and casting
考虑以下代码片段:
// The assigned numbers are random and not relevant
uint16_t val = 2;
uint32_t sum = 4;
sum += val; // point 1
sum /= val; // point 2
- 在这个操作中,val是否自动转换为
uint32_t
?如果不是,什么更快 - 铸造它或离开 uint16_t
?
- 在这个操作中,val是否自动转换为
uint32_t
?如果不是,什么更快 - 铸造它或离开 uint16_t
?
假设架构是 16 位。
在这两种情况下,val
的值都会自动转换为较大的类型 uint32_t
。精确的行为取决于 int
.
的实际大小
如果类型int
有15个值位,则val
转换为uint32_t
,保留值,加法和除法使用uint32_t
算术,对 232 进行模运算,结果存储在 sum
.
中
如果类型 int
具有 16 到 31 个值位,val
首先提升为 int
,保留其值,然后转换提升的值到 uint32_t
,再次保留该值,因为它是正数,并且操作如上所述完成。
如果类型 int
有超过 31 个值位,sum
和 val
都会提升为 int
,保留值,加法和除法使用int
有符号运算,结果被转换为uint32_t
,模232,存储到sum
.
对于上面的示例值,结果在所有情况下都是相同的,但对于下面的示例,在 int
将具有 32 个值位的假设体系结构上行为未定义:
uint16_t val = 2;
uint32_t sum = 0xffffffff;
sum += val; // signed arithmetic overflow if type `int` has 33 bits
这些隐式提升和转换不是 cast 操作,您可以添加诸如 sum += (uint32_t)val;
之类的显式强制转换,但行为将完全相同并且不会产生任何影响关于性能。
如果编译器可以在编译时确定 val
的值,它可能会将表达式 sum /= val;
编译为右移或乘法以避免昂贵的除法。将无符号值除以 2 的幂是一种廉价的右移操作,如果该值有符号且可能为负,则必须调整移位。对于其他 non-zero 股息,使用乘以 2k/val 到更大的类型。
考虑以下代码片段:
// The assigned numbers are random and not relevant
uint16_t val = 2;
uint32_t sum = 4;
sum += val; // point 1
sum /= val; // point 2
- 在这个操作中,val是否自动转换为
uint32_t
?如果不是,什么更快 - 铸造它或离开uint16_t
? - 在这个操作中,val是否自动转换为
uint32_t
?如果不是,什么更快 - 铸造它或离开uint16_t
?
假设架构是 16 位。
在这两种情况下,val
的值都会自动转换为较大的类型 uint32_t
。精确的行为取决于 int
.
如果类型
中int
有15个值位,则val
转换为uint32_t
,保留值,加法和除法使用uint32_t
算术,对 232 进行模运算,结果存储在sum
.如果类型
int
具有 16 到 31 个值位,val
首先提升为int
,保留其值,然后转换提升的值到uint32_t
,再次保留该值,因为它是正数,并且操作如上所述完成。如果类型
int
有超过 31 个值位,sum
和val
都会提升为int
,保留值,加法和除法使用int
有符号运算,结果被转换为uint32_t
,模232,存储到sum
.
对于上面的示例值,结果在所有情况下都是相同的,但对于下面的示例,在 int
将具有 32 个值位的假设体系结构上行为未定义:
uint16_t val = 2;
uint32_t sum = 0xffffffff;
sum += val; // signed arithmetic overflow if type `int` has 33 bits
这些隐式提升和转换不是 cast 操作,您可以添加诸如 sum += (uint32_t)val;
之类的显式强制转换,但行为将完全相同并且不会产生任何影响关于性能。
如果编译器可以在编译时确定 val
的值,它可能会将表达式 sum /= val;
编译为右移或乘法以避免昂贵的除法。将无符号值除以 2 的幂是一种廉价的右移操作,如果该值有符号且可能为负,则必须调整移位。对于其他 non-zero 股息,使用乘以 2k/val 到更大的类型。