Форум программистов, компьютерный форум, киберфорум
Catstail
Войти
Регистрация
Восстановить пароль

Некоторые соображения о массовом сознании

Запись от Catstail размещена 30.06.2024 в 18:59
Показов 5530 Комментарии 52
Метки нейросеть

Нейросеть - это грубая модель человеческого мозга... Читатели несомненно встречали эту фразу многократно. Наблюдая современных студентов (и, к сожалению, не только студентов) я вынужден констатировать обратное: это мозг - модель нейросети, а не наоборот. Нейросеть прекрасно "запоминает", но практически не способна к критическому анализу. Так и мозг некоторых "будущих программистов". Вот пара развёрнутых примеров.

Факториал

Как хорошо известно всем n! - это произведение всех целых чисел от 1 до n. Это очень важная целочисленная функция, которая находит широчайшее применение в самых разных разделах математики.

Как вычислять факториал? Исходя из данного выше определения, у разумного человека должен "родиться" следующий код:

C
1
2
3
4
5
6
int fact(int n)
{
    int r=1;
    for (int i=2; i<=n; i++) r*=i;
    return r;
}
Да, этот код будет работать только до значений n, не превышающих 10, но сейчас речь не об этом. Если не нужна абсолютная точность (и достаточно 16 значащих цифр), то можно перейти к типу double. Всё это понятно. Но почему же очень многие студенты вычисляют факториал, используя рекурсию:

C
1
2
3
4
5
6
7
int fact(int n)
{
     if (n == 0)
        return 1;
     else
        return n*fact(n-1);
}
Вполне очевидно, что рекурсивный код менее эффективен. Так почему многие и многие (и ChatGPT ?) используют этот код?
Я не вижу другого объяснения кроме самого очевидного: когда студентам "объясняют рекурсию", то в качестве одного из примеров (если не самого первого!) приводят расположенный выше код. И что же? Нейросеть обучается - в ней прочно "прожигается" пара "факториал - рекурсия". Всё. Акт обучения завершён. Теперь обучаемый будет программировать по принципу "мы говорим Ленин, подразумеваем партия" "мы говорим факториал, подразумеваем рекурсия"...

Читатели могут "пошерстить" разделы Форума (посвященные разным языкам) и убедиться, что "обучение работает".

Чтобы не заканчивать раздел негативом, приведу рациональный совет. Если вам, читатель, нужно интенсивно использовать факториал (скажем, для аргументов от нуля до 20), то самое разумное решение будет таким:

C
1
2
3
4
5
6
7
8
   double fact[21];
   
   /*...*/
 
   fact[0]=1;
   for (int i=1; i<=20; i++) fact[i]=i*fact[i-1];
 
   /*...*/
Теперь в любой формуле, содержащей факториал, пишите не fact(k), а fact[k]. Будет значительно быстрее, поверьте! (Замечание для пуристов: да, этот код использует значение факториала с плавающей точкой, т.е. с погрешностью. Если нужно представление без погрешности, то вместо double придётся использовать соответствующий тип.)

i++ vs ++i

Не так давно я стал замечать, что появились нонкорформисты, которые стали оператор цикла записывать так:

C
1
for (int i=1; i<20; ++i)
Я спросил одного, а почему не "i++"? Он ответил, что "так будет работать быстрее". Ответ меня изумил. Но "чем чёрт не шутит"... Я решил изучить вопрос. Ответ оказался не столь однозначным, как в случае факториала.

Действительно, накладные расходы на префиксную форму в вот таком операторе:

C
1
  x=y+t*(++w)+r;
будут меньше, чем в таком:

C
1
  x=y+t*(w++)+r;
Почему? Потому, что в первом случае можно смело увеличить w, а затем вычислять выражение. А во втором случае будет посложнее...

В языках с "сишным" синтаксисом не зря придуманы префиксная и постфиксная формы автоувеличения. Иногда (по смыслу) нужна префиксная, иногда постфиксная. А для того, чтобы выбрать, нужен акт размышления. Но нейросеть неокрепшие мозги на это не способны. Гораздо проще запомнить "рекомендацию", что префиксное автоувеличение работает быстрее постфиксного (и должно применяться вместо постфиксного).

Давайте рассмотрим следующий сишный код:

C
1
2
3
4
5
  int i;
  
  for (i=0; i<10; i++) printf("%d\n",i);
  
  for (i=10; i<20; ++i) printf("%d\n",i);
После трансляции (dev c++ 32бит) это породит следующий
ассемблерный код:

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
LM3:
    mov DWORD PTR [ebp-4], 0     # i,
L2:
    cmp DWORD PTR [ebp-4], 9     # i,
    jg  L3   #,
    mov eax, DWORD PTR [ebp-4]   # i, i
    mov DWORD PTR [esp+4], eax   #, i
    mov DWORD PTR [esp], OFFSET FLAT:LC0     #,
    call    _printf  #
    lea eax, [ebp-4]     # tmp75,
    inc DWORD PTR [eax]  # i  i++ !!!
    jmp L2   #
L3:
.stabn 68,0,10,LM4-_main
LM4:
    mov DWORD PTR [ebp-4], 10    # i,
L5:
    cmp DWORD PTR [ebp-4], 19    # i,
    jg  L6   #,
    mov eax, DWORD PTR [ebp-4]   # i, i
    mov DWORD PTR [esp+4], eax   #, i
    mov DWORD PTR [esp], OFFSET FLAT:LC0     #,
    call    _printf  #
    lea eax, [ebp-4]     # tmp77,
    inc DWORD PTR [eax]  # i      ++i !!!
    jmp L5   #
L6:
Как можно убедиться, в данном случае умный компилятор не делает разницы между префиксной и постфиксной формами. Так что здесь i++ и ++i не различаются. А к чему же я тогда цепляюсь? К бездумному следованию "советам".


Эти два примера наглядно показывают нейросетевой характер человеческого мышления...
Метки нейросеть
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 52
Комментарии
  1. Старый комментарий
    Аватар для Fedor92
    Если чат gpt попросить привести в пример оптимальный код вычисления факториала он выдаст следующее:
    C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    #include <stdio.h>
     
    unsigned long long factorial(int n) {
        if (n < 0) {
            return 0; // Факториал отрицательного числа не определён
        }
        if (n == 0) {
            return 1; // Факториал 0 равен 1
        }
        unsigned long long result = 1;
        while (n > 1) {
            result *= n;
            n--;
        }
        return result;
    }
     
    int main() {
        int number;
        printf("Введите число: ");
        scanf("%d", &number);
        unsigned long long result = factorial(number);
        if(result == 0 && number < 0) {
            printf("Факториал отрицательного числа не существует.\n");
        } else {
            printf("Факториал числа %d равен %llu\n", number, result);
        }
        return 0;
    }
    Подход итеративный без рекурсии.

    Но мысль уловил. У меня есть другой пример. В прошлом году помогал племяннице с физикой. В моё время g было принято считать равным 9,8 м/с². В современных учебниках 10. Хотя его значение варьируется от 9,78 м/с² на экваторе до 9,82 м/с² на полюсах. В головы молодых людей гадят со школы. Поэтому неудивительно, что факториал они вычисляют рекурсией, как научили - так и умеют.
    Запись от Fedor92 размещена 30.06.2024 в 21:45 Fedor92 вне форума
  2. Старый комментарий
    Аватар для Fulcrum_013
    Ну с постфиксной/префиксной икрементой там все не так однозначно. Особенно с учетом что советы эти для С++, где абсолютно все, включая итераторы имеет эти операторы перегруженным. Т.е. вот это гораздо сложнее действительно выливается в сохранение на стеке оператора копии и потом возврата оной копии. Поэтому может быть и быстрее. Может естественно не обязательно будет везде, но где то будет. Соответсвенно там где по контексту не важно какая именно форма используется, лучше все таки использовать префиксную, чтобы не копать под капотом каждой либы что именно они понаперегружали и как. Эт как в русском языке раньше мягкий знак был по дефолту, а потом заменили твердым по дефолту.

    P.S. С итераторами контейнеров STL префиксная форма будет действительно быстрее, потому что каждая копия итератора регистрирует/убирает себя в списке итераторов контейнера в конструторе/деструкторе, в том числе при копи/муве. а соответсвенно у постфиксного будет оверхед именно по этой операции для копии и не факт что оптимизатор сможет это убрать даже если возвращенное значение игнорируется. Побочныые эффекты то присутсвуют, а значит убирать копию, как в случае с интом, он не имеет права.
    Запись от Fulcrum_013 размещена 30.06.2024 в 22:59 Fulcrum_013 вне форума
  3. Старый комментарий
    Аватар для Fulcrum_013
    Цитата Сообщение от Fedor92
    В моё время g было принято считать равным 9,8 м/с². В современных учебниках 10. Хотя его значение варьируется от 9,78 м/с² на экваторе до 9,82 м/с² на полюсах. В головы молодых людей гадят со школы.
    Ну в одном из американских Штатов как то поставили в парламенте вопрос о том чтобы на территории Штата принять число Пи равное 3. И все к этому и шло. Но влез какой то прохфессор богомерзской математики,
    который прям на заседании очень недемократично, при помощи всяких синусов-косинусов и прочей чернокнижнической ереси, запугал всех депутатов что в таком сучае на всей территории Штата технический 3,1415здец поднимется в полный рост немедленно. Ну они недемократично законопроект и провалили. Россия в этом плане страна победившей демократии.
    Запись от Fulcrum_013 размещена 01.07.2024 в 11:26 Fulcrum_013 вне форума
  4. Старый комментарий
    Аватар для XLAT
    в соседних темах нейросеть притворившись гуманоидом проводит собеседования)))
    Запись от XLAT размещена 01.07.2024 в 11:58 XLAT на форуме
  5. Старый комментарий
    Аватар для sporta1982
    Цитата Сообщение от XLAT
    в соседних темах нейросеть притворившись гуманоидом проводит собеседования)))
    Запись от sporta1982 размещена 01.07.2024 в 12:08 sporta1982 вне форума
  6. Старый комментарий
    Аватар для Fedor92
    Цитата Сообщение от Fulcrum_013
    Ну в одном из американских Штатов как то поставили в парламенте вопрос о том чтобы на территории Штата принять число Пи равное 3. И все к этому и шло. Но влез какой то прохфессор богомерзской математики,
    который прям на заседании очень недемократично, при помощи всяких синусов-косинусов и прочей чернокнижнической ереси, запугал всех депутатов что в таком сучае на всей территории Штата технический 3,1415здец поднимется в полный рост немедленно. Ну они недемократично законопроект и провалили. Россия в этом плане страна победившей демократии.
    Скорее страна победившего западного дебилизма. Ибо Россия заимствует всегда всякое г., вместо чего-то хорошего.


    Цитата Сообщение от XLAT
    в соседних темах нейросеть притворившись гуманоидом проводит собеседования)))
    Судя по всему первая и последняя версия этой нейросети появилась лет 50-60 назад на перфокартах
    Запись от Fedor92 размещена 01.07.2024 в 15:44 Fedor92 вне форума
  7. Старый комментарий
    Аватар для sporta1982
    Действительно, накладные расходы на префиксную форму в вот таком операторе:
    x=y+t*(++w)+r;
    будут меньше, чем в таком:
    x=y+t*(w++)+r;
    Ну например так:
    C
    1
    2
    3
    4
    5
    6
    
    int y = 1;
    int t = 2;
    int w = 3;
    int r = 4;
    int x = y + t * (++w) + r;
    int x2 = y + t * (w++) + r;
    Assembler
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    mov dword ptr ss:[rbp+4],1                 // y
    mov dword ptr ss:[rbp+24],2               // t
    mov dword ptr ss:[rbp+44],3               // w
    mov dword ptr ss:[rbp+64],4               // r
     
    сначала вычислим x
     
    mov eax,dword ptr ss:[rbp+44]            // eax = w
    inc eax                                                // inc eax , (inc w)
    mov dword ptr ss:[rbp+44],eax            // inc w
    mov eax,dword ptr ss:[rbp+24]            // t
    imul eax,dword ptr ss:[rbp+44]            // w*t
    mov ecx,dword ptr ss:[rbp+4]              //  y
    add ecx,eax                                        // y+t*(++w)
    mov eax,ecx                                
    add eax,dword ptr ss:[rbp+64]             // y+t*(++w)+r
    mov dword ptr ss:[rbp+84],eax            // x=y+t*(++w)+r
     
    теперь вычислим x2
     
    mov eax,dword ptr ss:[rbp+24]            // t
    imul eax,dword ptr ss:[rbp+44]            // w
    mov ecx,dword ptr ss:[rbp+4]              // y
    add ecx,eax                                        // y+t*w
    mov eax,ecx                                
    add eax,dword ptr ss:[rbp+64]             // y+t*w+r
    mov dword ptr ss:[rbp+A4],eax            // x2=y+t*(w++)+r
    mov eax,dword ptr ss:[rbp+44]            // eax = w
    inc eax                                               //  w++
    mov dword ptr ss:[rbp+44],eax           //  w++
    Как видно здесь одинаковое количество строчек.
    Запись от sporta1982 размещена 01.07.2024 в 16:02 sporta1982 вне форума
  8. Старый комментарий
    Аватар для Catstail
    Цитата Сообщение от sporta1982
    Ну например так:
    Как видно здесь одинаковое количество строчек.
    Я привел достаточно произвольный пример.
    Запись от Catstail размещена 01.07.2024 в 16:48 Catstail вне форума
  9. Старый комментарий
    Аватар для sporta1982
    Цитата Сообщение от Catstail
    Почему? Потому, что в первом случае можно смело увеличить w, а затем вычислять выражение. А во втором случае будет посложнее...
    А во втором случае смело вычислять выражение, а потом увеличить w

    Ладно, не ругайтесь, я вредный просто.
    Запись от sporta1982 размещена 01.07.2024 в 17:28 sporta1982 вне форума
  10. Старый комментарий
    Аватар для Catstail
    Цитата Сообщение от sporta1982
    А во втором случае смело вычислять выражение, а потом увеличить w

    Ладно, не ругайтесь, я вредный просто.
    Всё норм! Ваша правда.
    Запись от Catstail размещена 02.07.2024 в 06:11 Catstail вне форума
  11. Старый комментарий
    Аватар для Fulcrum_013
    Цитата Сообщение от sporta1982
    Ну например так:
    Как видно здесь одинаковое количество строчек.
    А теперь попробуйте так:
    C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    #include<iostream> 
    #include<vector> 
    void main(){
       std::vector<int> a = {0, 1,2,3,4,5,6,7,8,9};
       auto it = a.begin();
       std::cout << *(++ it); 
       std::cout << *( it++);
     
    }
    Запись от Fulcrum_013 размещена 02.07.2024 в 06:29 Fulcrum_013 вне форума
  12. Старый комментарий
    Аватар для sporta1982
    Цитата Сообщение от Fulcrum_013
    А теперь попробуйте так:
    C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    #include<iostream> 
    #include<vector> 
    void main(){
       std::vector<int> a = {0, 1,2,3,4,5,6,7,8,9};
       auto it = a.begin();
       std::cout << *(++ it); 
       std::cout << *( it++);
     
    }
    ну да здесь сложнее все.
    Но все равно там и там три вызова, отличие только в первом call.
    и кстати получение единички одной и той же функцией делается .
    Запись от sporta1982 размещена 02.07.2024 в 09:09 sporta1982 вне форума
  13. Старый комментарий
    Цитата Сообщение от Catstail
    Я спросил одного, а почему не "i++"? Он ответил, что "так будет работать быстрее".
    Участвовал/читал в нескольких обсуждение данной темы (правда может лет 10 уж прошло) - вообще не помню, чтоб кто то приводил это в качестве аргумента

    В подавляющем большинстве случаев использую именно префиксный вариант, мне он кажется в принципе более логичным. И лишь когда это явно необходимо постфиксный. Правда я к тому же избегаю писать их внутри других выражений. И такой сложился именно на основании тех чтений/обсуждений.

    Цитата Сообщение от Catstail
    После трансляции (dev c++ 32бит) это породит следующий ассемблерный код:
    Это компилировалось с оптимизацией? Не пробовали без оптимизации?

    Как "идея" может это мнение про относительно заметную разницу в производительности сложилось давно и просто передавалось "из поколение в поколение"... Где то в средине 90ых переносил один научный расчет с паскаля на асм и это дало очень сильный прирост производительности. (типа стало часов 5 против 3 дней до переноса). Потом уже в начале нулевых повторил эксперимент (правда на более простых формулах, но все же) и профита такого не вышло - т.е. компиляторы становятся умнее.
    Запись от voral размещена 02.07.2024 в 11:06 voral вне форума
  14. Старый комментарий
    Аватар для Fulcrum_013
    Цитата Сообщение от sporta1982
    ну да здесь сложнее все.
    Но все равно там и там три вызова, отличие только в первом call.
    и кстати получение единички одной и той же функцией делается .
    А теперь посмотрите что внутри этих различающихся call. для it++ там будет море побочных эффектов вполне возможно с эквайром семафора и/или атомик эксчэндж.
    Запись от Fulcrum_013 размещена 03.07.2024 в 18:05 Fulcrum_013 вне форума
  15. Старый комментарий
    Аватар для Royal_X
    Я всегда пишу ++i и не надеюсь на авось "умного" компилятора. Постфиксный инкремент (декремент) в сишных языках нужно использовать тогда и только тогда, когда он нужен. В остальных случаях нужно юзать префиксный. Но во многих языках действительно нет разницы в производительности.
    Запись от Royal_X размещена 03.07.2024 в 19:13 Royal_X вне форума
  16. Старый комментарий
    Аватар для CoderHuligan
    Я всегда пишу ++i и не надеюсь на авось "умного" компилятора. Постфиксный инкремент (декремент) в сишных языках нужно использовать тогда и только тогда, когда он нужен.
    Его вообще не нужно использовать. Ну, только для инкремента/декремента указателей. Пожалейте тех кто будет разбирать ваш г..нокод.
    Запись от CoderHuligan размещена 04.07.2024 в 05:53 CoderHuligan вне форума
  17. Старый комментарий
    Цитата Сообщение от CoderHuligan
    Его вообще не нужно использовать. Ну, только для инкремента/декремента указателей. Пожалейте тех кто будет разбирать ваш г..нокод.
    В чем проблемы вы видите в этой записи?

    Как раз таки тому, кто не понимает разницы скорее больше "радости" доставит постфиксный вариант. Т.к., по опыту, новички сначала думать что i++ это замена i = i +1. И начинают так писать в формулах типа 10 * (i+1) заменяя на 10 * i++ получая необъяснимое и невероятное.
    Запись от voral размещена 04.07.2024 в 08:03 voral вне форума
  18. Старый комментарий
    Т.е. логика, на мой взгляд такая:

    В большинстве случаев осуждается стиль когда когда несколько инструкций пишутся в одну строку. типа
    C++
    1
    
    scanf("%s", name); printf("Your name is %s.", name);
    это плохо (и я так тоже считаю) и это признак Г кода. По сути следующий код из той же серии
    C++
    1
    
    b = 10 * i;  i = i + 1;
    Нижеследующий вариант еще хуже с точки зрения читабельности. Т.к. он делает "неявной" инструкцию. По крайней мере для новичков.
    C++
    1
    
    b = 10 * i++;
    Таким образом, как раз таки именно постфиксная запись , с точки зрения стиля кода, имеет очень узкую "полосу применения".

    С точки зрения производительности.... Ну тут, подозреваю, это касается узкого круга задач, в которых профит и в такт процессора это круто. (и опять же как я понмиаю, перевес в сторону префиксного)
    Запись от voral размещена 04.07.2024 в 08:28 voral вне форума
  19. Старый комментарий
    Аватар для CoderHuligan
    В чем проблемы вы видите в этой записи?

    Как раз таки тому, кто не понимает разницы
    Проблемы в понимании. Любое понимание требует времени. времени всегда мало. Почему я должен гадать на кофейной гуще: 10+++i+9???
    Я вовсе не должен этого делать. если в коде нечто подобное встретится в топку такой код. То естья, читая, код на этой строчке стопорюсь и стопорюсь надолго, теряя драгоценное время. Я ценю свое время. То что в Си ввели эти вещи было ошибкой. Это сделало код более лаконичным но не более понятным. А понятность кода это критерий правильной архитектуры языка.
    Запись от CoderHuligan размещена 04.07.2024 в 09:36 CoderHuligan вне форума
  20. Старый комментарий
    Цитата Сообщение от CoderHuligan
    Проблемы в понимании. Любое понимание требует времени. времени всегда мало. Почему я должен гадать на кофейной гуще: 10+++i+9???
    А при чем тут выбор "постфикс" vs "префикс"?
    Вам запись 10+i+++9 сразу становится понятнее что ли?
    Запись от voral размещена 04.07.2024 в 09:41 voral вне форума
 
Новые блоги и статьи
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru