Моя программа не работает должным образом при компиляции с ICC - PullRequest
0 голосов
/ 28 мая 2018

У меня проблема с icc, и до сих пор я не нашел никакого решения.Моя программа работает нормально при компиляции с помощью gcc, но, очевидно, не выполняет никаких операций при компиляции с помощью icc.Ошибки во время выполнения не возникают.Программа просто очень быстро заканчивается (несколько миллисекунд), но, как ожидается, займет несколько секунд (около 11 секунд для n = 1 миллиард).Тем не менее, это работает нормально, если я печатаю сумму в конце.

Это небольшой код:

# include <stdlib.h>
# include <stdio.h>

double f(double x){
    double pi = 3.141592653589793;
    double value;
    value = 50.0 / (pi * (2500.0 * x * x + 1.0));
    return value;
}
int main (int argc, char *argv[]){
    double a = 0.0, b = 10.0, total = 0.0, x;
    unsigned long int i, n = 1000000000;

    for(i = 0; i < n; i++){
        x = ((n - i - 1) * a + (i) * b) / (n - 1);
        total = total + f(x);
    }
    total = (b - a) * total / (double) n;

    //printf("%f\n", total);
    return 0;
}

Я также проверил, что он фактически запускает цикл и вызывает функцию n раз.

Кто-нибудь знает, что может быть причиной этой проблемы?

Спасибо!

1 Ответ

0 голосов
/ 28 мая 2018

Однако все работает нормально, если я печатаю итоговую сумму в конце.

Это, вероятно, оптимизирующий компилятор эффект (допустимый, согласно стандарту C11 n1570 ).

Поскольку в вашей программе нет видимого побочного эффекта (без printf), компилятор разрешен (согласно какЕсли правило ), чтобы оптимизировать его в безоперационную программу.

С некоторыми версиями GCC или Clang и некоторыми флагами оптимизации вы могли наблюдать то же самое.Попробуйте скомпилировать свой код с помощью gcc -O3 -S -fverbose-asm и посмотреть на сгенерированный ассемблерный код (вы увидите пустое сгенерированное main с GCC 8.1 для Linux / x86-64)

Кто-нибудь знает, чтоможет быть причиной этой проблемы?

Ваш код и ваше неправильное понимание хитрой семантики из C. Реализация ведет себя в соответствии со стандартом C (и ваша программа работает правильно ).

Кстати, даже с printf теоретически компилятору разрешено оптимизировать вашу программу до простой константы printf.На практике текущие компиляторы (к сожалению) не настолько умны.

Если вам нужен надежный тест, n может зависеть от аргументов программы (и вам все равно нужно сохранить printf, потому что выхотите некоторый видимый побочный эффект) возможно:

 unsigned long n = (argc<2)?1000:(unsigned long)atol(argv[1]);

При измерении производительности не забудьте включить оптимизацию в своем компиляторе!

Кстати, через несколько лет (после того, как вы следили заКурсы CS, включая курс по компиляции и / или прочтению Dragon Book ), вы можете попытаться реализовать некоторый плагин GCC , который сможет оптимизировать вашу функцию с явным printf (но все равно n инициализируется константой времени компиляции) в main, просто вызывающий некоторый printf и выполняющий цикл, вычисляющий total в во время компиляции (такая оптимизациязаконно).Вы обнаружите, что такая оптимизация занимает много работы (конечно, месяцы, может, годы!) И может , а не применяться ко многим существующим программам, но вы могли бы получить удовольствие от ее реализации.

Если вас интересуют вычисления с плавающей запятой, обязательно прочитайте руководство с плавающей запятой (это сложно).

...