定数を使用してint
いるため、コンパイラはオーバーフローを「使用」してコードをショートカットできます。以下のように U で修正すると「動作」します。
inline bool divisible15(unsigned int x)
{
//286331153 = (2^32 - 1) / 15
//4008636143 = (2^32) - 286331153
return x * 4008636143u <= 286331153u;
}
テスト:
#include <iostream>
inline bool divisible15a(unsigned int x)
{
//286331153 = (2^32 - 1) / 15
//4008636143 = (2^32) - 286331153
// return x * 4008636143 <= 286331153;
return x * 4008636143u <= 286331153;
}
inline bool divisible15b(unsigned int x)
{
//286331153 = (2^32 - 1) / 15
//4008636143 = (2^32) - 286331153
// return x * 4008636143 <= 286331153;
return x * 4008636143 <= 286331153;
}
int main()
{
for(unsigned int i = 0; i < 100; i++)
{
if (divisible15a(i))
{
std::cout << "a:" << i << std::endl;
}
if (divisible15b(i))
{
std::cout << "b:" << i << std::endl;
}
}
}
出力:
a:0
b:0
a:15
a:30
a:45
a:60
a:75
a:90
コード:
_Z12divisible15aj:
.LFB1192:
pushq %rbp
movq %rsp, %rbp
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
imull $-286331153, %eax, %eax
cmpl $286331153, %eax
setbe %al
popq %rbp
ret
_Z12divisible15bj:
.LFB1193:
pushq %rbp
movq %rsp, %rbp
movl %edi, -4(%rbp)
movl -4(%rbp), %edx
movl $4008636143, %eax
imulq %rdx, %rax
cmpq $286331153, %rax
setle %al
popq %rbp
ret
したがって、はい、32 ビットの int に収まらないため、long
orに昇格するという Carl/Adam の分析に同意しlong long
ます。