for flooders
:: Главная :: Решения :: Статьи :: Сайт М. Дроздова :: Файловый архив :: Книга по VFP 9 :: Русский Help Online :: OFF-LINE Форум
   Л и с о в о д ы   в с е х   с т р а н,  о б ъ е д и н я й т е с ь !!!  

Список Форумов  :: Visual Foxpro, Foxpro for DOS
   :: Помощь сайту :: 

Re: Удаление лишних пробелов
spinz

Сообщений: 5063
Дата: 13.01.18 19:08:19ОтветитьЦитировать
В общем, все не так просто, как выяснилось, фоксовый SECOND()где-то лажает. Немного модифицировал код Леонида и свой, добавил в ассемблерные функи вычисления разницы RDTSC в начале и конце выполнения. По тактам проца на моей машине моя функа занимает примерно 90 млн тактов, функа Леонида около 290 млн.

Код Леонида

  
  _test = REPLICATE("1",15000000)  
    
  res = reduce(_test , " ")    
        
    function Reduce    
    lparameter m.st, m.ch    
    if len(m.ch)<1    
    	return m.st    
    endif    
    if len(m.ch)>1    
    	m.ch=left(m.ch,1)    
    endif    
        
    if !pemstatus(_screen,"reduce_ptr",5)    
    	Declare Integer GetProcessHeap in Win32API    
    	Declare Integer HeapAlloc in Win32Api Integer, Integer, Integer    
    	Declare RtlMoveMemory in Win32API Integer, String, Integer    
        
    	local m.hhnd, m.ptr, m.st2    
        
    	m.st2= ;    
    		chr(0x55)+chr(0x89)+chr(0xE5)+chr(0x57)+chr(0x56)+chr(0x50)+chr(0x53)+chr(0x51)+;    
    		chr(0x52)+chr(0x0F)+chr(0x31)+chr(0x52)+chr(0x50)+chr(0x8B)+chr(0x75)+chr(0x08)+;    
    		chr(0xB0)+chr(0x20)+chr(0x8B)+chr(0x7D)+chr(0x10)+chr(0x8B)+chr(0x5D)+chr(0x14)+;    
    		chr(0x8B)+chr(0x0B)+chr(0x31)+chr(0xDB)+chr(0x3A)+chr(0x06)+chr(0x74)+chr(0x0E)+;    
    		chr(0x30)+chr(0xE4)+chr(0xFF)+chr(0x36)+chr(0x8F)+chr(0x07)+chr(0x46)+chr(0x47)+;    
    		chr(0x43)+chr(0x49)+chr(0x75)+chr(0xF0)+chr(0xEB)+chr(0x0D)+chr(0x80)+chr(0xFC)+;    
    		chr(0x01)+chr(0x74)+chr(0x04)+chr(0xFE)+chr(0xC4)+chr(0xEB)+chr(0xEB)+chr(0x46)+;    
    		chr(0x49)+chr(0x75)+chr(0xE1)+chr(0x0F)+chr(0x31)+chr(0x5F)+chr(0x29)+chr(0xF8)+;    
    		chr(0x5E)+chr(0x19)+chr(0xF2)+chr(0x8B)+chr(0x7D)+chr(0x0C)+chr(0x89)+chr(0x07)+;    
    		chr(0x8B)+chr(0x75)+chr(0x14)+chr(0x89)+chr(0x16)+chr(0x5A)+chr(0x59)+chr(0x5B)+;    
    		chr(0x58)+chr(0x5E)+chr(0x5F)+chr(0x89)+chr(0xEC)+chr(0x5D)+chr(0xC2)+chr(0x10)+;    
    		chr(0x00)  
        
    	m.hhnd=GetProcessHeap()    
    	m.ptr=HeapAlloc(m.hhnd,0,len(m.st2)+16)    
    	RtlMoveMemory(m.ptr,m.st2,len(m.st2))    
    	_screen.addproperty("reduce_ptr",m.ptr)    
        
    endif    
        
    local m.st3,m.ln    
    m.st3=replicate(chr(0),len(m.st)+4)    
    m.ln=len(m.st)    
        
    m.eax = 0  
        
    Declare CallWindowProc in Win32API Integer, String, Integer @, String @, Integer @   
      
    CallWindowProc(_screen.reduce_ptr, m.st+"    ", @m.eax , @m.st3, @m.ln)    
    ? m.eax  
    ? m.ln  
        
    return 1

Мой код
  
  _test = REPLICATE("1",15000000)  
    
  res = reduce(_test , " ")    
    
    function Reduce    
    lparameter m.st, m.ch    
    if len(m.ch)<1    
    	return m.st    
    endif    
    if len(m.ch)>1    
    	m.ch=left(m.ch,1)    
    endif    
        
    if !pemstatus(_screen,"reduce_ptr",5)    
    	Declare Integer GetProcessHeap in Win32API    
    	Declare Integer HeapAlloc in Win32Api Integer, Integer, Integer    
    	Declare RtlMoveMemory in Win32API Integer, String, Integer    
        
    	local m.hhnd, m.ptr, m.st2    
        
    	m.st2= ;    
    		chr(0x55)+chr(0x89)+chr(0xE5)+chr(0x9C)+chr(0x57)+chr(0x56)+chr(0x50)+chr(0x53)+;    
    		chr(0x51)+;  
    		chr(0x0F)+chr(0x31)+chr(0x52)+chr(0x50)+;  
    		chr(0x8B)+chr(0x7D)+chr(0x08)+chr(0xB0)+chr(0x20)+chr(0x8B)+;    
    		chr(0x5D)+chr(0x10)+chr(0x8B)+chr(0x4D)+chr(0x14)+chr(0x8B)+chr(0x09)+chr(0xFC)+;  
          chr(0xF3)+chr(0xAE)+chr(0x74)+chr(0x21)+chr(0x89)+chr(0xFE)+chr(0xF2)+chr(0xAE)+;    
    		chr(0x51)+chr(0x89)+chr(0xF9)+chr(0x74)+chr(0x01)+chr(0x41)+chr(0x29)+chr(0xF1)+;    
    		chr(0x4E)+chr(0x57)+chr(0x89)+chr(0xDF)+chr(0xF3)+chr(0xA4)+chr(0x89)+chr(0xFB)+;    
    		chr(0x5F)+chr(0x59)+chr(0xE3)+chr(0x09)+chr(0xF3)+chr(0xAE)+chr(0x74)+chr(0x05)+;    
    		chr(0x88)+chr(0x03)+chr(0x43)+chr(0xEB)+chr(0xDF)+;  
          chr(0x0F)+chr(0x31)+chr(0x5F)+chr(0x29)+chr(0xF8)+chr(0x5E)+chr(0x19)+chr(0xF2)+;  
          chr(0x8B)+chr(0x7D)+chr(0x0C)+chr(0x89)+chr(0x07)+chr(0x8B)+chr(0x75)+chr(0x14)+;  
          chr(0x89)+chr(0x16)+;  
    		chr(0x59)+;    
    		chr(0x5B)+chr(0x58)+chr(0x5E)+chr(0x5F)+chr(0x9D)+chr(0x89)+chr(0xEC)+chr(0x5D)+;    
          chr(0xC2)+chr(0x10)+chr(0x00)  
        
    	m.hhnd=GetProcessHeap()    
    	m.ptr=HeapAlloc(m.hhnd,0,len(m.st2)+16)    
    	RtlMoveMemory(m.ptr,m.st2,len(m.st2))    
    	_screen.addproperty("reduce_ptr",m.ptr)    
        
    endif    
        
    local m.st3,m.ln    
    m.st3=replicate(chr(0),len(m.st)+4)    
    m.ln=len(m.st)    
    
    m.eax = 0  
        
    Declare CallWindowProc in Win32API Integer, String, Integer @, String @, Integer @   
      
    CallWindowProc(_screen.reduce_ptr, m.st+"    ", @m.eax , @m.st3, @m.ln)    
    ? m.eax  
    ? m.ln  
        
    return 1

На экран выводится разница между конечным и начальным значением младшей и старшей части 64-битного счетчика тактов при выполнении функи.

P.S.
Существует какой-то косяк при таком вызове ассемблерного кода в пределах одного сеанса фоксового IDE. Если после выполнения моего кода, не закрывая фокс, запустить код Леонида,
то он выдает практически идентичные моим значения. При свежем запуске - в 3,5 раза больше.
Втф?



Исправлено: spinz, 13.01.18 19:11
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
leonid

Сообщений: 2520
Откуда: Рига
Дата: 13.01.18 19:31:04ОтветитьЦитировать
vic7tar
А почему бы действительно не использовать родной STRTRAN, или я не по теме?

По теме, но не в дугу. Ваша функция STRTRAN only обломится уже на такой строчке

inp_s = "a         b"

Ну а если по скорости, то попробуйте

inp_s = space(1000000) + REPLICATE("a", 15000000)

Естественно, уберите распечатку строк, да и nc установите в единичку. На вторую функцию при этом смотреть не надо, она все равно неправильный результат выдаст.
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
spinz

Сообщений: 5063
Дата: 13.01.18 19:31:20ОтветитьЦитировать
Справделивости ради замечу, если заменить
_test = REPLICATE("1",15000000)

на

FOR i = 1 TO 1024*3
_test = _test + SPACE(1024) + REPLICATE("1",1024)
ENDFOR

то результаты опять практически идентичны. Т.е. код Леонида сильно проигрывает только когда в строке преимущественно непробельные символы, за счет множественного исполнения группы инструкций вместо одной rep movsb.
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
spinz

Сообщений: 5063
Дата: 13.01.18 19:46:25ОтветитьЦитировать
Хе-хе, а вот для такой строки

FOR i = 1 TO 1024*1024
_test = _test + SPACE(4) + REPLICATE("1",4)
ENDFOR

мой код проигрывает в 5(!) раз
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
vic7tar

Сообщений: 48
Дата: 13.01.18 20:27:04ОтветитьЦитировать
leonid
vic7tar
А почему бы действительно не использовать родной STRTRAN, или я не по теме?

По теме, но не в дугу. Ваша функция STRTRAN only обломится уже на такой строчке

inp_s = "a         b"

Ну а если по скорости, то попробуйте

inp_s = space(1000000) + REPLICATE("a", 15000000)

Естественно, уберите распечатку строк, да и nc установите в единичку. На вторую функцию при этом смотреть не надо, она все равно неправильный результат выдаст.
Ну и что?
STRTRAN only (вложенные STRTRAN-ы) - это просто лишь пример для конкретной строки из вашего же поста, и все. Извините, но тут asm проигрывает встроенной функции.
Для s = space(1000000) + REPLICATE("a", 15000000) - да, asm вычисляет в двадцать раз быстрее.
А если перейти к более реальным данным, какой должен быть пример строки для тестирования, чтобы считать его общим?



Исправлено: vic7tar, 13.01.18 20:28
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
Simple777

Сообщений: 19366
Дата: 13.01.18 20:32:40ОтветитьЦитировать
Если речь идет о косяках юзера во время ввода/корректировки, то в 90% случаев это будет двойной пробел вместо одинарного. Вот на такой строке и надо проводить сравнение.
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
vic7tar

Сообщений: 48
Дата: 13.01.18 20:37:50ОтветитьЦитировать
Тем более, если речь идет об описках при вводе с клавиатуры - зачем такие сложные решения?
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
leonid

Сообщений: 2520
Откуда: Рига
Дата: 13.01.18 20:55:12ОтветитьЦитировать
vic7tar
STRTRAN only (вложенные STRTRAN-ы) - это просто лишь пример для конкретной строки из вашего же поста, и все.

Вы серьезно считаете, что для каждой конкретной строки нужно писать свою собственную функцию? Например для строки

str = "a  "

я могу написать функцию, которая сработает значительно быстрее Вашей

function reduce  
  lparameter m.str  
  return left(m.str, 2)

И что из этого?
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
spinz

Сообщений: 5063
Дата: 13.01.18 21:42:09ОтветитьЦитировать
Сделал небольшой тюнинг кода, теперь копирование идет двордами. Результат значительно улучшился - сейчас мой код проигрывает только когда последователности совсем короткие, порядка 20 символов
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
spinz

Сообщений: 5063
Дата: 13.01.18 21:53:38ОтветитьЦитировать
Пришла щас в голову мысль заменить SCASB на SCASW - одиночные пробелы нас ведь все равно не интересуют. Это может сушественно улучшить перфоманс
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
Igor Korolyov

Сообщений: 31691
Дата: 14.01.18 00:03:22ОтветитьЦитировать
Учитывая что современные процессоры x86/x64 архитектуры вовсе не выполняют x86/x64 "инструкции", как делали когда-то примитивные 286/386 и даже 486 камни...
habrahabr.ru
В общем результат "оптимизации" без тонкого понимания работы конкретной микроархитектуры конкретного процессора - сродни методу глубоко научного тыка. Вот возьмёшь банальный NOP (пустую, "ненужную" инструкцию) пропишешь между парой команд и скорость внезапно выросла
Всё же более/менее сложные компиляторы с того же C пытаются что-то оптимизировать для лучшей эффективности работы современных мега-CPU... Так что возможно самым лучшим было бы переписать код на си, откомпилить тем же интеловским компилятором и посмотреть на результат


------------------
WBR, Igor
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
spinz

Сообщений: 5063
Дата: 14.01.18 00:11:35ОтветитьЦитировать
Так тут дело не в оптимизации ассемблерного кода, а в оптимизации алго. Если мы ищем по символам, например, то компилятор не нарисует код, который будет искать по словам.
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
wow1970

Сообщений: 29
Дата: 14.01.18 00:16:43ОтветитьЦитировать
Все лишние пробелы удаляю так.

Function TextDropSpace  
  	Lparameters tcText  
  	Return ALLTRIM(chrtran(strtran(strtran(tcText, [  ], [ ] + chr[0]), chr[0] + [ ], []), chr[0], []))  
  EndFunc



Исправлено: wow1970, 14.01.18 00:20
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
spinz

Сообщений: 5063
Дата: 14.01.18 00:26:34ОтветитьЦитировать
Это просто откровение, спасибо. СПАСИБО!
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
Igor Korolyov

Сообщений: 31691
Дата: 14.01.18 00:33:35ОтветитьЦитировать
Simple777
Дак никто не спорит, что связка DOS+FPD хуже, нежели WIN+FPD.
FPD - продукт для DOS. В любой другой ОС он исполняется посредством эмулятора. Никакой эмулятор не может работать лучше/эффективнее/надёжнее нежели изначальная "эталонная" реализация. То что эмулятор позволяет защитить другие программы от того кода который работает внутри него, никак не говорит о том что он "надёжнее" оригинального DOS-а. В конце концов все эмулируемые программы запускаются как потоки в рамках одного общего ntvdm процесса - сбой в оном замечательно угробит ВСЕ запущенные DOS-программы.
Simple777
Какой бы ни была устаревшей DOS, с каждой новой версией Windows среда псевдо-DOS таки улучшалась.
Боюсь ты не понимаешь реального положения вещей... Со времени выхода MSDOS 7 - который являлся базовой, или лучше сказать "сопутствующей" ОС для линейки Win9x данная ОС не развивалась, не улучшалась, и, конечно же никак не могла "становиться лучше". А ЛЮБАЯ софтовая (есть ещё и "железячная" - через VirtualBox и ему подобные системы, но там таки нужно поверх виртуального железа установить один из "настоящих" вариантов DOS) эмуляция DOS - хоть через ntvdm хоть через dosbox - по определению ОГРАНИЧЕНА и работает хуже чем непосредственно работал бы DOS.
Как доступная для понимания аналогия - это запуск FPD кода в VFP - тоже своего рода эмуляция.
Simple777
Думается, что в VFP ситуация с критическими ошибками не такая прозрачная.
Смотря какими ошибками. Когда DOS вместе с запущенной программой (хоть FPD хоть какой другой) весело зависал или перегружал машину, о какой "прозрачности" могла идти речь?
И да, я видел вполне достаточно крахов DOS. И уж точно "непрозрачных" крахов VFP я видел ненамного больше То что кому-то и до поры до времени "непонятно" почему его убого написанный код или неправильно использованная компонента (или НЕНУЖНАЯ компонента - некоторые любят всякую каку тащить в программу, даже не задумываясь о том что это там совершенно не нужно) завалила систему, вовсе не значит что это была "непрозрачная критическая ошибка"
Это как в том анекдоте про чучку отпилившего сук на котором сам же и сидел "У-у-у, шаман..."


------------------
WBR, Igor
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
spinz

Сообщений: 5063
Дата: 14.01.18 00:46:22ОтветитьЦитировать
Если говорить о досе в целом, не привязываясь к фпд, то нужно заметить, что дос дает полный контроль над средой выполнения - нет разграничения по кольцам защиты - и значит теоретически годный код может исключить влияние ОС на систему. В случае с VFP это очевидно невозможно и кодер сильно зависит от ОС и ее разрабочиков
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
Igor Korolyov

Сообщений: 31691
Дата: 14.01.18 00:52:09ОтветитьЦитировать
vic7tar
А почему бы действительно не использовать родной STRTRAN, или я не по теме?
Потому что он производит кучу ненужных копирований данных из одного места памяти в другое.
Справедливости ради - вызов ассемблерной вставки через DECLARE DLL, и принятие назад обработанной строки (даже не суть важно той же самой, или отдельной, "новой") тоже производит ненужное копирование байтиков в памяти. С этой стороны использование FoxAPI будет гораздо выгоднее - можно напрямую залезть в байтики ОДНОЙ строки. Правда для этой задачи ( в отличие от задачи "реверса/переворачивания" строки) всё равно придётся инициировать процесс перераспределения памяти, а значит и скорее всего "копирования" значения строки - т.к. результат в случае удаления даже одного единственного "лишнего" пробела будет отличаться по размеру от исходной строки...
Пойми - тут не идёт речь о "практическом применении" для задачи "убрать мусор из 100 введенных символов". Это чисто теоретическая задача по поиску "идеального" алгоритма под весьма "надуманные" исходные данные.

Simple777
Если речь идет о косяках юзера во время ввода/корректировки, то в 90% случаев это будет двойной пробел вместо одинарного.
Совершенно необязательно. Такого рода ошибка скорее возникнет не при "вводе по символам", а при копировании текста из внешнего источника (того же Word/Excel или там письма присланного по email). А в этих системах, в свою очередь, зачастую неграмотные пользователи вместо работы с инструментами форматирования (те же отступы, колонки, позиции табуляции) предпочитают "подравнять" текст пробелами. Плюс копирование текста из браузера - там я вообще не понимаю что/почему/как работает, но чем дальше, тем сложнее адекватно что-то выделить... Нехорошие веб-девелоперы/дизайнЁры понасуют г*на на страницы, так что банальные пару строк с названием того же товара хрен выделишь не захватив 100500 абсолютно ненужных элементов... Хуже таких рукожопов только те, что картинки с буквами вместо текста ставят. Я б их в одну камеру со спаммерами сажал


------------------
WBR, Igor
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
Igor Korolyov

Сообщений: 31691
Дата: 14.01.18 01:01:33ОтветитьЦитировать
spinz
Если говорить о досе в целом, не привязываясь к фпд, то нужно заметить, что дос дает полный контроль над средой выполнения - нет разграничения по кольцам защиты - и значит теоретически годный код может исключить влияние ОС на систему.
Только для систем ЦЕЛИКОМ реализующих все функции ОС. По сути там DOS лишь как загрузчик выступает. Послде запуска проги его сервисы уже более не используются. Не очень распространённые, однако системы. Это типа Windows9x - запускается из DOS, но потом её не использует
Исходя из общих соображений, квалификация разработчиков "прикладного" софта не позволит такое провернуть. Разработчики же "систем программирования", хотя и получше будут, но тоже вряд ли дотянут до уровня писателей ядер ОС. А главное они не настолько психи, чтобы в каком-нить FPD реализовывать своё ядро ОС - чтобы не зависеть от тех же функций чтения/записи файлов, работы с клавиатурой/мышкой, поддержку сетей и т.п.
Это Симпла по простоте (он же человек простой, так и написал в нике ) может считать что FPD "сам по себе" работает, никакими сервисами ОС не пользуется, а при работе внутри эмулятора ntvdm в той же WinXP вообще божит - работает на какой-то волшебной супер-навороченной версии DOS-а и не страдает от ошибок в базовой ОС (ну он же не в WinXP работает, а в досе то чёрный экран и command.com в наличии)...


------------------
WBR, Igor
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
Igor Korolyov

Сообщений: 31691
Дата: 14.01.18 01:05:08ОтветитьЦитировать
wow1970
Все лишние пробелы удаляю так.
Function TextDropSpace  
  	Lparameters tcText  
  	Return ALLTRIM(chrtran(strtran(strtran(tcText, [  ], [ ] + chr[0]), chr[0] + [ ], []), chr[0], []))  
  EndFunc

strtran - перераспределение памяти, копирование строки. Два раза.
chrtran без замены 1-на-1 (т.е. с "вырезанием" символов) - перераспределение памяти, копирование строки.
ALLTRIM - перераспределение памяти, копирование строки.
Итого 4 операции по копированию символов туда-сюда, выделению и освобождению памяти.

И это в теме сведенной до оптимизации ассемблерного кода


------------------
WBR, Igor
Ratings: 0 negative/0 positive

Re: Удаление лишних пробелов
wow1970

Сообщений: 29
Дата: 14.01.18 01:09:32ОтветитьЦитировать
А, сорри! Мне показалось, что тема от том как удалить лишние пробелы.
Ratings: 0 negative/1 positive



Извините, только зарегистрированные пользователи могут писать в этом форуме.

On-line: 38 Chemberzhy Божья_коровка  and Guests: 36


© 2000-2018 Fox Club 
Яндекс.Метрика