CPP:防止溢出的类型转换

CPP: Type casting to prevent overflows

本文关键字:类型转换 溢出 CPP      更新时间:2023-10-16

我写的值可能溢出的语句如下:

fact = ((fact * (llu) (i - 1)) / (llu) (i - M)) % MOD;
llu Ans = (llu) C[k - 1] * fact;

这里llu表示unsigned long long

i是一个有符号整数,取值范围从210到220

MOD = 109 + 9

变量factAns的类型为unsigned long long

M是一个有符号整数,最多可以是210

C[k - 1]int数组C(k - 1)索引项,其数量级为109

所有值总是正。

问题:现在,关于我在上面的代码中所做的类型转换(从intunsigned long long);它是否足以处理溢出,或者我是否做了更多/更少/不正确的类型转换?

此外,在我的代码的第一行执行(i - M)除法是正确的,还是应该最好写成:

fact = fact * (llu) (i - 1);
fact = (fact / (llu) (i - M)) % MOD;

您没有定义fact的限制,因为它是第一个表达式的一部分。例如,如果fact最初可以是2^60,那么就会出现溢出。

当你乘整数位值时,你需要把位数加起来。例如,如果你将两个32位的值相乘,你将需要/得到32+32 = 64位。

fact=((fact*(llu)(i-1))/(llu)(i-M))%MOD;
在我们的示例中,i最多为20位,这意味着为了避免第一个表达式中的溢出事实必须最多为Bitsof(unsigned long long)-20。如果unsigned long long是64位,那么事实上可以高达44位,例如2^44。
llu Ans=(llu)C[k-1]*fact;
在第二个表达式中,我们有类似的情况,事实必须最多64-30位(10^9大约需要29位),在计算第一个表达式后,这是由%MOD表达式验证的。Fact将小于第一个表达式后的10^10,这几乎是32位。

简短的回答:如果fact初始值小于2^44,则它不会溢出。

在这种情况下,我更喜欢使用显式的整数大小,例如类型u_int64_t,我知道它是无符号64位。