Скрипт C++ иногда запускается, а иногда зависает

Я пытаюсь заниматься генетическим программированием на C++. Я собрал версию этого кода на Python, и она работала нормально (это было просто СЛИШКОМ МЕДЛЕННО). Основная предпосылка - рассматривать программы как древовидные выражения и развивать их.

Вот код для создания только одного дерева кандидатов (деревья хранятся как векторы узлов, которые указывают на своих дочерних узлов по индексу дочернего узла в том же векторе) (см. Функцию grow_tree):

Этот код компилируется нормально :) Я компилирую с помощью g ++, чтобы получить файл a.out, который я запускаю с помощью ./a.out

Моя проблема в том, что иногда он работает и завершается нормально, а иногда просто зависает и ничего не делает (тоже не выдает ошибок)

Любая помощь по этому вопросу будет принята с благодарностью! Спасибо!

#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <math.h>

const int MAX_TREE_DEPTH = 5;

int randint(int min, int max) {
    return (rand() % ((max - min) + 1)) + min;
}

struct node {
    int type, op, req_ch;
    std::vector<int> ch;
    std::map<std::string, float> params;
    node(int p, int rem_depth) {
        if ((p == -1) || (p == 0)) {
            req_ch = 2;
            if (rem_depth >= 2) { 
                type = randint(0, 1); 
                if (type == 0) { 
                    op = randint(0, 1); 
                } else if (type == 1) { 
                    op = randint(2, 5); 
                }
            } else { 
                type = 1; 
                op = randint(2, 5); 
            }
        } else if (p == 1) { 
            type = 2;  
            if (rem_depth >= 1) { 
                op =  randint(6, 11); 
            } else { op = 11; }
            if ((op >= 6) && (op <= 10)) { 
                req_ch = 2; 
            } else if (op >= 11) { req_ch = 0; }
        }
    }    
};

void grow_tree(std::vector<node>* func, int p, int rem_depth) {
    node n(p, rem_depth);
    func->push_back(n);
    int i = func->size() - 1;
    for (int j = 0; j < n.req_ch; j++) {
        func->at(i).ch.push_back(func->size());
        grow_tree(func, n.type, rem_depth - 1);
    }
}


struct rule {
    float score;
    bool scored;
    std::vector<node> func;
    rule(int m) {
        if (m == 0) { // Random initialisation
            int depth = randint(2, MAX_TREE_DEPTH);
            grow_tree(&func, -1, depth);
        }
    }
};


int main(void) {
    srand(time(NULL));  // Seed the random number generator
    int depth = randint(2, MAX_TREE_DEPTH);
    std::vector<node> f;
    grow_tree(&f, -1, depth);
    return 0;
}
Моя проблема в том, что иногда он запускается и завершается нормально, а иногда просто зависает и ничего не делает - что более чем вероятно означает, что в вашей программе есть одна или несколько ошибок. Совет - отлаживайте свою программу с помощью данных известен, которые создают проблему, а не случайных данных. Используя рандомизированные данные, вы не сможете легко сосредоточиться на проблеме. Зарегистрируйте значения, которые вы используете, когда используете случайные данные, вызывающие проблему, а затем перепишите свою программу, чтобы жестко запрограммировать эти значения, чтобы получить устойчивый случай сбоя.
PaulMcKenzie 04.07.2018 19:11

Бывают случаи, когда вы не присваиваете значения всем членам node.

molbdnilo 04.07.2018 19:19

И чтобы добавить к комментарию @molbdnilo, вы можете проверить это, распечатав значения op, p и т. д. Перед возвратом из конструктора node, чтобы точно подтвердить, какие значения используются. Если одно из этих значений является «диким», это один из способов подтвердить, что вы используете неинициализированное значение. Или вы можете инициализировать все на -1 и посмотреть, осталось ли какое-либо из этих значений -1, снова подтверждая, что вы не установили все значения в конструкторе. Все дело в отладке и обучении отладке кода.

PaulMcKenzie 04.07.2018 19:27

Из любопытства, какова была производительность кода Python по сравнению с кодом C++? По моему опыту, Python обычно запускается вдвое дольше. Но могут быть смягчающие факторы, которые могут сделать его равным с C++, или C++ может быть значительно быстрее (на порядок, возможно, даже на два порядка). И это при «прочих равных» (например, тот же алгоритм; соответствующие структуры данных).

Eljay 04.07.2018 19:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
102
1

Ответы 1

Как указывает @molbdnilo, ваш конструктор node восприимчив к наличию переменных, которые не инициализируются после возврата конструктора. Затем вы используете переменные экземпляра node здесь, в grow_tree:

for (int j = 0; j < n.req_ch; j++) {

Если n.req_ch - неинициализированное или «дикое» значение, цикл может продолжаться очень долго. Представьте, если бы n.req_ch вернулся со значением, близким к (при условии, что 32-битные целые числа), 2^32 - 1. Ваш цикл будет продолжаться более 2 000 000 000 итераций.

Чтобы подтвердить это, если вы инициализировали свой член переменных node значением, вы можете легко вывести эти переменные, чтобы увидеть, было ли изменено начальное значение. Если значение не было изменено, это подтверждает, что вы используете неинициализированные значения в своей функции grow_tree.

Пример:

node(int p, int rem_depth) :type(-100), op(-100), req_ch(-100) // Initialize everything to -100
{
   // your code
 ...
   // now check if all the variables have been initialized (values were changed from -100)
   if ( type == -100 || op == -100 || req_ch == -100 )
   {
       std::cout << "Oops.  I'm using uninitialized values for p = " << p << 
      " rem_depth = " << rem_depth << "\n";
       std::cout << type << " " << op << " " << req_ch << "\n\n";
    }   
}

Вот ваш код, измененный с помощью чека.

Как видите, ваш конструктор node не устанавливает все значения, и вы будете использовать эти значения позже в grow_tree.

Итак, ответ на вашу проблему - вернуться и закрыть дыру в конструкторе node, чтобы ваши переменные были инициализированы.

Другие вопросы по теме