|
|
 |
Ответов
(1 - 99)
|
Jun 24 2010, 18:57
|

Профессионал
    
Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634

|
Тут или пользоваться sprintf (или её вариантами - смотреть в описании Вашего компилятора) или утянуть откуда-нибудь (я в свой проект включил часть исходников библиотечных функций - под именем НЕ совпадающим с библиотечным). В книге K&R есть пример функции - переделайте под вывод в строку. Или вот ещё - как можно поступить, если под рукой нет зубной щётки: Код void lcd_menu_value( unsigned long freq, uint_least8_t width, // full width uint_least8_t comma, // comma position (from right, inside width) uint_least8_t rj // right truncated ) { static const prog_uint32_t vals [] = { 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1, }; const unsigned char j = (sizeof vals /sizeof vals [0]) - rj; unsigned char i = (j - width); unsigned char z = 1; // only zeroes
for (; i < j; ++ i) { ldiv_t res = ldiv(freq, pgm_read_dword(& vals [i]));
if (comma == (j - i)) { z = 0; ws1602_wrdata('.'); } if (z == 1 && (i + 1) < j && res.quot == 0) ws1602_wrdata(' '); // supress zero else { z = 0; ws1602_wrdata('0' + res.quot); } freq = res.rem; } }
|
|
|
|
|
Jun 25 2010, 12:21
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(zltigo @ Jun 25 2010, 14:38)  Совет - больше никому "такое" не показывайте, ну если только врагам. Я хотел приписать, что это один из первых моих "опусов", но подумал, что в качестве примера для изучения сгодится. Если можете выдать "достойный" образец, прошу! P.S. У меня знак рисуется непосредственно перед числом, выравнивается по правому краю. А, ну да, можно было применить указатель, но тогда не пришло в голову. P.P.S. Господа, давайте найдем, наконец, лучшее решение. А то, сколько людей, столько и мнений. Да, я помню высказывание zltigo, что тема избита. Однако...
|
|
|
|
|
Jun 25 2010, 12:24
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (sonycman @ Jun 25 2010, 15:15)  Что же в этой функции такого плохого? Абсолютно все  . Написано на уровне диалекта "Эллочки людоедки", лишние действия, вычиcления, циклы. QUOTE (ViKo @ Jun 25 2010, 15:21)  давайте найдем, наконец, лучшее решение. А что такое лучшее? Гуано оно всегда гуано, а лучшее, как минимум требует критериев для оценки. Если, например, скорость, то для AVR и 16bit чисел уж точно делений быть не должно, тем более громоздкого сочетания деления и взятия остатка от деления. А тема, действительно, избитая донельзя. Повторять мамнадцатый раз не вижу смысла.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 25 2010, 12:50
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(zltigo @ Jun 25 2010, 15:24)  лучшее, как минимум требует критериев для оценки Я писал для STM32. Виноват, не сказал сразу. Для PIC или AVR написал бы другое "гуано"  Критериев, собственно, два - высокое быстродействие и минимальный объем кода. Понятно, что это две крайности, а лучшее лежит где-то посередине. У вас есть что-нибудь для ARM - Cortex? И, если можно, выскажитесь о первом примере от Genadi Zawidowsky. И о последующих.
|
|
|
|
|
Jun 25 2010, 13:28
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 25 2010, 15:50)  У вас есть что-нибудь для ARM - Cortex? как и для всех других - наиболее часто используется усеченная реализация printf(). Для ARM, кстати, деление и иже с ним, в нем тоже не используются - десятичные числа, в отличии от hex у меня почти всегда немногозначные - на вычитании быстрее. QUOTE (sonycman @ Jun 25 2010, 16:13)  Нерусский учит русскому языку?  Я с середины шестого класса за границей CCCР в русской школе учился, а учителя там были очень хорошие. После той 'пятерки', особых проблем с грамотностью нет, хотя, конечно, забывается  . QUOTE (ViKo @ Jun 25 2010, 16:06)  во втором забивал пробелами.... Все делать в первом.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 25 2010, 13:34
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(zltigo @ Jun 25 2010, 16:28)  как и для всех других - наиболее часто используется усеченная реализация printf(). Для ARM, кстати, деление и иже с ним, в нем тоже не используются - десятичные числа, в отличии от hex у меня почти всегда немногозначные - на вычитании быстрее. Осталось только выложить его сюда. Цитата Я с середины шестого класса за границей CCCР в русской школе учился, а учителя там были очень хорошие. нужно писать "в отличие" Цитата Все делать в первом. А "минус" и "плюс" потом занести? Неужто эффективнее? У меня выводится следующим образом: (upd. добавил еще и 0 для полноты) Код " 0" " -12" "+32767"
|
|
|
|
|
Jun 25 2010, 13:39
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 25 2010, 16:34)  нужно писать "в отличие" Про "отличия" не знаю, а там хорошие. QUOTE (ViKo @ Jun 25 2010, 16:34)  Осталось только выложить его сюда. Это уже мое дело.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 25 2010, 13:56
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 25 2010, 16:43)  Это у вас ошибка в посте №18 Ну это да, предлог 'в отличие' и существительное в предложном падеже с предлогом 'в'  попутал. Я же говорю - забывается  . Язык не прост. Не 'C'  , ну и форум не филологический, а "сишный", к счастью. QUOTE (ViKo @ Jun 25 2010, 16:43)  Единственное, что я вынес из разговора - надо с указателем повозиться. А то, что ДВЕ операции деление и взятие остатка от деления замного будет, не вынесли
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 25 2010, 14:10
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 25 2010, 17:04)  О! А как... ? Ну, например, как у Genadi. И, если выбирать из двух, то тогда уж оставлять деление, а не остаток он него - много менее громоздко в подавляющем большинстве случаев.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 25 2010, 14:49
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(ViKo @ Jun 25 2010, 17:43)  И к коду aaarrr присмотреться, пока что не понимаю, как работает. Неправильно, кстати, работает для v >= 59074  В качестве отмазки скажу, что таких чисел у меня и не было. Можно, конечно, компенсатор ошибки округления приделать, типа: if(v >= 57074) vi -= 13422, но это уже некрасиво. Зато для знаковых 16-битных чисел исходный вариант годится без всяких допиливаний
|
|
|
|
|
Jun 25 2010, 16:19
|

Местный
  
Группа: Свой
Сообщений: 211
Регистрация: 6-08-07
Из: Приднестровье, Тирасполь
Пользователь №: 29 581

|
Когда то для дисплея (отсюда фиксированное число цифр в числе) делал примерно так: Код //-----------Функция преобразования числа в строку----------// void decbin_5dgt(uint8_t* x, uchar8* buffer) { uint8_t i; uint8_t buff[DSPL_BUFF_SIZE]; //промежуточный интовый буфер for (i=0; i<DSPL_BUFF_SIZE;i++)buff[i]=0; //зануляем //разлаживаем for (i=*x; i>=10000; i-=10000)buff[0]++; for (i=*x-10000*buff[0]; i>=1000; i-=1000)buff[1]++; for (i=*x-10000*buff[0]-1000*buff[1]; i>=100; i-=100)buff[2]++; for (i=*x-10000*buff[0]-1000*buff[1]-100*buff[2]; i>=10; i-=10)buff[3]++; for (i=*x-10000*buff[0]-1000*buff[1]-100*buff[2]-10*buff[3]; i>=1; i-=1)buff[4]++; for (i=0; i<DSPL_BUFF_SIZE;i++)buffer[i]=(uchar8)buff[i]; //переписываем в наш массив } } //==========================================================//
--------------------
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
|
|
|
|
|
Jun 25 2010, 16:30
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (sonycman @ Jun 25 2010, 17:55)  Будет быстрее. На 9999999999 типа, да, а вот на 123? Попробуйте. QUOTE (ViKo @ Jun 25 2010, 19:15)  А разве в коде Genadi видно, как у него реализована функция ldiv? Видно, на что он делит.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 25 2010, 17:26
|
Частый гость
 
Группа: Участник
Сообщений: 95
Регистрация: 22-01-09
Пользователь №: 43 819

|
Цитата(defunct @ Jun 25 2010, 19:48)  Другого наверно и быть не может. Ух какое обсуждение получилось. И циклы вам не нравятся и деления - страшны. Табличные решения должны быть быстрее. Экономия будет на циклах и на операциях деления. Каждая операция деления заменяется двеятью сравнениями в худшем случае. (9ю сравнениями для каждого десятичного знакоместа). Вопрос в том на какой таблице остановиться: Если на десятичной, то таблица будет 36 слов (4знака * 9цифр). Если на двоичной, то надо будет осуществлять двоично-десятичное сложение. Двоичная таблица будет медленнее (скорее всего) если есть аппаратный умножитель. А вот если его нет, то будет быстрее раз эдак в 200 чем программное деление.
|
|
|
|
|
Jun 25 2010, 19:15
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Пролистал K&R второе издание от корки до корки, нашел практически такое же "гуано" на языке Элочки Людоедовой, как у меня, defunct, да и Goodefin недалеко от него ушел  Раздел 3.6 стр. 77. Те же деление и взятие остатка от деления. С учетом функции reverse - 2 цикла. (замечу в скобках, что книжка эта у меня появилась не так давно, до этого пользовался Шилдтом, но решил "продвинуться", так что любые совпадения - случайны  ) Еще приводится пример рекурсивного вызова на стр. 100, тоже не скажу, что блещет производительностью. А табличный способ - самый быстрый. Но и самый жрущий память кода  Это одна из крайностей. Найти бы еще самый компактный. P.S. Кстати, автор топика не указал, для чего ему нужна функция itoa. А может, он под Windows пишет, и на производительность и компактность ему одинаково наплевать.
|
|
|
|
|
Jun 25 2010, 19:52
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Покопался в своих проектах, нашел преобразование для PIC16. 2 байта преобразовываются в 3 двоично-десятичных упакованных. От которых рукой подать до ASCII. Выдаю кусок из файла. Может кому-то покажется интересным. Цитата(sigmaN @ Jun 25 2010, 22:27)  ...К чему там ещё и к словам русского языка придираться то было? Исключительно с целью обучения навыкам культурного ведения диалогов при общении. Цитата(sigmaN @ Jun 25 2010, 22:27)  K&R не Ымбеддеры. А badik , с которого все началось, эмбеддер? Он об этом не говорил.
|
|
|
|
|
Jun 25 2010, 21:29
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(Genadi Zawidowski @ Jun 25 2010, 23:33)  Между прочим, это функция стандартной библиотеки C. Это я уже понял. Есть ли в Keil для Cortex-M3 не смотрел, надеюсь, есть. Тогда можно будет совместить деление и взятие остатка. Попробую на досуге. upd. Попробовал. Есть такая функция. Однако после замены деления и взятия остатка на div() размер кода остался тем же. Подробнее буду разбираться позже. Для ARM интересен вариант от aaarrr - из области трюков и фокусов. Реально полезный пример! А для процессоров без умножений и делений - вычитание, а на ассемблере - с помощью команд двоично-десятичной коррекции (вот бы на C ее задействовать).
|
|
|
|
|
Jun 26 2010, 04:36
|

developer
   
Группа: Свой
Сообщений: 902
Регистрация: 12-04-06
Из: Казань
Пользователь №: 16 032

|
Цитата(ViKo @ Jun 25 2010, 23:15)  Пролистал K&R второе издание от корки до корки Чутарик не в тему. На форуме все ссылаются на эту книгу. Хотя Дэнис Ричи и является отцом-основателем языка, но это не означает, что он написал хорошую книгу. Мне, например, вот ЭТА очень понравилась. Теперь по теме. Предлагаю глянуть, что ATMEL предлагает. А глядеть ЗДЕСЬ
--------------------
Все может быть и быть все может, и лишь того не может быть-чего уж точно быть не может, хотя..и это может быть.
|
|
|
|
|
Jun 26 2010, 08:11
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 25 2010, 22:15)  Пролистал K&R второе издание от корки до корки, нашел практически такое же "гуано" на языке Элочки Людоедовой Не обижайте Кернигана  . Проблема % / это одна частная проблема, которая на некоторых платформах и не проблема - настоятельно рекомендую откомпилировать и посмотреть на результат работы с 32bit для: Pentium Сortex-M3 ARM7 ATmega ATtiny Ильфа тоже не обижайте - Эл лочкина фамилия была Щукина, а "людоедкой" она была по причине того, что обходилась 30 словами. В чем ее превосходило даже племя людоедов Мумбо-Юмбо, чей словарный запас был 300 слов.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 26 2010, 09:04
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Genadi Zawidowski @ Jun 25 2010, 23:33)  После аппаратного (или программного) деления и частное и остаток обычно присутствуют в регистрах процессора и структура ldiv_t (div_t) эти самые регистры впрямую и отображает. Вот именно. Просто всё-таки нужно представлять себе, во что выливается операция / или %, даже если пишешь для x86, как вообще деление реализуется. Цитата(Genadi Zawidowski @ Jun 25 2010, 23:33)  Так было на x86. На ARM и AVR не интересовался. Да так же. Только для AVR в библиотеке компилятора есть функции для деления, которые вызываются и для /, %, только при этом берётся половина результата. А div просто переназначено на эту функцию, возвращающую на регистрах обе части результата деления. avr-gcc, stdlib.h Код /* __divmodhi4 and __divmodsi4 from libgcc.a */ extern div_t div(int __num, int __denom) __asm__("__divmodhi4") __ATTR_CONST__; extern ldiv_t ldiv(long __num, long __denom) __asm__("__divmodsi4") __ATTR_CONST__; Так что применение div и тут в два раза сокращает затраты времени на деление по сравнению с раздельной парой /, %. Оптимизатор сам не видит, что можно было бы вызвать еление один раз. Хотя для данной конкретной задачи для AVR другие способы побыстрее всё равно. Вариант с div, кажется, немного компактнее для случая, когда деление в программе всё равно есть и __divmod* всё равно линкуются.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jun 26 2010, 09:16
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
В свое время написал такое: CODE /** * "Указатель" на тетраду байта (обертка над указателем и признаком первая\вторая тетрада) */ struct TBCDLocation { byte *buf; bool isFH;
TBCDLocation(byte *buf = 0, bool isFH = true) { this->buf = buf; this->isFH = isFH; }
TBCDLocation& operator++(); TBCDLocation& operator--(); TBCDLocation& operator+=(byte b ); TBCDLocation& operator-=(byte b ); uint_fast16_t operator-(const TBCDLocation& b ) const; uint_fast16_t operator-(byte *b ) const; TBCDLocation operator-(uint_fast8_t b ) const; TBCDLocation operator+(uint_fast8_t b ) const; bool operator==(const TBCDLocation& b ) const; bool operator!=(const TBCDLocation& b ) const; bool operator>(const TBCDLocation& b ) const;
void put(byte val); void putAndInc(byte val); void putAndDec(byte val); byte get(); byte getAndInc(); byte getAndDec(); };
struct TBINtoBCDres { TBCDLocation loc; //!< Указатель на цифру перед первой результата bool isOverflow : 1; //!< признак переполнения bool isMinus : 1; //!< знак TBINtoBCDres (TBCDLocation loc, bool isOverflow, bool isMinus) : loc(loc), isOverflow(isOverflow), isMinus(isMinus) {} };
/** * Преобразование двоичного числа произвольной длины в десятичное число произвольной длины * (две цифры в байте). Результат выравнивается по правому краю. * Заполнение ведущими нулями НЕ производится (в частности, при преобразовании числа 0 * целевой массив НЕ ИЗМЕНИТСЯ вообще и будет возвращен lsBCD).\n * Если десяичное число не влезает в указанное число разрядов, * старшие разряды будут потеряны (т.е. 0xffff при преобразовании * в три разряда даст 535)\n * Двоичное число лежит младшим байтом вперед. Десятичное - старшей цифрой вперед. * * @param lsBCD указатель на младшую цифру результата (самую последнюю) * @param bin указатель на младший байт двоичного числа (самый первый) * @param halfbyteCnt * число тетрад в двоичном числе * @param bcdDigCnt число цифр в десятичном числе * * @return Указатель на цифру перед первой результата и признак переполнения */ TBINtoBCDres BINtoBCD(TBCDLocation lsBCD, void const *bin, uint_fast8_t halfbyteCnt, uint_fast8_t bcdDigCnt) { // используется сдвиговый алгоритм (полубайты выдвигаются из двоичного регистра и вдвигаются // в десятичный, при этом произодится коррекция) Число итераций = (число байт) * (число дес цифр) TBCDLocation msBCD = lsBCD; bool isOverflow = false; byte *pbin = ((byte*)bin) + (halfbyteCnt/2)-1; bool binIsFH = true; uint_fast8_t tmp; while(halfbyteCnt--) { uint_fast8_t sdv; // выдвинутый полубайт if (binIsFH) { tmp = *pbin--; sdv = HIGHPART(tmp); binIsFH = false; } else { sdv = LOWPART(tmp); binIsFH = true; } TBCDLocation bcd(lsBCD); while(true) // вдвигаем полубайт в десятичный регистр { bool isLim = msBCD == bcd; // признак достижения старшей цифры if(isLim && sdv == 0) break;
uint_fast8_t cur = isLim ? 0 : bcd.get(); uint_fast8_t tmp = tableBINtoBCD[(cur<<4) | sdv]; cur = HIGHPART(tmp); sdv = LOWPART(tmp); if (isLim) { if (cur || sdv) { if (bcdDigCnt) { bcd.putAndDec(cur); --bcdDigCnt; msBCD = bcd; } else { isOverflow = true; break; } } else break; } else bcd.putAndDec(cur); } } return TBINtoBCDres(msBCD, isOverflow, false); }
Таблицу tableBINtoBCD (160 байт) и класс TBCDLocation могу дать, если кому интересно. Написано на С++, но можно переделать на С. Когда написал, сравнил (на IAR АВР) с двумя алгоритмами - первый использовал деление, второй - вычитание. Цифр уже не помню, но оказался быстрее обоих. Кроме того работает с числами произвольной длины (несколько раз понадобилось  ) и контролирует переполнение. Конвертит не в АСКи, а в BCD - две десятичных цифры в байте - но потом легко преобразовать куда надо. ЗЫ смайлы почему-то парсятся в коде...
|
|
|
|
|
Jun 26 2010, 09:23
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(ReAl @ Jun 26 2010, 13:04)  Оптимизатор сам не видит, что можно было бы вызвать деление один раз. Да, я тоже замечал, что функция деления вызывается именно два раза (сначала остаток, потом деление), несмотря на то, что достаточно было бы единственного вызова. Хотя это было, вроде бы, ещё на AVR. Не знаю, как это будет компилироваться под кортекс и RealView.
|
|
|
|
|
Jun 26 2010, 10:24
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Следуя рекомендациям, слегка модернизировал код. Код void itoa(int16_t Number, uint8_t *String) { uint8_t Sign = ' '; if (Number > 0) Sign = '+'; if (Number < 0) { Sign = '-'; Number = - Number; } String[6] = '\0'; int8_t i = 5; div_t QR = {Number, 0}; do { QR = div(QR.quot, 10); String[i--] = QR.rem + '0'; } while (QR.quot); String[i] = Sign; for (i--; i >= 0; i--) String[i] = ' '; } Результат оказался несколько неожиданным  Ни в первом, ни во втором случае RealView MDK-ARM 4.10 не использует команды деления вообще. А код оказался равным по размеру (и по содержанию, похоже). Так что можно сделать вывод, что / и % компилятор все-же объединил. А заняла функция деления примерно 80 команд (не машинных тактов, а именно строк в ассемблерном коде). 2 Непомнящий Евгений
На таком принципе основан мой код для PIC, который чуть выше в файле лежит. Только написан на ассемблере. Цитата(zltigo @ Jun 26 2010, 12:18)  Посему повторяю рекомендации откомпилировать и посмотреть на результат с / % для всех ранее помянутых ядер. Так-же напомню, что слово "гуано" относилось далеко не только к использованию / %. Для всех ядер - это вы уж слишком многого от меня хотите.  У меня и компиляторов таких нет. А для Cortex-M3 я написал и откомпилировал, и из ваших высказываний так и не понял, что бы такого можно было улучшить в моем коде. А примера, как надо делать, вы не привели.
|
|
|
|
|
Jun 26 2010, 11:31
|
Частый гость
 
Группа: Участник
Сообщений: 95
Регистрация: 22-01-09
Пользователь №: 43 819

|
Цитата(ViKo @ Jun 26 2010, 14:24)  Следуя рекомендациям, слегка модернизировал код. вы бы озвучили с какой целью модифицировался код. надо "быстрый алгоритм", "короткий код", "читаемый текст" или еще что-то? Нужен быстрый и не требовательный алгоритм - в atoi_v1. слишком длинное решение - посмотрите в atoi_v2. Операции деления отсутствуют как класс. P.S. тексты в файлах - написаны за 2 минуты и на работоспособность не проверялись. демонстрируется метод табличного решения задачи. ничего более. P.P.S. метод имеет смысл применять на простых контроллерах без аппаратного умножителя. (с умножителем надо думать). Сергей.
Сообщение отредактировал ssvSerge - Jun 26 2010, 11:36
|
|
|
|
|
Jun 26 2010, 14:19
|
Частый гость
 
Группа: Участник
Сообщений: 95
Регистрация: 22-01-09
Пользователь №: 43 819

|
Цитата(ViKo @ Jun 26 2010, 16:55)  В алгоритмах число записывается задом наперед и нет индикации знака числа. кроме этого нет проверки на 0 и в одном из разрядов нет проверки на "bIsDigitPresent". Это если уж быть точным. Но это мелочи - код и не претендовал на работоспособность. Главное, что подход понятен. Цитата(ViKo @ Jun 26 2010, 16:55)  код сделать лучше, оптимальнее. Слово "оптимальнее" следует исключить из лексикона как антинаучное. Есть критерии: скорость, объем, читабельность и т.д. Для каждого человека, проекта, процессора критерии изменяются. Цитата(ViKo @ Jun 26 2010, 16:55)  В идеале - оптимальнее и по производительности, и по компактности. ну так озвучьте цифры какой из вариантов (табличный или с делениями) оптимальнее в конкретно вашем случае. на ваших процессорах и в ваших глазах. Сергей.
|
|
|
|
|
Jun 26 2010, 14:42
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(ssvSerge @ Jun 26 2010, 17:19)  ну так озвучьте цифры какой из вариантов (табличный или с делениями) оптимальнее в конкретно вашем случае. на ваших процессорах и в ваших глазах. В данный момент меня занимает алгоритм от aaarrr, поискал по компу своему книжку по цифровые трюки, но не нашел. А ведь была. Нельзя ли его расширить, чтобы принимал все числа. Второй вариант - преобразовать bin в BCD, а затем уже превратить в строку. Табличный способ меня не привлекает из-за громоздкости. Точные цифры по быстродействию и размеру кода я не смотрел. Если будет что сказать, доложу. P.S. Определился, пожалуй, что для меня значит оптимальность. = Компактность кода. А быстродействие мне STM32 и так обеспечит. P.P.S. Причем, часто бывает, что компактный код и работает быстро.
|
|
|
|
|
Jun 26 2010, 15:05
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 26 2010, 13:24)  Для всех ядер - это вы уж слишком многого от меня хотите.  У меня и компиляторов таких нет. Тем не менее, Вы уже второй раз утверждаете, что писали с оглядкой на Cortex? Лично я воспринял это, как то, что Вы знаете, что творите. QUOTE из ваших высказываний так и не понял, что бы такого можно было улучшить в моем коде. Хорошо,не затрагивая, так сказать основ, только то, что сразу режет глаз. CODE void si16toad (int16_t Number, char * StrBuf) { char Sign = ' '; // Зачем-то завели малополезную переменную 'Sign' if (Number > 0) Sign = '+'; if (Number < 0) { Sign = '-'; Number = -Number; } StrBuf[6] = '\0'; signed char i = 5; // Cortex говорите? Тогда за не 32 bit переменные, где в этом нет // небходимости по рукам надо давать. Да и сама переменная лишняя - только команд push/pop добавляет // А за использование "массивов" вместо указателей - еще один раз do { StrBuf[i--] = Number % 10 + '0'; Number /= 10; // 32 bit контроллер? Тогда зачем его беднягу опять без всякой надобности // заставлять с 16bit 'Number' работать? Сразу несколько лишних команд в цикле } while (Number); StrBuf[i] = Sign; // Цикл заполнения пробелами не более, чем 4x ,байтиков. А как это на 32битниках, тем более на // Cortex это можно сделать одной командой?( ну ладно двумя - одна регистр пробелами заполняет) for (i--; i >= 0; i--) StrBuf[i] = ' '; }
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 26 2010, 15:12
|
Частый гость
 
Группа: Участник
Сообщений: 95
Регистрация: 22-01-09
Пользователь №: 43 819

|
Цитата(ViKo @ Jun 26 2010, 18:42)  для меня оптимальность = Компактность кода. бывает, что компактный код и работает быстро. о - вот теперь всё понятно. табличные методы в таких условиях, конечно, проигрывают. я хотел сказатать только, что таблицу можно сделать на базе "2 в степени" и заниматься BCD сложением. Значительно компактнее, чем десятичная таблица, и реализация на ASM проста до смешного. Хотя в скорости, конечно, уступает десятичной. Сергей.
|
|
|
|
|
Jun 26 2010, 16:28
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(zltigo @ Jun 26 2010, 18:05)  // Зачем-то завели малополезную переменную 'Sign' // Cortex говорите? Тогда за не 32 bit переменные, где в этом нет // небходимости по рукам надо давать. Да и сама переменная лишняя - только команд ush/pop добавляет // А за использование "массивов" вместо указателей - еще один раз // 32 bit контроллер? Тогда зачем его беднягу опять без всякой надобности // заставлять с 16bit 'Number' работать? Сразу несколько лишних команд в цикле // Цикл заполнения пробелами не более, чем 4x ,байтиков. А как это на 32битниках, тем более на // Cortex это можно сделать одной командой?( ну ладно двумя - одна регистр пробелами заполняет) Sign - а как же без него, он же потом используется, в пока не известном месте. 32 бита - согласен. Согласен понести наказание (вернее, уже понес  ) push/pop - разве они там есть? Массивы вместо указателей - не уверен, не исключаю что в данном случае это одно и то же. Заполнение пробелами - их может быть разное количество, здесь 32-битовые слова не помогут. Над этим подумаю... Докладываю - создал тестовый проект, в котором только itoa, компилятор задействовал SDIV. Возрадуемся, братья!  2 aaarrr
Про формат 4.28 - что это, где почитать?
|
|
|
|
|
Jun 26 2010, 16:40
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 26 2010, 19:28)  Sign - а как же без него, он же потом используется, в пока не известном месте. Можно с большей пользой использовать регистр, например, взять и скопировать в него Ваш 'Number'. При этом будете работать с этим 32bit, а не 16ише, а плюсики и прочее рисовать потом по 'Number' QUOTE push/pop - разве они там есть? Напихаете разных переменных - будут. QUOTE Массивы вместо указателей - не уверен Ну-ну... Две переменных, вместо одной. QUOTE Заполнение пробелами - их может быть разное количество, здесь 32-битовые слова не помогут. Помогут, помогут - заполняйте до того, как начнете цифирки заносить. QUOTE (ViKo @ Jun 26 2010, 19:28)  Возрадуемся, братья!  Чему?
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 27 2010, 17:02
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(ViKo @ Jun 26 2010, 21:00)  Возрадуемся - что в Cortex есть команда деления, которая иногда используется. Ещё как используется. На днях посмотрел, для интереса, как скомпилировались операции (dword / 10) и, следом за ней, (dword % 10). В первом случае, естественно, UDIV. А во втором - MLS (Multiply and Subtract) с использованием результата предыдущего вычисления. Есть такая хитрая и полезная (как раз для этих целей) команда  Так что даже не пришлось делать вычитание ручками, RealView сам всё оптимизирует правильно.
|
|
|
|
|
Jun 27 2010, 18:51
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(ReAl @ Jun 26 2010, 13:04)  Так что применение div и тут в два раза сокращает затраты времени на деление по сравнению с раздельной парой /, %. Оптимизатор сам не видит, что можно было бы вызвать еление один раз. Я видел заплатку для этого случая. Сейчас gcc ИМХО это видит:-) To ViKo: Поделитесь насколько itoa будет медленнее Вашего самого лучшего варианта:-)
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Jun 28 2010, 17:43
|
Участник

Группа: Участник
Сообщений: 48
Регистрация: 29-11-06
Из: Екатеринбург
Пользователь №: 22 890

|
Господа всем огромный привет, ни как не думал, что моя маленькая проблема вызовет такой мощный отклик. Вот уж точно 100 друзей намного лучше.. Тут уважаемые "Местный" и "воинствующий философ" подсказали простое решение sprintf, посмотрел С Шилдта с примером, у меня всё идеальо сработало. Если не затруднил - осмелюсь ещё поспрашать столь почтенное сообщество. Я в начале ADSP-BF533, BF548
|
|
|
|
|
Jun 28 2010, 21:09
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Прежде, чем писать новое, изучил в отладчике работу обеих моих программ - начальной si16toad и измененной itoa, в которой операции % и / были заменены вызовом библиотечной функции div. Напомню: Keil uVision - RealView MDK-ARM 4.10, STM32F103. Результаты оказались интересными.
После компиляции в окне Build Ouitput для обеих программ выдаются одинаковые размеры для кода - 548 байтов при оптимизации O0 и 536 байтов при оптимизации O3. Почему они одинаковые, не понимаю (см. ниже)?! Размеры данных всех типов тоже одинаковые вообще всегда, но это, как раз, не удивляет.
Посчитал размер обеих функций по листингу C компилятора (есть галочка в настройках генерировать листинг). При O0 для si16toad насчитал 84 байта, для itoa 98 байтов (не считая 14 байтов в самой функции div, это уже в отладчике увидел). При O3 - 80 байтов и 94 байта, соответственно. Причем, при оптимизации O0 в si16toad команда деления использовалась дважды, а при O3 только один раз. В-общем, мой первый вариант оказался компактнее.
Посчитал в отладчике количество тактов. Счетчик тактов виден в окне регистров, засекал значение перед вызовом своей функции и после нее. При O0 si16toad выполнялась за 171 такт, itoa за 232 такта. При O3 - 121 такт и 210 тактов, соответственно. Мой первый вариант оказался еще и быстрее.
Увидел лишние знаковые и беззнаковые расширения для переменных меньше 32 байтов. Вот здесь буду совершенствовать программу. Массив или указатель - тоже проверю. Заносить пробелы сразу - их, к сожалению, максимум 5 (не 4). Над этим и др. пока думаю.
|
|
|
|
|
Jun 28 2010, 21:57
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(zltigo @ Jun 29 2010, 00:33)  Их у Вас четыре. Можете попробовать на пальцах посчитать от X0 (раз-два) до X32768(раз-два-..шесть). Ну и размер должен быть на на уровне 60 байт, ну и тактов заметно менее. Перед "0" я символ + или - не ставлю (считаю, так "красивее" и "правильнее"), потому и обработка такая в начале программ. Итого _ _ _ _ _ 0 \0. По поводу размеров и тактов - могу выдать весь проект в заархивированном виде. В настройках есть какие-то "галочки", которых не трогал. Может, что-то и упустил...
|
|
|
|
|
Jun 28 2010, 22:03
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 29 2010, 00:57)  Перед "0" я символ + или - не ставлю Вы ставите один из 3x символов. Вот и ставьте. Таки 4  QUOTE По поводу размеров и тактов - могу выдать весь проект в заархивированном виде. Я говорю об аккуратно написанном, посему про 80 байтов в Вашем варианте верю. Сделайте 60  .
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 29 2010, 13:48
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Код void itoad(int number, uint8_t *string) { uint8_t sign; *(int32_t *) string = ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24; *(int32_t *)(string + 4) = ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24; *(int32_t *)(string += 8) = ' ' | ' ' << 8 | '0' << 16 | '\0'<< 24; if (!number) return; if (number > 0) sign = '+'; else { number = -number; sign = '-'; } string += 2; do { *string-- = number % 10 + '0'; } while (number /= 10); *string = sign; } Работает с 32-битовыми числами со знаком. string должна быть 12 байтов для 32-битового числа. 60 байтов (+ 4 байта хранят константу "_ _ 0"). ~207 тактов.
|
|
|
|
|
Jun 29 2010, 14:18
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(ViKo @ Jun 29 2010, 16:48)  Код *(int32_t *) string = Знатная грабля. Исключение при первой же string, начало которой не попадает на границу 4 байт. Или просто порушенные соседние данные.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 29 2010, 14:34
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (Сергей Борщ @ Jun 29 2010, 17:18)  Знатная грабля. Исключение при первой же string, начало которой не попадает на границу 4 байт. Или просто порушенные соседние данные. Это гнулось под Cortex - такая вот игра. QUOTE (ViKo @ Jun 29 2010, 16:48)  60 байтов Чуть симпатичнее и скорее всего еще короче: CODE void itoad(int number, uint8_t *string) { uint8_t sign; *(uint32_t *) string = ' '; *(uint32_t *)(string + 4) = ' '; *(uint32_t *)(string += 10) = (uint32_t )" 0"; if (!number) return; if (number > 0) sign = '+'; else { number = -number; sign = '-'; } // string += 2; do { *string-- = number % 10 + '0'; } while (number /= 10); *string = sign; } Осталось первоначальную 16bit оптимизировать.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 29 2010, 14:45
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 29 2010, 17:39)  Кавычки не двойные? В первых двух - нет. Возможны warnings, правда, поскольку символ wide получается ИЗ 4x ПРОБЕЛОВ. А так нормально. В третьей - три символа в двойных. QUOTE Из этой 16-битов автоматически получается, если малое число использовать и буфер соответствующий. Автоматически, не значит оптимально.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 29 2010, 17:23
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(zltigo @ Jun 29 2010, 17:34)  Код *(uint32_t *)(string += 10) = (uint32_t )" 0"; Так - нельзя, пропускается два байта. С кавычками - понял, но варнинги... как бы удовлетворить требованиям компилятора? Код #define FOUR_SPACES 0x20202020 *(uint32_t *) string = FOUR_SPACES; Нормально?
|
|
|
|
|
Jun 29 2010, 17:40
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 29 2010, 20:23)  Так - нельзя, пропускается два байта. А, да. Что-то ошибся. Тогда так: CODE *(uint32_t *)(string += sizeof(int32_t)) = ' '; *(uint32_t *)(string += sizeof(int32_t)) = (uint32_t )" 0"; string += 2; Есть шанс на экономию пары байт. QUOTE С кавычками - понятно, но варнинги... как бы удовлетворить требованиям компилятора? Ну, например, отключить их локально прагмой, либо таки (long)" ", но константа займет 8 байт. QUOTE (ViKo @ Jun 29 2010, 20:23)  Нормально? Да.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 29 2010, 18:29
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(zltigo @ Jun 29 2010, 20:40)  Код *(uint32_t *)(string += sizeof(int32_t)) = ' '; *(uint32_t *)(string += sizeof(int32_t)) = (uint32_t )" 0"; string += 2; Есть шанс на экономию пары байт. В смысле, прилепить string +=2 сразу к предыдущему выражению, использующему указатель? А, заменить +8 +2 на +4 +4 +2? upd. Попробовал и так, и сяк, и +10, лучше не становится. 16-битовую хочу попробовать с применением формата 4.28, как у aaarrr. А с тем, что сделал для 32 битов, и не знаю, куда уж дальше "копать" для 16 битов. Я, собственно, с 16-битовой и возился, пока не увидел, что 32-битовая из нее получается практически "даром":)
|
|
|
|
|
Jun 29 2010, 18:38
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 29 2010, 21:29)  В смысле, прилепить string +=2 сразу к предыдущему выражению, использующему указатель? Вот как написано, так пробуйте. QUOTE что 32-битовая из нее получается практически "даром":) Полагаю, что там есть как минимум один нюанс - не ухудшить шестнадцатибитовостью ну и чуть поджать за счет меньшего буфера.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 29 2010, 19:52
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(zltigo @ Jun 29 2010, 21:38)  Вот как написано, так пробуйте. Во всех (!) перечисленнных вариантах делается одно и то же: +8 +2 Код ;;;34 *(uint32_t *)(string += sizeof(int32_t)) = ' '; 000006 600a STR r2,[r1,#0] ;;;35 *(uint32_t *)(string += sizeof(int32_t)) = (uint32_t )" 0"; 000008 604a STR r2,[r1,#4] 00000a a23b ADR r2,|L1.248| 00000c f8412f08 STR r2,[r1,#8]! ;;;36 string += 2; 000010 1c89 ADDS r1,r1,#2 ;;;37
|
|
|
|
|
Jun 29 2010, 21:13
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 29 2010, 22:52)  Во всех (!) перечисленнных вариантах делается одно и то же: +8 +2 CODE ;;;34 *(uint32_t *)(string += sizeof(int32_t)) = ' '; 000006 600a STR r2,[r1,#0] ;;;35 *(uint32_t *)(string += sizeof(int32_t)) = (uint32_t )" 0"; 000008 604a STR r2,[r1,#4] 00000a a23b ADR r2,|L1.248| 00000c f8412f08 STR r2,[r1,#8]! ;;;36 string += 2; 000010 1c89 ADDS r1,r1,#2 ;;;37 Выложите-ка просто целиком и без редактирования ДВА листинга, как у Вас было и как я предложил. Тогда будет видно. Пока "идеальный варинат" этого кусочка мог-бы быть такой: CODE STR r2,[r1,#0] STR r2,[r1,#4] ADR r2,...... STR r2,[r1,#8] ADDS r1,r1,#10 Все команды по 16бит и на два байта меньше относительно приведенного выше варианта. Но компилятору чего-то у уму заклинило  А что будет если так: CODE *(uint32_t *)(string + 4) = ' '; *(uint32_t *)(string + 8 ) = (uint32_t )" 0"; string += 10; P.S. Компильнул IAR-овским компилятором (слега еще подправив,но в общем, как в 73 посте) все, как задумывалось получилось и 54 байта размер кода.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 30 2010, 08:00
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Выкладываю ваш вариант. Последнее, что вы написали, тоже делал. Пара вопросов, возникших в процессе... - 1. Можно ли "заинлайнить" библиотечную функцию, ту же div, например? 2. Есть ли способ задать массив, выровненный по 4-байтовой границе? upd. Вах, получилось! Код void itoad(int number, uint8_t *string) { #define FOUR_SPACES ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24 uint8_t sign; *(uint32_t *)(string) = FOUR_SPACES; *(uint32_t *)(string + 4) = FOUR_SPACES; *(uint32_t *)(string + 8) = (uint32_t)" 0"; string += 10; // *(uint32_t *)(string += sizeof(int32_t)) = ' '; // *(uint32_t *)(string += sizeof(int32_t)) = (uint32_t )" 0"; // string += 2; if (!number) return; if (number > 0) sign = '+'; else { number = -number; sign = '-'; } do { *string-- = number % 10 + '0'; } while (number /= 10); *string = sign; } 58 байтов Код ;;;31 *(uint32_t *)(string) = FOUR_SPACES; 000002 f04f3220 MOV r2,#0x20202020 ;;;32 *(uint32_t *)(string + 4) = FOUR_SPACES; 000006 600a STR r2,[r1,#0] ;;;33 *(uint32_t *)(string + 8) = (uint32_t)" 0"; 000008 604a STR r2,[r1,#4] 00000a a23a ADR r2,|L1.244| ;;;34 string += 10; 00000c 608a STR r2,[r1,#8] 00000e 310a ADDS r1,r1,#0xa Вроде уже делал так.
|
|
|
|
|
Jun 30 2010, 09:22
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
"Шеф, все пропало!..." По команде *(uint32_t *)(string + 8) = (uint32_t)" 0"; заносится адрес строки, а не сама строка! На всякий случай, если кто-то заинтересуется, выдаю работающий код. Код void itoad(int number, uint8_t *string) { #define TETRASPACE ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24 #define TETRATAIL ' ' | ' ' << 8 | '0' << 16 | '\0'<< 24 uint8_t sign; *(uint32_t *)(string) = TETRASPACE; *(uint32_t *)(string + 4) = TETRASPACE; *(uint32_t *)(string + 8) = TETRATAIL; string += 10; if (!number) return; if (number > 0) sign = '+'; else { number = -number; sign = '-'; } do { *string-- = number % 10 + '0'; } while (number /= 10); *string = sign; } Часть листинга, обратите внимание, стоит команда LDR, а не ADR, как раньше Код ;;;31 *(uint32_t *)(string) = TETRASPACE; 000002 f04f3220 MOV r2,#0x20202020 ;;;32 *(uint32_t *)(string + 4) = TETRASPACE; 000006 600a STR r2,[r1,#0] ;;;33 *(uint32_t *)(string + 8) = TETRATAIL; 000008 604a STR r2,[r1,#4] 00000a 4a3a LDR r2,|L1.244| ;;;34 string += 10; 00000c 608a STR r2,[r1,#8] 00000e 310a ADDS r1,r1,#0xa
|
|
|
|
|
Jun 30 2010, 11:35
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(MrYuran @ Jun 30 2010, 14:31)  Вот никак не могу понять, почему никто до сих пор не придумал оператор, который возвращает сразу и частное, и остаток. В 51-й микроЭВМ была. А в Cortex заменяется двумя командами (upd. Вернее, тремя. Исправил код). Дважды не делается. Код 000022 4602 MOV r2,r0 000024 fb90f0f3 SDIV r0,r0,r3 000028 fb032210 MLS r2,r3,r0,r2
|
|
|
|
|
Jun 30 2010, 19:02
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 30 2010, 11:22)  На всякий случай.. Ну если упорно не хотите нормальное сравнение следать, то вот: CODE 59 void itoad(int number, uint8_t *string) 60 { \ itoad: \ 00000000 10B4 PUSH {R4} 61 int sign; 62 *(int32_t *) string = 0x20202020; \ 00000002 .... LDR.N R2,??DataTable1_1;; 0x20202020 \ 00000004 0A60 STR R2,[R1, #+0] 63 *(int32_t *)(string += 4) = 0x20202020; \ 00000006 4A60 STR R2,[R1, #+4] 64 *(int32_t *)(string += 4) = 0x00302020; \ 00000008 .... LDR.N R2,??DataTable1_2;; 0x302020 \ 0000000A 8A60 STR R2,[R1, #+8] 65 string += 2; \ 0000000C 0A31 ADDS R1,R1,#+10 66 if (!number) return; \ 0000000E 78B1 CBZ.N R0,??itoad_0 67 if (number > 0) sign = '+'; \ 00000010 0128 CMP R0,#+1 \ 00000012 AEBF ITEE GE \ 00000014 2B22 MOVGE R2,#+43 \ 00000016 4042 RSBLT R0,R0,#+0 \ 00000018 2D22 MOVLT R2,#+45 68 else { 69 number = -number; 70 sign = '-'; 71 } 72 do { 73 *string-- = number % 10 + '0'; \ ??itoad_1: \ 0000001A 0A23 MOVS R3,#+10 \ 0000001C 90FBF3F4 SDIV R4,R0,R3 \ 00000020 03FB1400 MLS R0,R3,R4,R0 \ 00000024 3030 ADDS R0,R0,#+48 \ 00000026 01F80109 STRB R0,[R1], #-1 74 } while (number /= 10); \ 0000002A 2000 MOVS R0,R4 \ 0000002C F5D1 BNE.N ??itoad_1 75 *string = sign; \ 0000002E 0A70 STRB R2,[R1, #+0] 76 } \ ??itoad_0: \ 00000030 10BC POP {R4} \ 00000032 7047 BX LR ;; return
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 30 2010, 20:29
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(zltigo @ Jun 30 2010, 22:02)  Ну если упорно не хотите нормальное сравнение сделать, то вот: Вы имеете в виду сравнение кода, или операции сравнения внутри кода? Почему не хочу? Еще как! Листинг я же выдал, там, в файлике keil_temp.txt (он и создается Keil-ом именно в таком виде, с расширением txt). Вот еще раз, после замены типа переменной sign (думал, может в ней дело). С недоумением разглядываю ваш и свой листинги, ничего путного на ум не приходит. Код itoad PROC ;;;27 *************************************************************************** ****/ ;;;28 void itoad(int number, uint8_t *string) 000000 b510 PUSH {r4,lr} ;;;29 { ;;;30 #define TETRASPACE ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24 ;;;31 #define TETRATAIL ' ' | ' ' << 8 | '0' << 16 | '\0'<< 24 ;;;32 // uint8_t sign; ;;;33 int sign; ;;;34 *(uint32_t *)(string) = TETRASPACE; 000002 f04f3220 MOV r2,#0x20202020 ;;;35 *(uint32_t *)(string + 4) = TETRASPACE; 000006 600a STR r2,[r1,#0] ;;;36 *(uint32_t *)(string + 8) = TETRATAIL; 000008 604a STR r2,[r1,#4] 00000a 4a62 LDR r2,|L1.404| ;;;37 string += 10; 00000c 608a STR r2,[r1,#8] 00000e 310a ADDS r1,r1,#0xa ;;;38 if (!number) return; 000010 2800 CMP r0,#0 000012 d011 BEQ |L1.56| ;;;39 if (number > 0) sign = '+'; 000014 dd02 BLE |L1.28| 000016 f04f042b MOV r4,#0x2b 00001a e001 B |L1.32| |L1.28| ;;;40 else { ;;;41 number = -number; 00001c 4240 RSBS r0,r0,#0 ;;;42 sign = '-'; 00001e 242d MOVS r4,#0x2d |L1.32| ;;;43 } ;;;44 do { ;;;45 *string-- = number % 10 + '0'; 000020 230a MOVS r3,#0xa |L1.34| 000022 4602 MOV r2,r0 000024 fb90f0f3 SDIV r0,r0,r3 000028 fb032210 MLS r2,r3,r0,r2 00002c 3230 ADDS r2,r2,#0x30 00002e f8012901 STRB r2,[r1],#-1 ;;;46 } while (number /= 10); 000032 2800 CMP r0,#0 000034 d1f5 BNE |L1.34| ;;;47 *string = sign; 000036 700c STRB r4,[r1,#0] |L1.56| ;;;48 } 000038 bd10 POP {r4,pc} ;;;49 ENDP У вас метка itoad играет какую-то роль? Почему-то у меня запоминается в стеке LR, а у вас нет. У вас в строке 63 должно быть число 0x20202020 или, как написано? Сравнение number производится по-разному, но я не вижу в исходниках разницы. И это LDR.N - там действительно будет по 2 байта? Где-то рядом таблица? Забавно, что байты в машинных кодах в IAR и Keil написаны по-разному. Где младший, где старший? Еще один прикол - у меня '+' заносится в регистр 4-байтовой командой (потому что не имеет повторяющейся последовательности?), а '-' 2-байтовой. У вас все 2-байтовые. Неужели IAR настолько лучше Keil?
|
|
|
|
|
Jun 30 2010, 21:14
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 30 2010, 22:29)  У вас в строке 63 должно быть число 0x20202020 или, как написано? Следы экспериментов. Все 20 QUOTE У вас метка itoad играет какую-то роль? Не у меня, а у ASM - точка входа в эту подпрограмму. QUOTE Где-то рядом таблица? А зачем ей быть далеко? IAR Компилятор сделал все корректно и на 6 байт короче. QUOTE Почему-то у меня запоминается в стеке LR Keil решил сэкономить на BX LR
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 1 2010, 08:55
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(Сергей Борщ @ Jun 29 2010, 17:18)  Знатная грабля. Исключение при первой же string, начало которой не попадает на границу 4 байт. Или просто порушенные соседние данные. Грабли можно избежать, если определить строку в виде объединения байтов и 4-байтовых слов. 2 all: Как сделать в Keil то же, что и в IAR? Цитата(zltigo @ Jul 1 2010, 00:14)  IAR Компилятор сделал все корректно и на 6 байт короче. Только в таблице у него 8 байтов, а у Keil-а 4. Итого, с учетом таблицы, 60 байтов против 62 байтов. P.S. А тема-то, действительно, начинает соответствовать своему названию - "Вопрос C"
|
|
|
|
|
Jul 1 2010, 11:57
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jul 1 2010, 10:55)  Только в таблице у него 8 байтов Это дело даже не второе, а третье, ибо байты кода это еще команды которые еще исполняются, а некоторые, типа PUSH/POP нескольких регистров, еще и не за один такт. QUOTE (ViKo @ Jul 1 2010, 10:55)  Как сделать в Keil то же, что и в IAR? Написать на ASM
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 1 2010, 13:59
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(zltigo @ Jul 1 2010, 15:55)  Посчитайте на пальцах. На пальцах до 200? У меня столько пальцев нет  Я лучше на бумаге  и калькуляторе. А SDIV r0,r0,r3 выполняется за 11 тактов... upd. Не всегда! - обнаружил и 10 тактов, и 9 тактов, похоже, от чисел зависит. О! чем меньше делимое, тем меньше тактов. Видел 4 такта. ... а MLS r2,r3,r0,r2 всего за 2. Так что на пальцах, извините, никак не посчитать. Максимальное количество тактов для SDIV заметил 12. Где про такты написано? 2 zltigoНу если упорно не хотите нормальное сравнение сделать...
|
|
|
|
|
Jul 1 2010, 15:24
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(ViKo @ Jul 1 2010, 17:59)  А SDIV r0,r0,r3 выполняется за 11 тактов... upd. Не всегда! - обнаружил и 10 тактов, и 9 тактов, похоже, от чисел зависит. О! чем меньше делимое, тем меньше тактов. Видел 4 такта. ... Максимальное количество тактов для SDIV заметил 12. Где про такты написано? Cortex-M3 Technical Reference ManualDivide: 2-12 Cycles DIV timings depend on dividend and divisor. DIV is interruptible (abandoned/restarted), with worst case latency of one cycle. When dividend and divisor are similar in size, divide terminates quickly. Minimum time is for cases of divisor larger than dividend and divisor of zero. A divisor of zero returns zero (not a fault), although a debug trap is available to catch this case.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|