Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопрос С
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2, 3
badik
Здравствуйте, Вопрос к людям хорошо знающим С.
Понадобилась функция перевода целого числа в строку. Перерыл спрвочник и help - результат 0.
Банальная проблема. Увы. Обраных функций вагон.
DRUID3
atoi()/itoa(); Или что-то отсюда...
Genadi Zawidowski
Тут или пользоваться 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;
    }
}

ViKo
В свое время я задавал такой же вопрос. Получил несколько ответов, в том числе и не очень "полезных и приятных". Сам написал такое:
Код
void si16toad (int16_t Number, char * StrBuf)
{
  char Sign = ' ';
  if (Number > 0) Sign = '+';
  if (Number < 0) {
    Sign = '-';
    Number = -Number;
  }
  StrBuf[6] = '\0';
  signed char i = 5;
  do {
    StrBuf[i--] = Number % 10 + '0';
    Number /= 10;
  } while (Number);
  StrBuf[i] = Sign;
  for (i--; i >= 0; i--) StrBuf[i] = ' ';
}
zltigo
QUOTE (ViKo @ Jun 25 2010, 14:29) *
Сам написал такое

Совет - больше никому "такое" не показывайте, ну если только врагам.
sonycman
Цитата(zltigo @ Jun 25 2010, 15:38) *
Совет - больше никому "такое" не показывайте, ну если только врагам.

Что же в этой функции такого плохого?
jorikdima
Цитата(ViKo @ Jun 25 2010, 15:29) *
В свое время я задавал такой же вопрос. Получил несколько ответов, в том числе и не очень "полезных и приятных". Сам написал такое:

тяжеловесно и потенциально опасно в смысле стрельбы по памяти
ViKo
Цитата(zltigo @ Jun 25 2010, 14:38) *
Совет - больше никому "такое" не показывайте, ну если только врагам.

Я хотел приписать, что это один из первых моих "опусов", но подумал, что в качестве примера для изучения сгодится.
Если можете выдать "достойный" образец, прошу!
P.S. У меня знак рисуется непосредственно перед числом, выравнивается по правому краю. А, ну да, можно было применить указатель, но тогда не пришло в голову.
P.P.S. Господа, давайте найдем, наконец, лучшее решение. А то, сколько людей, столько и мнений. Да, я помню высказывание zltigo, что тема избита. Однако...
zltigo
QUOTE (sonycman @ Jun 25 2010, 15:15) *
Что же в этой функции такого плохого?

Абсолютно все sad.gif. Написано на уровне диалекта "Эллочки людоедки", лишние действия, вычиcления, циклы.

QUOTE (ViKo @ Jun 25 2010, 15:21) *
давайте найдем, наконец, лучшее решение.

А что такое лучшее? Гуано оно всегда гуано, а лучшее, как минимум требует критериев для оценки. Если, например, скорость, то для AVR и 16bit чисел уж точно делений быть не должно, тем более громоздкого сочетания деления и взятия остатка от деления.
А тема, действительно, избитая донельзя. Повторять мамнадцатый раз не вижу смысла.
ViKo
Цитата(zltigo @ Jun 25 2010, 15:24) *
...лишние действия, вычиcления, циклы...

Оставил только значимую часть сообщения smile.gif
Лучший способ воспитания - на собственном примере.
Покажите, как надо.
sonycman
Цитата(ViKo @ Jun 25 2010, 16:31) *
Оставил только значимую часть сообщения smile.gif
Лучший способ воспитания - на собственном примере.
Покажите, как надо.

Особенно интересно, как можно это реализовать без циклов smile.gif
aaarrr
Просто как пример:
Код
unsigned int short2str(char *str, unsigned short v, unsigned int slz)
{
    unsigned int a, b, n = 0;
    unsigned long vi;

    vi = v * 26844UL;
    if(v >= 57074) vi -= 13422;    // Вдруг кто скопипастит без проверки
    for(a = 0; a < 5; a++)
    {
        b = vi >> 28;
        if(b || !slz)
        {
            *str++ = b + '0';
            n++;
            slz = 0;
        }
        vi &= ~(0x0f << 28);
        vi *= 10;
    }
    if(!n)
    {
        *str++ = '0';
        n = 1;
    }
    *str++ = 0;
    return n;
}
ViKo
Цитата(zltigo @ Jun 25 2010, 15:24) *
лучшее, как минимум требует критериев для оценки

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

Ну для этого сначала нужно понимать русский языка, в частности различие между единственным (цикл)и множественным числом (циклы). В данном конкретном случае, когда по неведомым причинам формат фиксирован 6 символами и используются страшные / и % не нужен и единственный цикл.

ViKo
Цитата(zltigo @ Jun 25 2010, 15:57) *
В данном конкретном случае, когда по неведомым причинам формат фиксирован 6 символами и используются страшные / и % не нужен и единственный цикл.

int16 укладывается в эти 6 символов, со знаком, ни больше, ни меньше.
В первом цикле вычисляются цифры, во втором забивал пробелами оставшееся место слева. Можно было сразу инициализировать массив пробелами, но было бы ли это эффективнее?
sonycman
Цитата(zltigo @ Jun 25 2010, 16:57) *
Ну для этого сначала нужно понимать русский языка, в частности различие между единственным (цикл)и множественным числом (циклы).

Нерусский учит русскому языку? smile.gif

Имхо, не стоит разворачивать циклы, получится мизерная прибавка к скорости, но чувствительно увеличится размер кода.
aaarrr
Цитата(sonycman @ Jun 25 2010, 17:13) *
Нерусский учит русскому языку? smile.gif

Многим стоило бы поучиться.

Цитата(sonycman @ Jun 25 2010, 17:13) *
Имхо, не стоит разворачивать циклы, получится мизерная прибавка к скорости, но чувствительно увеличится размер кода.

Нужно не разворачивать имеющиеся, а не плодить лишние.
zltigo
QUOTE (ViKo @ Jun 25 2010, 15:50) *
У вас есть что-нибудь для ARM - Cortex?

как и для всех других - наиболее часто используется усеченная реализация printf(). Для ARM, кстати, деление и иже с ним, в нем тоже не используются - десятичные числа, в отличии от hex у меня почти всегда немногозначные - на вычитании быстрее.
QUOTE (sonycman @ Jun 25 2010, 16:13) *
Нерусский учит русскому языку? smile.gif

Я с середины шестого класса за границей CCCР в русской школе учился, а учителя там были очень хорошие. После той 'пятерки', особых проблем с грамотностью нет, хотя, конечно, забывается sad.gif.
QUOTE (ViKo @ Jun 25 2010, 16:06) *
во втором забивал пробелами....

Все делать в первом.
ViKo
Цитата(zltigo @ Jun 25 2010, 16:28) *
как и для всех других - наиболее часто используется усеченная реализация printf(). Для ARM, кстати, деление и иже с ним, в нем тоже не используются - десятичные числа, в отличии от hex у меня почти всегда немногозначные - на вычитании быстрее.

Осталось только выложить его сюда.
Цитата
Я с середины шестого класса за границей CCCР в русской школе учился, а учителя там были очень хорошие.

нужно писать "в отличие"
Цитата
Все делать в первом.

А "минус" и "плюс" потом занести? Неужто эффективнее?
У меня выводится следующим образом:
(upd. добавил еще и 0 для полноты)
Код
"     0"
"   -12"
"+32767"
zltigo
QUOTE (ViKo @ Jun 25 2010, 16:34) *
нужно писать "в отличие"

Про "отличия" не знаю, а там хорошие.
QUOTE (ViKo @ Jun 25 2010, 16:34) *
Осталось только выложить его сюда.

Это уже мое дело.
ViKo
Цитата(zltigo @ Jun 25 2010, 16:39) *
Про "отличия" не знаю, а там хорошие.

Это у вас синтаксическая ошибка в посте №18

И на этом закончим? Единственное, что я вынес из разговора - надо с указателем повозиться. И к коду aaarrr присмотреться, пока что не понимаю, как работает.
zltigo
QUOTE (ViKo @ Jun 25 2010, 16:43) *
Это у вас ошибка в посте №18

Ну это да, предлог 'в отличие' и существительное в предложном падеже с предлогом 'в' sad.gif попутал. Я же говорю - забывается sad.gif. Язык не прост. Не 'C' smile.gif, ну и форум не филологический, а "сишный", к счастью.
QUOTE (ViKo @ Jun 25 2010, 16:43) *
Единственное, что я вынес из разговора - надо с указателем повозиться.

А то, что ДВЕ операции деление и взятие остатка от деления замного будет, не вынесли sad.gif
ViKo
Цитата(zltigo @ Jun 25 2010, 16:56) *
Ну это да, предлог 'в отличие' и существительное в предложном падеже с предлогом 'в' sad.gif попутал. Я же говорю - забывается sad.gif . Язык не прост.

Замечу, что я вам на ваши ошибки указал без оскорбительных выражений.
Учу на собственном примере. smile.gif

Цитата(zltigo @ Jun 25 2010, 16:56) *
А то, что ДВЕ операции деление и взятие остатка от деления замного будет, не вынесли sad.gif

О! А как... ?
zltigo
QUOTE (ViKo @ Jun 25 2010, 17:04) *
О! А как... ?

Ну, например, как у Genadi. И, если выбирать из двух, то тогда уж оставлять деление, а не остаток он него - много менее громоздко в подавляющем большинстве случаев.
aaarrr
Цитата(ViKo @ Jun 25 2010, 17:43) *
И к коду aaarrr присмотреться, пока что не понимаю, как работает.

Неправильно, кстати, работает для v >= 59074 biggrin.gif
В качестве отмазки скажу, что таких чисел у меня и не было.

Можно, конечно, компенсатор ошибки округления приделать, типа: if(v >= 57074) vi -= 13422, но это уже некрасиво. Зато для знаковых 16-битных чисел исходный вариант годится без всяких допиливаний smile.gif
sonycman
Цитата(zltigo @ Jun 25 2010, 17:56) *
А то, что ДВЕ операции деление и взятие остатка от деления замного будет, не вынесли sad.gif

Хм, но если делать вычитанием, то это будет цикл, а деление нужно сделать только один раз, тем более оно на кортексе аппаратное вроде?
Будет быстрее.
ViKo
Цитата(zltigo @ Jun 25 2010, 17:10) *
Ну, например, как у Genadi.

А разве в коде Genadi видно, как у него реализована функция ldiv?
Goodefine
Когда то для дисплея (отсюда фиксированное число цифр в числе) делал примерно так:
Код
//-----------Функция преобразования числа в строку----------//
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]; //переписываем в наш массив                                                }
      
}
//==========================================================//

zltigo
QUOTE (sonycman @ Jun 25 2010, 17:55) *
Будет быстрее.

На 9999999999 типа, да, а вот на 123? Попробуйте.

QUOTE (ViKo @ Jun 25 2010, 19:15) *
А разве в коде Genadi видно, как у него реализована функция ldiv?

Видно, на что он делит.

defunct
Цитата(ViKo @ Jun 25 2010, 14:29) *
Сам написал такое:void si16toad (int16_t Number, char * StrBuf)


Алгоритм один в один.. Другого наверно и быть не может.
Код
// convert and output decimal value
int IntToStrPrint( S32 val )
{
    U8  c, len = 0;
    U8  buf[ 10 ]; // max size for text representation of S32 value

    if (val < 0)
    {
        PutChar('-');
        val =  -val;
    }

    do {
        c = val % 10 + '0';
        val /= 10;
        buf[ len++ ] = c;
    } while (val != 0);
    
    while (len)
        PutChar(buf[ --len ]);
    return SUCCESS;
}
ViKo
Цитата(Goodefine @ Jun 25 2010, 19:19) *
void decbin_5dgt(uint8_t* x, uchar8* buffer)
...

Должно быть uint16_t *x
ssvSerge
Цитата(defunct @ Jun 25 2010, 19:48) *
Другого наверно и быть не может.

Ух какое обсуждение получилось.
И циклы вам не нравятся и деления - страшны.

Табличные решения должны быть быстрее.
Экономия будет на циклах и на операциях деления.

Каждая операция деления заменяется двеятью сравнениями
в худшем случае. (9ю сравнениями для каждого десятичного
знакоместа).

Вопрос в том на какой таблице остановиться:
Если на десятичной, то таблица будет 36 слов (4знака * 9цифр).
Если на двоичной, то надо будет осуществлять двоично-десятичное сложение.

Двоичная таблица будет медленнее (скорее всего) если есть аппаратный
умножитель. А вот если его нет, то будет быстрее раз эдак в 200 чем
программное деление.
ViKo
Пролистал K&R второе издание от корки до корки, нашел практически такое же "гуано" на языке Элочки Людоедовой, как у меня, defunct, да и Goodefin недалеко от него ушел smile.gif
Раздел 3.6 стр. 77. Те же деление и взятие остатка от деления. С учетом функции reverse - 2 цикла. (замечу в скобках, что книжка эта у меня появилась не так давно, до этого пользовался Шилдтом, но решил "продвинуться", так что любые совпадения - случайны smile.gif)
Еще приводится пример рекурсивного вызова на стр. 100, тоже не скажу, что блещет производительностью.

А табличный способ - самый быстрый. Но и самый жрущий память кода smile.gif Это одна из крайностей. Найти бы еще самый компактный.

P.S. Кстати, автор топика не указал, для чего ему нужна функция itoa. А может, он под Windows пишет, и на производительность и компактность ему одинаково наплевать. smile.gif
aaarrr
Цитата(ViKo @ Jun 25 2010, 23:15) *
Найти бы еще самый компактный.

Компактность зависит от архитектуры - если нет аппаратного умножения/деления, самым компактным получится вычитание.
sigmaN
K&R не Ымбеддеры. А zltigo дело говорит вам. К чему там ещё и к словам русского языка придираться то было?
ViKo
Покопался в своих проектах, нашел преобразование для PIC16. 2 байта преобразовываются в 3 двоично-десятичных упакованных. От которых рукой подать до ASCII. Выдаю кусок из файла. Может кому-то покажется интересным.

Цитата(sigmaN @ Jun 25 2010, 22:27) *
...К чему там ещё и к словам русского языка придираться то было?

Исключительно с целью обучения навыкам культурного ведения диалогов при общении.

Цитата(sigmaN @ Jun 25 2010, 22:27) *
K&R не Ымбеддеры.

А badik , с которого все началось, эмбеддер? Он об этом не говорил.
Genadi Zawidowski
Цитата(ViKo @ Jun 25 2010, 20:15) *
А разве в коде Genadi видно, как у него реализована функция ldiv?

А какая разница, как? Между прочим, это функция стандартной библиотеки C. Вместе с div(). В реализации библиотеки от CodeVision отсутствует.
Обычно эти функции инлайнятся, если есть аппаратное деление. После аппаратного (или программного) деления и частное и остаток обычно присутствуют в регистрах процессора и структура ldiv_t (div_t) эти самые регистры впрямую и отображает. Так было на x86. На ARM и AVR не интересовался.
ViKo
Цитата(Genadi Zawidowski @ Jun 25 2010, 23:33) *
Между прочим, это функция стандартной библиотеки C.

Это я уже понял. Есть ли в Keil для Cortex-M3 не смотрел, надеюсь, есть. Тогда можно будет совместить деление и взятие остатка. Попробую на досуге.
upd. Попробовал. Есть такая функция. Однако после замены деления и взятия остатка на div() размер кода остался тем же. Подробнее буду разбираться позже.
Для ARM интересен вариант от aaarrr - из области трюков и фокусов. Реально полезный пример!
А для процессоров без умножений и делений - вычитание, а на ассемблере - с помощью команд двоично-десятичной коррекции (вот бы на C ее задействовать).
dimka76
Цитата(ViKo @ Jun 25 2010, 23:15) *
Пролистал K&R второе издание от корки до корки


Чутарик не в тему. На форуме все ссылаются на эту книгу. Хотя Дэнис Ричи и является отцом-основателем языка, но это не означает, что он написал хорошую книгу. Мне, например, вот ЭТА очень понравилась.

Теперь по теме. Предлагаю глянуть, что ATMEL предлагает. А глядеть ЗДЕСЬ
zltigo
QUOTE (ViKo @ Jun 25 2010, 22:15) *
Пролистал K&R второе издание от корки до корки, нашел практически такое же "гуано" на языке Элочки Людоедовой

Не обижайте Кернигана sad.gif. Проблема % / это одна частная проблема, которая на некоторых платформах и не проблема - настоятельно
рекомендую откомпилировать и посмотреть на результат работы с 32bit для:
Pentium
Сortex-M3
ARM7
ATmega
ATtiny
Ильфа тоже не обижайте - Эллочкина фамилия была Щукина, а "людоедкой" она была по причине того, что обходилась 30 словами. В чем ее превосходило даже племя людоедов Мумбо-Юмбо, чей словарный запас был 300 слов.
ReAl
Цитата(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* всё равно линкуются.
ViKo
Цитата(zltigo @ Jun 26 2010, 11:11) *
Не обижайте Кернигана ... настоятельно
рекомендую откомпилировать и посмотреть на результат работы с 32bit для:
...Сortex-M3...

А я для чего написал? STM32. Вот и вы меня "не обижайте". Хоть я и не Керниган.smile.gif
Цитата
Ильфа тоже не обижайте...

Написал, как помнилось. Не входит в сферу моих обязательных знаний, которые нужно периодически обновлять. Наверное, вы правы. Признаю!
Непомнящий Евгений
В свое время написал такое:
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 АВР) с двумя алгоритмами - первый использовал деление, второй - вычитание. Цифр уже не помню, но оказался быстрее обоих. Кроме того работает с числами произвольной длины (несколько раз понадобилось smile.gif ) и контролирует переполнение.

Конвертит не в АСКи, а в BCD - две десятичных цифры в байте - но потом легко преобразовать куда надо.

ЗЫ смайлы почему-то парсятся в коде...
zltigo
QUOTE (ViKo @ Jun 26 2010, 12:08) *
А я для чего написал?

Вы написали для чего-то на момент написания неназванного. Топикстартер, тоже не сказал для чего. Посему повторяю рекомендации откомпилировать и посмотреть на результат с / % для всех ранее помянутых ядер. Так-же напомню, что слово "гуано" относилось далеко не только к использованию / %.

sonycman
Цитата(ReAl @ Jun 26 2010, 13:04) *
Оптимизатор сам не видит, что можно было бы вызвать деление один раз.

Да, я тоже замечал, что функция деления вызывается именно два раза (сначала остаток, потом деление), несмотря на то, что достаточно было бы единственного вызова.

Хотя это было, вроде бы, ещё на AVR. Не знаю, как это будет компилироваться под кортекс и RealView.
ViKo
Следуя рекомендациям, слегка модернизировал код.
Код
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] = ' ';
}

Результат оказался несколько неожиданным smile.gif Ни в первом, ни во втором случае RealView MDK-ARM 4.10 не использует команды деления вообще. А код оказался равным по размеру (и по содержанию, похоже). Так что можно сделать вывод, что / и % компилятор все-же объединил.
А заняла функция деления примерно 80 команд (не машинных тактов, а именно строк в ассемблерном коде).

2 Непомнящий Евгений
На таком принципе основан мой код для PIC, который чуть выше в файле лежит. Только написан на ассемблере.

Цитата(zltigo @ Jun 26 2010, 12:18) *
Посему повторяю рекомендации откомпилировать и посмотреть на результат с / % для всех ранее помянутых ядер. Так-же напомню, что слово "гуано" относилось далеко не только к использованию / %.

Для всех ядер - это вы уж слишком многого от меня хотите. smile.gif У меня и компиляторов таких нет.
А для Cortex-M3 я написал и откомпилировал, и из ваших высказываний так и не понял, что бы такого можно было улучшить в моем коде. А примера, как надо делать, вы не привели.
ssvSerge
Цитата(ViKo @ Jun 26 2010, 14:24) *
Следуя рекомендациям, слегка модернизировал код.
вы бы озвучили с какой целью модифицировался код.
надо "быстрый алгоритм", "короткий код", "читаемый текст" или еще что-то?

Нужен быстрый и не требовательный алгоритм - в atoi_v1.
слишком длинное решение - посмотрите в atoi_v2.

Операции деления отсутствуют как класс.

P.S. тексты в файлах - написаны за 2 минуты и на работоспособность
не проверялись. демонстрируется метод табличного решения задачи.
ничего более.

P.P.S. метод имеет смысл применять на простых контроллерах без
аппаратного умножителя. (с умножителем надо думать).

Сергей.
ViKo
2 ssvSerge
В ваших алгоритмах число записывается задом наперед, надо iStorePos++; и нет индикации знака числа. А в остальном - можно и так.

Для чего код модернизировал - сделать то, что имею, лучше, оптимальнее. В идеале - оптимальнее и по производительности, и по компактности.

ssvSerge
Цитата(ViKo @ Jun 26 2010, 16:55) *
В алгоритмах число записывается задом наперед и нет индикации знака числа.

кроме этого нет проверки на 0 и в одном из разрядов нет проверки на "bIsDigitPresent".
Это если уж быть точным. Но это мелочи - код и не претендовал на работоспособность.
Главное, что подход понятен.

Цитата(ViKo @ Jun 26 2010, 16:55) *
код сделать лучше, оптимальнее.

Слово "оптимальнее" следует исключить из лексикона как антинаучное.
Есть критерии: скорость, объем, читабельность и т.д.
Для каждого человека, проекта, процессора критерии изменяются.

Цитата(ViKo @ Jun 26 2010, 16:55) *
В идеале - оптимальнее и по производительности, и по компактности.

ну так озвучьте цифры какой из вариантов (табличный или с делениями)
оптимальнее в конкретно вашем случае. на ваших процессорах и в ваших
глазах.

Сергей.
ViKo
Цитата(ssvSerge @ Jun 26 2010, 17:19) *
ну так озвучьте цифры какой из вариантов (табличный или с делениями)
оптимальнее в конкретно вашем случае. на ваших процессорах и в ваших
глазах.

В данный момент меня занимает алгоритм от aaarrr, поискал по компу своему книжку по цифровые трюки, но не нашел. А ведь была. Нельзя ли его расширить, чтобы принимал все числа.
Второй вариант - преобразовать bin в BCD, а затем уже превратить в строку.
Табличный способ меня не привлекает из-за громоздкости.
Точные цифры по быстродействию и размеру кода я не смотрел. Если будет что сказать, доложу.

P.S. Определился, пожалуй, что для меня значит оптимальность. = Компактность кода. А быстродействие мне STM32 и так обеспечит.
P.P.S. Причем, часто бывает, что компактный код и работает быстро.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.