Задать вопрос
  • Не удаётся продолжить выполнение кода, поскольку система не обнаружила sfml-graphics-d-3.dll. Как исправить ошибку?

    @Mercury13
    Программист на «си с крестами» и не только
    Найти, где система сборки создаёт EXE. И положить рядом нужный DLL.
    Ответ написан
    Комментировать
  • Как правильно указать авторское право на шрифт?

    @Mercury13
    Программист на «си с крестами» и не только
    CC-BY-SA — очень неудачная лицензия для строительных блоков, у которых есть два метода пользования: построение новых блоков и использование по назначению в составной работе. Но если предполагать, что они разрешают менять ШРИФТ и использовать ГДЕ УГОДНО на манер OFL — то как-нибудь, достаточно простого указания где-то в about, титрах или другой сопроводительной документации:

    FONT: Minecraft Ten by Vania 5617sonfan, CC-BY-SA 3.0

    Если шрифт простым файлом, доступным методом «потянись и скопируй» — то лучше приложить текст лицензии в файле вроде LICENSE-MinecraftTen.
    Ответ написан
  • Приведите пример использования readObjectNoData() при десериализации?

    @Mercury13
    Программист на «си с крестами» и не только
    Так просто, одним куском кода, это сделать нельзя. readObjectNoData() работает только на враждебных данных, которые ещё надо ухитриться сфабриковать.

    // Пишет вот такой код
    class A implements Serializable { }
    class B extends A {}


    // А читает вот такой
    class A implements Serializable { }
    class AHalf extends A {
      private void readObjectNoData() throws ObjectStreamException {}
    }
    class B extends AHalf {}


    Если записать объект класса B первым кодом и прочитать вторым, должно сработать.

    Смысл readObjectNoData() — привести объект в подходящее состояние, когда 1) данных по промежуточному классу AHalf нет; 2) у него какие-то нехорошие инварианты, что так просто в свежеинициализированном состоянии он негодный: ну, к примеру, конструктор по умолчанию скрыт и служит только для десериализации, а так он просит объект для своего создания.
    Ответ написан
    Комментировать
  • Какой алгоритм можно применить при проверки числа на простое ли оно?

    @Mercury13
    Программист на «си с крестами» и не только
    Если нужно проверить а) точно, и б) одно; в) не очень большое число (миллион тоже небольшое) — ничего нет лучше, чем проверка нечётных чисел до корня из n. То есть до 1000.

    Если точно, много и небольшие — то придётся держать список простых чисел, пополняя его, когда попадётся слишком большое число. Список тоже до корня из n. Допустим, если предел — int4 (≈4 млрд), то нужно держать только список до 65535, это пара тысяч чисел.

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

    В криптографии востребован неточный поиск — «число, скорее всего, простое». Но об этом не будем, вы не настолько круты. Тут уже основано на том, что держим таблицу небольших простых чисел и делим на них, а затем гоняем неточные тесты.

    PERFECT number — это СОВЕРШЕННОЕ число. Это не то (сумма всех делителей равняется самому числу), и для теста на совершенное число тоже надо проверять до корня из n — если a делится на b, то добавляем и b, и a/b (кроме случаев, когда b=1 и b²=a, разумеется). Если есть простые числа до корня из n — тоже можно разбить на простые множители (один из множителей может быть больше корня из n!) и подключить комбинаторику, чтобы заполучить остальные.
    Ответ написан
    2 комментария
  • Можете посоветовать какой-нибудь задачник по патернам проектирования?

    @Mercury13
    Программист на «си с крестами» и не только
    Задачник невозможен, потому что…
    1. Паттерны проявляют себя в крупных программах. Даже 2000 строк можно написать по наитию.
    2. Нет единого ответа. И как вы будете сверяться, верно вы сделали или нет?
    3. Сильно зависит от языка: например, идиома pimpl — это чистый Си++.
    4. Даже зависит от того, библиотека встроенная или внешняя: внешние библиотеки в низкоуровневый код всегда стараются вносить очень осторожно.

    Пример: нам надо включать-выключать лог в консольной программе, простейший вопрос. Варианты…
    1. Просто переменная isLoggingOn, которая включает этот самый лог.
    2. Одиночка-стратегия-null object.

    И тут появляется вопрос: а что делать, если у нас тут ещё и форматирование на манер printf? Где находится утилита форматирования: в «волшебном круге» интерфейса Logger или нет? А если нет — то можно придумать модуль-утилиту за пределами этого «волшебного круга»? А если пишем на Си#, может, этот модуль-утилита — это метод-расширение? А если пишем на Си++, может, вообще можно не заморачиваться из-за того, что связанные с std::format функции шаблонные и если ни одна не расшаблонилась — с нас и взятки гладки?
    Ответ написан
    Комментировать
  • Почему строку можно изменить через массив, но через указатель нельзя?

    @Mercury13
    Программист на «си с крестами» и не только
    Потому что в Си++ — в отличие от Си — строковый литерал "hello" имеет тип const char[]. Как дополнительную подсказку, что даже если система (скажем, DOS) не имеет разделения памяти по типам и позволяет менять такие литералы — Windows имеет и не позволяет.

    РАЗ. У указателя и массива несколько разная семантика
    char hello1[] = "hello";   // массив длины 6, в изменяемом сегменте или стеке,
                             // данные скопированы из литерала, который
                             // сидит в неизменяемом сегменте
    const char* hello2 = "hello";   // указатель направлен прямо на литерал,
                             // и попытка изменить его под Windows — вылет


    ДВА. Компилятор имеет право спрессовать два литерала в один, и смена одного, скорее всего, сменит и другой. Не могу проверить на Windows — говорил же, что запись в строковый литерал под Windows приведёт к вылету — но, скорее всего, так будет. Что-то вроде
    char* hello1 = const_cast<char*>("hello");
    char* hello2 = const_cast<char*>("hello");
    hello1[1] = 'U';   // hello2 = "hUllo" в системах вроде DOS, где не вылетит
    Ответ написан
    4 комментария
  • Стоит ли использовать блоки кода для ограничения области видимости?

    @Mercury13
    Программист на «си с крестами» и не только
    Иногда, чтобы прикрыть теоретическую возможность важной ошибки.
    Чаще нужно в Си++ с его автодеструкторами.
    На чтение особо не влияет.

    Вот пример на Си…
    { char* buf = calloc(n, sizeof(char));  // Ради чего я создал блок — ставлю в той же строке
        snprintf(buf, n, some_shit);
        strcpy(dest, buf);
        free(buf);
    }


    Ну а это чистые «кресты».
    { std::ofstream os(fname);
       os << someData;
    }  // Тут файл закрыт
    Ответ написан
    Комментировать
  • Могу ли я активно ссылаться на видео с ютуба?

    @Mercury13
    Программист на «си с крестами» и не только
    Нет, не нарушите.
    Но сам YT может запрещать проигрывать видео на посторонних сайтах.
    Ответ написан
    2 комментария
  • Можно ли добиться постоянного O(nlogn) для квиксорта в любом случае?

    @Mercury13
    Программист на «си с крестами» и не только
    Наиболее распространённый метод — IntroSort. Если рекурсия ушла глубоко, переключиться на другой метод. Постоянные n log n и не теряются классные свойства QuickSort.

    Да, есть методы именно на быстрой сортировке, но, видимо, умные люди всё испытали и ничего лучшего не нашли.
    Ответ написан
    Комментировать
  • Почему методы length() и codePointCount() для знака копирайта (с) возвращают одинаковую длину?

    @Mercury13
    Программист на «си с крестами» и не только
    1F12F — это символ копилефта.
    А точно вы имеете дело с ним, а не вот с этим эмодзиком?
    6765db2f10ea3231097248.png
    В нём два символа базовой плоскости (codePointCount). Длина в единицах UTF-16 — тоже два (length).

    UPD. Да, вопрос
    Почему String.codePointCount() возвращает 2 для символа ©?
    ваш, и вы в нём отметили неправильный ответ. Второй символ - не пробел, а селектор начертания 16.

    Программа, если что, моя, и зовётся «Юникодия». Гуглите, она первая в выдаче.
    Ответ написан
    Комментировать
  • Что делать с переполнением дополнительного кода числа после умножения?

    @Mercury13
    Программист на «си с крестами» и не только
    В случае, если N=2b, тогда
    (N+y)(N+v) = N²−N(|y|+|v|)+yv ≡ yv (mod N), и, таким образом, можно множить дополнительные коды, растянув их до длины N².
    Как поступать, не растягивая? — ну, добавить N(|y|+|v|), наверное.
    Итак, ваши числа ДЕВЯТИбитные (N=512), и символизируют y=−217, v=−161. Ну, соответственно N+y=295, N+v=351.
    (N+y)(N+v) + N(|y|+|v|) = 295·351 + 512·(217+161) = 297081,
    N² = 262144,
    Выкинем один переполненный бит 297081−262144 = 34937,
    Ну что, есть у нас (−217)·(−161)?

    Что вы неправильно сделали…
    1. Я не понимаю, что здесь делают 2(|y|+|v|).
    2. Числа у нас ДЕВЯТИбитные, так что и начальные единицы нельзя выкидывать, и сдвиг должен быть на девять бит, а не на восемь или десять.

    Если попробовать отрубить знаковый бит и N²=65536…
    N=256, y=−217, v=−161, N+y=39, N+v=95.
    (N+y)(N+v) + N(|y|+|v|) = 39·95 + 256·(217+161) = 100473,
    вычтем переполненный бит 100473−65536=34937
    Но тогда придётся выкинуть ОБЕ начальных единицы, а сдвиг делать на 8.
    С отрубленными знаковыми битами только знание, что оба числа отрицательные, позволяет трактовать эти 34937 как 16-битное беззнаковое. А то мы же отрубили все признаки этого, верно?

    А то вы одну выкинули, а другую оставили.
    Ответ написан
    3 комментария
  • Как работает стирание типов?

    @Mercury13
    Программист на «си с крестами» и не только
    Потому что в коде
    Pair emp = person;
    …не угадываются шаблонные параметры, а просто берётся Pair<Object>.
    Ответ написан
    Комментировать
  • Почему объект не передается по ссылке?

    @Mercury13
    Программист на «си с крестами» и не только
    В BoxContainer, скорее всего, не происходит инициализация nbox.
    Поскольку NumberBox не имеет конструктора по умолчанию, компилятор ругается, что нельзя это поле инициализировать по умолчанию.
    Так что варианта два
    1. nbox инициализировать, наконец.
    BoxContainer::BoxContainer(NumberBox& nb) : nbox(nb) { ... }

    2. Придумать NumberBox конструктор по умолчанию
    class NumberBox {
    	...
    public:
    	NumberBox();
    	NumberBox(int i);
    	...
    };
    Ответ написан
    1 комментарий
  • Почему для добавления единичного бита используется именно 0x80?

    @Mercury13
    Программист на «си с крестами» и не только
    Мы обычно привыкли к порядку байтов в слове. Однако в криптографии и телекоммуникациях также играет роль порядок битов в байте — обычно у младшего бита номер 0, а у старшего 7. Это упрощает произвольный доступ к любому биту, передачу информации в порт по одному биту — я писал самодельные низкоуровневые коммуникационные протоколы, правда, давно и под DOS. Но тут, по-видимому, наоборот — байт начинается со СТАРШЕГО бита. Вижу в этом две причины.
    1. Межплатформенный стандарт двоичной передачи данных — передавать длинные числа, начиная со старшего байта, просто для удобства ручного исследования протоколов. Тут ручное исследование доведено до предела: байт делится на биты, которые также записываются от старшего к младшему — как мы бы записывали на бумаге.
    2. Криптографию по-чёрному оптимизируют, чтобы она оперировала не байтами, а самыми длинными единицами, доступными процессору: 64-битный — значит, блоками по 8 байтов.

    0x80 = 0b1000'0000. Вот вам и единичный бит и куча нулей.
    Ответ написан
    Комментировать
  • Как именовать два метода один из которых выбрасывает исключение?

    @Mercury13
    Программист на «си с крестами» и не только
    findById и requireById.
    В данном случае.
    Ответ написан
    Комментировать
  • Почему String.codePointCount() возвращает 2 для символа ©?

    @Mercury13
    Программист на «си с крестами» и не только
    Он не прав.
    Второй символ не пробел, а селектор начертания 16.
    Используется во многих символах базовой плоскости, чтобы превратить их в эмодзи.
    А уж в символах двойного назначения — и типографский, и эмодзи — и подавно.
    67253fc645640534308923.png
    Ответ написан
    Комментировать
  • Правильно ли вынесение метода проверки в другой сервис для упрощения тестирования?

    @Mercury13
    Программист на «си с крестами» и не только
    check1() иногда годится, если проверка многократно выполняется в разных функциях, по принципу «не повторяйся». Например, для const-корректности Си++, или для хитрых интерфейсов, когда есть objectId(i), objectName(i).

    А так зачем: тестирования с виду не упростит, ведь мы должны убедиться, что интерфейс верно реализован и действительно некорректные наборы данных (все или хотя бы некоторые) не проходят.

    UPD. Вынесение РАЗОВОЙ функциональности (если это реакция на некорректные данные, конечно) в отдельную функцию КРАЙНЕ РЕДКО делает код более тестопригодным: может быть, что реакция на некорректности так размыта, что вызов основной функции мало что даст. Может, реакция на некорректности так сложна, что стоило бы её проверить отдельно. Ну ХЗ, в большинстве случаев бессмысленно.

    UPD2. Тестируемость кода — это в первую очередь возможность выделить функциональность для тестирования и не тащить вместе с ней половину программы.
    Ответ написан
    Комментировать
  • Для чего нужен слой сервиса без логики?

    @Mercury13
    Программист на «си с крестами» и не только
    Нет, для автоматического построения связей Spring’ом.
    Почему-то этот товарищ сделал эту штуку очень тонкой обёрткой над предметной логикой: то ли имя findWriteLockedByName не нравится, то ли не знал, будет сделана служба на Spring или на чём-то другом.
    Ответ написан
    Комментировать
  • Расскажите пожалуйста как реализован sin в cmath?

    @Mercury13
    Программист на «си с крестами» и не только
    SET_RESTORE_ROUND_53BIT (FE_TONEAREST);
    Настройка сопроцессора. Это какая-то магия, имеющая две задачи: производительность и повторяемость.

    Дальше мы залезаем в устройство числа (причём для краткости имеем дело с 32-битными командами!) и проверяем на «малость» — если получилось малое, то sin x ≈ x.

    Дальше идёт проверка на |x|≲45° — идёт вычисление настоящего синуса. Опять-таки, проверка по верхним 32 битам числа (синус вычисляем по всем 64 битам ☺️).

    Если число не очень большое, мы загоняем его в диапазон ±45° и вычисляем синус или косинус.

    Если число побольше — идёт более злой загон в диапазон ±45° и то же самое.

    И последнее, что осталось,— ∞/NaN.

    Внутренние функции обозревать не буду, но что мы тут видим?
    1. Какие значения бывают чаще, какие реже?
    2. Для очень маленьких значений sin x ≈ x, cos x ≈ 1.
    3. Ещё одно — залезание во внутренний формат компьютерного дробного, причём даже на x64 имеем дело с 32-битными целыми.
    4. Даже функция приведения в ±45° есть в двух видах — упрощённом и «злом» в зависимости от абсолютной величины числа.
    Ответ написан
    4 комментария
  • Ошибка в вариативном шаблоне. Что не так?

    @Mercury13
    Программист на «си с крестами» и не только
    #include <iostream>
    #include <string>
    
    struct T {
        int x;
        std::string y;
    };
    
    T Deserialize(std::istream& stream, auto T::*... properties)
    {
        T object = {};
        auto FillObject = [&object, &stream] (auto property)
        {
            stream >> object.*property;
        };
    
        (FillObject(properties), ...);
        return object;
    };
    
    int main()
    {
        T r = Deserialize(std::cin, &T::x, &T::y);
        std::cout << "<" << r.x << "> <" << r.y << ">" "\n";
        return 0;
    }

    Что сделано: исправлен вызов FillObject (важно), уточнён тип properties (лучше).
    Ответ написан
    Комментировать