• Как разобрать матрицу трансформации на состовляющие?

    @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 (второй вариант).

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

    @Mercury13
    Программист на «си с крестами» и не только
    Причина, вероятно, в том, что ты допустил код в хедере, и sort_pred оказался реализован дважды в разных единицах компиляции.
    Либо сделай sort_pred inline (inline кода не производит, производит его тот, кто этот inline вызовет), либо вынеси его в cpp-файл.

    Ах, да. Почему всё правильно с этой функцией…

    bool operator()(two *t)
    {
        return t->getA()==a;
    }


    А потому что тело внутри класса автоматически inline и тоже кода не производит.
    Ответ написан
    Комментировать
  • Как правильно обрабатывать изображения в стороннем потоке?

    @Mercury13
    Программист на «си с крестами» и не только
    Что я пока вижу.
    1. В любой высокоуровневой библиотеке CreateThread использовать ЗАПРЕЩЕНО, вместо этого используй beginthreadex (или что-то ещё, предоставленное библиотекой). Или, раз уж ты по-чёрному используешь VCL, особо не убудет, если будешь использовать TThread.
    2. Lock и Unlock — это обыкновенный мьютекс. Все конкурирующие потоки, кому захочется рисовать на холсте, ждут и курят, ничего не делая.
    3. Самое-то главное ты упустил. Если ждёшь помощи, не нужно так секретничать, что не поймёшь, в чём дело. Где — хотя бы примерно — тело потока, и что делается в главном потоке?
    4. А как надо работать? Есть некая структура данных, в которой мы возвращаем из потока обработанные картинки, и volatile bool isWorking, который отвечает за то, работает поток или нет. Когда этот флажок false, главный поток имеет право работать с нашей структурой. Он переключается в true — в структуре может быть любой мусор, обращаться к ней запрещено! Если ещё и надо предупредить, когда поток закончился и можно забирать информацию — TThread.Synchronize или PostMessage. То и другое работает только в GUI-программах, если консольная — то через события (CreateEvent).
    5. А почему «нельзя этого делать»? Если партия приказала, значит, надо. Просто многопоточность — это тяжёлое дело, ошибки на каждом шагу, но «принципиально нельзя» — нет такого.
    Ответ написан
    4 комментария
  • Тригонометрическая регрессия?

    @Mercury13
    Программист на «си с крестами» и не только
    Совершенно верно. Вообще регрессия методом наименьших квадратов крайне легко выводится для любой формулы вида

    y = A1·f1(x) + A2·f2(x) + … + Am·fm(x)

    при условии, что заданы m пар (x1, y1) ... (xm, ym). Неизвестные — A1…Am.

    Чуть посложнее, надо вспоминать теорию матриц — для N > m пар.
    Ответ написан
    5 комментариев
  • Почему получается странная кодировка в файле?

    @Mercury13
    Программист на «си с крестами» и не только
    msc.insert(dat);
    Перед этой строчкой dat правильный, проверь?

    Если правильный — возможно, виновата ваша коллекция.
    Ответ написан
    1 комментарий
  • Странная кодировка в файле,с++?

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

    char* — это просто указатель на чей-то другой отрезок памяти. И программист должен чётко осознавать его время жизни. Скорее всего, строка исчезла раньше, чем указатель. Используй автоматические строки наподобие std::string.

    Кроме того, std::map будет, если я не ошибаюсь, сортировать по адресам, а не по строкам. Чтобы всё работало, надо писать свою операцию <, читай документацию, как.
    Ответ написан
    6 комментариев
  • [Delphi] Как постоянно генерировать новый класс окна формы?

    @Mercury13
    Программист на «си с крестами» и не только
    Если ты имел в виду оконный класс (понятие WinApi) — переопредели TWinControl.CreateParams.

    type
      TfmMain = class (TForm)
      .....
      protected
        procedure CreateParams(var Params : TCreateParams); override;
      end;
    
    procedure TfmMain.CreateParams(var Params : TCreateParams);
    begin
      inherited;
      // а затем подкорректируй Params по собственному желанию.
    end;

    Что, кстати, пишешь? Вирус? :)

    Если ты имел в виду класс как понятие ООП — никак.

    P.S. И всё-таки напиши свою задачу. Защититься от FindWindow? — я только что написал, как. Защитить «внутренности» программы от патчей? Придумать хакоустойчивое API?
    Ответ написан
    2 комментария