реклама на сайте
подробности

 
 
> Показать число с leading zeros.
Jenya7
сообщение Jan 21 2015, 07:38
Сообщение #1


Профессионал
*****

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



Мне нужно показать число (счетчик) с leading zeros, 8 позиций.
То есть вместо 1234 показать 00001234.
Делаю так
Код
void LCD_DisplayUpperCounter(uint32_t number)
{
    char strbuf[9] = "";
    ItoA(number, strbuf);
    char str[9] = "";

    if(number<10)
        strcat(str,"0000000");
    else if(number<100)
        strcat(str,"000000");
    else if(number<1000)
        strcat(str,"00000");
    else if(number<10000)
        strcat(str,"0000");
    else if(number<100000)
        strcat(str,"000");
    else if(number<1000000)
        strcat(str,"00");
    else if(number<10000000)
        strcat(str,"0");
    else
    {
        //str = "";
    }

    strcat(str,strbuf);
    LCD_DisplayUpperText(str);
}

Все работает. Вопрос можно ли оптимизировать функцию?

Сообщение отредактировал Jenya7 - Jan 21 2015, 07:39
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
SM
сообщение Jan 21 2015, 08:45
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Еще, если Ваш CPU умеет быстро вычислять экспоненту числа, то можно сразу вычислить смещение, куда и делать itoa. Но, это уже вне стандартного С, тут придется работать с интринсиками, и забыть о кроссплатформенности.

Еще, думаю, самый быстрый способ, сделать свой itoa:


char str[9];
int num_table[9] = {10000000, 1000000,100000,10000,1000,100,10,1,0};
int p=0;
char *str_p = str;
int i;

while (num_table[p]) {
i=0; while ( (number-=num_table[p]) >= 0) i++;
number += num_table[p++];
*str_p++='0' + i;
}


Извиняюсь, если где ошибся, писал прямо сюда, ни откуда не копировал. И никаких itoa с собой не притащит из либы.
И, добавлю, это быстро, если в процессоре нет аппаратного деления.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 21 2015, 09:24
Сообщение #3


Универсальный солдатик
******

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



Цитата(SM @ Jan 21 2015, 11:45) *
Еще, думаю, самый быстрый способ, сделать свой itoa:

Тем более, что в Keil, например, нет itoa для ARM.
Я сотворил когда-то вот такую функцию для Cortex. Но мне нужно, наоборот, чтобы лидирующие нули не писались. Можно переделать.
Код
void itoad_conv(int32_t numb, char *str)
{
  *(uint32_t *)(str)     = 0x20202020;
  *(uint32_t *)(str + 4) = 0x20202020;    
  *(uint32_t *)(str + 8) = 0x00302020;
  str += 10;
  char  sign = '+';
  if (!numb) return;
  if (numb < 0) { numb = -numb; sign = '-'; }
  do { *str-- = numb % 10 + '0'; } while (numb /= 10);
  *str = sign;
}
Go to the top of the page
 
+Quote Post
SM
сообщение Jan 21 2015, 09:41
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(ViKo @ Jan 21 2015, 12:24) *
numb % 10


Вот это - всегда делается за 32 итерации условного вычитания (если деление не аппаратное, да и там оно бывает итеративным), или условного сложения-вычитания (для 32-битного int). Поэтому, это не может быстрее, так как в том, что я предложил, для каждой цифры максимум 10 итераций вычитания, что в три раза меньше в самом худшем случае.

Цитата(ViKo @ Jan 21 2015, 12:24) *
Тем более, что в Keil, например, нет itoa для ARM.

Ой. А это, как? Это же ANSI стандартизованная ф-ция. Обязана быть!
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 21 2015, 09:47
Сообщение #5


Универсальный солдатик
******

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



Цитата(SM @ Jan 21 2015, 12:41) *
Ой. А это, как? Это же ANSI стандартизованная ф-ция. Обязана быть!

Нема, зуб даю. Года 4 назад писал об этом здесь же. И эту же программу выкладывал.
itoa - не стандартная функция. Предлагается пользоваться sprintf().
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jan 21 2015, 10:00
Сообщение #6


Профессионал
*****

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



я пользуюсь этим
Код
  
void Reverse(char s[])
{
  int c, i, j;

  for (i = 0, j = strlen(s)-1; i < j; i++ , j--)
  {
    c = s[i];
    s[i] = s[j];
    s[j] = c;
  }
  //s[i] = '\0';
}

void ItoA(uint32_t n , char s[])
{
  int i = 0;
  do
  {
    s[i++] = n % 10 + '0';
  }
  while ((n /= 10) >= 1);
   //s[i] = '\0';
  Reverse(s);
}



Сообщение отредактировал Jenya7 - Jan 21 2015, 10:01
Go to the top of the page
 
+Quote Post
CrimsonPig
сообщение Jan 21 2015, 11:37
Сообщение #7


Местный
***

Группа: Участник
Сообщений: 329
Регистрация: 23-04-14
Пользователь №: 81 502



Цитата(Jenya7 @ Jan 21 2015, 10:00) *
я пользуюсь этим
Код
  
void Reverse(char s[])
{
  int c, i, j;

  for (i = 0, j = strlen(s)-1; i < j; i++ , j--)
  {
    c = s[i];
    s[i] = s[j];
    s[j] = c;
  }
  //s[i] = '\0';
}

void ItoA(uint32_t n , char s[])
{
  int i = 0;
  do
  {
    s[i++] = n % 10 + '0';
  }
  while ((n /= 10) >= 1);
   //s[i] = '\0';
  Reverse(s);
}


Любителям прооптимизировать всякую мутоту на заметку:
1. операция взятия остатка от деления: (n%10) и деления (n/=10) насколько они дешевы ? Поддерживаются ли они на уровне железа процессора ? Можно ли без них обойтись ?
2. В цикле for (i = 0, j = strlen(s)-1; i < j; i++ , j--) есть наивное предположение, что компилятор вынесет strlen(s) за цикл как инвариант. В общем случае неверно. s передается как параметр в функцию и компилятор имеет право решить, что данные строки могут изменяться извне в другом треде, например. Поэтому с чистой совестью может оставить вызов strlen в каждой итерации цикла.
В то время как библиотечные функции (если они есть) все-таки пишутся обычно более качественно.

Go to the top of the page
 
+Quote Post
Jenya7
сообщение Jan 21 2015, 12:03
Сообщение #8


Профессионал
*****

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



Цитата(CrimsonPig @ Jan 21 2015, 17:37) *
Любителям прооптимизировать всякую мутоту на заметку:
1. операция взятия остатка от деления: (n%10) и деления (n/=10) насколько они дешевы ? Поддерживаются ли они на уровне железа процессора ? Можно ли без них обойтись ?
2. В цикле for (i = 0, j = strlen(s)-1; i < j; i++ , j--) есть наивное предположение, что компилятор вынесет strlen(s) за цикл как инвариант. В общем случае неверно. s передается как параметр в функцию и компилятор имеет право решить, что данные строки могут изменяться извне в другом треде, например. Поэтому с чистой совестью может оставить вызов strlen в каждой итерации цикла.
В то время как библиотечные функции (если они есть) все-таки пишутся обычно более качественно.


так нету библиотечных функций в том то и дело. и более лучшей генерик функции я не нашел.
Go to the top of the page
 
+Quote Post
SM
сообщение Jan 21 2015, 12:37
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(Jenya7 @ Jan 21 2015, 15:03) *
так нету библиотечных функций в том то и дело. и более лучшей генерик функции я не нашел.


То, что я дал код, переделывается на работу без нулей введением одного флага, который сначала запрещен, и разрешается при первом ненулевом символе. И управляет занесением символов в выходной буфер. Все равно шустрее, чем использовать % и /, и, даже шустрее, чем c div_t div(int numer, int denom); (сразу % и / в одном флаконе).


char str[9];
int num_table[9] = {10000000, 1000000,100000,10000,1000,100,10,1,0};
int p=0;
char *str_p = str;
int i;
int flag=0;

while (num_table[p]) {
i=0; while ( (number-=num_table[p]) >= 0) i++;
number += num_table[p++];
flag |= i;
if (flag) *str_p++='0' + i;
}

Еще можно дооптимизировать, чтобы условное занесение в буфер убрать из цикла, разделив цикл на две части, ну и убрать флаг.

char str[9];
int num_table[9] = {10000000, 1000000,100000,10000,1000,100,10,1,0};
int p=0;
char *str_p = str;
int i;
int flag=0;
int tmp;

if (!num) {
*str_p++='0';
return;
}

while ((tmp=num_table[p++]) && (number < tmp)) ;

do {
i='0'; while ( (number-=tmp) >= 0) i++;
number += tmp;
*str_p++=i;
} while (tmp = num_table[p++]);
Go to the top of the page
 
+Quote Post
CrimsonPig
сообщение Jan 21 2015, 12:39
Сообщение #10


Местный
***

Группа: Участник
Сообщений: 329
Регистрация: 23-04-14
Пользователь №: 81 502



Цитата(SM @ Jan 21 2015, 12:17) *
То, что я дал код, переделывается на работу без нулей введением одного флага, который сначала запрещен, и разрешается при первом ненулевом символе. И управляет занесением символов в выходной буфер. Все равно шустрее, чем использовать % и /, и, даже шустрее, чем c div_t div(int numer, int denom); (сразу % и / в одном флаконе).


<зевая> int у нас какой разрядности ?

Я практически отошел от использования "просто int". Гораздо спокойнее писать "uint32_t", "uint16_t", "uint8_t" и не беспокоиться о портабельности кода на машину с другой архитектурой ЦПУ.
А еще я ненавижу знаковый int, и использую int32_t только там, где знак нужет в явном виде.
Go to the top of the page
 
+Quote Post
SM
сообщение Jan 21 2015, 12:47
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(CrimsonPig @ Jan 21 2015, 15:39) *
<зевая> int у нас какой разрядности ?

Это пусть автор разбирается. Я предпочитаю соблюдать старые добрые стандарты, где еще нет int32_t.

Цитата(Jenya7 @ Jan 21 2015, 15:45) *
while ( (number-=num_table[p]) >= 0) всегда true.

Это с какого перепуга? Тип не unsigned.
А если нужен полный диапазон unsigned, то тут, к сожалению, С не покатит, так как нужно условие по флагу переноса после математической операции, что реализуемо только на ассемблере. Оптимизация, штука тонкая....
Go to the top of the page
 
+Quote Post
CrimsonPig
сообщение Jan 21 2015, 12:54
Сообщение #12


Местный
***

Группа: Участник
Сообщений: 329
Регистрация: 23-04-14
Пользователь №: 81 502



Цитата(SM @ Jan 21 2015, 12:47) *
А если нужен полный диапазон unsigned, то тут, к сожалению, С не покатит, так как нужно условие по флагу переноса после математической операции, что реализуемо только на ассемблере. Оптимизация, штука тонкая....


если почитать книжку "Hacker's delight" (она есть и в русском переводе) или опять же погуглить, то можно нарыть методов проверки операций над целыми числами на переполнение на чистом Ц.
там битхаки, завязанные на конкретную разрядность...
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- Jenya7   Показать число с leading zeros.   Jan 21 2015, 07:38
- - SM   1) sprintf(strbuf,"%08u",number); Притащ...   Jan 21 2015, 07:43
|- - Jenya7   Цитата(SM @ Jan 21 2015, 13:43) 1) sprint...   Jan 21 2015, 08:40
||- - SM   Цитата(ViKo @ Jan 21 2015, 12:47) Нема, з...   Jan 21 2015, 09:51
|||- - andrew_b   Цитата(SM @ Jan 21 2015, 12:51) Да, Вы пр...   Jan 21 2015, 11:01
|||- - CrimsonPig   Цитата(Jenya7 @ Jan 21 2015, 12:03) так н...   Jan 21 2015, 12:16
|||||- - SM   Цитата(CrimsonPig @ Jan 21 2015, 15:54) т...   Jan 21 2015, 12:57
|||||- - CrimsonPig   Цитата(SM @ Jan 21 2015, 12:57) Но это не...   Jan 21 2015, 13:02
||||- - Jenya7   Цитата(SM @ Jan 21 2015, 18:47) Это пусть...   Jan 21 2015, 13:00
||||- - SM   Цитата(Jenya7 @ Jan 21 2015, 16:00) надо ...   Jan 21 2015, 13:05
||||- - Jenya7   Цитата(SM @ Jan 21 2015, 19:05) Если же В...   Jan 21 2015, 13:24
||||- - SM   Цитата(Jenya7 @ Jan 21 2015, 16:24) и с ...   Jan 21 2015, 13:28
||||- - Jenya7   Цитата(SM @ Jan 21 2015, 19:28) Чего там ...   Jan 21 2015, 14:18
||||- - CrimsonPig   Цитата(Jenya7 @ Jan 21 2015, 14:18) в при...   Jan 21 2015, 14:36
||||- - SM   Цитата(CrimsonPig @ Jan 21 2015, 17:36) c...   Jan 21 2015, 14:40
||||- - CrimsonPig   Цитата(SM @ Jan 21 2015, 14:40) не const,...   Jan 21 2015, 14:53
||||- - SM   RE: Показать число с leading zeros.   Jan 21 2015, 15:02
|||||- - CrimsonPig   Цитата(SM @ Jan 21 2015, 15:02) Потому, ч...   Jan 21 2015, 15:09
|||||- - SM   Цитата(CrimsonPig @ Jan 21 2015, 18:09) К...   Jan 21 2015, 15:19
||||- - Jenya7   Цитата(CrimsonPig @ Jan 21 2015, 20:53) Н...   Jan 21 2015, 15:46
|||- - AHTOXA   Цитата(Jenya7 @ Jan 21 2015, 17:03) так н...   Jan 21 2015, 13:43
|||- - Jenya7   Цитата(AHTOXA @ Jan 21 2015, 19:43) Выбир...   Jan 21 2015, 14:45
||- - andrew_b   Цитата(CrimsonPig @ Jan 21 2015, 14:37) 2...   Jan 21 2015, 13:39
|- - Jenya7   Цитата(SM @ Jan 21 2015, 14:45) Еще, если...   Jan 21 2015, 12:45
- - Jenya7   интересно. спасибо. надо проверить.   Jan 21 2015, 09:11
- - SM   Извращение какое... Сначала сделать строку с напра...   Jan 21 2015, 10:07
|- - Jenya7   Цитата(SM @ Jan 21 2015, 16:07) Извращени...   Jan 21 2015, 10:48
- - SM   Что-то у вас косяк с уровнем оптимизации. Это пише...   Jan 21 2015, 14:21
|- - Jenya7   Цитата(SM @ Jan 21 2015, 20:21) Что-то у ...   Jan 21 2015, 14:50
- - SM   Вот еще оптимизация (все время забываю про то, что...   Jan 21 2015, 14:47


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 25th July 2025 - 03:47
Рейтинг@Mail.ru


Страница сгенерированна за 0.01528 секунд с 7
ELECTRONIX ©2004-2016