Subversion Repositories Kolibri OS

Rev

Rev 7615 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;
  2. ; функции для работы с числами float
  3. ;
  4.  
  5. ; Количество знаков числа после запятой (1-17)
  6. NumberSymbolsAD DW 5
  7. ; Константы (10 в степени N)
  8. MConst: DQ 1.0E1,1.0E2,1.0E3,1.0E4,1.0E5
  9.        DQ 1.0E6,1.0E7,1.0E8,1.0E9,1.0E10
  10.        DQ 1.0E11,1.0E12,1.0E13,1.0E14,1.0E15
  11.        DQ 1.0E16,1.0E17,1.0E18,1.0E19,1.0E20
  12.        DQ 1.0E21,1.0E22,1.0E23,1.0E24,1.0E25
  13.        DQ 1.0E26,1.0E27,1.0E28,1.0E29,1.0E30
  14.        DQ 1.0E31,1.0E32,1.0E33,1.0E34,1.0E35
  15.        DQ 1.0E36,1.0E37,1.0E38,1.0E39,1.0E40
  16.        DQ 1.0E41,1.0E42,1.0E43,1.0E44,1.0E45
  17.        DQ 1.0E46,1.0E47,1.0E48,1.0E49,1.0E50
  18.        DQ 1.0E51,1.0E52,1.0E53,1.0E54,1.0E55
  19.        DQ 1.0E56,1.0E57,1.0E58,1.0E59,1.0E60
  20.        DQ 1.0E61,1.0E62,1.0E63,1.0E64,1.0E65
  21.        DQ 1.0E66,1.0E67,1.0E68,1.0E69,1.0E70
  22.        DQ 1.0E71,1.0E72,1.0E73,1.0E74,1.0E75
  23.        DQ 1.0E76,1.0E77,1.0E78,1.0E79,1.0E80
  24.        DQ 1.0E81,1.0E82,1.0E83,1.0E84,1.0E85
  25.        DQ 1.0E86,1.0E87,1.0E88,1.0E89,1.0E90
  26.        DQ 1.0E91,1.0E92,1.0E93,1.0E94,1.0E95
  27.        DQ 1.0E96,1.0E97,1.0E98,1.0E99,1.0E100
  28.        DQ 1.0E101,1.0E102,1.0E103,1.0E104,1.0E105
  29.        DQ 1.0E106,1.0E107,1.0E108,1.0E109,1.0E110
  30.        DQ 1.0E111,1.0E112,1.0E113,1.0E114,1.0E115
  31.        DQ 1.0E116,1.0E117,1.0E118,1.0E119,1.0E120
  32.        DQ 1.0E121,1.0E122,1.0E123,1.0E124,1.0E125
  33.        DQ 1.0E126,1.0E127,1.0E128
  34. .end:
  35. ; Число с плавающей запятой двойной точности
  36. Data_Double   DQ ?
  37. ; Число в BCD-формате
  38. Data_BCD      DT ?
  39. ; Вспомогательный флаг
  40. Data_Flag     DB ?
  41. ; Знак результата (если не 0 - отрицательное число)
  42. Data_Sign     DB ?
  43. ; Знак результата - 0 для ..e+.. и 1 для ..e-..
  44. Data_Sign_Exp DB ?
  45.  
  46. align 4
  47. ; Строка для хранения числа в коде ASCII
  48. Data_String   DB 32 DUP (?)
  49.  
  50.  
  51.  
  52. ;*******************************************************
  53. ;*  ПРЕОБРАЗОВАНИЕ ЧИСЛА С ПЛАВАЮЩЕЙ ЗАПЯТОЙ В СТРОКУ  *
  54. ;* Число имеет формат с удвоенной точностью, результат *
  55. ;* выдается в десятичном коде, в "бытовом" формате с   *
  56. ;* фиксированным количеством знаков после запятой.     *
  57. ;* Входные параметры:                                  *
  58. ;* Data_Double - преобразуемое число;                  *
  59. ;* NumberSymbolsAD - количество знаков после           *
  60. ;*                   запятой (0-17).                   *
  61. ;* Выходные параметры:                                 *
  62. ;* Data_String - строка-результат.                     *
  63. ;*******************************************************
  64. align 4
  65. DoubleFloat_to_String:
  66.         pushad
  67.         ; Результат записывать в строку Data_String
  68.         mov     EDI, Data_String
  69.  
  70.         ; Сдвигаем число влево на NumberSymbolsAD
  71.         ; десятичных разрядов
  72.         fninit                 ;сброс сопроцессора
  73.         fld     [Data_Double]  ;загрузить число
  74.         xor ebx,ebx
  75.         mov     BX,[NumberSymbolsAD]
  76.         cmp     BX, 0
  77.         je      .NoShifts     ;нет цифр после запятой
  78.         jl      .Error        ;ошибка
  79.         dec     BX
  80.         lea ebx,[MConst+8*ebx]
  81.         fmul    qword [EBX] ;умножить на константу
  82. .NoShifts:
  83.         ; Извлечь число в коде BCD
  84.         fbstp   [Data_BCD]
  85. ; Проверить результат на переполнение
  86.         mov     AX,word [Data_BCD + 8]
  87.         cmp     AX,0FFFFh  ;"десятичное" переполнение?
  88.         je      .Overflow
  89. ; Выделить знак числа и записать его в ASCII-коде
  90.         mov     AL, byte [Data_BCD + 9]
  91.         and     AL,AL
  92.         jz      .NoSign
  93.         mov     AL,'-'
  94.         stosb
  95. .NoSign:
  96. ; Распаковать число в код ASCII
  97.         mov     ebx,8    ;смещение последней пары цифр
  98.         mov     ecx,9    ;счетчик пар цифр
  99.         ; Определить позицию десятичной точки в числе
  100.         mov     DX,18
  101.         sub     DX,[NumberSymbolsAD]
  102.         js      .Error  ;ошибка, если отрицательная
  103.         jz      .Error  ;или нулевая позиция
  104. .NextPair:
  105.         ; Загрузить очередную пару разрядов
  106.         mov     AL, byte [ebx + Data_BCD]
  107.         mov     AH,AL
  108.         ; Выделить, перевести в ASCII и
  109.         ; сохранить старшую тетраду
  110.         shr     AL,4
  111.         add     AL,'0'
  112.         stosb
  113.         dec     DX
  114.         jnz     .N0
  115.         mov     AL,'.'
  116.         stosb
  117. .N0:   ; Выделить, перевести в ASCII и
  118.         ; сохранить младшую тетраду
  119.         mov     AL,AH
  120.         and     AL,0Fh
  121.         add     AL,'0'
  122.         stosb
  123.         dec     DX
  124.         jnz     .N1
  125.         mov     AL,'.'
  126.         stosb
  127. .N1:
  128.         dec  BX
  129.         loop .NextPair
  130.         mov  AL,0
  131.         stosb
  132.  
  133. ; Убрать незначащие нули слева
  134.         mov     EDI, Data_String
  135.         mov     ESI, Data_String
  136.         ; Пропустить знак числа, если он есть
  137.         cmp     byte [ESI],'-'
  138.         jne     .N2
  139.         inc     ESI
  140.         inc     EDI
  141. .N2:   ; Загрузить в счетчик цикла количество разрядов
  142.         ; числа плюс 1 (байт десятичной точки)
  143.         mov     ecx,18+1+1
  144.         ; Пропустить незначащие нули
  145. .N3:
  146.         cmp byte [ESI],'0'
  147.         jne .N4
  148.         cmp byte [ESI+1],'.'
  149.         je .N4
  150.         inc ESI
  151.         loop .N3
  152.         ; Ошибка - нет значащих цифр
  153.         jmp     .Error
  154. ; Скопировать значащую часть числа в начало строки
  155. align 4
  156. .N4:    rep movsb
  157.         jmp    .End
  158. ; Ошибка
  159. align 4
  160. .Error:
  161.         mov     AL,'E'
  162.         stosb
  163.         mov     AL,'R'
  164.         stosb
  165.         mov     AL,'R'
  166.         stosb
  167.         xor     AL,AL
  168.         stosb
  169.         jmp     .End
  170. ; Переполнение разрядной сетки
  171. align 4
  172. .Overflow:
  173.         mov     AL,'#'
  174.         stosb
  175.         xor     AL,AL
  176.         stosb
  177. ; Конец процедуры
  178. align 4
  179. .End:
  180.         popad
  181.         ret
  182.  
  183. ;****************************************************
  184. ;* ПРЕОБРАЗОВАТЬ СТРОКУ В ЧИСЛО С ПЛАВАЮЩЕЙ ЗАПЯТОЙ *
  185. ;*      (число имеет обычный, "бытовой" формат)     *
  186. ;* Входные параметры:                               *
  187. ;* Data_String - число в коде ASCII.                *
  188. ;* Выходные параметры:                              *
  189. ;* Data_Double - число в двоичном коде.             *
  190. ;****************************************************
  191. align 4
  192. String_to_DoubleFloat:
  193.         pushad
  194.         cld
  195.         ; Очищаем Data_BCD
  196.         mov dword [Data_BCD],0
  197.         mov dword [Data_BCD+4],0
  198.         mov  word [Data_BCD+8],0
  199.         ; Очищаем байт знака
  200.         mov     [Data_Sign],0
  201.         ; Заносим в esi указатель на строку
  202.         mov     esi, Data_String
  203.         ; Пропускаем пробелы перед числом
  204.         mov     ecx,64 ;защита от зацикливания
  205. .ShiftIgnore:
  206.         lodsb
  207.         cmp     al,' '
  208.         jne .ShiftIgnoreEnd
  209.         loop .ShiftIgnore
  210.         jmp .Error
  211. align 4
  212. .ShiftIgnoreEnd:
  213.         ; Проверяем знак числа
  214.         cmp     al,'-'
  215.         jne     .Positive
  216.         mov     [Data_Sign],80h
  217.         lodsb
  218. .Positive:
  219.         mov     [Data_Flag],0 ;признак наличия точки
  220.         xor     edx,edx       ;позиция точки
  221.         mov     ecx,18        ;макс. число разрядов
  222. align 4
  223. .ASCIItoBCDConversion:
  224.         cmp     al,'.'        ;точка?
  225.         jne     .NotDot
  226.         cmp     [Data_Flag],0 ;точка не встречалась?
  227.         jne     .Error        ;если точка уже была
  228.         mov     [Data_Flag],1
  229.         lodsb
  230.         or al,al              ;конец строки?
  231.         jnz     .NotDot
  232.         jmp     .ASCIItoBCDConversionEnd
  233. align 4
  234. .NotDot:
  235.         ; Увеличить на 1 значение позиции точки,
  236.         ; если она еще не встречалась
  237.         cmp     [Data_Flag],0
  238.         jnz     .Figures
  239.         inc     edx
  240. .Figures:
  241.         cmp al,'e'
  242.         je .exp_form
  243.         cmp al,'E'
  244.         jne @f
  245.         .exp_form:
  246.                 call string_ExpForm ;если число в формате ..e..
  247.                 or al,al
  248.                 jnz .Error
  249.                 jmp     .ASCIItoBCDConversionEnd
  250.         @@:
  251.         ; Символы числа должны быть цифрами
  252.         cmp     al,'0'
  253.         jb      .Error
  254.         cmp     al,'9'
  255.         ja      .Error
  256.         ; Пишем очередную цифру в младшую тетраду BCD
  257.         and     al,15 ;символы 0-9 переводим в число
  258.         or      byte [Data_BCD],al
  259.         ; Проверка на конец строки
  260.         cmp     byte [esi],0
  261.         je      .ASCIItoBCDConversionEnd
  262.         ; Сдвигаем BCD на 4 разряда влево
  263.         ; (сдвигаем старшие 2 байта)
  264.         mov     ax,word [Data_BCD+6]
  265.         shld    word [Data_BCD+8],ax,4
  266.         ; (сдвигаем средние 4 байта)
  267.         mov     eax,dword [Data_BCD]
  268.         shld    dword [Data_BCD+4],eax,4
  269.         ; (сдвигаем младшие 4 байта)
  270.         shl     dword [Data_BCD],4
  271.         ; Загружаем следующий символ в AL
  272.         lodsb
  273.         loop .ASCIItoBCDConversion ;если не компил. то поставить dec ecx, jnz ...
  274.         ; Если 19-й символ не 0 и не точка,
  275.         ; то ошибка переполнения
  276.         cmp     al,'.'
  277.         jne     .NotDot2
  278.         inc     ecx ;пропуск точки в конце очень большого числа
  279.         lodsb
  280. .NotDot2:
  281.         or al,al        ;переполнение разрядной сетки?
  282.         jz      .ASCIItoBCDConversionEnd
  283. align 4
  284. .Error: ; При любой ошибке обнулить результат
  285.         fldz    ;занести ноль с стек сопроцессора
  286.         fstp    [Data_Double]
  287.         jmp     .End
  288.  
  289. ; ПРЕОБРАЗОВАТЬ ЧИСЛО ИЗ КОДА BCD В ВЕЩЕСТВЕННОЕ ЧИСЛО
  290. .ASCIItoBCDConversionEnd:
  291.         ; Вписать знак в старший байт
  292.         mov     al,[Data_Sign]
  293.         mov     byte [Data_BCD+9],al
  294.         ; Сбросить регистры сопроцессора
  295.         fninit
  296.         ; Загрузить в сопроцессор число в BCD-формате
  297.         fbld    [Data_BCD]
  298.         ; Вычислить номер делителя или множителя
  299.         lea ebx,[ecx+edx-18]
  300.         cmp ebx,0
  301.         jle .NoMul ;если число e-..
  302.         dec ebx
  303.         jz .NoDiv ;если число e+0
  304.         dec ebx
  305.         lea ebx,[MConst+8*ebx]
  306.         cmp ebx,MConst.end
  307.         jl @f
  308.                 ffree st0
  309.                 fincstp
  310.                 jmp .Error ;если очень большое число e+**
  311.         @@:
  312.         fmul qword [ebx] ;умножить на константу (для чисел с приставкой e+..)
  313.         jmp .NoDiv
  314. .NoMul:
  315.         neg ebx
  316.         lea ebx,[MConst+8*ebx]
  317.         cmp ebx,MConst.end
  318.         jl @f
  319.                 ffree st0
  320.                 fincstp
  321.                 jmp .Error ;если очень маленькое число e-**
  322.         @@:
  323.         fdiv qword [ebx] ;разделить на константу
  324. .NoDiv: ;Выгрузить число в двоичном формате
  325.         fstp [Data_Double]
  326. .End:
  327.         popad
  328.         ret
  329.  
  330. ;output:
  331. ; eax - 1 if error
  332. ; edx += size
  333. align 4
  334. proc string_ExpForm uses ebx
  335.         mov [Data_Sign_Exp],0
  336.         xor eax,eax
  337.         lodsb
  338.         cmp al,'+'
  339.         jne @f
  340.                 lodsb
  341.         @@:
  342.         cmp al,'-'
  343.         jne @f
  344.                 inc [Data_Sign_Exp]
  345.                 lodsb
  346.         @@:
  347.        
  348.         xor ebx,ebx
  349.         .cycle0:
  350.                 cmp al,0
  351.                 je .cycle0end
  352.                 cmp al,9
  353.                 je .cycle0end
  354.                 cmp al,10
  355.                 je .cycle0end
  356.                 cmp al,13
  357.                 je .cycle0end
  358.                 cmp al,' '
  359.                 je .cycle0end
  360.                 cmp     al,'0'
  361.                 jb .Error
  362.                 cmp     al,'9'
  363.                 ja .Error
  364.        
  365.                 imul ebx,10
  366.                 and     eax,15 ;символы 0-9 переводим в число
  367.                 add ebx,eax
  368.                 lodsb
  369.                 jmp .cycle0
  370.         .cycle0end:
  371.        
  372.         cmp ebx,328 ;308 - макс. размер степени для double + 20 - число разрядов в BCD
  373.         ja .Error
  374.         cmp [Data_Sign_Exp],0
  375.         je @f
  376.                 neg ebx
  377.         @@:
  378.         cmp     [Data_Flag],0 ;точка не встречалась?
  379.         jne @f
  380.                 dec edx
  381.         @@:
  382.         add edx,ebx
  383.  
  384.         xor eax,eax
  385.         jmp @f
  386.         .Error:
  387.                 xor eax,eax
  388.                 inc eax
  389.         @@:
  390.         ret
  391. endp
  392.  
  393. align 4
  394. proc str_cat uses eax ecx edi esi, str1:dword, str2:dword
  395.         mov esi,dword[str2]
  396.         stdcall str_len,esi
  397.         mov ecx,eax
  398.         inc ecx
  399.         mov edi,dword[str1]
  400.         stdcall str_len,edi
  401.         add edi,eax
  402.         cld
  403.         repne movsb
  404.         ret
  405. endp
  406.  
  407. ;output:
  408. ; eax = strlen
  409. align 4
  410. proc str_len, str1:dword
  411.         mov eax,[str1]
  412.         @@:
  413.                 cmp byte[eax],0
  414.                 je @f
  415.                 inc eax
  416.                 jmp @b
  417.         @@:
  418.         sub eax,[str1]
  419.         ret
  420. endp
  421.  
  422. align 4
  423. proc String_crop_0 uses eax ebx ecx edi
  424.         mov edi,Data_String
  425.         mov al,'.'
  426.         mov ecx,32
  427.         repne scasb
  428.         mov ebx,edi
  429.         mov edi,Data_String
  430.         xor al,al
  431.         mov ecx,32
  432.         repne scasb
  433.         cmp ebx,edi
  434.         jg .end_f
  435.         dec edi
  436.         .cycle0:
  437.                 dec edi
  438.                 cmp edi,Data_String
  439.                 jle .end_f
  440.                 cmp byte[edi],'0'
  441.                 jne .cycle0end
  442.                 mov byte[edi],0
  443.                 jmp .cycle0
  444.         .cycle0end:
  445.         cmp byte[edi],'.'
  446.         jne .end_f
  447.                 mov byte[edi],0
  448.         .end_f:
  449.         ret
  450. endp