Задать вопрос
  • Как исправить ошибку collect2.exe: error: ld returned 1 exit status?

    @Mercury13
    Программист на «си с крестами» и не только
    На довольно давней версии mingw, имевшейся у меня, получилось сделать вот так — запустив компилятор и линкер раздельно.

    PATH %PATH%;d:\MinGW\x86\bin
    g++ -fopenmp -c main.cpp -o main.o
    g++ -o test.exe main.o -lgomp
    pause

    Заодно пришлось скачать pthreads для win32, по умолчанию библиотеки (*.a) есть, а dll нет.

    И вообще, это зависит от сборки MinGW. На свежих сборках mingw-w64 — как с Win32-, так и с posix-потоками — всё заработало именно по-твоему. И pthreads нашёлся.
    PATH %PATH%;d:\MinGW\i686-5.2.0-win32-dwarf-rt_v4-rev0\mingw32\bin\
    g++ -fopenmp main.cpp -o test.exe
    pause

    Ну и, конечно, ты не указал, ПОЧЕМУ линкер вышел с кодом 1. Но это я уже сам понял, поэкспериментировав.
    Ответ написан
    Комментировать
  • Почему рекурсивные алгоритмы работают медленнее своих линейных аналогов?

    @Mercury13
    Программист на «си с крестами» и не только
    Потому что этот алгоритм, будучи рализован в лоб без всяких кэшей и ускорителей, неоптимален! F(n–2) высчитывается дважды, F(n–3) трижды, F(n–4) пять раз, и т.д. по Фибоначчи.

    Что читать, сказать не могу (в том издании Кормена, что у меня, маловато), гугли «динамическое программирование». Хотя поначалу поможет и Кормен.

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

    ЗЗЫ. Программисты не любят рекурсию по многим причинам. 1. Сложно наладить аварийный стоп. 2. Системный стек ограничен и есть риск переполнения.
    Ответ написан
    4 комментария
  • Как убрать зависание при сохранении большего файла txt Delphi?

    @Mercury13
    Программист на «си с крестами» и не только
    Вариантов много, какой-то да и подойдёт.
    1. Просто и грязно. Периодически делать Application.ProcessMessages. Сделать, чтобы во время работы ни одна кнопка не срабатывала.
    2. Лучше подходит для законченного продукта. Наладить поток. Внимание, сеть в основном потоке в принципе нехорошее дело, если она там есть — айда пиши второй!
    3. Оптимизировать алгоритм.
    4. Избавиться от левых перерисовок. Гугли сообщение WM_SETREDRAW. Не забудь в конце Invalidate.
    Ответ написан
    Комментировать
  • Как создать свою таблицу символов?

    @Mercury13
    Программист на «си с крестами» и не только
    В Юникоде есть области символов для внутреннего пользования (private use), специально для программ, которым нужен нестандартный символ. Есть два способа вывести такие символы на экран.
    1. Написать свой шрифт.
    2. Написать свой типографский движок. Используя элементы системного, разумеется.
    Первое, по-моему, проще, второе даст более интересный результат (например, символ может отображаться как цветная иконка).
    Ответ написан
  • Для чего же нужны указатели?

    @Mercury13
    Программист на «си с крестами» и не только
    Хорошо, попробую. Вот у нас есть файл на каком-нибудь NAS. Мы хотим его переслать товарищу. Мы можем…
    • приложить файл к сообщению, тогда у нас будут два независимых файла. Просто и надёжно, недостатка два. 1) Файл копируется, это трудоёмко. 2) Копия живёт своей жизнью, и изменения в копии не затронут оригинал. Это передача по копии.
    • дать имя файла. Один изменяет файл — второй прочитает изменение, и никакого копирования. Недостаток — надо договариваться, кто владеет файлом (т.е. уничтожит его, когда тот не будет нужен). Имя файла — это и есть указатель.
    Метафора неполная, ведь файловая система может сказать, есть ли файл, а в памяти указатель на отсутствующий «файл» — это Access Violation. Да и «учёток» в памяти нет. Тем не менее…
    Ответ написан
    Комментировать
  • Как реализовать расписание кругового турнира?

    @Mercury13
    Программист на «си с крестами» и не только
    Других методов я просто не вижу. Искать «round-robin tournament algorithm». Но, по-моему, проще поворачивать не кольцо, а схему матчей, поставив одну из команд (лучше последнюю) в центр круга.
    https://commons.wikimedia.org/wiki/File:Round-robi...
    Round-robin-schedule-span-diagram.svg
    Матчам 2-13, 3-12 и т.д. даём фиксированные направления, причём попеременно: 2-13, 12-3, 11-4…
    Направление матча 1-14 постоянно меняется.

    Если команды нумеруются от 0 до N−1, N — чётное, алгоритм получается такой.
    trans := случайная перестановка чисел 0 … N−1
    
    если N чётное
      то M := N−1
      иначе M := N
    
    цикл 2half = false…true
      цикл round = 0…M−1
        цикл shift = 1…[M/2]
          home := (round + shift) % M
          away := (round + M − shift) % M
          если (shift нечётное) xor 2half
            обменять home, away
          вывести trans[home], trans[away]
    
        если N чётное
          home := round
          away := M
          если (round нечётное) xor 2half
            обменять home, away
          вывести trans[home], trans[away]

    Для чётного N одна команда постоянно меняет поле, у остальных — единожды на круге сбивается. Для нечётного N ничего не сбивается.
    Ответ написан
    2 комментария
  • Как разобрать матрицу трансформации на состовляющие?

    @Mercury13
    Программист на «си с крестами» и не только
    Как я понял, твоя матрица 3×3 — это однородные координаты в 2D? Я бы поступил так.
    1. Убедиться, что элементы 3-1 и 3-2 нули (иначе — это не аффинное преобразование).
    2. Элемент 3-3 превратить в единицу, соответственно увеличив остальные (на что — читай, что такое однородные координаты).
    3. Элементы 1-3 и 2-3 — перенос. Отрежем их, получается матрица 2×2.
    4. То, что осталось, должно быть вида (c, s), (-s, c). Если с какой-то погрешностью это не так и 2-норма строк не единица (тоже с какой-то погрешностью) — это не поворот (т.е. может быть масштабирование или наклон). Остаётся взять atan2(c, s) — получается угол.
    Ответ написан
    Комментировать
  • Может ли юнит-тест метода класса зависеть также от других методов?

    @Mercury13
    Программист на «си с крестами» и не только
    Да, может. Всё, что я здесь пишу, — моё ИМХО, обусловленное вечной нехваткой времени и ошибками в базовых функциях (высокоуровневый код тестировать крайне сложно и я не в курсе, есть ли стандартные методы автоматизации тестирования).

    Излишне сложный код тестовых функций также приходится тестировать — поэтому нет ничего зазорного в том, чтобы использовать функции, проверенные другими тестами. Собственные низкоуровневые функции стоит использовать, если они либо проще, либо заводят объект в какое-то контролируемое состояние, которого сложно достичь общедоступным интерфейсом. Таким образом, код теста должен быть примерно такой.
    1. Собрать нужный нам список.
    2. Проверить, что список в нужном нам состоянии.
    3. Удалить один элемент.
    4. Проверить, что новое состояние правильное.

    В пунктах 2 и 4 проверок может быть много — например, в пункте 2 «список корректно связан, в нём 3 элемента и два последних Б, В», в пункте 4 — «список корректно связан, в нём 2 элемента и последний Б». Главное, чтобы а) проверялась одна концепция — например, «работает удаление с конца»; и б) все концепции, которые нужны для корректной работы теста — например, «конструируется пустой список», «добавить в пустой» и «добавить в конец» — тоже надо проверить.

    С зависимостью тестов друг от друга немного неоднозначно. Тесты не должны физически вмешиваться друг в друга: при отладке нужно запускать какое-то подмножество или даже один отказавший тест. Или изменилась внутренняя структура объекта и часть тестов вообще убираем, так как пропадает тестируемая концепция. А логическая — «если добавление не работает, этот тест бессмысленный» — да никаких проблем!
    Ответ написан
    2 комментария
  • Задача по методу Эйлера, за что отвечает функция F в данном коде?

    @Mercury13
    Программист на «си с крестами» и не только
    Качество кода — на уровне студенческой лабораторной. Причём очень хреновой.

    Программа решает четыре системы.
    y = f0(t)
    y' = f1(t, y)
    y'' = f2(t, y, y')
    y''' = f3(t, y, y'')

    1. Если уж говорить о методе Эйлера — в программе ошибка.
    y[1] = y[1] + delt * y[2];
    Тут нужно старое значение y[2], а не новое.

    2. Функцию eiler стоило бы обозвать eulerStep, заодно убрав лишние параметры.

    3. Автор не знает такой концепции, как процедурный тип aka callback, поэтому работа с правой частью у него вышла вот через такую задницу.

    4. В промышленном коде метод решения ОДУ я бы вынес в отдельную процедуру, с callback’ами на правую часть и на потребителя результата. Причём внешнее (доступное пользователю библиотеки) именование должно быть такое, чтобы её пользователь мог ею воспользоваться, даже если он не читал статью, по которой библиотеку писали. Так что смотрите, какие имена являются стандартизированными, понятными по любому учебнику, а какие стоит прояснить. Внутреннее именование — это уж думайте сами, научный код обычно сложен, и его постоянно приходится сличать со статьёй. Поэтому имена как в статье — для научного кода не WTF.

    5. Не слишком удачно разделена ответственность между функцией правой части и функцией шага по Эйлеру. Это привело к ограничению — программа может решать только ОДУ y{n} = f(t, y, y', ..., y{n−1}).
    Ответ написан
    8 комментариев
  • Надо решить проблему с include?

    @Mercury13
    Программист на «си с крестами» и не только
    Учи понятие «единица компиляции».

    Два варианта.
    a) Несколько единиц компиляции (основной вариант, когда идёт активная разработка проекта). Тогда в хедере каждую переменную отмечаешь модификатором extern — «переменная есть, но где-то в другом месте». В одной из единиц компиляции объявляешь переменные, уже без extern.

    Насколько мне известно, защита от двойного включения для extern-переменных не важна, но, например, для классов или функций ой как пригодится.

    ///// unit.h /////
    #ifndef UNIT_H
    #define UNIT_H
    
    extern int myVar;
    
    #endif
    
    ///// unit.cpp /////
    #include "unit.h"
    
    int myVar;
    
    ///// main.cpp /////
    #include "unit.h"
    
    int main()
    {
       myVar = 1;
    }


    б) Одна большущая единица компиляции (в такой вид часто преобразуют библиотеки перед выпуском). Тогда достаточно оградить каждый хедер от двойного включения, и всё в порядке.

    ///// unit.h /////
    #ifndef UNIT_H
    #define UNIT_H
    
    int myVar;
    
    #endif
    
    ///// main.cpp /////
    #include "unit.h"
    
    int main()
    {
       myVar = 1;
    }


    ЗЫ. Когда я писал ответ, кода ещё не было. А тут он взял и пришёл. Для переменных (SYMBOL_WIDTH, LINE_HEIGHT) решение то самое. А для констант вариантов несколько.

    Путь сишный.
    #define LEFTPANEL 200
    ВОЗМОЖНО для литеральных констант, и особенно классно работает с текстовыми строками (например, "[" TEXT "]").
    НЕДОСТАТКИ: это препроцессор, и при пересечении имён будет нехорошо.

    Путь перечислимый.
    enum {
      LEFTPANEL = 200
    };
    ВОЗМОЖНО для констант, влезающих в int.
    НЕДОСТАТКИ: возможны приколы с кроссплатформенностью, если на отдельных платформах константа вылезет за грань int.

    Путь переменный.
    extern const int LEFTPANEL;
    ....
    const int LEFTPANEL = 200;
    ВОЗМОЖНО для любых констант.
    НЕДОСТАТКИ: нет вычисления при компиляции. Только линкер знает, что это 200.

    Путь C++11.
    constexpr int LEFTPANEL = 200;
    ВОЗМОЖНО для литеральных констант.
    НЕДОСТАТКИ: только C++11.

    Путь «на рывок»
    static const int LEFTPANEL = 200;
    ВОЗМОЖНО для всех литеральных типов, но при этом может создавать дублирующиеся переменные: так, в Borland будет дублироваться всё сверх int — и, соответственно, не допускать предкомпилированных заголовков, ибо создаётся код.
    НЕДОСТАТКИ: семантика зависит от компилятора и типа, ради чего и сделали constexpr.
    Ответ написан
    2 комментария
  • Сложен ли язык программирования "C"?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Стандартный Паскаль — без классов и прочих ништяков — даст определённое понимание об аскетизме Си. Недостаток Си именно в том, что там нет автодеструкторов — фирменной фишки C++. Даже в строках. А обработка ошибок с корректным уничтожением созданных объектов — в C++ автоматом, в Delphi/C#/Java try/finally — может намотать немало нервов.
    2. Хороших UI-библиотек с визуальным редактированием, как VCL в Delphi и WinForms в C#, на Си нет. Во многом это связано с тем, что на Си нет простого и стандартного способа хранить строки. Разумеется, невизуально никто не мешает делать интерфейс, WinAPI (кроме COM, который ориентирован под устройство класса Microsoft C++) рассчитан именно на Си.

    Язык учи, это неплохо расширит твой кругозор и даст понять, откуда берутся кое-какие фишки языков, с которыми мы постоянно имеем дело. Большинство языков в те времена писали академики. Си писал практик, писал как попало, писал для своих, и хоть некоторые его решения оказались неверными, Юникс сослужил хорошую службу как реклама Си.
    Ответ написан
  • Почему умер Delphi?

    @Mercury13
    Программист на «си с крестами» и не только
    Что я могу сказать как человек, немало имевший дело с Delphi?
    1. Форменное начхательство Borland до передачи продукта Embarcadero. Delphi перестал быть дойной коровой компании (деньги приносит вроде какая-то СУБД) — и его перестали совершенствовать. Кажется, что между версиями 7 и 2010 — пустота. Только в 2010 году сделали что-то для поддержки Юникода. «Амбаркадебра», конечно, работает, да время упущено: x64 появился около 2011, полная поддержка C++11 на всех платформах — не знаю, как в XE10, но в XE8 на x86 только явно устаревший компилятор Borland…
    2. Странная ценовая политика Embarcadero. Самодельщик — не их аудитория, они пишут для тех, кто автоматизирует какие-то бизнес-процессы, у них и денежки водятся…
    3. По моему личному ИМХО, поставили не на тот кроссплатформенный фреймворк — FireMonkey. Этот фреймворк грубо имитирует внешний вид стандартных компонентов Windows, а когда начинаются нюансы — локализация с автоподгонкой, или просто ClearType не нравится — начинается ад. А один из компонентов — TeeChart — ухитряется на FireMonkey попадать точно между пикселями, причём в редакторе это дело обойти можно, а в рабочей проге — нет.
    4. Появление в этой же нише бесплатного WinForms (да и у «мусорного» языка C# порог входа пониже будет). Да, как я забыл про это! — хоть ухитрился «на шару» пройти начальное обучение по C#, никогда с ним не работал, ни профессионально, ни «так просто».
    Ответ написан
    1 комментарий
  • Как создать custom массив, где каждому элементу выдано N-байт?

    @Mercury13
    Программист на «си с крестами» и не только
    1. В какой стек? В стек вызовов так не скопируешь (насколько я знаю, в некоторых реализациях Си есть функция alloca, выделяющая память на стеке до return), а в самодельный стек — тут ничего не сказано про стековую структуру, ёмкость и указатель на верхушку. В куче вы выделяете память, в куче…
    2. Посмотри функцию calloc. В Си в такой ситуёвине принято именно указывать количество байт на один элемент.
    3. Sizeof, чтобы ты знал, вычисляется при компиляции.
    Ответ написан
    Комментировать
  • Как называется такой стиль в искусстве?

    @Mercury13
    Программист на «си с крестами» и не только
    Textureless 3D.
    Есть ещё поджанр Flat-shaded 3D, но эта картинка — только без текстур, освещение же самое настоящее.
    Ответ написан
    Комментировать
  • Как улучшить крестовину в пульте для Xbox 360?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Снова отвечаю сам себе. Копия моего отзыва с hotline.ua.

    На всякий случай напишу, как исправить крестовину.

    Замечаем, какие плечи суперчувствительны, а какие подглючивают.

    Вырезаем из пластмассы толщиной ≈0,4 мм (лавсановая упаковка от пульта?) такую конструкцию. Квадрат 19×19, в центре вырезана дырка в виде квадрата 7×7. С уголков снимаем «фаску» порядка 2…3 мм. Пульт разбираем отвёрткой PH1 (внимание, один из винтов под наклейкой с серийником) и надеваем всю эту конструкцию на крестообразный шток крестовины. Те «лучи», которые соответствуют суперчувствительным направлениям, отрезаем аж до самого отверстия.

    После этого из пластмассы толщиной <0,3 мм (изолента? блистер от лекарств?) вырезаем «конфетти» диаметром миллиметров шесть, и приклеиваем «Моментом» на плату в центр крестовины.

    Может так случиться, что всё идеально, но одна диагональ вызывается с большой силой. В таком случае разбираем крестовину (откручиваем два шурупа и пинцетом сжимаем защёлки), находим выступ, соответствующий ПРОТИВОПОЛОЖНОЙ диагонали, и счищаем немного материала с самого выступа и с того места, куда он встаёт.

    После этой переделки значительно уменьшились шансы получить в пылу игры холостую диагональ, да и «дубовые» плечи стали по-человечески нажиматься.
    Ответ написан
    Комментировать
  • Qt: как проверить, раскрыт ли combobox?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Конкретную задачу, которую я просил, kozura решил. Однако надзадачу (перейти вниз по таблице) решал часа два, и решается она примерно так:
    1. Запросить текущий индекс.
    2. Преобразовать координаты, запросить у модели данных новый индекс по этим координатам.
    3. Попросить модель выделения перейи на этот индекс.
    Ответ написан
    Комментировать
  • Поддержание максимума в окне?

    @Mercury13
    Программист на «си с крестами» и не только
    Порядок, придумал.

    Создадим список максимальной длины w, в котором содержатся пары (index, value) и value нестрого убывает. Как устроен этот список — разберём позже.

    Сначала список пуст. Сначала w раз проводим операцию «a[i] вошёл». Затем n−w раз — сначала «a[i−w] вышел», затем «а[i] вошёл». Каждый раз list.front — это индекс и значение макс. элемента.

    Операция «a[i] вошёл». С конца списка удаляем все элементы, чей value меньше, чем a[i]. Затем прицепляем пару (i, a[i]) к концу.
    Операция «a[i] вышел». Если в начале списка index=i, удаляем первый элемент. Иначе — ничего не делаем.

    Почему O(n)? Единственное, где сложность неочевидна — удаление в операции «a[i] вошёл». Но удалений будет не больше, чем вставок, а их точно O(n) — так что никаких проблем.

    Ну и на сладкое — как должен быть устроен список.
    — Ограниченная длина (не более w).
    — Удаление из начала.
    — Вставка в конец.
    — Удаление из конца.

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

    @Mercury13
    Программист на «си с крестами» и не только
    Параллельное программирование — расчёт чего-либо на нескольких вычислительных ядрах.
    Многопоточное программирование — написание программ, работающих в несколько потоков.

    Параллельное, но не многопоточное: SETI@Home и прочие распределённые системы.
    Многопоточное, но не параллельное: шахматный ИИ работает независимо от интерфейса: пока человек думает, программа считает.
    Ответ написан
    Комментировать
  • Как избавиться от зависания формы при выполнении работы в потоке через Synchronize?

    @Mercury13
    Программист на «си с крестами» и не только
    Как ни странно, не использовать Synchronize на долгих операциях! Сабж выполняет операцию в главном потоке и, значит, главный поток всё это время не отвечает.

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

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

    @Mercury13
    Программист на «си с крестами» и не только
    Попробую рассказать.

    Некоторые поисковые функции STL требуют для работы функцию. Например, www.cplusplus.com/reference/algorithm/find_if или www.cplusplus.com/reference/algorithm/sort (второй вариант).

    А что делать, если какие-то параметры поиска или сортировки задаются программно? Можно, конечно, эти параметры сделать глобальными переменными — но, как известно, «избегайте незнакомых женщин и глобальных переменных». В таком случае используют т.н. функтор — некий объект с операцией (). Другими словами, его «вызывают», как функцию. Все изменяемые параметры будут храниться в полях этого объекта.
    Ответ написан
    Комментировать