Blog. Just Blog

Быстрый поиск

Введите фрагмент названия статьи для поиска

Преобразование числа в строку с разделением на разряды

17.01.2016 | Категория: Образ мышления: Assembler | Автор: ManHunter

Преобразование числа в строку с разделением на разряды

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

Читать статью целиком »
Просмотров: 1988 | Комментариев: 9

Преобразование вещественного числа в строку на Ассемблере

14.03.2014 | Категория: Образ мышления: Assembler | Автор: ManHunter
Ранее я выкладывал статью о том, как на Ассемблере перевести строку в вещественное число, теперь настало время произвести обратную операцию, то есть перевести вещественное число в строку. В отличие от целых чисел, где достаточно нескольких строк кода, с преобразованием вещественных чисел пришлось повозиться. В результате появилась следующая функция. За основу взята аналогичная функция из пакета MASM, но со значительными доработками.
  1. ;------------------------------------------------------------
  2. ; Функция перевода вещественного числа в строку
  3. ;------------------------------------------------------------
  4. ; Портирование с MASM, доработка и оптимизация - ManHunter
  5. ; Параметры:
  6. ;   lpFloat - указатель на вещественное число TBYTE
  7. ;   lpResult - указатель на строку-приемник результата
  8. ;------------------------------------------------------------
  9. proc    FloatToString lpFloat:DWORD, lpResult:DWORD
  10.         ; Локальные переменные
  11.         local   digits_count:DWORD
  12.         local   old_cw:WORD
  13.         local   new_cw:WORD
  14.         local   saved_float:TBYTE
  15.         local   tmp1 rb 11h
  16.         local   tmp2 rb 11h
  17.  
  18.         ; Сохранить все регистры
  19.         pusha
  20.  
  21.         ; Указатель на строку-приемник
  22.         mov     edi,[lpResult]
  23.  
  24.         ; Это ноль?
  25.         mov     esi,[lpFloat]
  26.         cmp     dword [esi],0
  27.         jne     loc_not_zero
  28.         cmp     dword [esi+4],0
  29.         jne     loc_not_zero
  30.         cmp     word [esi+8],0
  31.         jne     loc_not_zero
  32.         ; Записать в строку ноль
  33.         mov     al,'0'
  34.         stosb
  35.         jmp     loc_ret
  36.  
  37. loc_not_zero:
  38.         ; Скопировать число в локальную переменную
  39.         push    edi
  40.         mov     esi,[lpFloat]
  41.         lea     edi,[saved_float]
  42.         movsd
  43.         movsd
  44.         movsw
  45.         pop     edi
  46.         ; Число отрицательное?
  47.         cmp     dword [saved_float+6],0
  48.         jge     loc_not_signed
  49.         ; Привести число к абсолютному значению
  50.         and     byte [saved_float+9],7Fh
  51.         ; Записать в строку минус
  52.         mov     al,'-'
  53.         stosb
  54.  
  55. loc_not_signed:
  56.         ; Проверить число на наличие дробной части и
  57.         ; подсчитать количество цифр в нем
  58.         fclex
  59.         ; Сохранить управляющее слово
  60.         fstcw   [old_cw]
  61.         ; Установить управляющее слово
  62.         mov     [new_cw],0000001001111111b
  63.         fldcw   [new_cw]
  64.         lea     esi,[saved_float]
  65.         fld     tbyte [esi]
  66.         fld     st
  67.         ; Выделить мантиссу и порядок
  68.         fxtract
  69.         fstp    st
  70.         fldlg2
  71.         ; Получить количество цифр в числе
  72.         fmulp   st1,st
  73.         fistp   [digits_count]
  74.         ; Если цифр больше 16, то число отображается в
  75.         ; нормализованном виде с мантиссой и экспонентой
  76.         cmp     [digits_count],10h
  77.         jnb     loc_not_integer
  78.         ; У числа есть дробная часть?
  79.         fld     st
  80.         frndint
  81.         fcomp   st1
  82.         fstsw   ax
  83.         test    ah,01000000b
  84.         ; Да, отображать число с дробной частью
  85.         jz      loc_not_integer
  86.  
  87.         ; Целое число без дробной части и экспоненты
  88.         lea     eax,[tmp1]
  89.         fbstp   [eax]
  90.  
  91.         ; Перевести BCD-число в строку
  92.         push    edi
  93.         lea     esi,[tmp1+8]
  94.         lea     edi,[tmp2]
  95.         mov     ecx, 9
  96. @@:
  97.         std
  98.         xor     eax,eax
  99.         lodsb
  100.         cld
  101.         rol     ax,12
  102.         rol     ah,4
  103.         add     ax,'00'
  104.         stosw
  105.         loop    @b
  106.         pop     edi
  107.  
  108.         ; Пропустить лидирующий ноль
  109.         mov     eax,11h
  110.         mov     ecx,[digits_count]
  111.         sub     eax,ecx
  112.         inc     ecx
  113.         lea     esi,[tmp2+eax]
  114.         cmp     byte [esi],'0'
  115.         jne     @f
  116.         inc     esi
  117.         dec     ecx
  118. @@:
  119.         ; Перенести полученное число из временного буфера
  120.         rep     movsb
  121.         jmp     loc_clear_stack
  122.  
  123. loc_not_integer:
  124.         mov     eax,10h
  125.         sub     eax,[digits_count]
  126.  
  127.         ; Преобразовать число в целое до 16 разрядов
  128.         mov     ecx,eax
  129.         cmp     eax,0
  130.         jge     @f
  131.         neg     eax
  132. @@:
  133.         ; Для чисел больше 0 корректировка округления в сторону 0
  134.         mov     [new_cw],0000101001111111b
  135.         cmp     ecx,0
  136.         jge     @f
  137.         mov     [new_cw],0000011001111111b
  138. @@:
  139.         ; Установить управляющее слово
  140.         fldcw   [new_cw]
  141.  
  142.         ; Возвести 10 в степень количества цифр
  143.         fld     [float2]
  144.         fld     [float2]
  145. @@:
  146.         fmul    st,st1
  147.         dec     eax
  148.         cmp     eax,1
  149.         ja      @b
  150.  
  151.         ; Почистить стек
  152.         fxch    st1
  153.         fstp    st
  154.  
  155.         ; Если число меньше 0, то умножить, иначе разделить
  156.         cmp     ecx,0
  157.         jge     @f
  158.         fdivp   st1,st
  159.         jmp     loc_rounded
  160. @@:
  161.         fmulp   st1,st
  162.  
  163. loc_rounded:
  164.         ; Полученное значение меньше 1.0e16 ?
  165.         fcom    [float1]
  166.         fstsw   ax
  167.         test    ah,1
  168.         jz      @f
  169.         fmul    [float2]
  170.         dec     [digits_count]
  171. @@:
  172.         ; Целое число без дробной части и экспоненты
  173.         lea     eax,[tmp1]
  174.         fbstp   [eax]
  175.  
  176.         ; Перевести BCD-число в строку
  177.         push    edi
  178.         lea     esi,[tmp1+8]
  179.         lea     edi,[tmp2]
  180.         mov     ecx, 9
  181. @@:
  182.         std
  183.         xor     eax,eax
  184.         lodsb
  185.         cld
  186.         rol     ax,12
  187.         rol     ah,4
  188.         add     ax,'00'
  189.         stosw
  190.         loop    @b
  191.         pop     edi
  192.  
  193.         ; Числу требуется мантисса и экспонента?
  194.         lea     esi,[tmp2+1]
  195.         mov     ecx,[digits_count]
  196.         cmp     ecx,-0Fh
  197.         jl      loc_mantiss_and_exponent
  198.         cmp     ecx,10h
  199.         jg      loc_mantiss_and_exponent
  200.  
  201.         ; Заполнить дробную часть числа
  202.         inc     ecx
  203.         cmp     ecx,0
  204.         jg      @f
  205.         mov     ax,'0.'
  206.         stosw
  207.         neg     ecx
  208.         mov     al,'0'
  209.         rep     stosb
  210.         mov     ecx,10h
  211.         jmp     loc_fraction_filled
  212. @@:
  213.         rep     movsb
  214.         mov     al,'.'
  215.         stosb
  216.         mov     ecx,10h
  217.         sub     ecx,[digits_count]
  218.  
  219. loc_fraction_filled:
  220.         rep     movsb
  221.         jmp     @f
  222.  
  223. loc_clear_fraction:
  224.         ; Удалить завершающие нули дробной части
  225.         dec     edi
  226. @@:
  227.         cmp     byte [edi-1],'0'
  228.         jz      loc_clear_fraction
  229.         cmp     byte [edi-1],'.'
  230.         jnz     @f
  231.         dec     edi
  232. @@:
  233.         jmp     loc_clear_stack
  234.  
  235. loc_mantiss_and_exponent:
  236.         ; Дробная часть мантиссы
  237.         movsb
  238.         mov     al,'.'
  239.         stosb
  240.         movsd
  241.         movsd
  242.         movsw
  243.         ; Удалить завершающие нули дробной части
  244. @@:
  245.         cmp     byte [edi-1],'0'
  246.         jne     @f
  247.         cmp     byte [edi-2],'.'
  248.         je      @f
  249.         dec     edi
  250.         jmp     @b
  251. @@:
  252.         ; Символ и знак экспоненты
  253.         mov     al,'e'
  254.         stosb
  255.         mov     al,'+'
  256.         mov     ebx,[digits_count]
  257.         cmp     ebx, 0
  258.         jge     @f
  259.         mov     al,'-'
  260.         neg     ebx
  261. @@:
  262.         stosb
  263.  
  264.         ; Значение экспоненты
  265.         mov     eax,ebx
  266.         mov     ecx,10
  267.         mov     ebx,4
  268. @@:
  269.         dec     ebx
  270.         xor     edx,edx
  271.         div     ecx
  272.         add     dl,'0'
  273.         mov     [tmp1+ebx],dl
  274.         or      ebx,ebx
  275.         jnz     @b
  276.  
  277.         ; Пропустить лидирующие нули экспоненты
  278.         mov     ecx,4
  279.         lea     esi,[tmp1]
  280. @@:
  281.         lodsb
  282.         cmp     al,'0'
  283.         jne     @f
  284.         dec     ecx
  285.         jmp     @b
  286. @@:
  287.         dec     esi
  288.         rep     movsb
  289.  
  290. loc_clear_stack:
  291.         ; Восстановить управляющее слово
  292.         fldcw   [old_cw]
  293. loc_ret:
  294.         ; Окончание строки
  295.         mov     al,0
  296.         stosb
  297.  
  298.         ; Восстановить все регистры
  299.         popa
  300.         ret
  301.  
  302. float1  dq      1.0e16
  303. float2  dq      10.0
  304.  
  305. endp
Параметры вызова: lpFloat - указатель на вещественное число TBYTE (10 байт), lpResult - указатель на строку-приемник результата. Функция самодостаточная, не требует никаких дополнительных переменных в секции данных и вспомогательных функций, исходное число не меняется. В отличие от MASM'овской функции, поддерживаются вещественные числа в диапазоне -1e4932..+1e4932, увеличено количество отображаемых цифр после запятой, улучшена точность округления мантиссы для очень больших и очень маленьких чисел, улучшено форматирование значения экспоненты и выполнены другие действия по оптимизации алгоритма.

Читать статью целиком »
Просмотров: 6693 | Комментариев: 21

Оптимизация умножения на константу на Ассемблере

05.08.2013 | Категория: Образ мышления: Assembler | Автор: ManHunter
В предыдущей статье по оптимизации мы рассматривали замену команд деления, как это описано в "AMD Athlon Processor x86 Code Optimization Guide". Но в этом же мануале описана оптимизация умножения на константу. Тут нет универсальных алгоритмов, по которым можно было бы однозначно определить нужную последовательность команд замены, как в случае с делением. Для каждой константы набор команд определяется на основании их "весовых коэффициентов" и количества тактов процессора, необходимых для их выполнения. В качестве примера приведена вот такая табличка оптимизации умножения с 2 до 32. Ее всегда можно посмотреть и в самом мануале, но лучше пусть будет под рукой.
  1. ; Умножение на 2
  2. add reg1, reg1          ; 1 такт процессора
  3.  
  4. ; Умножение на 3
  5. lea reg1, [reg1+reg1*2] ; 2 такта процессора
  6.  
  7. ; Умножение на 4
  8. shl reg1, 2             ; 1 такт процессора
  9.  
  10. ; Умножение на 5
  11. lea reg1, [reg1+reg1*4] ; 2 такта процессора
  12.  
  13. ; Умножение на 6
  14. lea reg1, [reg1+reg1*2] ; 3 такта процессора
  15. add reg1, reg1
  16.  
  17. ; Умножение на 7: 
  18. mov reg2, reg1          ; 2 такта процессора
  19. shl reg1, 3
  20. sub reg1, reg2
  21.  
  22. ; Умножение на 8: 
  23. shl reg1, 3             ; 1 такт процессора
  24.  
  25. ; Умножение на 9: 
  26. lea reg1, [reg1+reg1*8] ; 2 такта процессора
  27.  
  28. ; Умножение на 10: 
  29. lea reg1, [reg1+reg1*4] ; 3 такта процессора
  30. add reg1, reg1
  31.  
  32. ; Умножение на 11:
  33. lea reg2, [reg1+reg1*8] ; 3 такта процессора
  34. add reg1, reg1
  35. add reg1, reg2
  36.  
  37. ; Умножение на 12:
  38. lea reg1, [reg1+reg1*2] ; 3 такта процессора
  39. shl reg1, 2
  40.  
  41. ; Умножение на 13:
  42. lea reg2, [reg1+reg1*2] ; 3 такта процессора
  43. shl reg1, 4
  44. sub reg1, reg2
  45.  
  46. ; Умножение на 14:
  47. lea reg2, [reg1+reg1]   ; 3 такта процессора
  48. shl reg1, 4
  49. sub reg1, reg2
  50.  
  51. ; Умножение на 15:
  52. lea reg1, [reg1+reg1*2] ; 4 такта процессора
  53. lea reg1, [reg1+reg1*4]
  54.  
  55. ; Умножение на 16:
  56. shl reg1, 4             ; 1 такт процессора
  57.  
  58. ; Умножение на 17:
  59. mov reg2, reg1          ; 2 такта процессора
  60. shl reg1, 4
  61. add reg1, reg2
  62.  
  63. ; Умножение на 18:
  64. lea reg1, [reg1+reg1*8] ; 3 такта процессора
  65. add reg1, reg1
  66.  
  67. ; Умножение на 19:
  68. lea reg2, [reg1+reg1*2] ; 3 такта процессора
  69. shl reg1, 4
  70. add reg1, reg2
  71.  
  72. ; Умножение на 20:
  73. lea reg1, [reg1+reg1*4] ; 3 такта процессора
  74. shl reg1, 2
  75.  
  76. ; Умножение на 21:
  77. lea reg2, [reg1+reg1*4] ; 3 такта процессора
  78. shl reg1, 4
  79. add reg1, reg2
  80.  
  81. ; Умножение на 22:
  82. lea reg2, [reg1+reg1*4] ; 4 такта процессора
  83. add reg1, reg1
  84. lea reg1, [reg1+reg2*4]
  85.  
  86. ; Умножение на 23:
  87. lea reg2, [reg1+reg1*8] ; 3 такта процессора
  88. shl reg1, 5
  89. sub reg1, reg2
  90.  
  91. ; Умножение на 24:
  92. lea reg1, [reg1+reg1*2] ; 3 такта процессора
  93. shl reg1, 3
  94.  
  95. ; Умножение на 25:
  96. lea reg1, [reg1+reg1*4] ; 4 такта процессора
  97. lea reg1, [reg1+reg1*4]
  98.  
  99. ; Умножение на 26:
  100. lea reg2, [reg1+reg1*2] ; 4 такта процессора
  101. add reg1, reg1
  102. lea reg1, [reg1+reg2*8]
  103.  
  104. ; Умножение на 27:
  105. lea reg1, [reg1+reg1*2] ; 4 такта процессора
  106. lea reg1, [reg1+reg1*8]
  107.  
  108. ; Умножение на 28:
  109. lea reg2, [reg1*4]      ; 3 такта процессора
  110. shl reg1, 5
  111. sub reg1, reg2
  112.  
  113. ; Умножение на 29:
  114. lea reg2, [reg1+reg1*2] ; 3 такта процессора
  115. shl reg1, 5
  116. sub reg1, reg2
  117.  
  118. ; Умножение на 30:
  119. lea reg2, [reg1+reg1]   ; 3 такта процессора
  120. shl reg1, 5
  121. sub reg1, reg2
  122.  
  123. ; Умножение на 31:
  124. mov reg2, reg1          ; 2 такта процессора
  125. shl reg1, 5
  126. sub reg1, reg2
  127.  
  128. ; Умножение на 32:
  129. shl reg1, 5             ; 1 такт процессора
В разделе мануала, посвященном оптимизации целочисленного умножения, упоминается программа "FINDMUL", которая находится на "AMD Documentation CD-ROM". Как написано в мануале, эта программа должна рассчитывать оптимальный алгоритм умножения на константу. К сожалению, ни саму программу, ни этот диск в интернетах мне найти не удалось, поэтому больше ничего про нее сказать не могу. Неизвестны ни алгоритм ее работы, ни диапазон констант, которые она в состоянии оптимизировать. Если кто-то знает где его взять, то, пожалуйста, напишите. Буду очень благодарен.

Читать статью целиком »
Просмотров: 5690 | Комментариев: 7

Замена деления умножением на Ассемблере

07.07.2013 | Категория: Образ мышления: Assembler | Автор: ManHunter

Замена деления умножением на Ассемблере

При написании на Ассемблере алгоритмов, использующих деление на константу, операции деления можно заменять на операции умножения. Зачем это надо? Дело в том, что процессор выполняет операцию умножения в несколько раз быстрее, чем операцию деления. К примеру, на умножение тратится 5-9 тактов процессора (знаковое умножение) или 4-8 (беззнаковое умножение), тогда как для деления необходимо 22-47 тактов (знаковое деление) или 17-41 тактов (беззнаковое деление). В высокооптимизированных алгоритмах, таких как шифрование, математические расчеты, архивация больших объемов данных, подсчет контрольных сумм и других подобных задачах, экономия каждого такта процессора может дать значительный прирост общей скорости работы программы.

В руководстве по оптимизации "AMD Athlon Processor x86 Code Optimization Guide" вопрос замены деления умножением расписан очень подробно. Рассмотрены частные случаи деления, такие как деление на степень двойки, описан выбор алгоритма для знакового и беззнакового деления и приведен код для вычисления вспомогательных корректирующих значений. Кроме этого, в руководстве описаны методы оптимизации и других математических операций. Даже если вы никогда не будете использовать на практике замену деления умножением, почитать о других способах оптимизации будет очень полезно.

Читать статью целиком »
Просмотров: 10119 | Комментариев: 4

Преобразование строки в вещественное число на Ассемблере

31.05.2012 | Категория: Образ мышления: Assembler | Автор: ManHunter
Про преобразование строки в обычное число я уже писал, теперь задача посложнее - надо преобразовать строку в вещественное число с плавающей запятой (float). Для этого я написал вот такую функцию преобразования:
  1. ;------------------------------------------------------------
  2. ; Функция преобразования строки в вещественное число
  3. ; by ManHunter / PCL
  4. ; http://www.manhunter.ru
  5. ;
  6. ; Параметры:
  7. ;   lpStr - указатель на исходную строку в формате ASCIIZ
  8. ;   lpResult - указатель на переменную-приемник значения
  9. ; На выходе:
  10. ;   EAX = 1 - строка успешно преобразована
  11. ;   EAX = 0 - строка не может быть преобразована в число
  12. ;
  13. ; Примечание: переменная-приемник может иметь размер DWORD
  14. ; или QWORD, в зависимости от этого должна изменяться и
  15. ; функция (см. комментарии в конце кода). По умолчанию
  16. ; считается, что переменная имеет размер DWORD
  17. ;------------------------------------------------------------
  18. proc    string2float lpStr:DWORD, lpResult:DWORD
  19.         ; Локальные переменные
  20.         locals
  21.           dot    dd ?   ; Указатель на дробную часть
  22.           exp    dd ?   ; Указатель на экспоненту
  23.  
  24.           digit  dd ?   ; Цифра
  25.         endl
  26.  
  27.         pusha
  28.  
  29.         ; Проверка строки на валидность
  30.         mov     [digit],1
  31.  
  32.         mov     [exp],0
  33.         mov     [dot],0
  34.         mov     esi,[lpStr]
  35.         ; Минус или плюс может быть только в начале
  36.         cmp     byte [esi],'-'
  37.         je      @f
  38.         cmp     byte [esi],'+'
  39.         jne     .loc_chk_loop
  40. @@:
  41.         inc     esi
  42.  
  43.         ; После знака не может быть нуля
  44.         cmp     byte [esi],0
  45.         je      .loc_chk_error
  46. .loc_chk_loop:
  47.         ; В строке должны быть цифр, экспонента и не более одной точки
  48.         lodsb
  49.         or      al,al
  50.         jz      .loc_chk_complete
  51.         cmp     al,'e'
  52.         je      .loc_chk_exp
  53.         cmp     al,'E'
  54.         je      .loc_chk_exp
  55.         cmp     al,'.'
  56.         je      .loc_chk_dot
  57.         cmp     al,'0'
  58.         jb      .loc_chk_error
  59.         cmp     al,'9'
  60.         ja      .loc_chk_error
  61.         jmp     .loc_chk_loop
  62.  
  63. .loc_chk_dot:
  64.         ; Точка в строке уже есть?
  65.         cmp     [dot],0
  66.         ; Строка имеет некорректный формат
  67.         jne     .loc_chk_error
  68.  
  69.         ; Экспонента уже есть?
  70.         cmp     [exp],0
  71.         ; Строка имеет некорректный формат
  72.         jne     .loc_chk_error
  73.  
  74.         ; Указатель на дробную часть
  75.         mov     [dot],esi
  76.  
  77.         jmp     .loc_chk_loop
  78.  
  79. .loc_chk_exp:
  80.         ; Экспонента уже есть?
  81.         cmp     [exp],0
  82.         ; Строка имеет некорректный формат
  83.         jne     .loc_chk_error
  84.  
  85.         ; Указатель на начало экспоненты
  86.         mov     [exp],esi
  87.  
  88.         ; Сразу после экспоненты не может быть нуля
  89.         cmp     byte [esi],0
  90.         je      .loc_chk_error
  91.  
  92.         ; После экспоненты может быть знак
  93.         cmp     byte [esi],'-'
  94.         je      @f
  95.         cmp     byte [esi],'+'
  96.         jne     .loc_chk_loop
  97. @@:
  98.         inc     esi
  99.  
  100.         ; Сразу после минуса не может быть нуля
  101.         cmp     byte [esi],0
  102.         je      .loc_chk_error
  103.  
  104.         ; Проверить следующий символ
  105.         jmp     .loc_chk_loop
  106.  
  107. .loc_chk_error:
  108.         ; Строка не является числом
  109.         mov     [digit],0
  110.         jmp     .loc_ret
  111.  
  112. .loc_chk_complete:
  113.         ; Инициализация сопроцессора
  114.         finit
  115.  
  116.         ; Начальное значение числа
  117.         fldz
  118.  
  119.         ; Множитель и делитель
  120.         mov     [digit],10
  121.         fild    dword [digit]
  122.  
  123.         ; Запись значений до запятой
  124.         mov     esi,[lpStr]
  125.  
  126.         ; В начале строки минус?
  127.         cmp     byte [esi],'-'
  128.         je      @f
  129.         cmp     byte [esi],'+'
  130.         jne     .loc_before_dot
  131. @@:
  132.         inc     esi
  133.         ; Преобразование числа до запятой
  134. .loc_before_dot:
  135.         lodsb
  136.         ; Конец строки?
  137.         or      al,al
  138.         jz      .loc_complete
  139.  
  140.         cmp     al,'.'
  141.         je      .loc_complete_before_dot
  142.         cmp     al,'e'
  143.         je      .loc_exp
  144.         cmp     al,'E'
  145.         je      .loc_exp
  146.  
  147.         ; Очередная цифра
  148.         sub     al,'0'
  149.         movzx   eax,al
  150.         mov     [digit],eax
  151.  
  152.         ; Записать
  153.         fild    dword [digit]
  154.         fxch    st2
  155.         fmul    st0,st1
  156.         fxch    st2
  157.         fadd    st2,st0
  158.  
  159.         ffree   st0     ; Почистить стек
  160.         fincstp
  161.  
  162.         jmp     .loc_before_dot
  163.  
  164.         ; Преобразование дробной части числа
  165. .loc_complete_before_dot:
  166.         ; Дробная часть есть?
  167.         cmp     [dot],0
  168.         je      .loc_complete_after_dot
  169.  
  170.         ; Экспонента есть?
  171.         cmp     [exp],0
  172.         je      @f
  173.  
  174.         ; Указатель на начало экспоненты
  175.         mov     esi,[exp]
  176.         jmp     .loc_start_after_dot
  177. @@:
  178.         ; Иначе перенести указатель на конец строки
  179.         xor     ecx,ecx
  180.         dec     ecx
  181.         xor     eax,eax
  182.         mov     edi,esi
  183.         repne   scasb
  184.  
  185.         mov     esi,edi
  186.  
  187. .loc_start_after_dot:
  188.         std
  189.         dec     esi
  190.         dec     esi
  191.  
  192.         ; Дробная часть
  193.         fldz
  194.         fxch    st1
  195. .loc_after_dot:
  196.         lodsb
  197.         ; Конец дробной части?
  198.         cmp     al,'.'
  199.         je      .loc_complete_after_dot
  200.  
  201.         ; Очередная цифра
  202.         sub     al,'0'
  203.         movzx   eax,al
  204.         mov     [digit],eax
  205.  
  206.         ; Записать
  207.         fild    dword [digit]
  208.         fadd    st2,st0
  209.         fxch    st2
  210.         fdiv    st0,st1
  211.         fxch    st2
  212.  
  213.         ffree   st0     ; Почистить стек
  214.         fincstp
  215.  
  216.         jmp     .loc_after_dot
  217.  
  218. .loc_complete_after_dot:
  219.         ; Сбросить флаг направления
  220.         cld
  221.  
  222.         ffree   st0     ; Почистить стек
  223.         fincstp
  224.  
  225.         ; Сложить дробную и целую часть
  226.         fadd    st1,st0
  227.  
  228. .loc_exp:
  229.         ; Экспонента есть?
  230.         cmp     [exp],0
  231.         je      .loc_complete
  232.  
  233.         ; Получить значение экспоненты
  234.         xor     ecx,ecx
  235.  
  236.         mov     esi,[exp]
  237.         ; В начале строки минус?
  238.         cmp     byte [esi],'-'
  239.         je      @f
  240.         cmp     byte [esi],'+'
  241.         jne     .loc_start_exp
  242. @@:
  243.         inc     esi
  244. .loc_start_exp:
  245.         lodsb
  246.         or      al,al
  247.         jz      .loc_end_exp
  248.  
  249.         sub     al,'0'
  250.         movzx   eax,al
  251.         imul    ecx,10
  252.         add     ecx,eax
  253.  
  254.         jmp     .loc_start_exp
  255. .loc_end_exp:
  256.  
  257.         or      ecx,ecx
  258.         jz      .loc_complete
  259.  
  260.         ffree   st0     ; Почистить стек
  261.         fincstp
  262.  
  263.         mov     [digit],10
  264.         fild    dword [digit]
  265.  
  266.         ; Делить или умножать?
  267.         mov     esi,[exp]
  268.         cmp     byte [esi],'-'
  269.         je      .loc_exp_divide
  270.  
  271. .loc_exp_multiple:
  272.         fmul    st1,st0
  273.         loop    .loc_exp_multiple
  274.         jmp     .loc_complete
  275.  
  276. .loc_exp_divide:
  277.         fdiv    st1,st0
  278.         loop    .loc_exp_divide
  279.  
  280. .loc_complete:
  281.         ffree   st0     ; Почистить стек
  282.         fincstp
  283.  
  284.         ; В начале строки минус?
  285.         mov     esi,[lpStr]
  286.         cmp     byte [esi],'-'
  287.         jne     @f
  288.  
  289.         ; Изменить знак числа
  290.         fchs
  291. @@:
  292.         ; Записать значение в ячейку памяти
  293.         mov     eax,[lpResult]
  294.         ; Если требуется повышенная точность, то приемник
  295.         ; должен иметь размер QWORD, а следующую команду
  296.         ; надо заменить на fstp qword [eax]
  297.         fstp    dword [eax]
  298.  
  299.         ; Успешное преобразование
  300.         mov     [digit],1
  301. .loc_ret:
  302.         popa
  303.  
  304.         ; Результат преобразования
  305.         mov     eax,[digit]
  306.  
  307.         ret
  308. endp
Функция универсальная, понимает положительные и отрицательные, нормализованные и денормализованные числа, с любой мантиссой и экспонентой. Например, "123.45", "-1.67e+4", "99.999e-99", "45e004" и т.п. Также выполняется проверка на корректность исходной строки. Заведения дополнительных переменных в сегменте данных не требуется. Параметры вызова: lpStr - указатель на строку для преобразования, lpResult - указатель на переменную-приемник для записи результата, ее размер может быть DWORD или QWORD, в зависимости от желаемой точности результата. Соответственно, вы должны изменить команду (строка 297 в листинге) на fstp dword [eax] или fstp qword [eax].

Читать статью целиком »
Просмотров: 6374 | Комментариев: 12

prev 01 02 next
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2017
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.09 сек. / MySQL: 3 (0.0339 сек.) / Память: 4.75 Mb
Наверх