HIBYTE, LOBYTE, HIWORD, LOWORD, WORD, DWORD, SHIFT

Здесь можно найти готовые «кирпичики» — части кода, пригодные для построения более крупных проектов, а также решения различных типовых и не очень задач на VB.

Модератор: Brickgroup

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

HIBYTE, LOBYTE, HIWORD, LOWORD, WORD, DWORD, SHIFT

Сообщение GSerg » 09.02.2005 (Ср) 10:51

Производится пробный запуск фабрики :)
Для начала - что-нибудь маленькое и простенькое...
Вложения
modDWORD.zip
HIBYTE, LOBYTE, HIWORD, LOWORD, WORD, DWORD, SHIFT
(1022 байт) Скачиваний: 586
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

kuhtiov
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 419
Зарегистрирован: 03.08.2006 (Чт) 5:31

Сообщение kuhtiov » 03.10.2006 (Вт) 12:51

Это по поводу чего?

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 03.10.2006 (Вт) 12:55

Читать умеем? во второй строчке описание.
Изображение

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 04.10.2006 (Ср) 16:06

Кстати, можно заменить деление на целочисленное деление.
Побыстрее должно быть.
Lasciate ogni speranza, voi ch'entrate.

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 04.10.2006 (Ср) 17:19

если переделать это в класс, то можно и проинициализировать :wink:

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Сообщение arthur2 » 29.05.2008 (Чт) 19:21

Вот эта функция работает не корректно:
Код: Выделить всё
Public Function LOWORD(ByVal DblWord As Long) As Integer
  LOWORD = DblWord And &HFFFF&
End Function

Если передать отрицательное число, она загибается. Переполнение.

Подскажите, как поправить, чтобы сильно не замедлить?

А ещё интересно, что делает функция Shift? Где это можно применить?
Артур
 
   

ANDLL
Великий гастроном
Великий гастроном
Аватара пользователя
 
Сообщения: 3450
Зарегистрирован: 29.06.2003 (Вс) 18:55

Сообщение ANDLL » 29.05.2008 (Чт) 19:30

А ещё интересно, что делает функция Shift?
Умножает на два в степени n.
Если возьмешь любое число, распишешь в виде ноликов и единичек, а потом умножишь на два(да еще и несколько раз), то вероятно сразу поймешь. Ну или просто поищи bitwise shift :D
Гастрономия - наука о пище, о ее приготовлении, употреблении, переварении и испражнении.
Блог

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16473
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 29.05.2008 (Чт) 21:41

1)
Код: Выделить всё
Public Function LOWORD(ByVal DblWord As Long) As Integer
    LOWORD  = DblWord And &H7FFF&
    If DblWord And &h8000& then LOWORD = LOWORD or &h8000%
End Function


2) Использовать GetMem2

А ещё интересно, что делает функция Shift?

У него (у GSerg'а) эта функция может делать 4 вещи: сдвигать биты влево, сдвигать биты вправо, и аналогично - вращать влево, и вращать вправо.

Подбробнее - [url=http://ru.wikipedia.org/wiki/Битовый_сдвиг]здесь[/url]. (Вращение там называется циклическим сдвигом).

Где это можно применить?

Да хоть в твоей проблеме - заменить LOWORD(x) на HIWORD(SHIFT(smShiftLeft, x, 16)). Только это более криво, чем предложенный выше вариант.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Сообщение arthur2 » 29.05.2008 (Чт) 21:50

ANDLL
То есть, это побитовое смещение? Тогда понятно. Ну, ShiftLeft, ShiftRight - это смещение влево-вправо. А что такое RotateLeft?

И всё-таки, первый вопрос интересней. Как код LOWORD поправить? На сколько я понял, в hex-то она даёт правильный ответ.

НО:

&hffff=-1
А вот &hffff&=65535, что в intege помещаться отказывается

Можно ли исправить, не пребегая к копимемери?
Артур
 
   

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Сообщение arthur2 » 29.05.2008 (Чт) 21:52

Хакер
Понятно!

То есть, без перемещения памяти, чисто логически - не получится? обидно (а кирпич-то, кстати, нужно поправить).

Да и с loword в кирпиче тоже не всё в порядке - если там поставить целочисленное деление, то функция ошибается на один в некоторых случаях, а если обычное - то ошибается на один в других некоторых случаях.

Чуть позже:
Прости, туплю - мне показалось, у тебя там цитата, а там исправленный код! Работает на ура - спасибо! :lol:
Артур
 
   

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16473
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 29.05.2008 (Чт) 22:21

То есть, без перемещения памяти, чисто логически - не получится?

Что значит "чисто логически"?
Что значит "без перемещения памяти - не получится"? Где ты увидел в моём примере признаки перемещения памяти??

Да и с loword в примере тоже не всё в порядке - если там поставить целочисленное деление, то функция ошибается на один в некоторых случаях, а если обычное - то ошибается на один в других некоторых случаях.

Чё? Какое ещё деление? Куда подставить?

И всё-таки, первый вопрос интересней. Как код LOWORD поправить? На сколько я понял, в hex-то она даёт правильный ответ.

В хексе всё, разумеется, даёт правильный ответ.
Здесь Overflow происходит главным образом из-за конвертации Long-а в Integer. Дело в том, что для Singned-типов (а вб-шные Integer и Long таковыми и являются) конвертация - чуть более интеллектуальное действие, чем простое копирование двух-байт. На словах это можно описать так:
Отдельно берётся знаковый бит, и отдельно берутся биты числа.

Знаковый бит устаналивается в обоих переменных одинаково , числовые биты копируются, причём при Long2Int-конвертации, они проверяются на возможность втиснутсья в Int-переменную. При этом лишние биты заполняются единицами или нулями, в зависимости от знаового бита.

Именно из-за этой интеллектуальной особенности приведения типов, когда ты преобразуешь -1% в Long, ты получаешь -1&, а не 65535&, как получил бы при использовании CopyMemory.

Можно ли исправить, не пребегая к копимемери?

Я ведь вроде бы показал, что можно.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Сообщение arthur2 » 29.05.2008 (Чт) 22:46

Хакер
Стоп-стоп-стоп... Я же уже сказал, что ступил, не туда поглядел. Я про getmem и двиг битов :D

Исправленный код работает на ура - ещё раз спасибо

Чё? Какое ещё деление? Куда подставить?

а это про hiword из кирпича (кажется, слова уже заплетаются, пора спать идти, пол-третьего как ни как)

Код: Выделить всё
Public Function HIWORD(ByVal DblWord As Long) As Integer
  HIWORD = DblWord / &H10000
End Function

Для некоторых чисел она ошибается на один. Если поменять / на \ как предложил alibek, она исправляется, но начинает ошибаться для других чисел.

А вот так:
?hex(HIWORD(&hfff08001))
FFF1

?hex(HIWORD(&hffff8001))
0

она ошибается в любом варианте! :lol:

Именно из-за этой интеллектуальной особенности приведения типов...

Ну, в общем, это я более-менее понимаю. &hffff& на самом-то деле &h0000ffff, поэтому оно и положительное - бит знака сброшен.
Артур
 
   

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16473
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 30.05.2008 (Пт) 7:51

Такой вариант устроит?
Код: Выделить всё
Public Function HIWORD(ByVal DblWord As Long) As Integer
  HIWORD = ((DblWord And &HFFFF0000) \ &H10000)
End Function
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Сообщение arthur2 » 30.05.2008 (Пт) 8:33

В общем, методом своего любимого тыка дорылся-таки.

"Неправильное" округление при делении получается при отрицательных числах. Функция ошибается на один всегда, если установлен хотя бы один бит в loword.

В связи с чем исправил так:
Код: Выделить всё
Public Function HIWORD(ByVal DblWord As Long) As Integer
  HIWORD = DblWord \ &H10000
  If DblWord < 0 Then
    If DblWord And &HFFFF& Then HIWORD = HIWORD - 1
  End If
End Function

Функция больше не ошибается. Но, мне кажется, то же самое можно сделать как-то по-оптимальнее. А?
Артур
 
   

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Сообщение arthur2 » 30.05.2008 (Пт) 8:35

Хакер
Упс... Пока я методом тыка, ты уже исправил! Спасибо! :lol:

Теперь бы автору просигналить, чтобы поправил кирпич...
Артур
 
   

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16473
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 30.05.2008 (Пт) 8:45

Теперь бы автору просигналить, чтобы поправил кирпич...

На форуме был большой бунт, "после чего автор красиво свалил оттуда, махнув хвостом" (с) Мышъх.
Последний раз редактировалось Хакер 30.05.2008 (Пт) 11:51, всего редактировалось 1 раз.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Сообщение arthur2 » 30.05.2008 (Пт) 11:29

А чё за буча-то была? Великая октабрьская?

Сделат тест на скорость:
Код: Выделить всё
Public Sub testLo()
Dim l As Long, tc As Long, k As Long
tc = GetTickCount
For l = 0 To 10000000
  loWord k
Next
Debug.Print "без апи"; GetTickCount - tc

tc = GetTickCount
For l = 0 To 10000000
  loWord_ k
Next
Debug.Print "copyMem"; GetTickCount - tc

End Sub

Public Function loWord(ByVal DblWord As Long) As Integer
    loWord = DblWord And &HFFFF&
    If DblWord And &H8000& Then loWord = loWord Or &H8000
End Function

Public Function loWord_(ByVal DblWord As Long) As Integer
  CopyMemory loWord_, DblWord, 2
End Function


Получилось:
без апи 2875
copyMem 2531

Практически, поровну. Но апи всё-же чуточку быстрее (в прошлом варианте и правда было быстрее где-то на треть, но нафига быстрее, если с косяком :) )

Появился ещё такой вопрос: параметры приходят в процедуру рядышком? можно ли вот так сделать:

Код: Выделить всё
Public Sub HLWord(dw As Long, hW As Integer, lW As Integer)
   CopyMemory lW, dw, 4
'  Debug.Print Hex(dw)
'  Debug.Print Hex(hW); " "; Hex(lW)
End Sub

Вроде бы, работает - но не черевато ли это каким глюком?..
Артур
 
   

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 30.05.2008 (Пт) 11:40

Да нет, с числовыми параметрами глюков быть не должно.
Но если нужно будет заниматься поддержкой кода, это не самая лучшая реализация.
Lasciate ogni speranza, voi ch'entrate.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16473
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 30.05.2008 (Пт) 11:44

Public Sub testLo()
Dim l As Long, tc As Long, k As Long
tc = GetTickCount
For l = 0 To 10000000
loWord k
Next
Debug.Print "без апи"; GetTickCount - tc

tc = GetTickCount
For l = 0 To 10000000
loWord_ k
Next
Debug.Print "copyMem"; GetTickCount - tc

End Sub

Public Function loWord(ByVal DblWord As Long) As Integer
loWord = DblWord And &HFFFF&
If DblWord And &H8000& Then loWord = loWord Or &H8000
End Function

Public Function loWord_(ByVal DblWord As Long) As Integer
CopyMemory loWord_, DblWord, 2
End Function


1) Нельзя так измерять скорость. Нельзя ни при каких обстоятельствах использовать Declare Function для API-функций, где важна скорость.

2) Использовать CopyMemory для копирования двух байт - извращенство. Видел бы, сколько там кода, внутри CopyMemory, а сколько внутри GetMem2.

3) Судя по тому, что ты используешь Debug.Print, ты замеряешь скорость не в скомпилированном варианте, а в IDE. А этого нельзя делать - в IDE твой код компилируется в P-code, а он хоть-как будет медленнее нативного (внутри CopyMemory).

Появился ещё такой вопрос: параметры приходят в процедуру рядышком? можно ли вот так сделать:

Да. Но лучше для первого аргументы использовать ByVal.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 30.05.2008 (Пт) 12:06

Я думаю при количестве циклов аж в 10000000 и нескольких запусках, можно полагаться и на IDE. Для получения точного результата нужно использовать VB Watch2.
Лучший способ понять что-то самому — объяснить это другому.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16473
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 30.05.2008 (Пт) 12:43

Antonariy
Нельзя. Отношение времён будет одинаковым что при 100 циклах, что при 10000000. Случайная погрешность в последнем случае будет меньше, да. Но зато будет лишнее время засчёт работы самого цикла.

Взять хотя бы то, что в IDE после вызове любой API-функции осуществляется проверка валидности структуры стека.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Сообщение arthur2 » 30.05.2008 (Пт) 12:47

alibek
Но если нужно будет заниматься поддержкой кода...

В том смысле, что потом не пойму, чё это такое? а какая реализация лучше?

Хакер
1. Способ - какой придумался. Обе функции из win32.tlb А как измерять лучше?

2. Это в том смысле, что лучше getmem2? я просто не очень с ней знаком :oops:

3. Да, это я снова ступил. Заменил на msgbox и скомпилировал - без апи почти в 5 раз быстрее!
без апи 109
copyMem 484

А вот разница с проектом, где функции из win32.tlb и где Declare почти не заметна :lol:
Она есть, но очень маленькая
Да. Но лучше для первого аргументы использовать ByVal
Это я не понял. В смысле, в деклорации апи? Если byval, то передавать надо не переменную, а указатель? или как? Или в смысле первого аргумента моей процедуры( byval dw As Long )? А почему? внутри же она всё равно не изменяется?
Артур
 
   

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16473
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 30.05.2008 (Пт) 13:02

1. Способ - какой придумался. Обе функции из win32.tlb А как измерять лучше?

Тогда ок.

2. Это в том смысле, что лучше getmem2? я просто не очень с ней знаком

http://www.vbstreets.ru/VB/Articles/65973.aspx

А вот разница с проектом, где функции из win32.tlb и где Declare почти не заметна :D

Это очень просто объяснить: ты используешь всего-лишь одну API-функция. Компилятор VB для многократных вызовов Declare-функций используется регистр ESI для хранения указателя на функцию.

При этом, в регистр ESI указатель попадает до первого использования. Там де осуществляется проверка ячейки кастомной таблицы импорта (есть внутри VB-программ такая, для всех Declare-функций) и вызов DllFunctionCall (которая на самом деле нифига не Call) в начеле безопасного контекста.

Но стоит тебе вынести вызов loWord k и вызов loWord_ k в отдельные функции Fun и Fun_, и вставить в циклы вызовы функций Fun и Fun_ -- как ты заметишь значительную разницу.

Ибо между вызовами функции Fun_ хранить указатель в ESI уже не получится, и код будет вынужден каждый раз его получать из ячейки кастомной таблицы импорта.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 30.05.2008 (Пт) 13:16

arthur2 писал(а):В том смысле, что потом не пойму, чё это такое? а какая реализация лучше?

Именно. Напиши обычно, с использованием логических операторов (AND и целочисленное деление).
Будет не так изящно, но зато ты (или кто другой) никогда не застрянут на этом месте, пытаясь понять, что делает код.
Lasciate ogni speranza, voi ch'entrate.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Сообщение arthur2 » 30.05.2008 (Пт) 14:01

Antonariy
нужно использовать VB Watch2.
А что это? Поиском не ищется :cry:

Хакер
Но стоит тебе вынести вызов loWord k и вызов loWord_ k в отдельные функции Fun и Fun_, и вставить в циклы вызовы функций Fun и Fun_ -- как ты заметишь значительную разницу.
Спасибо, понял! А есть у .tlb подводные камни? Скажем, если на машине нет нужной библиотеки, то при Declare вызов такой функции легко ловится обработчиком ошибок. А с .tlb - будит ли так же?

alibek
Будет не так изящно, но зато ты (или кто другой) никогда не застрянут на этом месте, пытаясь понять, что делает код.
Ага! И, как выяснилось - ещё и быстрее! :lol: (Но сам способ интересный - может где в другом месте использую. Да и в чужом коде увижу - теперь соображу)

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

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16473
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 30.05.2008 (Пт) 14:12

Спасибо, понял! А есть у .tlb подводные камни? Скажем, если на машине нет нужной библиотеки, то при Declare вызов такой функции легко ловится обработчиком ошибок. А с .tlb - будит ли так же?

Подводных камней нет. .tlb предоставляет возможность воспользоваться родным виндозным механизмом импорта функций из DLL. Родной виндовый загрузчик при подгрузке DLL в случае её отсутсвия будет вынужден обрадовать тебя таким сообщением:
Изображение
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Сообщение arthur2 » 30.05.2008 (Пт) 14:47

Хакер
Я вот про что:

Код: Выделить всё
Option Explicit
Private Declare Function lalala Lib "figlimigli.dll" () As Long
Private Declare Function trampampam Lib "kernel32" () As Long

Private Sub Form_Load()
  On Error Resume Next
  lalala
  trampampam
End Sub

У меня нет библиотеки figlimigli.dll, а в kernal32 нет функции trampampam, но скомпилированный ехе нормально загружает окно и ничего не сообщает. Будет ли так же с .tlb? (я бы сам проверил, да не придумаю, как)
Артур
 
   

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16473
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 30.05.2008 (Пт) 14:51

Ты перечитай верхнее сообщение. А то, кажется, ты его не понял. Если так и не поймёшь, я перефразирую.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Сообщение arthur2 » 30.05.2008 (Пт) 14:55

Да, не понял.
Артур
 
   

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16473
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 30.05.2008 (Пт) 14:59

Может у тебя отображение картинок выключено?

Ещё раз:
Библиотеки, функции которых импортируеются статическим импортом, грузятся при загрузке EXE.

Если какая-то библиотека будет не найдена, отобразится сообщение, скриншот которого я выше показал, и загрузка будет остановлена на этом. Т.е. приложение не запустится. (Ну а толку-то его запускать, если библиотеки нет?)
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

След.

Вернуться в Кирпичный завод

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2

    TopList