Советы по оптимизации :)

Тема в разделе "LANGS.C", создана пользователем S4urp8n, 5 апр 2009.

  1. S4urp8n

    S4urp8n New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    30
    Ниже кусок кода, точнее функция, переделывающая число,записанное цифрами (до одного миллиарда), в числительное (число записанное буквами, порядковое). Я уверен что оптимизировать это ещё как можно, так как скорость не приемлимая (на асме запарюсь писатьЖ)))), поэтому прошу помочь в этом нелёгком оптимизационном деле, с чего начать то?
     
  2. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    S4urp8n
    Case замени на выбор из массива. Так что бы в массиве были все числа из разряда записанные пропесью. Для младших можно все два забить.
     
  3. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    а почему бы не составить таблицу типа
    bin_number, char_name[], но упорядочить в ней все строки по алфавиту и собрать все указатели на bin_number в массив, тогда можно предположить следующий вариант поиска
    сравниваем символ i текущей строки, если он совпадает, то переходим к следующему, если нет, то к следующей строке. когда найдешь пробел, то сравниваешь всю строку целиком.
    Код (Text):
    1. я не буду все упорядочивать, но вот так
    2. mas  dd v0, v1, ...
    3. v0 dd 0
    4.     db "НОЛЬ "
    5. ...
    6.  
    7. mov ebp, str
    8. mov edx, ebp
    9. xor edi, edi
    10. xor esi, esi
    11. @@:
    12. mov ebx, [mas+edi*4]
    13. lp:
    14. mov al, [ebx+esi+4]
    15. cmp al, [ebp]
    16. jz @f
    17. inc edi
    18. jmp @b
    19. @@:
    20. cmp al, 32
    21. jz @f
    22. inc ebp
    23. inc esi
    24. jmp lp
    25. @@:
    26. mov esi, edx
    27. mov ecx, ebp
    28. sub ecx, edx
    29. mov edi, [mas+edi*4]
    30. add edi, 4
    31. repe cmpsb
    32. jnz @f
    33. ;все ок
    34. ret
    35. @@:
    36. ;error
    37. ret
    ADD: главное чтобы указатели в массиве mas указывали на структуры в алфавитном порядке, а не как у меня с 0
     
  4. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    S4urp8n
    Когда-то очень давно писал для друга. С подробными комментариями. Не припоминаю, чтобы были проблемы с быстродействием. Поддерживает числа до 10^36, включая десятичные дроби.
    Код (Text):
    1. //Библиотека содержит функции ввода-вывода
    2. #include <stdio.h>
    3. //Библиотека содержит функции для работы со строками
    4. #include <string.h>
    5. //Библиотека содержит функцию int atoi (const char *)
    6. #include <stdlib.h>
    7. //Библиотека содежит функцию int getch ()
    8. #include <conio.h>
    9.  
    10. //Функция перевода строки из кодировки Windows в кодировку DOS
    11. char *todos(char *str);
    12. //Функция преобразования целого положительного числа в текстовое
    13. //представление
    14. void convert(char *number);
    15. //Функция перевода тройки цифр в текстовое представление
    16. void conv3(char *number, int trion);
    17. //Функция дописывания статуса тройки цифр (тысяча, миллион и т.д.)
    18. void conv3name(char *number, int trion);
    19. //Функция дописывания статуса дробной части (десятая, сотая,
    20. //тысячная, десятитысячная и т.д.)
    21. void addSubZero(int numSigns, bool female);
    22.  
    23. //Переменная, определяющая, является ли исходное число целым
    24. bool isInt;
    25. //Строка для результата работы программы
    26. char numstr[1500] = {0};
    27. //Массивы строк, содержащие соответствующие наименования базовых
    28. //чисел
    29. const char nums1[][13]={"один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять", "десять", "одиннадцать",
    30.  
    31. "двенадцать", "тринадцать", "четырнадцать", "пятнадцать", "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать"};
    32. const char nums2[][12]={"двадцать", "тридцать", "сорок", "пятьдесят", "шестьдесят", "семьдесят", "восемьдесят", "девяносто"};
    33. const char nums3[][10]={"сто", "двести", "триста", "четыреста", "пятьсот", "шестьсот", "семьсот", "восемьсот", "девятьсот"};
    34. const char great[][12]={"тысяч", "миллион", "миллиард", "триллион", "квадриллион", "квинтиллион", "секстиллион", "септиллион",
    35.  
    36. "октиллион", "нониллион", "дециллион"};
    37.  
    38. //С этой функции начинается работа программы
    39. void main()
    40. {
    41.     //Строка-приглашение для ввода пользователю
    42.     char invit[]="Введите число ";
    43.     //Строка, содержащая исходное число и указатель на нее
    44.     char numbuf[80]; char *number = numbuf;
    45.     //Выводим приглашение для ввода, предварительно преобразовав
    46.     //его в DOS-кодировку
    47.     printf(todos(invit));
    48.     //Первые два байта строки, содержащей исходное число
    49.     //забиваем символом "0"
    50.     number[0] = '0'; number[1] = '0';
    51.     //Смещаем указатель на строку на эти два байта
    52.     number += 2;
    53.     //Читаем с клавиатуры исходное число
    54.     scanf ("%s", number);
    55.     //Проверяем, целое ли введенное число, и записываем результат
    56.     //проверки в переменную isInt
    57.     isInt = (strchr(number, '.') == 0 && strchr(number, ',') == 0);
    58.     //Если число дробное, то...
    59.     if (!isInt)
    60.         //...заменяем разделитель дробной и целой части
    61.         //нуль-терминатором
    62.         *(strchr(number, '.') != 0 ? strchr(number, '.') : strchr(number, ',')) = 0;
    63.     //Если исходное число не нуль, то вызываем функцию
    64.     //преобразования числа в текстовое представление, а...
    65.     if (*number!='0') convert(number);
    66.     //если нуль, то добавляем в строку-результат текст "нуль "
    67.     else strcat(numstr, "нуль ");
    68.     //Если число дробное, то...
    69.     if (!isInt)
    70.     {
    71.         //...переводим и дробную часть в текстовое представление
    72.         //Учитываем род, число и падеж целой части
    73.         if (number[strlen(number)-1] == '1' && number[strlen(number)-2] != '1')
    74.             strcat (numstr, "целая ");
    75.         else
    76.             strcat (numstr, "целых ");
    77.         //Смещаем указатель на дробную часть
    78.         number += strlen(number)+1;
    79.         //Два предшествующих байта забиваем символами "0"
    80.         number[-1] = '0'; number[-2] = '0';
    81.         //Рассматриваем, как отдельный случай, когда дробная
    82.         //часть нулевая:
    83.         if (atoi(number) == 0 && strlen(number) != 0)
    84.             strcat (numstr, "нуль ");
    85.         else
    86.             convert(number);
    87.         //Дописываем статус дробной части
    88.         addSubZero (strlen(number), number[strlen(number)-1] == '1' && number[strlen(number)-2] != '1');
    89.     }
    90.     //Выводим сформированную строку на экран
    91.     printf("%s\n", todos(numstr));
    92.     //Предлагаем пользователю завершить работу с программой
    93.     printf("Press any key to continue\n");
    94.     //Ожидаем его реакцию
    95.     getch();
    96. }
    97.  
    98. //Функция преобразования целого положительного числа в текстовое
    99. //представление
    100. void convert(char *number)
    101. {
    102.     //Объявляем счетчик троек цифр и хранитель длины строки-числа
    103.     int counter, numlen;
    104.     //Запоминаем длину строки-числа
    105.     numlen = strlen(number);
    106.     //Забиваем строку-число спереди нужным числом нулей
    107.     if (numlen%3 != 0) number -= 3-numlen%3;
    108.     //Обновляем длину строки-числа
    109.     numlen = strlen(number);
    110.     //Перебираем тройки цифр числа и для каждой тройки...
    111.     for (counter = 0; counter <= numlen-1; counter+=3)
    112.     {
    113.         //...находим ее текстовое представление и...
    114.         conv3(number+counter, (numlen-counter)/3-1);
    115.         //...определяем ее статус в числе
    116.         conv3name(number+counter, (numlen-counter)/3-1);
    117.     }
    118. }
    119.  
    120. //Функция перевода тройки цифр в текстовое представление
    121. void conv3(char *number, int trion)
    122. {
    123.     //Переменная-тройка цифр-строка
    124.     char sTrio[4] = {0};
    125.     //Переменная-тройка цифр-число
    126.     int iTrio;
    127.     //Получаем тройку цифр, как строку и как число
    128.     strncpy(sTrio, number, 3); iTrio = atoi(sTrio);
    129.     //Если это число больше сотни, то...
    130.     if (iTrio >= 100)
    131.     {
    132.         //...дописываем текстовое представление разряда сотен
    133.         //числа
    134.         strcat(numstr, nums3[iTrio/100-1]);
    135.         //Ставим в конце пробел
    136.         strcat(numstr, " ");
    137.     }
    138.     //Рассматриваем, как отдельные случаи, когда
    139.     //разряд десятков больше единицы и...
    140.     if (iTrio%100 >= 20)
    141.     {
    142.         //Дописываем текстовое представление цифры разряда
    143.         //десятков
    144.         strcat(numstr, nums2[iTrio/10%10-2]);
    145.         //Ставим пробел
    146.         strcat(numstr, " ");
    147.         //Если у разряда единиц есть текстовое представление, то...
    148.         if (iTrio%10 >= 1)
    149.         {
    150.             //...его тоже дозаписываем в строку-результат
    151.             strcat(numstr, nums1[iTrio%10-1]);
    152.             //Ставим пробел
    153.             strcat(numstr, " ");
    154.         }
    155.     }
    156.     //...когда меньше или равен единице
    157.     else
    158.     {
    159.         //Для случаев, когда это необходимо, дописываем текстовое
    160.         //представление оставшейся части числа
    161.         if ((iTrio > 1 || (trion == 0 && iTrio >= 1)) && iTrio%100 != 0)
    162.         {
    163.             strcat(numstr, nums1[iTrio%100-1]);
    164.             strcat(numstr, " ");
    165.         }
    166.     }
    167. }
    168.  
    169. //Функция дописывания статуса тройки цифр (тысяча, миллион и т.д.)
    170. void conv3name(char *number, int trion)
    171. {
    172.     //Переменная-тройка цифр-строка
    173.     char sTrio[4] = {0};
    174.     //Переменная-тройка цифр-число, переменная-хранитель
    175.     //длины числа-строки
    176.     int iTrio, numstrlen;
    177.     //Получаем тройку цифр, как строку и как число
    178.     strncpy(sTrio, number, 3); iTrio = atoi(sTrio);
    179.     //Если тройка цифр равна нулю, то статус не описывается
    180.     if (iTrio == 0) return;
    181.     //Запоминаем длину числа-строки
    182.     numstrlen = strlen(numstr);
    183.     //Если это первая тройка чисел, то для дробных чисел...
    184.     if (trion == 0 && !isInt)
    185.     {
    186.         //...согласуем в роде, числе и падеже текстовое представление
    187.         //тройки цифр и текстовое представление ее статуса
    188.         if (iTrio%10 == 1 && iTrio%100 != 11)
    189.         {
    190.             //Преобразуем "один" в "одна"
    191.             numstr[numstrlen-2] = 'a';
    192.             numstr[numstrlen-3] = 'н';
    193.         }
    194.         if (iTrio%10 == 2 && iTrio%100/10 != 1)
    195.         {
    196.             //Преобразуем "два" в "две"
    197.             numstr[numstrlen-2] = 'е';
    198.         }
    199.     }
    200.     //Тройка цифр-тысячи, рассматривается, как отдельный случай, т.к.
    201.     //тысяча — единственный статус в женском роде
    202.     if (trion == 1)
    203.     {
    204.         //...согласуем в роде, числе и падеже текстовое представление
    205.         //тройки цифр и текстовое представление ее статуса
    206.         if (iTrio%10 == 1 && iTrio > 20)
    207.         {
    208.             //Преобразуем "один" в "одна"
    209.             numstr[numstrlen-2] = 'a';
    210.             numstr[numstrlen-3] = 'н';
    211.         }
    212.         if (iTrio%10 == 2 && iTrio%100/10 != 1)
    213.         {
    214.             //Преобразуем "два" в "две"
    215.             numstr[numstrlen-2] = 'е';
    216.         }
    217.         //Дописываем текстовое представление статуса
    218.         strcat(numstr, great[0]);
    219.         //В требуемых случаях меняем...
    220.         if (iTrio%100 <= 4 || iTrio%100 >= 21)
    221.         {
    222.             //..."тысяч" на "тысяча" или...
    223.             if (iTrio%10 == 1)  strcat(numstr, "а");
    224.             //...на "тысячи"
    225.             if (iTrio%10 >= 2 && iTrio%10 <= 4) strcat(numstr, "и");
    226.         }
    227.         //Дописываем пробел
    228.         strcat(numstr, " ");
    229.     }
    230.     //Остальные статусы(миллион, миллиард и т.д.) рассматриваются
    231.     //вместе (они все мужского рода)
    232.     if (trion > 1)
    233.     {
    234.         //Дописываем текстовое представление статуса
    235.         strcat(numstr, great[trion-1]);
    236.         //В требуемых случаях согласуем текстовое представление
    237.         //статуса с текстовым представлением соответствующей
    238.         //тройки чисел в роде, числе и падеже
    239.         if (iTrio%10 == 0 || iTrio%10 >= 5 || iTrio%100/10 == 1) strcat(numstr, "ов");
    240.         else if (iTrio%10 != 1) strcat(numstr, "а");
    241.         //Дописываем пробел
    242.         strcat(numstr, " ");
    243.     }
    244. }
    245.  
    246. //Функция дописывания статуса дробной части (десятая, сотая,
    247. //тысячная, десятитысячная и т.д.)
    248. void addSubZero(int numSigns, bool female)
    249. {
    250.     //Если число знаков дробной части...
    251.     switch (numSigns)
    252.     {
    253.     //...нуль, то у пустой дробной части нет и статуса
    254.     case 0:
    255.         return;
    256.     //...один, то это десятые доли
    257.     case 1:
    258.         strcat(numstr, "десят");
    259.         break;
    260.     //...два — сотые доли
    261.     case 2:
    262.         strcat(numstr, "сот");
    263.         break;
    264.     //...остальные случаи
    265.     default:
    266.         //Для числа знаков, кот. дают в остатке при делении на
    267.         //три единицу статусы: десятитысячные доли, десятимиллионные
    268.         //доли и т.д
    269.         if (numSigns%3 == 1)
    270.             strcat(numstr, "десяти");
    271.         //Аналогично: стотысячные, стомиллионные и т.д. доли
    272.         if (numSigns%3 == 2)
    273.             strcat(numstr, "сто");
    274.         //Дописываем следующие части текстового представления
    275.         //статуса дробной части
    276.         strcat (numstr, great[numSigns/3-1]);
    277.         strcat (numstr, "н");
    278.     }
    279.     //Согласуем в роде, числе и падеже текстовое представление
    280.     //статуса дробной части с текстовым представлением дробной части
    281.     strcat (numstr, female ? "ая" : "ых");
    282. }
    283.  
    284. //Функция перевода строки из кодировки Windows в кодировку DOS
    285.  
    286. char *todos(char *str)
    287. {
    288.     unsigned char ch;
    289.     short i=0;
    290.     do
    291.     {
    292.         ch=str[i];
    293.         if(ch >= 128)
    294.         {
    295.             if(ch >= 192 && ch <= 239)
    296.                 ch -= 64;
    297.             else if(ch >= 240)
    298.                 ch -= 16;
    299.             else if(ch == 185)
    300.                 ch = 252;
    301.             else if(ch == 168)
    302.                 ch = 240;
    303.             else if(ch == 184)
    304.                 ch = 241;
    305.             str[i] = ch;
    306.         }
    307.         i++;
    308.     } while(ch != 0);
    309.     return str;
    310. }
    P.S. Правильно не "ноль", а "нуль". :)
     
  5. S4urp8n

    S4urp8n New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    30
    Спасибо всем кто ответил. )

    Напоследок хотел спросить как функция будет работать быстрее, если её одну вызвать, либо если разбить её на подфункции и вызвать по подряд их все?
     
  6. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Начать с изучения Алгоритма маляра Шлемиля.