Две одинаковые проги. Одна на C, другая на C++. Компилируются GCC и G++ соответственно с опцией -O2. Спойлер: Код на C Код (C): #include <stdio.h> #include <time.h> typedef unsigned long long uint64_t; int inner_loop(uint64_t *n, uint64_t i) { int count = 0; while (*n % i == 0) { ++count; *n /= i; } return count; } int prime_count(uint64_t n) { int count = 0; for (uint64_t i = 2; i*i <= n; ++i) { count += inner_loop(&n, i); } if (n > 1) { ++count; } return count; } int main() { double elapsed = clock(); int n = prime_count(1000000000000000003); elapsed = (clock()-elapsed) / CLOCKS_PER_SEC; printf("Elapsed time: %.3f sec (result = %d)\n", elapsed, n); return 0; } Спойлер: Код на C++ Код (C++): #include <iostream> #include <ctime> using std::cout; int inner_loop(uint64_t &n, uint64_t i) { int count = 0; while (n % i == 0) { ++count; n /= i; } return count; } int prime_count(uint64_t n) { int count = 0; for (uint64_t i = 2; i*i <= n; ++i) { count += inner_loop(n, i); } if (n > 1) { ++count; } return count; } int main() { double elapsed = clock(); int n = prime_count(1000000000000000003); elapsed = (clock()-elapsed) / CLOCKS_PER_SEC; cout << "Elapsed time: " << elapsed << " sec (result = " << n << ")\n"; return 0; } Запускаем. C работает 7.4 сек, C++ – 8.5 сек (плюс-минус ≈0.1 сек), т.е. разница секунда (примерно 15%). Внушительно для такого простого кода, не так ли? Заглянем под капот. Спойлер: Листинг C Код (ASM): call clock mov r9d, 2 xor r10d, r10d movabs rcx, 1000000000000000003 cvtsi2sd xmm6, eax .p2align 4,,10 .L22: add r9, 1 add ebx, r10d mov rax, r9 imul rax, r9 cmp rax, rcx ja .L24 xor edx, edx mov rax, rcx xor r10d, r10d div r9 test rdx, rdx jne .L22 .p2align 4,,10 .L23: mov rax, rcx xor edx, edx add r10d, 1 div r9 xor edx, edx mov rcx, rax div r9 test rdx, rdx je .L23 jmp .L22 .p2align 4,,10 .L24: cmp rcx, 2 sbb ebx, -1 call clock Спойлер: Листинг C++ Код (ASM): call clock mov r8d, 2 xor r9d, r9d movabs rcx, 1000000000000000003 cvtsi2sd xmm7, eax .p2align 4,,10 .L20: add r8, 1 add ebx, r9d mov rax, r8 imul rax, r8 cmp rax, rcx ja .L28 xor edx, edx mov rax, rcx xor r9d, r9d div r8 test rdx, rdx jne .L20 .p2align 4,,10 .L22: mov rax, rcx xor edx, edx add r9d, 1 div r8 xor edx, edx mov rcx, rax div r8 test rdx, rdx je .L22 jmp .L20 .p2align 4,,10 .L28: cmp rcx, 2 pxor xmm6, xmm6 sbb ebx, -1 call clock Один в один, только регистры разные (ну и pxor xmm6,xmm6 в плюсах, но проблема явно не в этом). Откроем через HIEW, чтобы посмотреть адреса. C: C++: В плюсах даже код основного цикла выравнен (всё это время цикл крутится между add r8/r9,1 и test rdx,rdx+jnz)! Но он работает ДОЛЬШЕ НА СЕКУНДУ !!! В чём прикол? Кто мне скажет? p.s. В архиве все файлы, включая EXE.
Кстати, на заметку. Для простых чисел можете сразу i увеличивать на 2, т.к. не существует чётных простых чисел кроме числа 2: Код (Text): for (uint64_t i = 2; i*i <= n; ++i)
А вот тут наоборот C отстаёт буквально на пару десятых долей секунды. Спойлер: C Код (C): #include <stdio.h> #include <time.h> typedef unsigned long long uint64_t; int prime_count(uint64_t n) { int count = 0; for (uint64_t i = 2; i*i <= n; ++i) { while (n % i == 0) { ++count; n /= i; } } if (n > 1) { ++count; } return count; } int main() { double elapsed = clock(); int n = prime_count(1000000000000000003); elapsed = (clock()-elapsed) / CLOCKS_PER_SEC; printf("Elapsed time: %.3f sec (result = %d)\n", elapsed, n); return 0; } Спойлер: C++ Код (C++): #include <iostream> #include <ctime> using std::cout; int prime_count(uint64_t n) { int count = 0; for (uint64_t i = 2; i*i <= n; ++i) { while (n % i == 0) { ++count; n /= i; } } if (n > 1) { ++count; } return count; } int main() { double elapsed = clock(); int n = prime_count(1000000000000000003); elapsed = (clock()-elapsed) / CLOCKS_PER_SEC; cout << "Elapsed time: " << elapsed << " sec (result = " << n << ")\n"; return 0; } Хотя по сути всё то же самое! p.s. Всё это, разумеется, запускалось многократно, так что это не погрешности. --- Сообщение объединено, 9 ноя 2018 --- Точно, спасибо! Банально, но ведь не задумывался об этом раньше
И сразу прикол! Поменял на Код (C++): count += inner_loop(n, 2); for (uint64_t i = 3; i*i <= n; i += 2) { count += inner_loop(n, i); } И плюсы стали обгонять. --- Сообщение объединено, 9 ноя 2018 --- Всё просто: gcc -s -O2 testC.c -o testC.exe g++ -s -O2 testCPP.cpp -o testCPP.exe и gсс -S -O2 -masm=intel testC.c -o testC.s g++ -S -O2 -masm=intel testCPP.cpp -o testCPP.s --- Сообщение объединено, 9 ноя 2018 --- Очепятка была, исправил... --- Сообщение объединено, 9 ноя 2018 --- Везде одинаково. Для test2 так же.
Разницы никакой, на уровне стат. погрешности: Компиляция: Код (Text): #!/bin/bash gcc -m64 -s -O2 testC.c -o testC.exe g++ -m64 -s -O2 testCPP.cpp -o testCPP.exe g++ -m64 -S -O2 testC.c -o testC.s gcc -m64 -S -O2 testCPP.cpp -o testCPP.s У вас никакого CPU frequency scaling, случаем, не включено? Попробуйте для начала его отключить и ещё раз тесты попробовать прогнать.
SadKo, ну как? В Электропитании → Управление питанием процессора → Минимальное состояние процессора стоит 5%. Но я код перезапускал многократно, всё время одинаковый результат. Не может же проц в одной программе всё время scale'иться, а в другой – нет. Ещё вы же в Linux'е собираете, а я в винде. Я думаю, это влияет, там как минимум адреса разные. Если есть винда, Wine (etc), попробуйте запустить мои EXE-шники.
Jin X, тоже разницa ~1 sec, если компилировать cl от ms то разница ~0,065, но прирост по времени ~10 sec у каждого из подопытных.
Ronin_, то есть дольше на 10 сек становится? Тут какой-то прикол с выравниванием, видимо. Если добавить в начало main'а строку: Код (C): volatile int x = 5; то код на C начинает выполняться на секунду дольше, как C++. --- Сообщение объединено, 9 ноя 2018 --- Только хочется найти объяснение этому...
Jin X, и вызовов на плюсах в майн 11 против Си где их всего 7. c Код (Text): call fcn.004017d0 call sub.msvcrt.dll_clock_950 ; clock_t clock(void) call fcn.004027d0 call fcn.004026d0 call fcn.004027d0 call sub.msvcrt.dll_clock_950 ; clock_t clock(void) call sub.msvcrt.dll_printf_910 ; int printf(const char *format) cpp: Код (Text): call fcn.00401820 call sub.msvcrt.dll_clock_794 ; clock_t clock(void) call sub.libgcc_s_dw2_1.dll___umoddi3_6f0 call sub.libgcc_s_dw2_1.dll___udivdi3_6f8 call sub.libgcc_s_dw2_1.dll___umoddi3_6f0 call sub.msvcrt.dll_clock_794 ; clock_t clock(void) call sub.libstdc___6.dll__ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ost call sub.libstdc___6.dll__ZNSo9_M_insertIdEERSoT_788 call sub.libstdc___6.dll__ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ost call sub.libstdc___6.dll__ZNSolsEi_780 call sub.libstdc___6.dll__ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc_7
Ronin_, а вы ставите оптимизацию на -O2 и компилите гнусавым (судя по msvcrt это не шланг)? У меня вообще без вызовов всё сплошной простынёй идёт, только call __main и call clock (2 шт) и таи, и там. Да даже если и есть, то фиг с ними! Основной же код между двумя вызовами clock'а – он же замеряется! А там всё одинаково...
Прикол в том, что я авер отключил и забыл включить, так что без него всё тестилось... Ronin_, интересно, почему результат разный? Ааа, может, под x86? Я под x64 делал...
Thetrik, не грузится картинка. А что за проц? Несколько раз запускал? --- Сообщение объединено, 9 ноя 2018 --- А если x64 ?