Архив рубрики: Статьи Руденко Олега

Недавно в буржуинской переписке видал, что операции с ULONG медленнее чем с LONG в 100-200 раз.

Недавно в буржуинской переписке промелькнуло, что операции с ULONG медленнее чем с LONG в 100-200 раз. И предполагается что это потому что базовый тип для ULONG есть DECIMAL. И вот вопросик (вероятно к Олегу 🙂 ) Что вы думаете по этому поводу? Действительно ли Decimal  базовый тип для Ulong?

Да, это так. Правда там несколько не так. Как и при работе со строками, для работы с переменными типа ULONG и DECIMAL используется спец. стек. Т.е., например, для выполнения такого кода UlongVar += 1 компилятор генерит код, в котором вызываются четыре стековые функции.

А насчет скорости выполнения — считайте сам. Тест для простого инкремента (Var += 1):

LONG примем за единицу, тогда для других типов увеличение времени обработки будет соответственно:

ULONG   — ~150 раз
DECIMAL — ~100 раз
REAL    — ~2 раза    !!!

Как видно ULONG — самый медленный. Медленнее даже чем DECIMAL! А вот от REAL, если честно я такой прыти не ожидал! Хотя чего удивляться — все операции с REAL производятся через мат.сопроцессор, а он — достойный помощник основному ядру проца.

Вот если бы ещё динамически создавать переменные…

Вот если бы ещё динамически создавать переменные…
Да все так-же, через RTL Клариона!
1. Выделяем память под новую переменную.
Для этого лучше воспользоваться этими процедурами:

!   Выделяет память и инициализирует ее двоичными нулями
  RTL::NewMem(UNSIGNED _Size),ULONG,NAME('Cla$NewMemZ')
!   Выделяет память и инициализирует ее пробелами
  RTL::NewStr(UNSIGNED _Size),ULONG,NAME('Cla$NewMemB')

_Size — размер выделяемой памяти, определяешь сам по типу переменной.
Возвращает адрес выделенного блока памяти. Читать далее

Обстановка C55F+ABC

Объясните пожалуйста следующую ситуацию и способы борьбы.

 MyVar   DECIMAL(20,0)

 MyVar = 1234567891 * 2
 STOP(MyVar) ! Выдает    -1825831514

а если написать так:

 MyVar = 1234567891
 MyVar = MyVar * 2
 STOP(MyVar) !То получим  2469135782

Может кто объяснит какого ….. он преобразует DECIMAL в LONG. Все становится просто, если вспомнить из доки, что базовым типом при вычислениях (если не задан явно тип операндов) принимается LONG.
Где в твоем примере сказано, что эти операнды имеют тип, отличный от LONG? Поэтому компилятор для вычисления данного примера использует временную переменную LONG-типа для приема результата вычисления. И уже после вычисления он эту LONG-переменную преобразует в DECIMAL.
Чтобы твой пример вычислялся правильно надо написать так:

MyVar = 1234567891,00 * 2,00

Вот теперь, при вычислении, для временного хранения результата будет использована REAL-переменная. Заметь — именно REAL! Поэтому, например, для расчета суммы лучше использовать две DECIMAL-переменные. Тогда не будет потерь в копейках и общая сумма всегда сойдется.

Кто-нить знает, что возвращает What()

Кто-нить знает, что возвращает сабж, если по всем признакам он должен вернуть массив? Что-то ведь возвращает. Но это вроде не массив, поскольку клара его как массив не распознает. Я попытался скормить его функции с параметром-массивом неопределенной длины. Она его выплюнула. Но и не переменная, поскольку попытка вывести его через message заканчивается плачевно.

WHAT() по полю-массиву возвращает ссылку на массив, описанный во внутреннем формате, принятом для нетипизированных переменных. Так называемые UFO-переменные. К сожалению, как либо легально воспользоваться данной инфой для работы с таким массивом невозможно!

Что то с драйверами…

Во-первых не True/False, а ‘on’/’off’:

 DRIVER('TOPSPEED', '/FULLBUILD = on | off' )
          [ State" = ] SEND(file, 'FULLBUILD [ = on | off ]' )
          [ State" = ] file{PROP:FULLBUILD} [ = on | off ]' )

А во-вторых, «This is the default behavior. Use the FULLBUILD driver string to modify this default behavior.» Имеется ввиду FULLBUILD = off. Так что «забыл» — это не страшно 🙂

Спасибо, что поправил! Но и ты не прав! Точнее — «врет» хелп.

На самом деле, со свойствами надо работать внимательно и избирательно. Некоторые нормально реагируют на False/True. К таким, в основном, относятся практически все свойства экранных элементов. Что же касается свойств файлов и View, то они, в основном, реагируют на НЕПУСТУЮ строку.

Т.е., например:
File{PROP:FullBuild} = True/False/’0’/’1’/’бла-бла’ — включает данное свойство файла.
Выключается свойство ТОЛЬКО так File{PROP:FullBuild} = ».

Так что, если какое-либо свойство у вас работает не так, как должно — проверьте, возможно вы включаете/выключаете его неверно.

… переменная MyValue так и остается UFO-переменной с типом ULONG …

>> Но! Именно из-за того, что в процедуре не происходит преобразование
>> типа, переменная MyValue так и остается UFO-переменной с типом ULONG.
>> А UFO-переменные ЛЮБОГО типа перед арифметическими операциями ВСЕГДА
>> преобразуются в тип REAL. Именно из-за этого преобразования значение
>> x80000001 становиться x80000000!!!
>> Ну а дальше — понятно: BXOR(x80000000,x80000000) = 0!

Если передать в процедуру LONG переменную она тоже UFO?
Но почему с ней все происходит корректно, если она тоже преобразуется к REAL?

Как я уже писал, в REAL-тип преобразуется любая переменная.
Другое дело, как это преобразование происходит! Хотя, в случае с LONG и ULONG переменными генерится абсолютно одинаковый код преобразования. Так что, или компилятор не прав и надо генерить другой код, или такие чудеса вытворяет сопроцессор, через чьи регистры и команды происходит это преобразование.

Кто нить может объяснить сей феномен (C5ee-b)

Кто нить может объяснить сей феномен (C5ee-b):

  PROGRAM
  MAP
    ChangeValue(*? MyValue)
  END

 TstValue           ULONG

  CODE
  ! Так нормально
  TstValue = 1                             ; MESSAGE(TstValue)
  TstValue = BOR (TstValue, BSHIFT(1, 31)) ; MESSAGE(TstValue)
  TstValue = BXOR(TstValue, BSHIFT(1, 31)) ; MESSAGE(TstValue)

  ! А так нет, TstValue обнуляется после BXOR
  ChangeValue(TstValue)

 ChangeValue        PROCEDURE(*? MyValue)
  CODE
  MyValue = 1                            ; MESSAGE(MyValue)
  MyValue = BOR (MyValue, BSHIFT(1, 31)) ; MESSAGE(MyValue)
  MyValue = BXOR(MyValue, BSHIFT(1, 31)) ; MESSAGE(MyValue)

Когда TstValue LONG, работает нормально.

Сразу же отвечу на несколько писем по данной теме.

Во-первых, при передаче ULONG-переменной через не типизированную ссылку СОХРАНЯЕТСЯ тип ULONG. Так что, никаких преобразований на данном этапе не происходит. Во-вторых, исходя из первого — понятно, что и в процедуре не происходит никаких явных или неявных преобразований к LONG-типу.

Но! Именно из-за того, что в процедуре не происходит преобразование типа, переменная MyValue так и остается UFO-переменной с типом ULONG. А UFO-переменные ЛЮБОГО типа перед арифметическими операциями ВСЕГДА преобразуются в тип REAL. Именно из-за этого преобразования значение x80000001 становиться x80000000!!! Ну а дальше — понятно: BXOR(x80000000,x80000000) = 0!

Так что, это — не глюк Клариона. Точнее — не совсем глюк, а документированная фича! Из-за подобной фичи, например, невозможно во View-фильтр прямо передавать ULONG-константы.

Есть процедура в которой обрабатывается глобальная очередь…

Столкнулся со следующей проблемой:
Есть процедура в которой обрабатывается глобальная очередь

GloQueue             QUEUE,TYPE
ID                            LONG
                             END
MyQueue           &GloQueue, THREAD

В пределах одного модуля пишу процедуру с описанием myProc ( Queue, long, long ) вызываю ее из этого же модуля —  myProc ( MyQueue, MyQueue.ID, curNumber ) Читать далее

GET на очередь с ANY

VY> 1.В чем отличие (в данном контексте) между операторами:
VY> RefQue &= WHAT(AnyQue, 1) и RefQue &= WHAT(AQ:ID)

Ты, вероятно, имел в виду:

RefQue &= WHAT(AnyQue,1) и RefQue &= AQ:ID

Отличие очень большое!
В первом случае оператор WHAT() не обрабатывает, как положено, поле типа ANY. Это — известная недоработка таких оператор, как WHAT/WHO/WHERE. Я уже как-то описывал все особенности их работы.
Так вот, в данном случае, WHAT() просто формирует внутреннюю UFO-переменную (внутренний аналог ANY) и назначает ей ссылку на 4-байтовую область памяти по адресу, равному адресу поля AQ:ID в буфере записи очереди AnyQue. Читать далее

Проблемка в фильтре VIEW

А никто не замечал, что фильтр от VIEW не понимает ULONG-чисел, заданных явно?!
Т.е., такой вот фильтр, например, будет работать неверно:

BrwView{PROP:Filter} = 'DOC:Index > 4000000000'

В итоге, фильтр преобразует число в LONG и выдаст все документы с индексами больше чем -294967296, что, как Вы понимаете, «немного» не то, что просили! Преобразование в LONG происходит не компилятором а именно драйвером обработки VIEW.

Для решения данной проблемы надо завести ULONG-переменную (глобальную или локальную — не важно) и забиндить ее:

ULongVar  ULONG

  Code
  BIND(ULongVar)
  ...
  ULongVar = 4000000000
  BrwView{PROP:Filter} = 'DOC:Index > ULongVar'

Вот теперь View правильно отберет документы с индексами больше чем 4 млрд.

Интересно, это — ошибка или так и должно быть?
Я так думаю, что это — именно ошибка. Так как я, в случае необходимости, могу явно задать негативное число, вместо того, чтобы гадать — преобразует View его или нет.