|
Показать число с leading zeros. |
|
|
|
Jan 21 2015, 07:38
|
Профессионал
    
Группа: Участник
Сообщений: 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
|
|
|
|
|
 |
Ответов
|
Jan 21 2015, 08:45
|
Гуру
     
Группа: Свой
Сообщений: 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 с собой не притащит из либы. И, добавлю, это быстро, если в процессоре нет аппаратного деления.
|
|
|
|
|
Jan 21 2015, 09:24
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 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; }
|
|
|
|
|
Jan 21 2015, 09:41
|
Гуру
     
Группа: Свой
Сообщений: 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 стандартизованная ф-ция. Обязана быть!
|
|
|
|
|
Jan 21 2015, 11:37
|

Местный
  
Группа: Участник
Сообщений: 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 в каждой итерации цикла. В то время как библиотечные функции (если они есть) все-таки пишутся обычно более качественно.
|
|
|
|
|
Jan 21 2015, 12:37
|
Гуру
     
Группа: Свой
Сообщений: 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++]);
|
|
|
|
|
Jan 21 2015, 12:39
|

Местный
  
Группа: Участник
Сообщений: 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 только там, где знак нужет в явном виде.
|
|
|
|
|
Jan 21 2015, 12:47
|
Гуру
     
Группа: Свой
Сообщений: 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, то тут, к сожалению, С не покатит, так как нужно условие по флагу переноса после математической операции, что реализуемо только на ассемблере. Оптимизация, штука тонкая....
|
|
|
|
|
Jan 21 2015, 12:54
|

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

|
Цитата(SM @ Jan 21 2015, 12:47)  А если нужен полный диапазон unsigned, то тут, к сожалению, С не покатит, так как нужно условие по флагу переноса после математической операции, что реализуемо только на ассемблере. Оптимизация, штука тонкая.... если почитать книжку "Hacker's delight" (она есть и в русском переводе) или опять же погуглить, то можно нарыть методов проверки операций над целыми числами на переполнение на чистом Ц. там битхаки, завязанные на конкретную разрядность...
|
|
|
|
Сообщений в этой теме
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            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
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|