Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4721 Akyltist 1
;-----------------------------------------------------------------------------+
2
; Функция перевода вещественного числа в строку      [ by ManHunter / PCL ]   |
3
;-----------------------------------------------------------------------------|
4
; Параметры:                                                                  |
5
;   lpFloat - указатель на вещественное число TBYTE                           |
6
;   lpResult - указатель на строку-приемник результата                        |
7
;-----------------------------------------------------------------------------+
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
    lea     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