7
; These are bits in the FP status word.
24
dt @CatStr(1.0e,%iexp)
30
dt @CatStr(1.0e,%iexp)
34
;--- just the first exponent is necessary for 8-byte doubles
38
dt @CatStr(1.0e,%iexp)
44
;--- called by FloatToStr
51
cmp ax, 0 ;.IF (SWORD PTR ax < 0)
71
and bl, 1fh ;bits 8-12
77
cmp ax, 0 ;.IF (SWORD PTR ax < 0)
87
mov al,10 ; sizeof TBYTE
91
fld tbyte ptr [bx + si]
97
; Convert a floating point register to ASCII. For internal use.
98
; The result always has exactly 18 digits, with zero padding on the
101
; Entry: ST(0) = a number to convert, 0 <= ST(0) < 1E19.
102
; DI = an 18-character buffer.
103
; modifies SI,DI,CX,AX
115
; The fbstp instruction converts the top of the stack to a
116
; packed BCD form in ten bytes, with two digits per byte. The top
117
; byte has the sign, which we ignore.
125
; Now we need to unpack the BCD to ASCII.
135
mov al, ss:[esi] ; xxxx xxxx AAAA BBBB
138
mov al, [si] ; xxxx xxxx AAAA BBBB
142
rol ax, 12 ; BBBB xxxx xxxx AAAA
143
rol ah, 4 ; xxxx BBBB xxxx AAAA
144
and ax, 0f0fh ; 0000 BBBB 0000 AAAA
146
db 0D4h,10h ; aam 16: 0000 AAAA 0000 BBBB
147
xchg al,ah ; 0000 BBBB 0000 AAAA
162
; Convert a double precision number to a string.
164
; Entry: SI=fpin = 10-byte double to convert
165
; DI=pszDbl = buffer to hold converted double
167
; Exit: DI = behind converted double
169
FloatToStr PROC USES si
180
;local szTemp[22]:BYTE
183
;--- Special case zero has been filtered already (fxtract fails for zero).
185
;--- Check for a negative number.
190
and byte ptr [si+9], 07fh ; change to positive
191
mov al,'-' ; store a minus sign
195
;--- load our value onto the stack.
199
mov [si+9], cl ; restore fpin, must be preserved.
201
; Compute the closest power of 10 below the number. We can't get an
202
; exact value because of rounding. We could get close by adding in
203
; log10(mantissa), but it still wouldn't be exact. Since we'll have to
204
; check the result anyway, it's silly to waste cycles worrying about
207
; The exponent is basically log2(fpin). Those of you who remember
208
; algebra realize that log2(fpin) x log10(2) = log10(fpin), which is
211
fxtract ; ST=> mantissa, exponent, fpin
212
fstp st ; drop the mantissa
213
fldlg2 ; push log10(2)
214
fmulp st(1), st ; ST = log10(fpin), fpin
215
fistp iExp ; ST = fpin
217
;--- A 10-byte double can carry almost 19 digits, but fbstp only stores the
218
;--- guaranteed 18. If you're doing 10-byte doubles, change the '16' to '18'.
223
fld st ; ST = fpin, fpin
224
frndint ; ST = int(fpin), fpin
225
fcomp st(1) ; ST = fpin, status set
235
;--- We have an integer! Lucky day. Go convert it into a temp buffer.
250
;--- The off-by-one order of magnitude problem below can hit us here.
251
;--- We just trim off the possible leading zero.
253
cmp byte ptr [si],'0'
259
;--- Copy the rest of the converted BCD value to our buffer.
267
;--- Have fbstp round to 17 places.
270
sub ax, iExp ; adjust exponent to 17
273
; Either we have exactly 17 digits, or we have exactly 16 digits. We can
274
; detect that condition and adjust now.
276
fcom qword ptr [ten_16]
277
; x0xxxx00 means top of stack > ten16
278
; x0xxxx01 means top of stack < ten16
279
; x1xxxx00 means top of stack = ten16
288
fmul qword ptr [ten_1]
292
;--- Go convert to BCD.
299
; lea si, [szTemp+1] ; point to converted buffer
300
lea si, [di+8+1] ; point to converted buffer
302
;--- If the exponent is between -15 and 16, we should express this as a number
303
;--- without scientific notation.
310
ja fts6 ;if scientific notation
312
; If the exponent is less than zero, we insert '0.', then -ecx
313
; leading zeros, then 16 digits of mantissa. If the exponent is
314
; positive, we copy ecx+1 digits, then a decimal point (maybe), then
315
; the remaining 16-ecx digits.
336
;--- Trim off trailing zeros.
339
cmp byte ptr [di-1],'0'
345
;--- If we cleared out all the decimal digits, kill the decimal point, too.
347
cmp byte ptr [di-1], '.'
356
; Now convert this to a standard, usable format. If needed, a minus
357
; sign is already present in the outgoing buffer, and di already points
360
movsb ; copy the first digit
362
stosb ; plop in a decimal point
363
movsw ; copy four more digits
365
movsw ; copy two more digits
369
; The printf %g specified trims off trailing zeros here. I dislike
370
; this, so I've disabled it. Comment out the if 0 and endif if you
374
cmp byte ptr [di-1],'0'
381
;--- Shove in the exponent. If you support 10-byte reals, remember to
382
;--- allow 4 digits for the exponent.
408
; add di, 4 ; point to terminator