我正在写的值可能会溢出的声明如下:
fact = ((fact * (llu) (i - 1)) / (llu) (i - M)) % MOD;
llu Ans = (llu) C[k - 1] * fact;
此处llu
表示unsigned long long
i
是有符号整数,在2 10 到2 20 的值之间变化
MOD
是10 9 + 9
变量fact
和Ans
属于unsigned long long
类型。
M
是有符号整数,最高可达2 10
C[k - 1]
是(k - 1)
数组int
的{{1}}索引术语,大约为10 9
所有值始终为正。
问题:
现在,关于我在上面的代码中完成的类型转换(从C
到int
);它是否足以处理溢出或我做更多/更少/不正确的类型转换?
此外,在我的代码的第一行中按unsigned long long
进行除法是否正确,或者最好将其写为:
(i - M)
答案 0 :(得分:1)
你没有定义 fact 的限制,因为它是第一个表达式的一部分。如果 fact 最初可以是2 ^ 60,那么你就有溢出。
当您乘以整数位值时,需要对位数求和。例如,如果您需要多个两个32位值,则需要/得到32 + 32 = 64位。
fact=((fact*(llu)(i-1))/(llu)(i-M))%MOD;
在我们的示例中,我们 i 最多20位,这意味着为了避免第一个表达式中的溢出事实必须至多为Bitsof(unsigned long long) -20。如果无符号长long为64位,则事实最多可为44位,例如2 ^ 44。
llu Ans=(llu)C[k-1]*fact;
在第二个表达式中我们有类似的情况,事实在评估第一个表达式之后必须至多为64-30位(10 ^ 9需要大约29位),这是由%MOD表达式。在第一次表达之后,事实将小于10 ^ 10,几乎是32位。
简短回答:如果事实最初小于2 ^ 44则不会溢出。
在这种情况下,我更喜欢使用显式整数,例如类型 u_int64_t ,我知道它是无符号的64位。