Subversion Repositories Kolibri OS

Rev

Rev 5153 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5153 IgorA 1
;
2
; функции для работы с числами float
3
;
4
 
5
; Количество знаков числа после запятой (1-17)
6
NumberSymbolsAD DW 5
7
; Константы (10 в степени N)
8408 IgorA 8
MConst: DQ 1.0E1,1.0E2,1.0E3,1.0E4,1.0E5
5153 IgorA 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
8408 IgorA 34
.end:
5153 IgorA 35
; Число с плавающей запятой двойной точности
36
Data_Double   DQ ?
37
; Число в BCD-формате
38
Data_BCD      DT ?
39
; Вспомогательный флаг
40
Data_Flag     DB ?
41
; Знак результата (если не 0 - отрицательное число)
42
Data_Sign     DB ?
8408 IgorA 43
; Знак результата - 0 для ..e+.. и 1 для ..e-..
44
Data_Sign_Exp DB ?
5153 IgorA 45
 
8408 IgorA 46
align 4
5153 IgorA 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
;*******************************************************
8408 IgorA 64
align 4
5153 IgorA 65
DoubleFloat_to_String:
66
	pushad
67
	; Результат записывать в строку Data_String
8408 IgorA 68
	mov	EDI, Data_String
5153 IgorA 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
8408 IgorA 80
	lea ebx,[MConst+8*ebx]
5153 IgorA 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
; Убрать незначащие нули слева
8408 IgorA 134
	mov	EDI, Data_String
135
	mov	ESI, Data_String
5153 IgorA 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
; Скопировать значащую часть числа в начало строки
8408 IgorA 155
align 4
5153 IgorA 156
.N4:	rep movsb
157
	jmp    .End
158
; Ошибка
8408 IgorA 159
align 4
5153 IgorA 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
; Переполнение разрядной сетки
8408 IgorA 171
align 4
5153 IgorA 172
.Overflow:
173
	mov	AL,'#'
174
	stosb
175
	xor	AL,AL
176
	stosb
177
; Конец процедуры
8408 IgorA 178
align 4
5153 IgorA 179
.End:
180
	popad
181
	ret
182
 
183
;****************************************************
184
;* ПРЕОБРАЗОВАТЬ СТРОКУ В ЧИСЛО С ПЛАВАЮЩЕЙ ЗАПЯТОЙ *
185
;*      (число имеет обычный, "бытовой" формат)     *
186
;* Входные параметры:                               *
187
;* Data_String - число в коде ASCII.                *
188
;* Выходные параметры:                              *
189
;* Data_Double - число в двоичном коде.             *
190
;****************************************************
8408 IgorA 191
align 4
5153 IgorA 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
8408 IgorA 201
	; Заносим в esi указатель на строку
202
	mov	esi, Data_String
5153 IgorA 203
	; Пропускаем пробелы перед числом
204
	mov	ecx,64 ;защита от зацикливания
205
.ShiftIgnore:
206
	lodsb
8408 IgorA 207
	cmp	al,' '
208
	jne .ShiftIgnoreEnd
209
	loop .ShiftIgnore
210
	jmp .Error
211
align 4
5153 IgorA 212
.ShiftIgnoreEnd:
213
	; Проверяем знак числа
8408 IgorA 214
	cmp	al,'-'
5153 IgorA 215
	jne	.Positive
216
	mov	[Data_Sign],80h
217
	lodsb
218
.Positive:
219
	mov	[Data_Flag],0 ;признак наличия точки
8408 IgorA 220
	xor	edx,edx	      ;позиция точки
5153 IgorA 221
	mov	ecx,18	      ;макс. число разрядов
8408 IgorA 222
align 4
5153 IgorA 223
.ASCIItoBCDConversion:
8408 IgorA 224
	cmp	al,'.'	      ;точка?
5153 IgorA 225
	jne	.NotDot
226
	cmp	[Data_Flag],0 ;точка не встречалась?
8408 IgorA 227
	jne	.Error        ;если точка уже была
5153 IgorA 228
	mov	[Data_Flag],1
229
	lodsb
8408 IgorA 230
	or al,al	      ;конец строки?
231
	jnz	.NotDot
5153 IgorA 232
	jmp	.ASCIItoBCDConversionEnd
8408 IgorA 233
align 4
5153 IgorA 234
.NotDot:
235
	; Увеличить на 1 значение позиции точки,
236
	; если она еще не встречалась
237
	cmp	[Data_Flag],0
238
	jnz	.Figures
8408 IgorA 239
	inc	edx
5153 IgorA 240
.Figures:
8408 IgorA 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
	@@:
5153 IgorA 251
	; Символы числа должны быть цифрами
8408 IgorA 252
	cmp	al,'0'
5153 IgorA 253
	jb	.Error
8408 IgorA 254
	cmp	al,'9'
5153 IgorA 255
	ja	.Error
256
	; Пишем очередную цифру в младшую тетраду BCD
8408 IgorA 257
	and	al,15 ;символы 0-9 переводим в число
258
	or	byte [Data_BCD],al
5153 IgorA 259
	; Проверка на конец строки
8408 IgorA 260
	cmp	byte [esi],0
5153 IgorA 261
	je	.ASCIItoBCDConversionEnd
262
	; Сдвигаем BCD на 4 разряда влево
263
	; (сдвигаем старшие 2 байта)
8408 IgorA 264
	mov	ax,word [Data_BCD+6]
265
	shld	word [Data_BCD+8],ax,4
5153 IgorA 266
	; (сдвигаем средние 4 байта)
8408 IgorA 267
	mov	eax,dword [Data_BCD]
268
	shld	dword [Data_BCD+4],eax,4
5153 IgorA 269
	; (сдвигаем младшие 4 байта)
270
	shl	dword [Data_BCD],4
271
	; Загружаем следующий символ в AL
272
	lodsb
8408 IgorA 273
	loop .ASCIItoBCDConversion ;если не компил. то поставить dec ecx, jnz ...
5153 IgorA 274
	; Если 19-й символ не 0 и не точка,
275
	; то ошибка переполнения
8408 IgorA 276
	cmp	al,'.'
5153 IgorA 277
	jne	.NotDot2
8408 IgorA 278
	inc	ecx ;пропуск точки в конце очень большого числа
5153 IgorA 279
	lodsb
280
.NotDot2:
8408 IgorA 281
	or al,al	;переполнение разрядной сетки?
282
	jz	.ASCIItoBCDConversionEnd
283
align 4
284
.Error: ; При любой ошибке обнулить результат
285
	fldz	;занести ноль с стек сопроцессора
286
	fstp	[Data_Double]
287
	jmp	.End
5153 IgorA 288
 
289
; ПРЕОБРАЗОВАТЬ ЧИСЛО ИЗ КОДА BCD В ВЕЩЕСТВЕННОЕ ЧИСЛО
290
.ASCIItoBCDConversionEnd:
291
	; Вписать знак в старший байт
8408 IgorA 292
	mov	al,[Data_Sign]
293
	mov	byte [Data_BCD+9],al
5153 IgorA 294
	; Сбросить регистры сопроцессора
295
	fninit
296
	; Загрузить в сопроцессор число в BCD-формате
297
	fbld	[Data_BCD]
8408 IgorA 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]
5153 IgorA 326
.End:
327
	popad
328
	ret
329
 
8408 IgorA 330
;output:
331
; eax - 1 if error
332
; edx += size
5153 IgorA 333
align 4
8408 IgorA 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
5153 IgorA 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
8408 IgorA 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
5153 IgorA 450
endp