Операции с FP числами без FPU

Тема в разделе "WASM.BEGINNERS", создана пользователем Exp10der, 3 май 2008.

  1. Exp10der

    Exp10der Мастер дзена

    Публикаций:
    0
    Регистрация:
    27 авг 2007
    Сообщения:
    337
    Адрес:
    Красноярск
    Хочу разобраться с форматом IEEE 754, но не очень понимаю как оно работает - достаю из числа порядок и мантиссу и вот... что дальше с ними делать чтобы получить целое число до точки и после?
     
  2. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    полагаю нужно мантиссу умножить на 10 в степени равной порядку. сколько "лишних" бит вылезло - это целая часть, остальное - дробная
     
  3. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    KeSqueer
    не угадал - формат двоичный и степень соответственно 2 а не 10 ;)

    Exp10der
    см.
    Код (Text):
    1. +-------------------------------------------------------------------------+
    2. ¦                                                                         ¦
    3. ¦                                                                         ¦
    4. ¦  SOURCE                                                                 ¦
    5. ¦                                                                         ¦
    6. ¦  +1 $title('Перевод числа с плавающей точкой в ASCII вид')              ¦
    7. ¦                                                                         ¦
    8. ¦                                                                         ¦
    9. ¦       name    floating_to_ascii                                         ¦
    10. ¦                                                                         ¦
    11. ¦       public  floating_to_ascii                                         ¦
    12. ¦       extrn   get_power_10:near, tos_status:near                        ¦
    13. ¦  ;                                                                      ¦
    14. ¦  ; Эта подпрограмма переводит число с плавающей точкой                  ¦
    15. ¦  ; из вершины стека FPU в строку типа ASCII и отделяет                  ¦
    16. ¦  ; степень 10, масштабируя значение (в двоичном виде).                  ¦
    17. ¦  ; Максимальная длина строки символов регулируется                      ¦
    18. ¦  ; параметром, который должен быть больше 1.                            ¦
    19. ¦  ; Не-нормальные значения, денормальные значения и псевдо               ¦
    20. ¦  ; -нули переводятся корректно. Однако, не-нормальные                   ¦
    21. ¦  ; величины и псевдо-нули более не поддерживаются                       ¦
    22. ¦  ; процессором i486 (в соответствии со стандартом IEEE) и               ¦
    23. ¦  ; внутренне не генерируются. Возвращаемое значение                     ¦
    24. ¦  ; указывает сколько двоичных разрядов точности было                    ¦
    25. ¦  ; потеряно в не-нормальных или денормальных значениях.                 ¦
    26. ¦  ; Также указывается и величина мантиссы псевдо-нуля                    ¦
    27. ¦  ; (двоичным порядком). Целые числа меньшие 10**18                      ¦
    28. ¦  ; переводятся точно, если принимающая строка ASCII                     ¦
    29. ¦  ; символов содержит достаточное количество позиций для                 ¦
    30. ¦  ; цифр этих чисел. В противном случае значение                         ¦
    31. ¦  ; переводиться в научную нотацию.                                      ¦
    32. ¦  ;                                                                      ¦
    33. ¦  ; В зависимости от результата подпрограмма выдает                      ¦
    34. ¦  ; следующие значения:                                                  ¦
    35. ¦  ;                                                                      ¦
    36. ¦  ;       0  перевод выполнен, размер строки определен                   ¦
    37. ¦  ;       1  недопустимые аргументы                                      ¦
    38. ¦  ;       2  точный целочисленный перевод, размер строки                 ¦
    39. ¦  ;            определен                                                 ¦
    40. ¦  ;       3  неопределенность                                            ¦
    41. ¦  ;       4  + NaN (не-число)                                            ¦
    42. ¦  ;       5  - NaN                                                       ¦
    43. ¦  ;       6  + Бесконечность                                             ¦
    44. ¦  ;       7  - Бесконечность                                             ¦
    45. ¦  ;       8  встречен псевдо-ноль, размер строки определен               ¦
    46. ¦  ;                                                                      ¦
    47. ¦  ;    Интерфейс для вызова из PLM-386/486                               ¦
    48. ¦  ;                                                                      ¦
    49. ¦  ; floating_to_ascii:                                                   ¦
    50. ¦  ;   procedure (number, denormal_ptr, string_ptr, size_ptr,             ¦
    51. ¦  ;   field_size, power_ptr) word external;                              ¦
    52. ¦  ;   declare (denormal_ptr, string_ptr, power_ptr, size_ptr)            ¦
    53. ¦  ;   pointer;                                                           ¦
    54. ¦  ;   declare field_size word;                                           ¦
    55. ¦  ;   string_size based size_ptr word;                                   ¦
    56. ¦  ;   declare number real;                                               ¦
    57. ¦  ;   declare denormal integer based denormal_ptr;                       ¦
    58. ¦  ;                                                                      ¦
    59. ¦                                                                         ¦
    60. ¦  ; declare power integer based power_ptr;                               ¦
    61. ¦  ; end floating_to_ascii;                                               ¦
    62. ¦  ;                                                                      ¦
    63. ¦  ; Величина с плавающей точкой должна быть на вершине                   ¦
    64. ¦  ; стека FPU. Эта подпрограмма требует три свободные                    ¦
    65. ¦  ; регистра в стеке и после отработки выталкивает                       ¦
    66. ¦  ; передаваемые значения из стека. Полученная строка                    ¦
    67. ¦  ; будет иметь начальный символ либо "+", либо "-",                     ¦
    68. ¦  ; указывая на знак величины. Затем следуют десятичные                  ¦
    69. ¦  ; цифры в ASCII виде. Числовое значение строки типа                    ¦
    70. ¦  ; ASCII будет равно (ASCII СТРОКА)*10**ПОРЯДОК. Если                   ¦
    71. ¦  ; данное число было нулем, то строка будет содержать                   ¦
    72. ¦  ; только знак и один символ 0. Величина размера строки                 ¦
    73. ¦  ; (string_size) указывает на полную длину строки символов,             ¦
    74. ¦  ; включая символ знака. Строка (0) всегда будет                        ¦
    75. ¦  ; содержать знак. Возможно, что размер строки будет                    ¦
    76. ¦  ; меньше размера поля. Это бывает при нулях и целых                    ¦
    77. ¦  ; числах. Псевдо-ноль выдает особый код возврата. При                  ¦
    78. ¦  ; денормальных числах указывается степень двух                         ¦
    79. ¦  ; представленного значения. Степень десяти и строка будут              ¦
    80. ¦  ; такими же, как если бы величина была бы простым нулем.               ¦
    81. ¦  ;                                                                      ¦
    82. ¦  ; Эта подпрограмма точно выдает десятичные целые до 18                 ¦
    83. ¦  ; цифр. Целые величины имеют десятичный показатель                     ¦
    84. ¦  ; степени в строке из нулей. При нецелых величинах                     ¦
    85. ¦  ; точность результата заключена в двух последних                       ¦
    86. ¦  ; десятичных цифрах (двойная точность). Для                            ¦
    87. ¦  ; масштабирования величины в диапазоне, приемлемом для                 ¦
    88. ¦  ; данных типа BCD, используются команды возведения в                   ¦
    89. ¦  ; степень. Для перевода используется режим округления,                 ¦
    90. ¦  ; действующий при входе в подпрограмму.                                ¦
    91. ¦  ;                                                                      ¦
    92. ¦  ;       Следующие регистры не видны:                                   ¦
    93. ¦  ;                                                                      ¦
    94. ¦  ;      eax ebx ecx edx esi edi eflags                                  ¦
    95. ¦  ;                                                                      ¦
    96. ¦  ; Определение стека.                                                   ¦
    97. ¦  ;                                                                      ¦
    98. ¦  ebp_save       equ     dword ptr [ebp]                                 ¦
    99. ¦  es_save        equ     ebp_save + size ebp_save                        ¦
    100. ¦  return_ptr     equ     es_save + size es_save                          ¦
    101. ¦  power_ptr      equ     return_ptr + size return_ptr                    ¦
    102. ¦  field_size     equ     power_ptr + size power_ptr                      ¦
    103. ¦  size_ptr       equ     field_size + size size_ptr                      ¦
    104. ¦  string_ptr     equ     size_ptr + size size_ptr                        ¦
    105. ¦  denormal_ptr   equ     string_ptr + size string_ptr                    ¦
    106. ¦                                                                         ¦
    107. ¦  parms_size     equ     size power_ptr + size field_size +              ¦
    108. ¦  &              size    size_ptr + size string_ptr +                    ¦
    109. ¦  &              size    denormal_ptr                                    ¦
    110. ¦  ;                                                                      ¦
    111. ¦  ; Определение используемых констант.                                   ¦
    112. ¦  ;                                                                      ¦
    113. ¦  BCD_DIGITS   equ  18  ; Количество цифр в величине типа BCD            ¦
    114. ¦  WORD_SIZE    equ  4                                                    ¦
    115. ¦  BCD_SIZE     equ  10                                                   ¦
    116. ¦  MINUS        equ  1   ; Определение выдаваемых значений                ¦
    117. ¦  NAN          equ  4   ; Выбраные здесь точные величины -               ¦
    118. ¦  INFINITY     equ  6   ; важны. Они должны соответствовать              ¦
    119. ¦  INDEFINITE   equ  3   ; возможным выдаваемым значениям и               ¦
    120. ¦  PSEUDO_ZERO  equ  8   ; тестироваться в том же порядке, как            ¦
    121. ¦  INVALID      equ  -2  ; показано в этой программе.                     ¦
    122. ¦  ZERO         equ  -4                                                   ¦
    123. ¦  DENORMAL     equ  -6                                                   ¦
    124. ¦  UNNORMAL     equ  -8                                                   ¦
    125. ¦  NORMAL       equ  0                                                    ¦
    126. ¦  EXACT        equ  2                                                    ¦
    127. ¦  ;                                                                      ¦
    128. ¦  ;       Определение положения временной области хранения.              ¦
    129. ¦  ;                                                                      ¦
    130. ¦  power_two    equ  word ptr [ebp - WORD_SIZE]                           ¦
    131. ¦  bcd_value    equ  tbyte ptr power_two - BCD_SIZE                       ¦
    132. ¦  bcd-byte     equ  byte ptr bcd_value                                   ¦
    133. ¦  fraction     equ  bcd_value                                            ¦
    134. ¦                                                                         ¦
    135. ¦  lokal_size   equ  size power_two + size bcd_value                      ¦
    136. ¦  ;                                                                      ¦
    137. ¦  ;      Выделить достаточный объем стека для                            ¦
    138. ¦  ;      временных результатов.                                          ¦
    139. ¦  ;                                                                      ¦
    140. ¦  stack  stackseg (lokal_size+6) ; Выделить пространство стека           ¦
    141. ¦                                 ; для локальных данных.                 ¦
    142. ¦  +1 $eject                                                              ¦
    143. ¦                                                                         ¦
    144. ¦  code         segment public er                                         ¦
    145. ¦               extrn   power_table:qword                                 ¦
    146. ¦  ;                                                                      ¦
    147. ¦  ;      Константы, используемые этой функцией.                          ¦
    148. ¦  ;                                                                      ¦
    149. ¦               even               ; Оптимизировать до 16 цифр.           ¦
    150. ¦  const10      dw      10         ; Подрегулировать значение для         ¦
    151. ¦  ;                               ; слишком больших BCD.                 ¦
    152. ¦  ;                                                                      ¦
    153. ¦  ;        Перевести биты C3, C2, C1 и C0 в                              ¦
    154. ¦  ;        значащие флаги и величины, используя                          ¦
    155. ¦  ;        процедуру tos_status.                                         ¦
    156. ¦  ;                                                                      ¦
    157. ¦  status_table db      UNNORMAL, NAN, UNNORMAL+MINUS,                    ¦
    158. ¦  &                    NAN+MINUS, NORMAL, INFINITY,                      ¦
    159. ¦  &                    NORMAL+MINUS, INFINITY+MINUS,                     ¦
    160. ¦  &                    ZERO, INVALID, ZERO+MINUS, INVALID,               ¦
    161. ¦  &                    DENORMAL, INVALID, DENORMAL+MINUS, INVALID        ¦
    162. ¦  floting_to_ascii proc                                                  ¦
    163. ¦                                                                         ¦
    164. ¦         call   tos_status   ; Посмотреть на состояние ST(0)             ¦
    165. ¦  ;                                                                      ¦
    166. ¦  ;         Взять дескриптор из таблицы                                  ¦
    167. ¦  ;                                                                      ¦
    168. ¦         movzx      eax, status_table[eax]                               ¦
    169. ¦         cmp        al,INVALID             ; ST(0) пуст?                 ¦
    170. ¦         jne        not_empty                                            ¦
    171. ¦  ;                                                                      ¦
    172. ¦  ;        ST(0) - пуст! Возвращает значение состояния.                  ¦
    173. ¦  ;                                                                      ¦
    174. ¦         ret    parms_size                                               ¦
    175. ¦  ;                                                                      ¦
    176. ¦  ;        Удалить бесконечность из стека и выйти.                       ¦
    177. ¦  ;                                                                      ¦
    178. ¦  found_infinity:                                                        ¦
    179. ¦         fstp       st(0)       ; Оставить fstp                          ¦
    180. ¦         jmp        short exit_proc                                      ¦
    181. ¦  ;                                                                      ¦
    182. ¦  ;              Длина строки слишком мала!                              ¦
    183. ¦  ;              Выдает код недопустимости.                              ¦
    184. ¦  ;                                                                      ¦
    185. ¦  small_string:                                                          ¦
    186. ¦         mov    al,INVALID                                               ¦
    187. ¦  exit_proc:                                                             ¦
    188. ¦         leave                          ; Восстановить стек              ¦
    189. ¦                                                                         ¦
    190. ¦         pop    es                                                       ¦
    191. ¦         ret    parms_size                                               ¦
    192. ¦  ;                                                                      ¦
    193. ¦  ;          В ST(0) находится NaN или                                   ¦
    194. ¦  ;          неопределенность. Сохранить значение                        ¦
    195. ¦  ;          в памяти и просмотреть дробное поле                         ¦
    196. ¦  ;          для того, чтобы отличить                                    ¦
    197. ¦  ;          неопределенность от обычного NaN.                           ¦
    198. ¦  ;                                                                      ¦
    199. ¦  NAN_or_indefinite:                                                     ¦
    200. ¦         fstp   fraction       ; Для проверки - удалить значение         ¦
    201. ¦                               ; из стека.                               ¦
    202. ¦         test   al,MINUS       ; Посмотреть бит знака.                   ¦
    203. ¦         fwait                 ; Убедиться в выполнении сохранения.      ¦
    204. ¦         jz     exit_proc      ; Если положительный знак, то не          ¦
    205. ¦                               ; может быть неопределенностью.           ¦
    206. ¦                                                                         ¦
    207. ¦         mov    ebx,0C0000000H ; Подавить верхние 32 разряда дробной     ¦
    208. ¦                               ; части.                                  ¦
    209. ¦                                                                         ¦
    210. ¦  ;             Сравнить разряды 63-32                                   ¦
    211. ¦         sub    ebx,dword ptr fraction + 4                               ¦
    212. ¦                                                                         ¦
    213. ¦  ;             Разряды 31-0 должны быть нулями                          ¦
    214. ¦         or     ebx,dword ptr fraction                                   ¦
    215. ¦         jnz    exit_proc                                                ¦
    216. ¦                                                                         ¦
    217. ¦  ;             Установить выдаваемое значение на                        ¦
    218. ¦  ;             неопределенность                                         ¦
    219. ¦         mov   al,INDEFINITE                                             ¦
    220. ¦         jmp   exit_proc                                                 ¦
    221. ¦  ;                                                                      ¦
    222. ¦  ;             Выделить место в стеке для локальных переменных          ¦
    223. ¦  ;             и установить параметр адресации.                         ¦
    224. ¦  ;                                                                      ¦
    225. ¦  not_empty:                                                             ¦
    226. ¦         push  es            ; Сохранить рабочий регистр                 ¦
    227. ¦         enter local_size,0  ; Установить адресацию стека                ¦
    228. ¦                                                                         ¦
    229. ¦  ;             Проверить, достаточно ли места в строке                  ¦
    230. ¦         mov   ecx,field_size                                            ¦
    231. ¦         cmp   ecx,2                                                     ¦
    232. ¦         jl    small_string                                              ¦
    233. ¦                                                                         ¦
    234. ¦         dec   ecx           ; Установить символ знака                   ¦
    235. ¦                                                                         ¦
    236. ¦  ; Посмотреть, может быть строка слишком большая для типа BCD           ¦
    237. ¦         cmp   ecx,BCD_DIGITS                                            ¦
    238. ¦         jbe   size_ok                                                   ¦
    239. ¦                                                                         ¦
    240. ¦  ; Иначе установить максимальный размер строки                          ¦
    241. ¦         mov   ecx,BCD_DIGITS                                            ¦
    242. ¦  size_ok:                                                               ¦
    243. ¦         cmp   al,INFINITY   ; Может быть бесконечность?                 ¦
    244. ¦                                                                         ¦
    245. ¦  ; Возвратить значение состояния для + или - бесконечности              ¦
    246. ¦         jge   found_infinity                                            ¦
    247. ¦                                                                         ¦
    248. ¦         cmp   al,NAN              ; Можеть быть NaN или                 ¦
    249. ¦         jge   NAN_or_indefinite   ; неопределенность                    ¦
    250. ¦                                                                         ¦
    251. ¦  ;                                                                      ¦
    252. ¦  ;             Установить выдаваемое значение по умолчанию              ¦
    253. ¦  ;             и проверить, нормализовано ли число.                     ¦
    254. ¦  ;                                                                      ¦
    255. ¦         fabs        ; Использовать только положительные значения        ¦
    256. ¦  ;                                                                      ¦
    257. ¦  ;      Бит знака в регистре AL содержит истинный знак величины.        ¦
    258. ¦  ;                                                                      ¦
    259. ¦         xor   edx,edx          ; Подготовить константу 0                ¦
    260. ¦         mov   edi,denormal_ptr ; Обнулить счетчик денормальных чисел    ¦
    261. ¦         mov   [edi],dx                                                  ¦
    262. ¦         mov   ebx,power_ptr    ; Обнулить значение степени десяти       ¦
    263. ¦         mov   [ebx],dx                                                  ¦
    264. ¦         mov   dl,al                                                     ¦
    265. ¦         and   dl,1                                                      ¦
    266. ¦         add   dl,EXACT                                                  ¦
    267. ¦         cmp   al,ZERO          ; Проверить на ноль                      ¦
    268. ¦         jae   convert_integer  ; Перейти программу возведения в         ¦
    269. ¦                                ; степень, если значение равно нулю.     ¦
    270. ¦                                                                         ¦
    271. ¦         fstp  fraction                                                  ¦
    272. ¦         fwait                                                           ¦
    273. ¦         mov   al,bcd_byte + 7                                           ¦
    274. ¦         or    byte ptr bcd_byte +7,80h                                  ¦
    275. ¦         fld   fraction                                                  ¦
    276. ¦         fxtract                                                         ¦
    277. ¦         test  al,80h                                                    ¦
    278. ¦         jnz   normal_value                                              ¦
    279. ¦                                                                         ¦
    280. ¦         fld1                                                            ¦
    281. ¦         fsub                                                            ¦
    282. ¦         ftst                                                            ¦
    283. ¦         fstsw ax                                                        ¦
    284. ¦         sahf                                                            ¦
    285. ¦         jnz   set_unnormal_count                                        ¦
    286. ¦  ;                                                                      ¦
    287. ¦  ;                 Найден псевдо-ноль                                   ¦
    288. ¦  ;                                                                      ¦
    289. ¦         fldlg2                 ; Оценить степень десяти                 ¦
    290. ¦         add   dl,PSEUDO_ZERO - EXACT                                    ¦
    291. ¦         fmulp st(2),st                                                  ¦
    292. ¦         fxch                   ; Взять степеть десяти                   ¦
    293. ¦         fistp word ptr [ebx]   ; Установить степень десяти              ¦
    294. ¦         jmp   convert_integer                                           ¦
    295. ¦                                                                         ¦
    296. ¦  set_unnormal_count:                                                    ¦
    297. ¦         fxtract                ; Взять исходную дробь,                  ¦
    298. ¦                                ; и нормализовать.                       ¦
    299. ¦         fxch              ; Взять счетчик не-нормальных чисел           ¦
    300. ¦         fchs                                                            ¦
    301. ¦         fistp word ptr [edi]   ; Установить счетчик                     ¦
    302. ¦                                ; не-нормальных чисел                    ¦
    303. ¦                                                                         ¦
    304. ¦  ;                                                                      ¦
    305. ¦  ; Вычислить десятичную величину вместе с этим числом                   ¦
    306. ¦  ; внутри одного порядка.                                               ¦
    307. ¦  ;                                                                      ¦
    308. ¦  ; Всегда при округлении будет присутствовать ошибка                    ¦
    309. ¦  ; из-за потери точности. В результате, мы                              ¦
    310. ¦  ; преднамеренно при вычислении порядка не стали                        ¦
    311. ¦  ; рассматривать LOG10 от значения дроби. Так как                       ¦
    312. ¦  ; дробь всегда больше или равна 1 и меньше двух, то                    ¦
    313. ¦  ; LOG10 от этой дроби не изменяет основной точности                    ¦
    314. ¦  ; функции. Для того, чтобы получить десятичный                         ¦
    315. ¦  ; порядок величины, надо просто умножить степень                       ¦
    316. ¦  ; двух на LOG10(2) и округлить результат с                             ¦
    317. ¦  ; отсечением до целого.                                                ¦
    318. ¦  ;                                                                      ¦
    319. ¦  normal_value:                                                          ¦
    320. ¦         fstp  fraction    ; Для дальнейшего использования               ¦
    321. ¦                           ; сохранить поле дроби.                       ¦
    322. ¦         fist  power_twq   ; Сохранить степень двух                      ¦
    323. ¦         fldlg2            ; Взять LOG10(2)                              ¦
    324. ¦                           ; Теперь можно безопасно использовать         ¦
    325. ¦                           ; power_two                                   ¦
    326. ¦         fmul              ; Подготовить LOG10 от порядка числа          ¦
    327. ¦         fistp word ptr [ebx]   ; Здесь может быть применен любой        ¦
    328. ¦                                ; режим округления                       ¦
    329. ¦  ;                                                                      ¦
    330. ¦  ;            Проверить, чтобы величина числа                           ¦
    331. ¦  ;            интерпретировалась как целое.                             ¦
    332. ¦  ;                                                                      ¦
    333. ¦  ; CX имеет максимально позволенное количество десятичных цифр.         ¦
    334. ¦  ;                                                                      ¦
    335. ¦         fwait              ; Ожидать допустимой степени десяти          ¦
    336. ¦  ;                                                                      ¦
    337. ¦  ;             Возвести десять в степень величины значения              ¦
    338. ¦  ;                                                                      ¦
    339. ¦         movsx si,word ptr [ebx]                                         ¦
    340. ¦         sub   esi,ecx         ; Подготовить в AX необходимый            ¦
    341. ¦                               ; коэффициент масштабирования.            ¦
    342. ¦         ja    adjust_result   ; Перейти, если число не подходит         ¦
    343. ¦  ;                                                                      ¦
    344. ¦  ; Число между 1 и 10**(field_size - размер поля)                       ¦
    345. ¦  ; Проверить на целочисленность                                         ¦
    346. ¦  ;                                                                      ¦
    347. ¦         fild  power_two         ; Восстановить начальное значение       ¦
    348. ¦         sub   dl,NORMAL-EXACT   ; Перевести в точное выдаваемое         ¦
    349. ¦                                 ; значение                              ¦
    350. ¦         fld   farction                                                  ¦
    351. ¦         fscale              ; Подготовить полную величину, в этой       ¦
    352. ¦                             ; команде она не портится                   ¦
    353. ¦         fst   st(1)         ; Скопировать значение для сравнения        ¦
    354. ¦         frndint             ; Проверить на целочисленность              ¦
    355. ¦         fcomp               ; Сравнить значения                         ¦
    356. ¦         fstsw ax            ; Сохранить состояние                       ¦
    357. ¦         sahf                ; C3 = 1, значит это была целое число       ¦
    358. ¦                                                                         ¦
    359. ¦         jnz   convert_integer                                           ¦
    360. ¦                                                                         ¦
    361. ¦         fstp  st(0)            ; Удалить нецелочисленное значение       ¦
    362. ¦         add   dl,NORMAL-EXACT  ; Восстановить начальнное выдаваемое     ¦
    363. ¦                                ; значение                               ¦
    364. ¦  ;                                                                      ¦
    365. ¦  ; Масштабировать число внутри диапазона,                               ¦
    366. ¦  ; позволенного форматом BCD. Операция                                  ¦
    367. ¦  ; масштабирования выдает число внутри одного                           ¦
    368. ¦  ; десятичного порядка величины наибольшего                             ¦
    369. ¦  ; десятичного числа, представимого для данной длины                    ¦
    370. ¦  ; строки.                                                              ¦
    371. ¦  ;                                                                      ¦
    372. ¦  ;     Величина степени десяти для масштабирования                      ¦
    373. ¦  ;     находится в регистре SI.                                         ¦
    374. ¦  ;                                                                      ¦
    375. ¦  adjust_result:                                                         ¦
    376. ¦         mov   eax,esi            ; Подготовить для возведения в         ¦
    377. ¦                                  ; степень                              ¦
    378. ¦         mov   word ptr [ebx],ax  ; Установить начальную величину        ¦
    379. ¦                                  ; степени десяти                       ¦
    380. ¦         neg   eax                ; Вычесть единицу для каждого порядка  ¦
    381. ¦                                  ; величины, на который масштабируется  ¦
    382. ¦                                  ; значение.                            ¦
    383. ¦         call  get_power_10       ; Коэффициент масштабирования          ¦
    384. ¦                                  ; представляется как порядок и дробь.  ¦
    385. ¦         fld   fraction           ; Взять дробь                          ¦
    386. ¦         fmul                     ; Комбинировать дроби                  ¦
    387. ¦         mov   esi,ecx            ; Возвести десять в максимальную       ¦
    388. ¦                                  ; степень                              ¦
    389. ¦         shl   esi,3              ; Для того, чтобы значение BCD         ¦
    390. ¦                                  ; входило в строку                     ¦
    391. ¦         fild  power_two          ; Комбинировать степень двух           ¦
    392. ¦         faddp st(2),st                                                  ¦
    393. ¦         fscale                   ; Подготовить полное значение,         ¦
    394. ¦                                  ; порядок остался не тронутым          ¦
    395. ¦         fstp  st(1)              ; Удалить порядок                      ¦
    396. ¦  ;                                                                      ¦
    397. ¦  ; Проверьте установленное значение по таблице                          ¦
    398. ¦  ; точных степеней десяти. Суммарные ошибки оценки                      ¦
    399. ¦  ; величины и степенной функции могут привести к                        ¦
    400. ¦  ; тому, что значение одного порядка величины будет                     ¦
    401. ¦  ; либо слишком маленькое, либо слишком большое для                     ¦
    402. ¦  ; поля типа BCD. Для устранения этой проблемы                          ¦
    403. ¦  ; протестируйте полученное значение - является ли                      ¦
    404. ¦  ; оно слишком большим или слишком маленьким. Затем                     ¦
    405. ¦  ; отрегулируйте его и значение степени десяти.                         ¦
    406. ¦  ;                                                                      ¦
    407. ¦  test_power:                                                            ¦
    408. ¦  ;                                                                      ¦
    409. ¦  ; Сравните с точной степенью. Используйте следующую                    ¦
    410. ¦  ; степень при уменьшении CX на единицу.                                ¦
    411. ¦  ;                                                                      ¦
    412. ¦         fcom  power_table[esi]+type power_table                         ¦
    413. ¦         fstsw ax               ; Не надо ждать                          ¦
    414. ¦         sahf                   ; Если C3=C0=0, то слишком большое       ¦
    415. ¦         jb    test_for-small                                            ¦
    416. ¦         fidiv const10          ; Иначе установить значение              ¦
    417. ¦         and   dl,not EXACT     ; Удалить флаг того, что число точное    ¦
    418. ¦         inc   word ptr [ebx]   ; Установить значение степени десяти     ¦
    419. ¦         jmp   short in_range   ; Перевести значение в целое типа BCD    ¦
    420. ¦                                                                         ¦
    421. ¦  test_for_small:                                                        ¦
    422. ¦         fcom  power_table[esi] ; Проверить относительный размер         ¦
    423. ¦                                                                         ¦
    424. ¦         fstsw ax               ; Не ждать                               ¦
    425. ¦         sahf                   ; Если C0 = 0, то ST(0) больше или       ¦
    426. ¦                                ; равен нижшей границе                   ¦
    427. ¦         jc    in_range         ; Перевести значение в целое типа BCD    ¦
    428. ¦         fimul const10          ; Подогнать значение под диапазон        ¦
    429. ¦         dec   word ptr [ebx]   ; Подобрать значение степени десяти      ¦
    430. ¦  in_range:                                                              ¦
    431. ¦         frndint                ; Подготовить целое значение             ¦
    432. ¦  ;                                                                      ¦
    433. ¦  ; Утверждение: 0 <= TOS <= 999,999,999,999,999,999                     ¦
    434. ¦  ; Число TOS будет точно представлено                                   ¦
    435. ¦  ; 18-ю цифрами в формате BCD.                                          ¦
    436. ¦  ;                                                                      ¦
    437. ¦  convert_integer:                                                       ¦
    438. ¦         fbstp bcd_value        ; Сохранить число в формате BCD          ¦
    439. ¦  ;                                                                      ¦
    440. ¦  ; При сохранении формата BCD установить регистры                       ¦
    441. ¦  ; для перевода в ASCII вид.                                            ¦
    442. ¦  ;                                                                      ¦
    443. ¦         mov   esi,BCD_SIZE-2   ; Инициализировать значение              ¦
    444. ¦                                ; индекса BCD                            ¦
    445. ¦         mov   cx,0f04h         ; Установить счетчик сдвига и маску      ¦
    446. ¦         mov   ebx,1            ; Установить начальный размер ASCII      ¦
    447. ¦                                ; поля для знака                         ¦
    448. ¦         mov   edi,string_ptr   ; Взять адрес начала ASCII строки        ¦
    449. ¦         mov   ax,ds            ; Скопировать DS в ES                    ¦
    450. ¦         mov   es,ax                                                     ¦
    451. ¦         cld                    ; Установить режим автоматического       ¦
    452. ¦                                ; добавления единицы                     ¦
    453. ¦         mov   al,'+'           ; Очистить поле знака                    ¦
    454. ¦         test  dl,MINUS         ; Проверить на отрицательное значение    ¦
    455. ¦         jz    positive_result                                           ¦
    456. ¦                                                                         ¦
    457. ¦         mov   al,'-'                                                    ¦
    458. ¦  positive_result:                                                       ¦
    459. ¦         stosb                  ; Установить указатель строки на         ¦
    460. ¦                                ; последний знак                         ¦
    461. ¦         and   dl,not MINUS     ; Выключить бит знака                    ¦
    462. ¦         fwait                  ; Ожидать окончания команды fbstp        ¦
    463. ¦  ;                                                                      ¦
    464. ¦  ; Используемые регистры:                                               ¦
    465. ¦  ;                                                                      ¦
    466. ¦  ;          AH:          байт со значением типа BCD                     ¦
    467. ¦  ;          AL:          значение строки ASCII                          ¦
    468. ¦  ;          DX:          возвращаемое значение                          ¦
    469. ¦  ;          CH:          маска BCD = 0fh                                ¦
    470. ¦  ;          CL:          счетчик сдвига BCD = 4                         ¦
    471. ¦  ;          BX:          ширина поля строки ASCII                       ¦
    472. ¦  ;          ESI:         индекс поля BCD                                ¦
    473. ¦  ;          DI:          указатель поля строки BCD                      ¦
    474. ¦  ;          DS, ES:      адрес сегмента строки ASCII                    ¦
    475. ¦  ;                                                                      ¦
    476. ¦  ;          Удалить начальные нули из числа.                            ¦
    477. ¦  ;                                                                      ¦
    478. ¦  ;                                                                      ¦
    479. ¦  skip_leading_zeroes:                                                   ¦
    480. ¦         mov   ah,bcd_byte[esi]    ; Взять байт BCD                      ¦
    481. ¦         mov   al,ah               ; Скопировать значение                ¦
    482. ¦         shr   al,cl               ; Взять верхнюю по порядку цифру      ¦
    483. ¦         and   al,0fh              ; Установить флаг нуля                ¦
    484. ¦         jnz   enter_odd           ; Выйти из цикла, если в начале       ¦
    485. ¦                                   ; обнаружены не нули                  ¦
    486. ¦                                                                         ¦
    487. ¦         mov   al,ah               ; Взять снова байт BCD                ¦
    488. ¦         and   al,0fh              ; Взять нижнюю по порядку цифру       ¦
    489. ¦         jnz   enter-even          ; Выйти из цикла, если обнаружены     ¦
    490. ¦                                   ; ненулевые цифры                     ¦
    491. ¦                                                                         ¦
    492. ¦         dec   esi                 ; Уменьшить индекс BCD                ¦
    493. ¦         jns   skip_leading_zeroes                                       ¦
    494. ¦  ;                                                                      ¦
    495. ¦  ;               Вся мантисса состоит из нулей                          ¦
    496. ¦  ;                                                                      ¦
    497. ¦         mov   al,'0'              ; Установить начальный ноль           ¦
    498. ¦         stosb                                                           ¦
    499. ¦         inc   ebx                 ; Увеличить длину строки              ¦
    500. ¦         jmp   short exit_with_value                                     ¦
    501. ¦  ;                                                                      ¦
    502. ¦  ;               Теперь расширяем строку цифрами от                     ¦
    503. ¦  ;               0 до 9 по одной цифре на байт                          ¦
    504. ¦  ;                                                                      ¦
    505. ¦  digit_loop:                                                            ¦
    506. ¦         mov   ah,bcd_byte[esi]    ; Взять байт BCD                      ¦
    507. ¦         mov   al,ah                                                     ¦
    508. ¦         shr   al,cl               ; Взять верхнюю по порядку цифру      ¦
    509. ¦  enter_odd:                                                             ¦
    510. ¦         add   al,'0'              ; Перевести в ASCII                   ¦
    511. ¦         stosb                     ; Занести цифру в строку ASCII        ¦
    512. ¦         mov   al,ah               ; Взять нижнюю по порядку цифру       ¦
    513. ¦         and   al,0fh                                                    ¦
    514. ¦         inc   ebx                 ; Увеличить счетчик размера поля      ¦
    515. ¦  enter-even:                                                            ¦
    516. ¦         add   al,'0'              ; Перевести в ASCII                   ¦
    517. ¦         stosb                     ; Занести цифру в строку ASCII        ¦
    518. ¦         inc   ebx                 ; Увеличить счетчик размера поля      ¦
    519. ¦         dec   esi                 ; Перейти к следующему байту BCD      ¦
    520. ¦         jns   digit_loop                                                ¦
    521. ¦  ;                                                                      ¦
    522. ¦  ;           Перевод закончен. Установить размер                        ¦
    523. ¦  ;           строки и остаток                                           ¦
    524. ¦  ;                                                                      ¦
    525. ¦  exit_with_value:                                                       ¦
    526. ¦         mov   edi,size_ptr                                              ¦
    527. ¦         mov   word ptr [edi],bx                                         ¦
    528. ¦         mov   eax,edx             ; Установить выдаваемое значение      ¦
    529. ¦         jmp   exit_proc                                                 ¦
    530. ¦                                                                         ¦
    531. ¦  floating_to_ascii       endp                                           ¦
    532. ¦                          code          ends                             ¦
    533. ¦                                        end                              ¦
    534. ¦                                                                         ¦
    535. ¦                                                                         ¦
    536. ¦  +1 $title(Вычислить значение 10**AX)                                   ¦
    537. ¦                                                                         ¦
    538. ¦  ; Эта подпрограмма вычисляет значение степени                          ¦
    539. ¦  ; 10**EAX. Точный результат выдается для значений в                    ¦
    540. ¦  ; диапазоне 0 <= EAX < 19. Все регистры прозрачны                      ¦
    541. ¦  ; и значение выдается в TOS как два числа: порядок                     ¦
    542. ¦  ; в ST(1) и дробь в ST(0). Величина порядка может                      ¦
    543. ¦  ; превышать наибольший порядок числа в расширенном                     ¦
    544. ¦  ; вещественном формате. В программе используются                       ¦
    545. ¦  ; три стековых регистра.                                               ¦
    546. ¦  ;                                                                      ¦
    547. ¦         name      get_power_10                                          ¦
    548. ¦         public    get_power_10, power_table                             ¦
    549. ¦                                                                         ¦
    550. ¦  stack  stackseg  8                                                     ¦
    551. ¦                                                                         ¦
    552. ¦  code  segment public er                                                ¦
    553. ¦  ;                                                                      ¦
    554. ¦  ;          Использовать точные значения от 1.0 до 1E18.                ¦
    555. ¦  ;                                                                      ¦
    556. ¦         even               ; Оптимизировать 16-ти битовый доступ        ¦
    557. ¦  power_table   dq  1.0,1e1,1e2,1e3                                      ¦
    558. ¦                                                                         ¦
    559. ¦                dq  1e4,1e5,1e6,1e7                                      ¦
    560. ¦                                                                         ¦
    561. ¦                dq  1e8,1e9,1e10,1e11                                    ¦
    562. ¦                                                                         ¦
    563. ¦                dq  1e12,1e13,1e14,1e15                                  ¦
    564. ¦                                                                         ¦
    565. ¦                dq  1e16,1e17,1e18                                       ¦
    566. ¦                                                                         ¦
    567. ¦  get_power_10  proc                                                     ¦
    568. ¦         cmp   eax,18      ; Проверить диапазон 0 <= AX < 19             ¦
    569. ¦         ja    out_of_range                                              ¦
    570. ¦                                                                         ¦
    571. ¦         fld   power_table[eax*8]  ; Взять точное значение               ¦
    572. ¦         fxtract           ; Отделить степень и                          ¦
    573. ¦                           ; дробную часть                               ¦
    574. ¦         ret               ; Оставить fxtract                            ¦
    575. ¦  ;                                                                      ¦
    576. ¦  ; Вычислить значение, используя команду возведения                     ¦
    577. ¦  ; в степень. Используются следующие соотношения:                       ¦
    578. ¦  ;                                                                      ¦
    579. ¦  ; 10**X = 2**(log2(10)*X)                                              ¦
    580. ¦  ; 2**(I+F) = 2**I * 2**F                                               ¦
    581. ¦  ;                                                                      ¦
    582. ¦  ; Если ST(1) = I и ST(0) = 2**F, то команда fscale                     ¦
    583. ¦  ; выдает 2**(I+F).                                                     ¦
    584. ¦  ;                                                                      ¦
    585. ¦  out_of_range:                                                          ¦
    586. ¦                                                                         ¦
    587. ¦         fldl2t                   ; TOS = LOG2(10)                       ¦
    588. ¦         enter 4,0                                                       ¦
    589. ¦                                                                         ¦
    590. ¦  ;            Сохранить значение степени десяти, P                      ¦
    591. ¦  ;                                                                      ¦
    592. ¦         mov   [ebp-4],eax                                               ¦
    593. ¦                                                                         ¦
    594. ¦  ;            TOS, X = LOG2(10)*P = LOG2(10**P)                         ¦
    595. ¦  ;                                                                      ¦
    596. ¦         fimul dword ptr [ebp-4]                                         ¦
    597. ¦         fld1                     ; Установить TOS = -1.0                ¦
    598. ¦         fchs                                                            ¦
    599. ¦         fld   st(1)              ; Скопировать значение степени по      ¦
    600. ¦                                  ; основанию два                        ¦
    601. ¦         frndint                  ; TOS = I; -бесконечность < I <= X,    ¦
    602. ¦                                  ; где I - целое                        ¦
    603. ¦                                  ; Режим округления не имеет значения   ¦
    604. ¦         fxch  st(2)              ; TOS = X, ST(1) = -1.0                ¦
    605. ¦                                  ; ST(2) = I                            ¦
    606. ¦         fsub  st,st(2)           ; TOS, F = X-I:                        ¦
    607. ¦                                  ; -1.0 < TOS <= 1.0                    ¦
    608. ¦                                                                         ¦
    609. ¦  ;      Восстановить начальный режим управления точностью               ¦
    610. ¦         pop   eax                                                       ¦
    611. ¦         f2xm1            ; TOS = 2**(F) - 1.0                           ¦
    612. ¦         leave            ; Восстановить стек                            ¦
    613. ¦         fsubr            ; Подготовить 2**(F)                           ¦
    614. ¦         ret              ; Оставить fsubr                               ¦
    615. ¦                                                                         ¦
    616. ¦  get_power_10   endp                                                    ¦
    617. ¦                                                                         ¦
    618. ¦  code           ends                                                    ¦
    619. ¦                 end                                                     ¦
    620. ¦                                                                         ¦
    621. ¦  +1 $title(Определение содержимого регистра TOS)                        ¦
    622. ¦  ;                                                                      ¦
    623. ¦  ; Эта подпрограмма выдает значение от 0 до 15 в                        ¦
    624. ¦  ; регистр EAX в соответствии с содержанием вершины                     ¦
    625. ¦  ; стека FPU. Все регистры прозрачны, поэтому ошибки                    ¦
    626. ¦  ; исключены. Выдаваемое значение соответствует                         ¦
    627. ¦  ; битам C3, C2, C1 и C0 команды FXAM.                                  ¦
    628. ¦  ;                                                                      ¦
    629. ¦         name           tos_status                                       ¦
    630. ¦         public         tos_status                                       ¦
    631. ¦                                                                         ¦
    632. ¦  stack        stackseg   6                                              ¦
    633. ¦                                                                         ¦
    634. ¦  code         segment public er                                         ¦
    635. ¦                                                                         ¦
    636. ¦  tos_status  proc                                                       ¦
    637. ¦         fxam             ; Взять состояние регистра TOS                 ¦
    638. ¦         fstsw ax         ; Взять текущее состояние                      ¦
    639. ¦         mov   al,ah      ; Положить биты 10-8 в биты 2-0                ¦
    640. ¦         and   eax,4007h  ; Маскировать биты C3, C2, C1 и C0             ¦
    641. ¦         shr   ah,3       ; Положить бит C3 в бит 11                     ¦
    642. ¦         or    al,ah      ; Положить бит C3 в бит 3                      ¦
    643. ¦         mov   ah,0       ; Очистить возвращаемое значение               ¦
    644. ¦         ret                                                             ¦
    645. ¦                                                                         ¦
    646. ¦  tos_status endp                                                        ¦
    647. ¦                                                                         ¦
    648. ¦  code       ends                                                        ¦
    649. ¦             end                                                         ¦
    650. ¦                                                                         ¦
    651. ¦                                                                         ¦
    652. +-------------------------------------------------------------------------+
    и аттач
     
  4. Exp10der

    Exp10der Мастер дзена

    Публикаций:
    0
    Регистрация:
    27 авг 2007
    Сообщения:
    337
    Адрес:
    Красноярск
    Всё разобрался, спасибо за помощь.
     
  5. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    Y_Mur
    Да, потом только допер
     
  6. aggro

    aggro New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    8
    Простите за археологию, но подскажите как делить эти числа? Т.е. 0\0 Nan\Nan ...
     
  7. edemko

    edemko New Member

    Публикаций:
    0
    Регистрация:
    25 ноя 2009
    Сообщения:
    454
    aggro
    через fpu это: fdiv(r),fdiv(r)p,fidiv(r)
     
  8. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    edemko
    Эм.. вас же забанили за исчерпание лимита бесполезных сообщений, как это вы пишите не понимаю оО.
     
  9. edemko

    edemko New Member

    Публикаций:
    0
    Регистрация:
    25 ноя 2009
    Сообщения:
    454
    оО понимаю не пишите вы это как, сообщений безполезных за исчерпание лимита

    привет!
     
  10. aggro

    aggro New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    8
    Привидите пример пожалуйста
     
  11. edemko

    edemko New Member

    Публикаций:
    0
    Регистрация:
    25 ноя 2009
    Сообщения:
    454
    Код (Text):
    1. f2.0 dt 2.0
    2. ...
    3. entry $
    4.         finit
    5.         fld     [f2.0]
    6.         fld1
    7.         fdiv    st0,st1   ; st0 = 1.0/2.0, st1 = 2.0
    8.         fdivr   st0,st1   ; st0 = 2.0/0.5, st1 = 2.0
    9.         fdivp             ; st0 = 2.0/4.0
    10.         fld1
    11.         fdivrp            ; st0 = 1.0/0.5
    12.         push    10
    13.         fidiv   dword[esp]; st0 = 2.0/10
    14.         add     esp,4
    15. ...
     
  12. aggro

    aggro New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    8
    Не могу разобраться с делением Нанов, может кто поможет?
     
  13. edemko

    edemko New Member

    Публикаций:
    0
    Регистрация:
    25 ноя 2009
    Сообщения:
    454
    зачем, те. практический смысл
     
  14. edemko

    edemko New Member

    Публикаций:
    0
    Регистрация:
    25 ноя 2009
    Сообщения:
    454
    aggro
    fdivx поддерживает деление (не)нормализированных, деление на 0.
    На входе инициализирует fpu.
    На выходете st0 = результат работы.
    ps: переписка... для отбрасыввания дроби пользуем fisttp [mem16/mem32/mem64]; icq не пользуюсь из-за ограниченного доступа в интернет :) Успехов, я думал чекнусь.

    Код (Text):
    1. format pe gui 4.0
    2. include 'win32ax.inc'
    3.  
    4.  
    5. section '' code import readable writable executable
    6. library advapi32, 'advapi32.dll',\
    7.         kernel32, 'kernel32.dll',\
    8.         user32,   'user32.dll'
    9. include 'api\advapi32.inc'
    10. include 'api\kernel32.inc'
    11. include 'api\user32.inc'
    12.  
    13.  
    14.  
    15. ;include '../fl.inc'
    16.  
    17.  
    18.  
    19.  
    20. f1 dq 01000000'00000000'00000000'00000000''00000000'00000000'00000000'00000000b
    21.    dw 0'000000000000000b
    22. f2 dq 01100000'00000000'00000000'00000000''00000000'00000000'00000000'00000000b
    23.    dw 0'000000000000000b
    24.  
    25. .f1 dt 1.0
    26. .f2 dt 2.0
    27.  
    28. entry $
    29.         stdcall fdivx,.f1,.f2
    30.  
    31.         invoke  ExitProcess,0
    32.  
    33.  
    34. proc fdivx; dividend:dword, divisor:dword
    35.         pushfd
    36.         push    eax
    37.         finit
    38.         mov     eax,[esp+16]
    39.         call    .test
    40.         mov     eax,[esp+12]
    41.         call    .test
    42.         fxtract
    43.         fxch    st2
    44.         fxtract
    45.         fdivp   st3,st0
    46.         fsubp   st1,st0
    47.         fxch
    48.         fscale
    49.         jmp     .done
    50. .test:  fld     tbyte[eax]
    51.         fxam
    52.         fstsw   ax
    53.         and     ah,01000101b
    54.         cmp     ah,00000100b
    55.         je      .test_ok
    56.         cmp     ah,01000100b
    57.         je      .test_ok
    58.         mov     dword[esp],.done
    59.         fldz
    60. .test_ok:
    61.         pop     eax
    62.         jmp     eax
    63. .done:  pop     eax
    64.         popfd
    65.         ret     8
    66. endp
     
  15. aggro

    aggro New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    8
    edemko, а можно хотя-бы краткие комментарии к коду?
     
  16. edemko

    edemko New Member

    Публикаций:
    0
    Регистрация:
    25 ноя 2009
    Сообщения:
    454
    *.exe в аттаче.
    Возможны ошибки(но вряд), я просто хочу спать :)ь

    Код (Text):
    1. format pe gui 4.0
    2. include 'win32ax.inc'
    3.  
    4.  
    5.  
    6.  
    7. section '' code import readable writable executable
    8. library advapi32, 'advapi32.dll',\
    9.     kernel32, 'kernel32.dll',\
    10.     user32,   'user32.dll'
    11. include 'api\advapi32.inc'
    12. include 'api\kernel32.inc'
    13. include 'api\user32.inc'
    14.  
    15.  
    16.  
    17.  
    18.  
    19.  
    20.  
    21. f1 dq 00000000'00000000'00000000'00000000''00000000'00000000'00000000'00000001b ;1*2^-16445
    22.    dw 0'000000000000000b                            ;...
    23. f2 dq 10000000'00000000'00000000'00000000''00000000'00000000'00000000'00000000b ;1*2^-16382
    24.    dw 0'000000000000001b                            ;...
    25.  
    26.  
    27. f3 dq 11111111'11111111'11111111'11111111''11111111'11111111'11111111'11111111b
    28.    dw 1'111111111111111b
    29.  
    30.  
    31. entry $
    32.     ;finit
    33.     fld tbyte[f2]
    34.     fld tbyte[f1]
    35.     call    fdivx
    36.     fscale
    37.     ;fabs
    38.     ;fisttp  qword[f1]
    39.     invoke  ExitProcess,0
    40.  
    41.  
    42. ; -> st0 = dividend,    st1 = divisor
    43. ; <- st0 = significand, st1 = exponent
    44. proc fdivx
    45.     push    eax
    46.     call    fxtractx    ;st0=a1,st1=a2,st2=B
    47.     fxch    st2     ;st0=B,st1=a2,st2=a1
    48.     call    fxtractx    ;st0=b1,st1=b2,st2=a2,st3=a1
    49.     fdivp   st3,st0     ;st0=b2,s1=a2,st2=a1/b1
    50.     fsubp   st1,st0     ;st0=a2-b2,st1=a1/b1
    51.     fxch            ;st0 = мантисса, st1=експонента
    52.     ftst            ;куку?
    53.     fstsw   ax; 3   2 0     ;сохранить инф. о числе
    54.     and ah,01000101b    ;нам нужны только fpu.sw.{c0,c2,c3}
    55.     cmp ah,01000101b
    56.     jne @f      ;претензий нет
    57.     fstp    st0     ;выкинуть плохой результат
    58.     fldz            ;загрузить 0
    59. @@: pop eax
    60.     ret
    61. endp
    62.  
    63.  
    64.  
    65. ;Приступая к истолкованию следующей процедуры, следует разобраться с fpu-форматом.
    66. ;Сопроцессор подерживает несколько типов данных, которые перед исполнением всегда
    67. ;преобразуются в конечный 80 битный = 10 байтный вид. Подобно десятичной записи
    68. ;(123.123 = 1*10^2 + 2*10^1 + 3*10^0 + 1*10^-1 + 2*10^-2 + 3*10^-3 = 1.23123*10^2),
    69. ;эти 80 бит имеют специальную область под мантиссу(0..63), указатель степени(64..78),
    70. ;знак числа(79):
    71. ;0'000000000000000'0000000000000000000000000000000000000000000000000000000000000000b
    72. ;| |               |поле мантиссы
    73. ;| |
    74. ;| |поле экспоненты(000000000000000b(-16383d)..011111111111111b(0d)..111111111111111b(+16384d))
    75. ;|
    76. ;поле знака(0b = "+", 1b = "-")
    77. ;
    78. ;Приведем 123.123 к двоичному виду, для этого нужно кадую цифру вынести за знак запятой(точки),
    79. ;т.е. число до запятой(логарифм которого за основанием с-мы счисления>0) делить на два, и наоборот:
    80. ;дробную часть числа(логарифм которой за основанием счисления<0) - умножать на 2:
    81. ;123/2 1 <- младший остаток от деления
    82. ;061/2 1
    83. ;030/2 0
    84. ;015/2 1
    85. ;007/2 1
    86. ;003/2 1
    87. ;001/2 1 <- старший остаток от деления
    88. ;Складываем остатки(запутались, попробуйте то же проделать с 123, делив на 10) с конца:
    89. ;1111011b
    90. ;Переведем обратно: 1*2^6 + 1*2^5 + 1*2^4 + 1*2^3 + 0*2^2 + 1*2^1 + 1*2^0 =
    91. ;                 = 64    + 32    + 16    + 8     + 0     + 2     + 1     =
    92. ;                 = 123
    93. ;Поиграем с точкой(запятой):
    94. ;1111011b = 1.111011b*2^6 = 11.11011b*2^5 ...
    95. ;Хотя-бы 1.111011b*2^6 проверим: (1*2^0 + 1*2^-1 + 1*2^-2 + 1*2^-3 + 0*2^-4 + 1*2^-5 + 1*2^-6)*2^6 =
    96. ;                              = (1     + 1/2    + 1/4    + 1/8    + 0      + 1/32   + 1/64  )*64  =
    97. ;                              =  64    + 32     + 16     + 8      + 0      + 2      + 1           =
    98. ;                              = 123
    99. ;Продолжим... 0.123:
    100. ; .123*2
    101. ;0.246*2
    102. ;0.492*2
    103. ;0.984*2
    104. ;1.968*2
    105. ;1.936*2
    106. ;...
    107. ;Складываем остатки(запутались вновь, умножайте 0.123 на 10) с начала:
    108. ; 00011b...
    109. ;Наконец лепим целую и дробную часть: 1111011.00011b...
    110. ;Нормализируем число: 1.11101100011b <- сдвинули на 6 позиций левее
    111. ;Мантисса готова, пишем експоненту: 011111111111111b + 110b = 100000000000101b.
    112. ;Готово!
    113. ;
    114. ;В случае преобразования только 0.123: 00011b... <- это и есть Denormal\"ненормальный *)".
    115. ;Нормализируем: 1.1b... * 2^-4.
    116. ;Готово!
    117. ;
    118. ;
    119. ;
    120. ;Ура, добрались. Так зачем нам эта fxtractx? Проблема в "плохом" отношении процессора к числам
    121. ;до->$0001'8000000000000000..$7FFE'FFFFFFFFFFFFFFFF<-после. Прока игнорит допустимые кордоны
    122. ;и тупо выдирает мантиссу в st, степень двойки в st1, расширяя пространство значений.
    123. proc fxtractx uses eax ebx ecx edx
    124.     pushfd             ;сохранить флаги
    125.     sub esp,10         ;тут будем ковырсаться
    126.     fstp    tbyte[esp]     ;извлекаем число
    127.     pop ebx edx        ;edx:ebx = мантисса
    128.     xor eax,eax        ;считаем ее нормализированной
    129.     mov ecx,eax
    130.     bsr ecx,edx        ;ищем единицу
    131.     jz  @f         ;возможно число очень маленькое или 0
    132.     neg ecx
    133.     add ecx,31         ;позиция еденицы относительно 31 бита
    134.     sub eax,ecx        ;уменьшить степень двойки(експоненту)
    135.     shld    edx,ebx,cl     ;выплюнуть входные нули
    136.     shl ebx,cl         ;подтянуть младшую часть мантиссы
    137.     jmp .significand_found ;мантиссу нормализировали
    138. @@: cmp ebx,ecx
    139.     jz  .significand_found ;т.е. мантисса = 0
    140.     mov edx,ebx        ;подсунуть младшую часть мантиссы
    141.     mov ebx,ecx        ;обнулить бышую младшую
    142.     bsr ecx,edx        ;пробуем оптимизировать
    143.     neg ecx
    144.     add ecx,31         ;шаг
    145.     shl edx,cl         ;оптиимзации
    146.     neg ecx
    147.     lea eax,[eax-32+ecx +1];-62 максимум
    148. .significand_found:
    149.     mov ecx,$7ffe0000      ;узнаем знак числа, $3fff = 0(см. вступление)
    150.     pop cx         ;получить знак и експоненту числа
    151.     shl cx,1           ;получить знак числа
    152.     rcr ecx,1          ;установить $3fff(+0) или $bfff(-0), убрать бит знака с експоненты числа
    153.     ror ecx,16         ;записать последние 16 бит нормализированной мантиссы
    154.     push    cx edx ebx     ;...
    155.     fld tbyte[esp]     ;загрузить ее
    156.     shr ecx,16         ;вспоминаем експоненту входного числа
    157.     lea eax,[eax+ecx-$3fff];корректируем ее согласно проделаным подтягиваниям(shl)
    158.     mov [esp],eax
    159.     fild    dword[esp]     ;грузим
    160.     fxch               ;делаем словно fxtract
    161.     add esp,10         ;освобождаем стек
    162.     popfd              ;восстанавливаем влаги
    163.     ret            ;до скорой встречи
    164. endp
     
  17. edemko

    edemko New Member

    Публикаций:
    0
    Регистрация:
    25 ноя 2009
    Сообщения:
    454
    аттачка
     
  18. aggro

    aggro New Member

    Публикаций:
    0
    Регистрация:
    30 апр 2010
    Сообщения:
    8
    edemko, спасибо большое!
     
  19. edemko

    edemko New Member

    Публикаций:
    0
    Регистрация:
    25 ноя 2009
    Сообщения:
    454
    !Сочетанием отмечены поправки ";;"
    Код (Text):
    1. proc fxtractx uses eax ebx ecx edx
    2.     pushfd             ;сохранить флаги
    3.     sub esp,10         ;тут будем ковырсаться
    4.     fstp    tbyte[esp]     ;извлекаем число
    5.     pop ebx edx        ;edx:ebx = мантисса
    6.     xor eax,eax        ;считаем ее нормализированной
    7.     mov ecx,eax
    8.     bsr ecx,edx        ;ищем единицу
    9.     jz  @f         ;возможно число очень маленькое или 0
    10.     neg ecx
    11.     add ecx,31         ;позиция еденицы относительно 31 бита
    12.     sub eax,ecx        ;уменьшить степень двойки(експоненту)
    13.     shld    edx,ebx,cl     ;выплюнуть входные нули
    14.     shl ebx,cl         ;подтянуть младшую часть мантиссы
    15.     jmp .significand_found ;мантиссу нормализировали
    16. @@: cmp ebx,ecx
    17.     jz  .significand_found ;т.е. мантисса = 0
    18.     mov edx,ebx        ;подсунуть младшую часть мантиссы
    19.     mov ebx,ecx        ;обнулить бышую младшую
    20.     bsr ecx,edx        ;пробуем оптимизировать
    21.     neg ecx
    22.     add ecx,31         ;шаг
    23.     shl edx,cl         ;оптиимзации
    24.     neg ecx
    25.     ;;
    26.     lea eax,[eax-32+ecx]   ;-63 максимум
    27.     ;;
    28. .significand_found:
    29.     mov ecx,$7ffe0000      ;узнаем знак числа, $3fff = 0(см. вступление)
    30.     pop cx         ;получить знак и експоненту числа
    31.     shl cx,1           ;получить знак числа
    32.     rcr ecx,1          ;установить $3fff(+0) или $bfff(-0), убрать бит знака с експоненты числа
    33.     ;;
    34.     cmp cx,1
    35.     adc cx,0
    36.     ;;
    37.     ror ecx,16         ;записать последние 16 бит нормализированной мантиссы
    38.     push    cx edx ebx     ;...
    39.     fld tbyte[esp]     ;загрузить ее
    40.     shr ecx,16         ;вспоминаем експоненту входного числа
    41.     lea eax,[eax+ecx-$3fff];корректируем ее согласно проделаным подтягиваниям(shl)
    42.     mov [esp],eax
    43.     fild    dword[esp]     ;грузим
    44.     fxch               ;делаем словно fxtract
    45.     add esp,10         ;освобождаем стек
    46.     popfd              ;восстанавливаем влаги
    47.     ret            ;до скорой встречи
    48. endp