20.05.2010, 17:15 | #1 |
Участник
|
Табличный процессор
Коллеги, кто-нибудь сталкивался с вопросом как устроен изнутри табличный процессор, как у него получается мгновенно вычислять достаточно большой объем данных? Может, есть ссылки, книги etc?
|
|
20.05.2010, 17:39 | #2 |
Moderator
|
Уж не собираетесь ли Вы... Excel того... подвинуть плечом?!
А если серьезно, то в стародавние, почти былинные времена был у Борланда такой замечательный продукт, как Turbo Pascal. Так вот, в версии то ли в 6.0, то ли в 7.0 (а может и в обеих) были исходники демки табличного процессора. Напомню, что у этой фирмы был (есть?) свой собственный табличный процессор Quattro Pro. Так что они знавали толк в этом деле. |
|
|
За это сообщение автора поблагодарили: Lemming (5). |
20.05.2010, 18:42 | #3 |
Microsoft Dynamics
|
О чем идет речь? Какой табличный процессор? Какие объемы данных считаются достаточно большими?
Современные процессоры для настольных ПК могут выполнять десятки миллиардов операций в секунду http://www.intel.com/support/ru/proc.../cs-023143.htm. Сложить один миллиард чисел с другим миллиардом чисел может занять по времени меньше секунды. |
|
20.05.2010, 21:46 | #4 |
Участник
|
вопрос не просто в сложении чисел как таковом, а в их организации из реляционной модели в модель процессора, оперирования с ней и обратной конвертации.
ну те то что бы подвинуть, хотя бы прикинуть... что почем |
|
21.05.2010, 08:59 | #5 |
Microsoft Dynamics
|
Если вы говорите о табличном процессоре, как понимаю, вы говорите об программах подбных Microsoft Excel? Если так, то причем здесь реляционная модель?
Если вспомнить устройство уже упомянутой программы входящей в комплект Turbo Pascal, то там в качестве внутренней структуры хранения данных в первых версиях использовался массив X++: const FXMax: Char = 'G'; { Maximum number of columns in spread sheet } FYMax = 21; { Maximum number of lines in spread sheet } type Anystring = string[70]; SheetIndex = 'A'..'G'; Attributes = (Constant,Formula,Txt,OverWritten,Locked,Calculated); { The spreadsheet is made out of Cells every Cell is defined as } { the following record:} CellRec = record CellStatus: set of Attributes; { Status of cell (see type def.) } Contents: String[70]; { Contains a formula or some text } Value: Real; { Last calculated cell value } DEC,FW: 0..20; { Decimals and Cell Whith } end; [B] Cells = array[SheetIndex,1..FYMax] of CellRec;[/B] ... |
|
21.05.2010, 09:34 | #6 |
Участник
|
Используем решение, в котором поженены ActiveX Excel и сама Axapta, часть вычислений делает ActiveX Excel и потом значение считываются и записываются в Axapta, порой это не так быстро как хотелось бы и достаточно сложно в настройках.
|
|
21.05.2010, 10:00 | #7 |
Участник
|
Это решение случайно не Axcision ? (Если так, то я бы на вашем месте подумал над установкой какой-нибудь более традиционной аналитической системы...)
|
|
21.05.2010, 10:55 | #8 |
Moderator
|
|
|
21.05.2010, 12:16 | #9 |
Участник
|
нет это не Axcision, называть не буду дыба не заниматься рекламой/антирекламой
Порядок примерно такой 150 строк*30 столбцов 4500 ячеек. Десятую часть из них вычисляет сам Excel т.е. около 450, считывание занимает в среднем секунд 5-10, т.е. гораздо дольше чем сам Excel считает и если нужно ввести 900 значений *5-10 секунд то полная обработка занимает около о 1часа - до 2,5 часов |
|
21.05.2010, 12:26 | #10 |
Moderator
|
Цитата:
Сообщение от Serg
Порядок примерно такой 150 строк*30 столбцов 4500 ячеек. Десятую часть из них вычисляет сам Excel т.е. около 450, считывание занимает в среднем секунд 5-10, т.е. гораздо дольше чем сам Excel считает и если нужно ввести 900 значений *5-10 секунд то полная обработка занимает около о 1часа - до 2,5 часов
что вы чуть выше называете "ActiveX Excel"? OWC Spreadsheet или всё-таки большой "Microsoft Excel"? что такое "считывание"? Аксапта читает из "Excel" или пользователь считывает с бумажки? спрашиваю про пользователя, потому что тогда становится логичным "ввести (!) 900 значений", умноженное на "время считывания (!)"... |
|
21.05.2010, 12:41 | #11 |
Участник
|
речь о OWC Spreadsheet, пользовтаель в нем вводит данные, далее OWC Spreadsheet по формулам расчитывает показатели и их нужно считать т.е. просто activeCell = xExcelSheetManager.selected(Row, Сol) и записать в таблицу. Проблема еще в том, что нет данных какая имеено ячейка пересчиталсь и приходиться их считывать все;
|
|
21.05.2010, 13:35 | #12 |
Moderator
|
Я бы воспользовался методом чтения из Excel (он подходит и для Spreadsheet), предложенным AndyD'ом здесь: Построчный импорт из Excel через COM . Скорость выполнения вас приятно удивит. Нужно будет скачать и зарегистрировать dll.
Что же касается того, как определить, что из ячеек изменилось (пересчиталось), то я бы воспользовался возможностью статического метода Set::difference, который может сравнить состав двух множеств и вернуть несовпадения (из первого множества). На псевдокоде это выглядит примерно так: Код: setРасхожденияПосле = Set::difference( setПослеОперации, setДоОперации ); Перед грядущим изменением пробегаетесь по всем ячейкам и заполняете множество setДоОперации. После изменения опять пробегаетесь по всем ячейкам и заполняете множество setПослеОперации. Наконец, вычисляете множество setРасхожденияПосле (изменившиеся ячейки), которое затем циклом перебираете и записываете в нужную таблицу Аксапты (ну, или куда там вам надо). |
|
21.05.2010, 14:22 | #13 |
Участник
|
спасибо! попробуем.
|
|
21.05.2010, 16:58 | #14 |
Moderator
|
Что ж, "утром - в газете, вечером - в куплете". Сваял я демонстрашку по этой задачке. Время сравнения двух множеств из заявленных 4500 элементов и перебора их расхождений у меня сплошь и рядом менее 1 секунды!
Перед запуском джоба необходимо зарегистрировать на компе упомянутую выше dll-ку AndyD'а (Построчный импорт из Excel через COM). После загрузки формы измените какие-нибудь ячейки (сотрите или замените иным текстом в ячейке). Закройте форму крестиком - в инфологе список расхождений. Имейте в виду, что время вывода в инфолог - "огромно" по сравнению с временем сравнения и перебора, поэтому оно и вынесено в отдельный цикл за пределы засечки по времени. X++: static void job_SpreadsheetAsTableProcessor(Args _args) { Form form = new Form(); FormBuildDesign formBuildDesign = form.addDesign('Design'); Args args = new Args(); FormRun formRun; FormActiveXControl ss; COM SafeArray = new COM('AxSafeArray.SafeArray'); COM range; COMVariant cvRange; COMVariant cvRow, cvCell; Array arr; int rowCount, colCount; int row, col; str val; Set setBefore = new Set(Types::Container); Set setAfter = new Set(Types::Container); Set setDiffer = new Set(Types::Container); SetEnumerator enumr; int timeStart, timeDuration; ; // динамически генерируем форму args.object(form); formRun = classFactory.formRunClass(args); formRun.init(); formRun.design().caption('Табличный процессор'); ss = formRun.design().addControl(FormControlType::ActiveX, 'Spreadsheet'); ss.className('{0002E541-0000-0000-C000-000000000046}'); // Microsoft Office Spreadsheet 10.0 //ss.className('{0002E559-0000-0000-C000-000000000046}'); // Microsoft Office Spreadsheet 11.0 ss.heightMode(FormHeight::ColumnHeight); ss.widthMode(FormWidth::ColumnWidth); range = ss.Range('A1:O300'); // 15 колонок - 300 строк range.Formula('="["&ROW()&","&COLUMN()&"]"'); // или, если будет ругаться, то: range.Formula('="["&СТРОКА()&","&СТОЛБЕЦ()&"]"'); cvRange = range.Value2(); rowCount = SafeArray.GetArrayRowCount(cvRange); colCount = SafeArray.GetArrayColCount(cvRange); // записываем состояние ячеек ДО изменения for (row=1; row<=rowCount; row++) { cvRow = SafeArray.GetArrayRow(cvRange, row); arr = cvRow.safeArray(); for (col=1; col<=colCount; col++) { cvCell = arr.value(col); setBefore.add([row, col, cvCell.bStr()]); } } formRun.run(); formRun.wait(); // здесь вручную изменяем несколько ячеек и закрываем форму крестиком timeStart = WinAPI::getTickCount(); // записываем состояние ячеек ПОСЛЕ изменения cvRange = range.Value2(); for (row=1; row<=rowCount; row++) { cvRow = SafeArray.GetArrayRow(cvRange, row); arr = cvRow.safeArray(); for (col=1; col<=colCount; col++) { cvCell = arr.value(col); setAfter.add([row, col, cvCell.bStr()]); } } // находим расхождения в состояниях setDiffer = Set::difference( setAfter, setBefore ); // "трогаем" все значения расхождений - как бы используем для каких-то наших целей enumr = setDiffer.getEnumerator(); while (enumr.moveNext()) { [row,col,val] = enumr.current(); } timeDuration = WinAPI::getTickCount() - timeStart; info(strFmt('Сравнение и перебор расхождений выполнены за %1 миллисек.', timeDuration)); setPrefix('Изменились следующие ячейки:'); // отдельным циклом, чтобы исключить время вывода в инфолог enumr = setDiffer.getEnumerator(); while (enumr.moveNext()) { [row,col,val] = enumr.current(); info(strFmt('Строка: %1 -- Столбец: %2 -- Новое значение: %3', row, col, val)); } } P.S. А если фрагмент вывода в инфолог слегка изменить, то удобнее (по крайней мере, с точки зрения тестирования) будет вывести адрес ячейки вместо номеров строки и столбца: X++: COM cells, cell; // добавлено ........... setPrefix('Изменились следующие ячейки:'); // отдельным циклом, чтобы исключить время вывода в инфолог cells = ss.Cells(); // добавлено enumr = setDiffer.getEnumerator(); while (enumr.moveNext()) { [row,col,val] = enumr.current(); cell = cells.Item(row,col); // добавлено info(strFmt('Адрес: %1 -- Новое значение: %2', cell.Address(false,false), val)); // изменено } Последний раз редактировалось Gustav; 21.05.2010 в 19:33. |
|
|
За это сообщение автора поблагодарили: Serg (1), Poleax (1). |
11.06.2010, 09:37 | #15 |
Участник
|
а как задать range в формате RC...Все перепробывал и R1C1:R2C2, 1:1,2:2 и 1:1;2:2...?
|
|
11.06.2010, 11:01 | #16 |
Moderator
|
А в Spreadsheet, по-моему, нотация R1C1 не поддерживается... А цель какая? Если нужно перебирать в цикле, то можно Range.Cells(i, j) использовать. А если формулу в диапазон вставить, то просто задаете формулу в нотации A1 для первой ячейки, т.е. как если бы только в одну ячейку вводили. При этом для других ячеек диапазона формула корректно настроится автоматически, например, Range("B1:B10").Formula = "=A1" даст формулу =А1 в ячейке B1 и формулу =A10 в ячейке B10.
|
|
11.06.2010, 11:30 | #17 |
Участник
|
Проблема в том, что бы определить этот range, а он динамический т.е. на входе есть значения типа координат 1:1 до 100:100
|
|
11.06.2010, 12:13 | #18 |
Moderator
|
Как-то так? Выделяется 10 первых строк:
X++: { Form form = new Form(); Args args = new Args(); FormRun formRun; FormActiveXControl ss; COM worksheet; COM range; COM cells; ; form.addDesign('Design'); args.object(form); formRun = classFactory.formRunClass(args); formRun.init(); formRun.design().caption('Табличный процессор'); ss = formRun.design().addControl(FormControlType::ActiveX, 'Spreadsheet'); ss.className('{0002E541-0000-0000-C000-000000000046}'); // Microsoft Office Spreadsheet 10.0 //ss.className('{0002E559-0000-0000-C000-000000000046}'); // Microsoft Office Spreadsheet 11.0 ss.heightMode(FormHeight::ColumnHeight); ss.widthMode(FormWidth::ColumnWidth); range = ss.Range("A1"); worksheet = range.Parent(); cells = worksheet.Cells(); range = ss.Range(cells.Item(1,1),cells.Item(10,10)); // ЭТО??? range = range.EntireRow(); box::info(range.Address(true,true,-4150)); // R1:R10 range.Select(); formRun.run(); formRun.wait(); } |
|
|
За это сообщение автора поблагодарили: Serg (1). |
17.06.2010, 10:26 | #19 |
Участник
|
ок, все помогло.
|
|
|
Похожие темы | ||||
Тема | Ответов | |||
aEremenko: Как обнаружить какой пользователь загружает процессор AOS? | 4 | |||
Табличный Mapping - список используеиых таблиц | 6 |
|