Ответы пользователя по тегу Pascal
  • Как ускорить функцию?

    @Mercury13
    Программист на «си с крестами» и не только
    Название, конечно, не по прогерскому фэншую, и вспоминается знаменитый стих столетней давности:
    «We slog, slog, slog, slogging over Africa,
    Boots, boots, boots, boots moving up and down again».

    ПЕРВОЕ. Главный тормоз — дополнение строк нулями, которое квадратичное по скорости.
    for i:=length(s1)+1 to m do
             s1:='0'+s1;
          for i:=length(s)+1 to m do
             s:='0'+s;


    Как решить?
    function add1(const large,small:string):string;
    
    function add(const x, y : string) : string;
    begin
      if length(x) > length(y)
        then add := add1(x, y)
        else add := add1(y, x);
    end;


    Ну и разумеется, сделать, чтобы add1 работала с числами разной длины.

    ВТОРОЕ. У вас, по-видимому, ошибка — 99+1 = 100 не создаст третьего разряда.

    ТРЕТЬЕ. Я не знаю, какой у вас Паскаль, но, вероятно, передача строк по const/var также повысила бы скорость.

    ОФТОП. Если ваша задача не «ввести два числа, сложить и всё», я бы отделил длинное число от его строкового представления, примерно так.
    TLongNum = record
      length : integer;
      data : array [1..1000] of byte;
    end;
    Ответ написан
    1 комментарий
  • Какие действия несут эти знаки @ & % # ^ в delphi или pascal?

    @Mercury13
    Программист на «си с крестами» и не только
    Это символ не Delphi, а Win32. Как налаживается горячая клавиша в других ОС — я не в курсе, но в Qt под всеми ОС горячая клавиша задаётся точно так же, амперсандом. В текстовой системе Turbo Vision было ~H~otkey.
    Никакого особого смысла эти символы в окнах Win32 не несут. Но могут нести где-то в других местах, сами понимаете:
    • на некоторых сайтах #hashtag или @user
    • в строках типа printf процент — это символ подстановки типа «Привет, %s»
    • а какой смысл несут все эти символы в Паскале — вы и так должна знать.
    Ответ написан
    Комментировать
  • Как запустить .EXE создаваемый Турбо Паскалем?

    @Mercury13
    Программист на «си с крестами» и не только
    Можно после запуска нажать Alt-F5, чтобы увидеть, что программа вывела.
    Есть там эта кнопка в меню — пункт не помню, а кнопку помню.
    UPD. Команда называется «User screen».
    Ответ написан
    Комментировать
  • Как мне записать конечный результат деления?

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

    1. Работать с погрешностью. Например.
    q := X1 / X2;
    if abs(q - Round(q)) < 1e-5 then ...

    Я в основном сейчас на «си с крестами» и непривычка не брать условие в скобки :)

    2. Работать в рациональных числах.
    type
      TRatio = record
        Num, Den : integer;
      end;

    Думаю, сами сможете написать операции ±×/ и, если надо, сокращение.

    3. Работать в фиксированной запятой — например, перевести рубли в копейки.
    var
      X1 : integer = 100;
      X2 : integer = 20;
    
    if X1 mod X2 = 0 then ...


    4. Работать в десятичной длинной арифметике. Это уже совсем «большая пушка», и может быть что-то типа
    type
      TDecFloat = record
        mantissa : uint64;  // например, от 1e17 до 1e18
        order : integer;
        sign : boolean;
      end;

    Примерно так можно сделать калькулятор, работающий в десятичной системе и переводящий в extended и обратно, если, например, нужно взять синус. Погрешность перевода для трансцендентных функций, разумеется, будет, зато 0,2 в такой системе — это точное 0,2, и это важно для калькуляторов: он вычислит в точности то, что человек вычислит ручкой на бумаге.

    ВНИМАНИЕ! Для методов 2,3,4 придётся переработать всю цепочку, через которую появляются 1 и 0,2. В float/double нет числа 0,2, и точка.
    Ответ написан
  • Free Pascal ANSI или Unicode?

    @Mercury13
    Программист на «си с крестами» и не только
    Плавали, знаем. Долго видел на BCB6, а потом преобразовывал ANSI → UTF-16.
    1. Раз у нас UTF-16, придётся усложнить работу с путями и прочим (например, сокращение строк). Раньше символ был один char, стало — один-два WideChar.
    2. Где у нас низкоуровневые строки — придётся корректировать объёмы памяти. На всех языках, кроме Си и Си++, такого обычно мало: на Си нет своих строк, а в Си++ автодеструкторы.
    3. Где у нас сериализация — придётся перекодировать. В ANSI адресуемая единица (байт) совпадает с символом текста, в Юникоде уже нет.
    Ответ написан
    3 комментария
  • Как сделать управляемый интерфейс?

    @Mercury13
    Программист на «си с крестами» и не только
    Дело тут вот в чём. Оконные ОС работают в событийном режиме: пришло событие «перерисовать», мы рисуем; пришло событие «щёлкнуть», мы щёлкаем. Но поскольку учебным программам надо быть предельно простыми, куда удобнее написать: нарисовать, дождаться нажатия клавиши — как во времена ДОС, когда процессорное время было полностью вашим от точки входа до передачи управления, когда был прямой доступ к видеопамяти… Для консольных программ всю эту событийщину скрыли, хитрым образом на уровне ОС засинхронизировав два потока: один отвечает за поддержание консольного окна, второй — собственно программа. А Pascal.ABC пришлось наладить простейшую эмуляцию, сделав «видеопамять» в виде внутреннего буфера.

    Так что придётся подключать события — см. pascalabc.net/downloads/pabcnethelp/scr/PABCUnits/... — и смотреть, какие в этой абстракции найдутся дыры. А они, по Спольскому, будут обязательно: TCP — это протокол гарантированной доставки, но кто её гарантирует, когда физически выдернули провод…
    Ответ написан
    9 комментариев
  • Как создать компонент в потоке и оставить его в delphi?

    @Mercury13
    Программист на «си с крестами» и не только
    Можно, только синхронно. Используй TThread.Synchronize. Код пишется с листа, не уверен, что действующий.
    procedure TMyThread.SyncCreateMemo;
    begin
     Memo:=TMemo.Create(Form6);
      Memo.Parent:=Form6;
      Memo.Left:=50;
      Memo.Top:=50;
      Memo.Width:=250;
      Memo.Height:=100;
      Memo.Text:='Мама я родился!';
    end;
    
    procedure TMyThread.Execute;
    begin
      Synchronize(SyncCreateMemo);
    end;


    Второй способ, более сложный и опасный — PostMessage. Здесь никаких задержек поток испытывать не будет. Но будьте осторожны — форма создаст компонент когда угодно и нельзя его заполнять сразу же.
    procedure TForm6.WmCreateMemo; // message WM_CREATEMEMO = WM_USER + 1
    begin
     Memo:=TMemo.Create(Form6);
      Memo.Parent:=Self;
      Memo.Left:=50;
      Memo.Top:=50;
      Memo.Width:=250;
      Memo.Height:=100;
      Memo.Text:='Мама я родился!';
    end;
    
    procedure TMyThread.Execute;
    begin
      PostMessage(Form6.Handle, WM_CREATEMEMO, 0, 0);
    end;


    Заполнять наш редактор тоже можно путём PostMessage, но тут тоже будьте осторожны: сообщения-то выполнятся по порядку, но никто не знает, до окончания потока или нет. Бывает и такое, что два сообщения ушли в очередь, но ещё не обработались. В общем, будьте предельно осторожны с временем жизни объекта.
    Ответ написан
    Комментировать
  • Как изменить класс компонента?

    @Mercury13
    Программист на «си с крестами» и не только
    Самый простой способ. Открываем DFM (ПКМ на форме, View as Text) и проводим Search-Replace.
    После этого вносим любые изменения в модуль (да хоть пробел добавляем и удаляем), и сохраняем. Автоматика будет спрашивать: заменить? — соглашаемся.

    Я изменял в Unit1.pas - type TPanel на sPanel и в Unit1.dfm TPanel на sPanel.
    Но при открытии пишет, что класс sPanel не найден, хотя в uses прописано sPanel.

    Если модуль называется sPanel, то сам компонент должен немного по-другому. TsPanel?

    UPD. Да, TsPanel, если это он.
    Ответ написан
    Комментировать
  • Как удалить файлы по маске в подкаталогах Delphi?

    @Mercury13
    Программист на «си с крестами» и не только
    Ну ясен перец.
    Каталоги надо искать по *, а файлы удалять по *.log.
    Ответ написан
    Комментировать
  • Как присвоить выражение boolean полю TObject?

    @Mercury13
    Программист на «си с крестами» и не только
    Попробую угадать задачу. Есть некое поле (назовём его UserData), но у нас-то пользовательские данные boolean!

    Решение 1. Прямое преобразование, невзирая на несовместимости типов.
    someObj.UserData := TObject(true);
    someBool := boolean(someObj.UserData);

    + Эффективнее всех.
    − Запрещено разыменовывать.

    Решение 2. Создать некий объект DummyObject. Обозначить nil=false, <>nil = true.
    someObj.UserData := dummyObject;
    someBool := (someObj.UserData <> nil);
    
    initialization
      dummyObject := TObject.Create;
    finalization
      dummyObject.Free;
    end.

    + Достаточно эффективно, можно разыменовывать.
    − Если в классе есть неотключаемое автоуничтожение UserData — облом!

    Решение 3. Создать класс TBoolObject.
    TBoolObject = class
    public
      Value : boolean;
      // конструкторы опущу, деструктор не нужен
    end.
    
    someObj.UserData := TBoolObject(true);
    someBool := (someObj.UserData as TBoolObject).Value;

    + Работает, когда в классе есть автоуничтожение UserData.
    − Иначе — овчина не стоит выделки, тогда нам эти объекты придётся уничтожать самим.

    Если же у вас тут экономия памяти и надо в одной памяти держать object или boolean, работает решение 4.
    TObjBool = record
    case integer of
    0 : ( asObj : TObject );
    1 : ( asBool : boolean );
    end;

    + Очень эффективно.
    − Программист сам должен следить за тем, что там: объект или буль.
    Ответ написан
    2 комментария
  • Как округлить число до 2-3 знаков после запятой на "pascal.A.B.C" если выдается ошибка?

    @Mercury13
    Программист на «си с крестами» и не только
    Обычно в учебных работах (и даже не в учебных — именно так работает Excel) не округляют, а выводят с округлением.
    writeln(x1:0:3);
    writeln(x2:0:3);

    Каких-то продвинутых средств округления, которые округляют дробное число до i-го знака я не вижу.
    Кроме того, вы подсказали, с каким Паскалем вы имеете дело, я загрузил его и повторил прошлую ошибку — такая ошибка происходит именно что из-за округления NaN.
    Ответ написан
    Комментировать
  • Ошибка времени выполнения: Значение было недопустимо малым или недопустимо большим для Int32, как это решить?

    @Mercury13
    Программист на «си с крестами» и не только
    1. У вас неправильная формула корней.
    2. Хотелось бы узнать, чему равны a, b, c.
    3. Зачем вы округляете?
    4. Собственно причина ошибки. Думаю, у вас отрицательное d, sqrt(d) = NaN (не-число), и ваша реализация Паскаля вот так поступает, когда нужно округлить NaN.
    Ответ написан
    Комментировать
  • Как нужно изменить алгоритм Дейкстры чтобы он искал самый длинный путь?

    @Mercury13
    Программист на «си с крестами» и не только
    Варианты.
    1. Если граф циклический, максимальный путь — ∞.
    2. Если циклический, но путь обязан быть несамопересекающимся — Дейкстра не подойдёт. Подобную олимпиадную задачу я решал и там решением был перебор с кэшированием (вершин вроде до 15).
    3. Если граф циклический, но есть отрицательные веса, которые в определённых случаях дают-таки точный максимум — меняем знак, применяем модификацию Дейкстры для отрицательных весов. Он либо скажет, что есть цикл, позволяющий сколь угодно уменьшить сумму, либо даст точный минимум.
    4. Если ациклический ненаправленный — то либо один, либо нет вообще (т.н. лес);
    5. Если ациклический направленный — должен работать совсем другой алгоритм: отсортировать в топологическом порядке, убрать те элементы, которые перед началом и за концом, а на оставшихся пустить динамическое программирование.
    Ответ написан
    Комментировать