Вот короткая программа для подсчета количества делителей целого числа. Программа работает правильно. Проблема, однако, в том, что под -O3
Флаг оптимизации текущей магистрали компилятора Clang C ++ (версия 3.3, магистраль 180686), поведение программы изменяется, и результат больше не корректен.
Вот код:
#include <iostream>
constexpr unsigned long divisors(unsigned long n, unsigned long c)
{
// This is supposed to sum 1 anytime a divisor shows up
// in the recursion
return !c ? 0 : !(n % c) + divisors(n, c - 1);
}
int main()
{
// Here I print the number of divisors of 9 numbers! (from 1 to 9)
for (unsigned long i = 1; i < 10; ++i)
std::cout << i << " has " << divisors(i, i) << " divisors" << std::endl;
}
Вот используемая команда компиляции, и правильный и ожидаемый результат, который программа показывает при нормальных обстоятельствах:
clang++ -O2 -std=c++11 -stdlib=libc++ -lcxxrt -ldl sample.cpp -o sample
./sample
1 has 1 divisors
2 has 2 divisors
3 has 2 divisors
4 has 3 divisors
5 has 2 divisors
6 has 4 divisors
7 has 2 divisors
8 has 4 divisors
9 has 3 divisors
Это используемая командная строка, которая производит двоичный файл, который дает некорректный выход. Обратите внимание, что единственным изменением является флаг оптимизации (-O2
в -O3
.)
clang++ -O3 -std=c++11 -stdlib=libc++ -lcxxrt -ldl sample.cpp -o sample
./sample
1 has 1 divisors
2 has 2 divisors
3 has 2 divisors
4 has 1 divisors
5 has 2 divisors
6 has 3 divisors
7 has 2 divisors
8 has 2 divisors
9 has 2 divisors
Я обновился до кончика багажника, лязг версии 3.4 (багажник 183073). Поведение больше не воспроизводится, должно быть уже как-то исправлено. Любой, кто знает, что это была за проблема, если она была действительно проверена и исправлена, пожалуйста, не стесняйтесь дать ответ. Если ничего не подтверждено, может произойти регрессия.
Похоже, тебя укусила эта ошибка в llvm. Вы можете обойти это, отключив векторизатор цикла или (как вы уже нашли), обновив до сборки llvm с ревизией, более новой, чем r181286.
Если вы посмотрите различия, вы увидите, что тестовый пример был добавлен как часть исправления. Это должно предотвратить появление этой проблемы в будущем.
Других решений пока нет …