Ответы пользователя по тегу C++
  • Таблица истинности С++. Почему здесь разные результаты?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    ( x == z) || (!x || (y && z)) == 0 означает ( x == z) || ( (!x || (y && z)) == 0 ).
    Приоритет у сравнения выше, чем у ||, которое, по идее, есть лишь часть считаемого выражения. Поэтому у вас полечается не "выражение == 0" а "выражение1" или "выражение2 == 0".
    Возьмите все ваше выражение в скобки и все заработает.

    Во втором куске кода у вас 2 отдельных выражение сравнивается с 0 и скобочки у вас там расставлены правильно.
    Ответ написан
    1 комментарий
  • Как реализовать операторы в классе математического вектора?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Вектора можно складывать. Покомпонентно. Сложение векторов разного размера или вектора и числа бессмысленны.

    Вектора можно перемножать. Скалярное или вектороное произведения. Чаще скалярное ставят на operator*, а векторное на какое-нибудь operator^

    Операторы сравнения обычно делают лексикографически, покомпонентно. Сравнили первое число - у какого вектора больше - тот и больше. Если числа равны, сравниваем вторые компоненты. И т.д. Но это делают редко, потому что смысла вектора сортировать особо нет. Лексикографический порядок пользы особо не приносит.
    Ответ написан
    9 комментариев
  • Как сделать чтоб одна вункция роботала всегда а другая паралельно каждую секунду?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    {
      thread gameThread(game_loop, ref(star_pleced), ref(staircase_placed), ref(c), ref(t_placed), ref(r_placed), ref(p_placed), rows, cols, ref(map));
      thread monsterThread(monster_move, ref(map));
      gameThread.join();
      monsterThread.join();
      refresh();
    } while ((c = getch()) != '0');


    Этот код запускает потоки (они один раз исполняются) потом ждет их завершения. И это в цикле.
    Проблема в том, что на каждой итерации этого цикла вы будете ждать, пока monster thread спит.

    Потоки тут вообще бесполезны, вы с тем же успехом можете просто вызвать функции напрямую.

    Потоки должны быть запущены один раз и работать в фоне. Тот, который каждую секунду что-то делает, должен внутри содержать цикл и работать бесконечно, на каждой итерации засыпать на 1 секунду.
    Ответ написан
    Комментировать
  • Как исправить ошибку -nan(ind) в С++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Это значение - это результат какого-то запрещенного математического действия. Деление на 0, например. Но на него вы, вроде как, проверяете.

    Другая опасность в вашем коде: логарифм отрицательных чисел. Закомментируйте log в вашем выражении, если результат где-то отрицательный - функцию в этом значении x тупо не вычеслить - оно вне области определения.
    Ответ написан
  • Возможна ли гонка данных при отправке их на сокет?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    ssize_t numBytes = sendto

    Вот эта часть кода, что по вашему делает? Почему sendto возвращает количество байт, а не код ошибки?

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

    Это связано с тем, что сокеты работают на низком уровне и не гарантируют сохранение порядка отправленных данных. Когда два приложения отправляют данные одновременно, они могут перемешиваться в процессе передачи по сети и приходить в произвольном порядке.


    А это очередная галлюцинация ГПТ. Забудьте эти слова - они не имеют ничего общего с реальностью.

    Попробуйте строки ваши сделать побольше - в пару миллионов символов, вот тут-то вам мешанина и будет приходить.
    Ответ написан
    4 комментария
  • Входит в бесконечный цыкл,как исправить?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    После while (collision && try_counter <= 100); вставьте:
    if (try_counter > 100) break;

    Добавьте отладочный вывод в каждый цикл - посмотрите, а в каком же цикле оно висьнет-то.
    Вам еще понадобиться try_counter в цикл по монстрам (while (map[py][px] != ' ')).

    А вообще, очень странный цикл вот:
    do
            {
                center_y = ry + (r_size_y / 2);
                center_x = rx + (r_size_x / 2);
            } while (map[center_y][center_x] != ' ');


    Тут явно какая-то ошибка, потому что center_x и center_y на каждой итерации получатся одинаковые и цикл или сразу закончится, или повиснет.
    Ответ написан
  • Возможно ли избежать ошибку чтения в массиве если алгоритм задействует ячейку которой нет?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Для игры "жизнь" есть несколько вариантов:
    1) Увеличить поле на 2 клетки по каждому измерению, поле будет храниться с 1, а индексы 0 и n+1 - всегда будут пустыми. Потребление памяти это почти не увеличит, а код упростит.
    2) Если соседние клетки считаются циклами, то можно границы области 3x3 пересечь с полем:
    for (int nx = max(0, x-1); nx < min(x+2, n); ++nx) {
      for (int ny = max(0, y-1); ny < min(y+2, n); ++ny) {
        if (nx == x && ny == y) continue;
        // {nx, ny} - сосед в поле, обрабатываем его.
      }
    }

    Можно код чуть ускорить, предподсчитав границы.
    3) Более читаемый, но чуть более медленный метод - явно проверять, а не за границей ли соседняя клетка:
    for (int nx = x-1; nx <= x+1; ++nx) {
      for (int ny = y-1; ny <= y+1; ++ny) {
        if ((nx == x && ny == y) || nx < 0 || ny < 0 || nx >= n || ny >= n) continue;
        // {nx, ny} - соседняя клетка.
      }
    }


    Я бы просто раздул поле - так код сильно проще.

    Но вотрой метод так легко реализуется только тут, где нужно именно количетсво живых соседей и можно просто игнорировать клетки вне поля.
    Ответ написан
    Комментировать
  • Консоль игра, попадает в бесконечный цикл,что тут не так?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вы случайным образом генерируете координаты комнаты в цикле, пока вам не повезет выбрать полностью пустое место (while (collision == true);).

    Но, чем больше заполнено поле, тем меньше вероятность найти пустое место. Может вообще быть так, что комната заданного размера просто не помещается на поле, потому что вы неудачно запихали предыдущие комнаты по середине, перекрыв все пространство. В итоге, если вам невезет, программа или очень долго ищет пустое место, или виснет, потому что его вообще нет.

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

    Еще можно сделать немного по другому - вместо случайного выбора места и потом проверки на пересечение, найдите все места, куда комнату можно впихнуть и из их списка выбирайте случайное одним rand(). Тут уже не будет цикла, завершающегося только когда вам повезло. Но тут тоже может быть проблема, что мест для размещения новой комнаты вообще нет. Или перезапускайте с нуля расстановку комнат, или требуйте, чтобы они были маленькие. Еще можно их ставить в порядке от больших к маленьким.
    Ответ написан
    2 комментария
  • Не могу, понять как компьютер перемещает свой знак?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Не понятно, говорится если ход не дает победы, то компьютер ставит фигуру в следующую клетку,


    Вот этот код ставит фигуру в текущую клетку: board[move] = computer;
    Двумя строчками ниже этот ход откатывается: board[move] = EMPTY;

    found = winner(board) == computer; - этот код присваивает булевой переменной found значение выражения winner(board) == computer.
    Ответ написан
    9 комментариев
  • Что быстрее индексы или указатели?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Зависит от модели процессора, версии и опций компилятора и немножечко фазы луны. В целом без разницы.

    Практический совет - лучше писать через индексы, ибо так понятнее и больше шансов что компилятор там все наоптимизирует (например, он сможет векторизовать работу через какие-нибудь SSE инструкции процессора).

    Совет по бенчмарку - если памяти не хватает, стоит по одному достаточно большому массиву пройтись 10000 раз. А лучше использовать готовые фреймворки для измерения скорости, вроде того де gbenchmark.

    Еще, иногда полезно посмотреть на ассемблерный выхлоп. Вот, например, что происходит при -O3 опции компилятора. Он генерирует вообще идентичный код для обеих функций (развернув циклы)! И даже при -O2 оно одинаковый код выдает.

    Без оптимизаций код разный, но там все не так как вы думаете. Вместо инструкции mov eax, dword ptr [rax + 4*rcx] в варианте с индексами используется инструкция mov eax, dword ptr [rax] для указателей. Это самое "складывание с указателем массива" вообще не отдельная операция - а вариант адрессации в инструкции mov. Они могут вообще одинаковое количество тактов занимать, это надо мануал по конкретной архитектуре процессоров читать.
    Ответ написан
    Комментировать
  • Как обеспечивается совместимость динамических библиотек при ликовке в рантайме?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    То, что экспортируется из дин. библиотеки имеет стандартизированные имена.
    Ответ написан
    Комментировать
  • Как лучше добавить перед структурой ещё одну и поместить в массив?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вообще, работу с указателем на base тоже надо переписать через memcpy. Потому что это UB. Вдруг выравнивание у массива не такое, как у структуры Base. Без memcpy тут никак. Другого способа разместить 2 структуры в памяти подряд компактно - нет.

    Edit: конечно, можно объявить вашу стоуктуру где поля base и S1 идут рядом, но там будет какой-то padding. Работать с этим как с сериализированным массивом байт - нельзя.
    Ответ написан
    1 комментарий
  • Как использовать класс, определенный в двух подключаемых файлах?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Есть костыль:
    #define Class3 Class3_Unused
    #include "module1.h"
    #undef Class3


    Таким побразом при включении module1.h вместо Class3 будет объявлятся какая-то хрень, которую нигде вы использовать не будете.

    Правда, все ломается, если у вас этот module1.h включен по цепочке других инклудов. Надо аккуратно в каждом месте, где вы его включаете так же обарачивать в define.

    Но по уму, это большой косяк авторов module1 и module2, что они не используют namespace. Их надо бы переписать.
    Ответ написан
    1 комментарий
  • Как решить подобную задачу?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Ошибка, если интересно, в том, что в коде написан & вместо %. Соответственно, пропускаются не числа, которые не делят n, а числа, дающие не 0 в побитовом И с n.

    Вообще, не понятно условие задачи. Какие там ограничения? Так-то можно вот прям этот код взять и тупо вставить в исходник и посмотреть, что он вернет.

    Если надо побыстрее, то можно, например, запустить программу на нескольких прервых числах, посмотреть результат и попробовать вывести закономерность, смотря на битовую запись n и корня из n. Правда там не похоже, что что-то простое.

    Совсем быстрое решение - это динамическое программирование по бинарным цифрам корня. Это весьма сложный алгоритм. Сработает, в общем-то, для n до 2^64. Считайте F(l,f) - количество способов как-то расставить первые l бит числа, т.ч. все биты, единичные в n, взяты по 0, и число не превосходит корня из n, а f - флаг, означающий, что число уже строго меньше корня.

    Легче считать это циклом снизу вврех. Смотрите, какую цифру можно дописать к (l,f): если в n стоит 1 в этом бите - то только 0. Иначе, можно дописать 1, только если f=1 или в sqrt(n) стоит 1 в этом бите. Новый флаг f' будет 1, только если f=1, или вы поставили 0, а в sqrt(n) стоит 1.

    Потом ответ надо домножить на 2 и вычесть 1, если (int)sqrt(n) & n == 0.
    Ответ написан
    1 комментарий
  • Как найти наикратчайшие пути взвешенного орграфа, представленного матрицей инцидентности, используя алгоритм Дейкстры?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Матрица инцидентности - абсолютно не эффективная структра представления графа практически для всех алгоритмов. Поэтому вы ее использование нигде найти и не можете.

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

    Кстати, у вас матрица инцидентности неправильная: должно быть по 2 числа в каждой строке. Обычно ставят -цену у начальной вершины и +цену у конечной.
    Ответ написан
    4 комментария
  • Как преобразовать char* содержащий символы unicode?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вам надо \uXXXX преобразовать в char16_t? Можно это руками делать. Берете по 6 байт из строки. Последние 4 руками преобразуете из 16ричной системы. Если символ от a до f, то прибавляете к нему 10-'a'. Если от 0 до 9 - 0-'0'.

    Удобно это циклом делать, сдвигая ответ на 4 бита влево и прибавляя новый символ:
    std::wstring Parse(const std::string encoded) {
      std::wstring result;
      for (int start = 0; start < encoded.length(); start += 6) {
        if (encoded[start] != '\\' || encoded[start+1] != 'u') return result // строка неправильного формата.
        char16_t nxt = 0;
        for (int i = start +2; i < start+6; ++i) {
          int cur = 0;
          char &chr = encoded[i];
          if ('0' <= chr && chr <= '9') cur = chr - '0';
          if ('a' <= chr && chr <= 'f') cur = chr - 'a' + 10;
          if ('A' <= chr && chr <= 'F') cur = chr - 'A' + 10;
          nxt = (nxt << 4) + cur;
        }
        result += nxt;
      }
      return result;
    }
    Ответ написан
  • Как можно улучшить код?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    В задании же написано:
    Используйте процедуру.


    Разбейте на функции. Хотя бы выделите основной алгоритм в функцию, которая возвращает вектор из цифр. Отдельную функцию для вывода. символов. Минус можно вывести отдельно.
    Ответ написан
    Комментировать
  • Как правильно округлять числа с плавающей точкой с заданной точностью?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Очень многие числа нельзя записать в виде числа с плавающей запятой, потому что они не представимы в виде доичной дроби с заданным количеством знаков. Например вы 1/3 как десятичную дробь не запишите. Ибо там 0.3333... - бесконечная последовательность троек. Для хранения double выделенно сколько-то бит под мантиссу, но их сильно меньше бесконечности.
    Поэтому ни 1/10, ни 3/100, ни 1467/1000 и почти любая дробь будет непредставима в виде float. Поэтому, если вам нужна точность, то вы округляете до целого и храните количество, скажем, тысячных долей в целых числах. Как сумму денег вы храните не долларах, округленных до 2 знаков, а как целое число центов.
    Ответ написан
    Комментировать
  • В чем проблема в коде работы с графом?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Ошибка в том, что у вас граф криво задан. У вас там ровно 6 списков. А размер графа - 7. Поэтому в MakeStep вы обращаетесь к graph[6], а это undefined behavior. А там непонятно, что происходит. Может вы таблицу портите каким-то значениями и никогда положительного значения не получаете. Скорее всего корраптите память через обращение к мусорным adj в std::array (который на стеке лежит) и получаете мусор в каких-то локальных переменных.
    Ответ написан
  • Компиляция C++ кода на Ubuntu и Windows даёт мне разный результат, почему?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Скорее всего там где-то Undefined behavior. Например, выход за границу массива. Вы там вектора везде возвращаете, но может быть там вы где-то его заполняете на на ожидаемые 8 позиций.

    Советую переписать код. Возвращайте std::array<std::bitset<16>,4> например. Вместо push_back сразу обращайтесь к i-ому элементу ответа.

    Далее, у вас там 2 функции делают одно и то же - разбивают большой bitset на несколько маленьких. Напишите template функцию, которая выделяет из битсета длиной N битсет длиной M со сдвигом offset. Внутри просто циклом присваивайте res[i] = input[i+offset].

    Переписав и упрастив вот так вот код, вы, возможно, исправите ошибку.
    Ответ написан
    Комментировать