Converting Text into FLoating Point Numbers in Assembler.

Started by Charles Pegge, June 27, 2007, 11:59:23 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Charles Pegge


Updated 28 June 2007 with "E+" notation, and now returns Error code

This does the same job as  number=VAL(numbertext) but about 2.5 times faster, (In Freebasic anyway)

It may look long and complicated but most of the opcodes used are very cheap in clock cycles. There is also a degree of parallel processing with the CPU doing things while the FPU crunches its numbers.

This supports extended precision floating point and E notation. Some tests are provided. It reads up to eighteen decimal digits, ignoring the rest, which should match the resolution of the x87 FPU.


'
' DVAL
' text to floating point number conversion in Assembler

' Charles E V Pegge
' 28 June 2007

' FreeBasic ver 0.16b
' using inline assembler.




function dval(byval p as byte ptr, byval le as long, byref v as double) as long
dim as long m10=10
dim as long m1e4=1e4
dim as long m1e8=1e8
dim as long tm1,tm2
dim as long sgg=0
dim as long sgx=0
'
asm
'======================'
xor eax,eax           ' clear eax
fldz                  ' load zero to fpu
mov ebx,[le]          ' length
mov ecx,[p]           ' text pointer
'======================'
a0:                    ' loop for reaching the sign or first digit
cmp ebx,0             ' is it zero or less?
jle a2                ' then terminate now with zero
mov al,[ecx]          ' first char
cmp al,44             ' is it
jl aa                 ' if less then .. aa treat as leading space
jz a2                 ' terminate now with zero
cmp al,45             ' is it '-' sign?
jnz a1                ' then
dec ebx               ' is it last char?
jle a2                ' then terminate now with zero
inc ecx               ' next char
mov dword ptr [sgg],1 ' set neg flag
jmp a1                ' procede to a1
'======================'
aa:                    ' skip space chars
dec ebx               ' down count chars to go
inc ecx               ' next char
jmp a0                ' loop back to a0
'======================'
a1:                    ' begin collecting digits
mov al,[ecx]          ' load next char
dec ebx               ' down count
jl a2                 ' no more digits so goto E section
inc ecx               ' ready next char
cmp al,46             ' is this a dot?
jz bb                 ' if so then goto decimals section
cmp al,48             ' check lower limit
jl a2                 ' below '0' char so goto E section
cmp al,57             ' check upper limit
jg a2                 ' above '9' so goto E section
fimul dword ptr [m10] ' premultiply the accummulator st
sub al,48             ' base to 0
mov [tm1],eax         ' store in temp
fiadd dword ptr [tm1] ' add from temp
jmp a1                ' repeat for next digit
'======================'
a2:                    ' relay to E section
mov esi,ecx           ' transfer index to esi
mov cl,al             ' transfer char to cl
jmp c2                ' go on to E section
'======================'
bb:                    ' decimal point
cmp ebx,0             ' is this the last char?
jle c2                ' then finish now
mov esi,ecx
xor edx,edx           ' clear edx
mov eax,1             ' set eax to 10
xor ecx,ecx           ' clear to act as char reg
xor edx,edx           ' while edx:eax is used as a digit multiplier
'======================'
xor edi,edi           ' zero the decimal places tally
b1:                    ' do loop
                       ' start of decimals loop
dec ebx               ' any more chars?
jl c1                 ' finish now
mov cl,[esi]          ' get next char
inc esi               ' ready for next char
cmp cl,48             ' range check lower
jl c1                 ' finish
cmp cl,57             ' range check upper
jg c1                 ' check for E numbers
cmp edi,18            ' limit of decimal places
jge b1                ' too many decimal places error so ignore rest
fimul dword ptr [m10] ' premultiply accummulator
mul dword ptr[m10]    ' multiply eax ready for next loop
inc edi               ' tally decimal places
cmp edi,9             ' is this 9 dps done ?
jnz b2                ' skip if not
mov [tm2],eax         ' move the multiplier to a second stage
mov eax,1             ' reset the multiplier
b2:                    ' continue
sub cl,48             ' base  to zero
mov [tm1],ecx         ' store to tm1
fiadd dword ptr [tm1] ' add from tm1
jmp b1                ' repeat for next digit
'======================'

'======================'
cc:                    '
c1:                    ' decimal place scaling
mov [tm1],eax         ' save eax to tm1
fidiv dword ptr [tm1] ' divide by this factor (up to 9 decimal places)
cmp dword ptr [tm2],0 ' is there a second stage?
jz c2                 ' skip if not
fidiv dword ptr [tm2] ' divide by this factor (up to 9 more decimal places)
'======================'
c2:                    ' inserted E number checking procedure here:
'======================'
ee:                    ' E & e numbers
cmp cl,&h45           ' is it E?
jz e1                 ' okay
cmp cl,&h65           ' is it e?
jz e1                 ' okay
jmp c3                ' else skip E numbers
'----------------------'
e1:                    ' ready to procede with E number
xor eax,eax           ' clear eax
mov ch,10             ' x10 multiplier
dec ebx               ' check if end
jl c3                 ' finish if at end
mov cl,[esi]          ' next char
inc esi               ' increment char pointer
cmp cl,43             ' is it a '+' sign?
jz e1a                ' then ignore and get next char
cmp cl,45             ' it it a '-' sign
jnz e2                ' skip if not
mov dword ptr [sgx],1 ' set negation flag
'----------------------'
e1a:                   ' get the next digit
dec ebx               ' check if at end
jl c3                 ' then finish now
mov cl,[esi]          ' get a digit
inc esi               ' increment char pointer
'----------------------'
e2:                    ' first digit is ready
cmp cl,48             ' is it less then 0?
jz e1a                ' ignore leading zeros, get next
jl c3                 ' then finish
cmp cl,57             ' is it greater than 9?
jg c3                 ' then finish
sub cl,48             ' base to zero
mov al,cl             ' move to accummulator
dec ebx               ' check at end
jl e3                 ' if so then procede to process
mov cl,[esi]          ' next digit
inc esi               ' next digit pointer
cmp cl,48             ' check below 0
jl e3                 ' if so then procede to process
cmp cl,57             ' check above 9
jg e3                 ' if so then procede to process
mul ch                ' multiply accum by 10
sub cl,48             ' base digit to zero
add al,cl             ' add it to accum
dec ebx               ' check if at end
jl e3                 ' then process
mov cl,[esi]          ' get the final digit
inc esi               ' ready for next xhar
cmp cl,48             ' is it below 0
jl e3                 ' then process
cmp cl,57             ' is it above 9
jg e3                 ' then process
mul ch                ' multiply accum by 10
sub cl,48             ' base digit to zero
add al,cl             ' add to accum
adc ah,0              ' carry thru to ah
'----------------------'
'                      ' ERROR CHECKS
'cmp eax,307           ' E too great
'jle ee1               '
'mov eax,1             ' error code: E out of range
'jmp xx                '
ee1:                   '
dec ebx               ' Excess E digits
jl e3                 '
mov cl,[esi]          '
inc esi
cmp cl,48             '
jl e3                 '
cmp cl,57             '
jg e3                 '
mov eax,2             ' error code: E overflow
jmp xx                '
'----------------------'
e3:                    ' E is now in binary form in eax
cmp dword ptr [sgx],1  ' is it negative
jz e4m                 ' if so then go to divider section
'----------------------'
e4:                    ' multiply by 10 for each E number
cmp eax,8             ' step of 10^8
jl e5                 ' try smaller step
fimul dword ptr [m1e8]'
sub eax,8             '
jmp e4                ' repeat
e5:                    '
cmp eax,4             ' step of 10^4
jl e6                 ' try smaller step
sub eax,4             '
fimul dword ptr [m1e4]'
jmp e5                ' repeat
e6:                    '
cmp eax,0             ' step of 10^1
jle c3                ' done
dec eax               '
fimul dword ptr [m10] '
jmp e6                ' repeat till ecx=0
'======================'

'======================'
e4m:                   ' divide by 10 for each negative E number
cmp eax,8             ' step of 10^8
jl e5m                ' try smaller step
fidiv dword ptr [m1e8]'
sub eax,8             '
jmp e4m               ' repeat
e5m:                   '
cmp eax,4             ' step of 10^4
jl e6m                ' try smaller step
sub eax,4             '
fidiv dword ptr [m1e4]'
jmp e5m               ' repeat
e6m:                   '
cmp eax,0             ' step of 10^1
jle c3                ' done
dec eax               '
fidiv dword ptr [m10] '
jmp e6m               ' repeat till ecx=0
'======================'

'======================'
c3:                    '
cmp dword ptr [sgg],1 ' check if sign '-'
jnz c4                ' skip if not.
fchs                  ' otherwise change the accummulator sign
'======================'
c4:                    '
mov eax,[v]           ' get pointer to result
fstp qword ptr [eax]  ' store the result and pop the FPU stack                  '
xor eax,eax           ' no error
'======================'
xx:
mov [function],eax    ' return error code
'======================'
end asm
end function

  '--------'
  '  TEST  '
  '--------'


dim as string s="-123456.6789e5"
dim v as double
dim erc as long

erc=dval( strptr(s),len(s),v )
print "input:  ";s
print "output: ";v
print
print "Error code: ";erc

  '-----------------'
  '  EXTREME TESTS  '
  '-----------------'
print
print "TESTS AND INTERPRETATIONS"
s=" 0":  dval( strptr(s),len(s),v ): print s;"    ",v
s=" ":   dval( strptr(s),len(s),v ): print s;"    ",v
s=" ,":  dval( strptr(s),len(s),v ): print s;"    ",v
s=" -":  dval( strptr(s),len(s),v ): print s;"    ",v
s=" .":  dval( strptr(s),len(s),v ): print s;"    ",v
s=" 0,1":dval( strptr(s),len(s),v ): print s;"    ",v
s=" 1,2":dval( strptr(s),len(s),v ): print s;"    ",v
s=" 0.1,2":dval( strptr(s),len(s),v ): print s;"    ",v
s=" !3":dval( strptr(s),len(s),v ): print s;"    ",v
s=" $3":dval( strptr(s),len(s),v ): print s;"    ",v
s=" $3$4":dval( strptr(s),len(s),v ): print s;"    ",v
s=" 3-4":dval( strptr(s),len(s),v ): print s;"    ",v
s=" 3.4":dval( strptr(s),len(s),v ): print s;"    ",v
s=" .000456":dval( strptr(s),len(s),v ): print s;"    ",v
s=" 3.4.5":dval( strptr(s),len(s),v ): print s;"    ",v
s=" 3e2":dval( strptr(s),len(s),v ): print s;"    ",v
s=" 3.4e2":dval( strptr(s),len(s),v ): print s;"    ",v
s=" -.4e2":dval( strptr(s),len(s),v ): print s;"    ",v
s=" .04e2":dval( strptr(s),len(s),v ): print s;"    ",v
s=" .04e-2":dval( strptr(s),len(s),v ): print s;"    ",v
s=" -.04e-2":dval( strptr(s),len(s),v ): print s;"    ",v
s=" -.0012345E-10":erc=dval( strptr(s),len(s),v ): print s;"    ",v
print
s=" .123456789012345678E-10":erc=dval( strptr(s),len(s),v ): print s;"    ",v
s=" 123456789012345678E+10":erc=dval( strptr(s),len(s),v ): print s;"    ",v
s=" 12345678.9012345678E100!?*":erc=dval( strptr(s),len(s),v ): print s;"    ",v
's=" 123456789012345678E999":erc=dval( strptr(s),len(s),v ): print s;"    ",v
s=" 123456.789012345678E000300":erc=dval( strptr(s),len(s),v ): print s;"    ",v
's=" 1234567890.12345678E300":erc=dval( strptr(s),len(s),v ): print s;"    ",v

print
print "Error Code: ";erc

  '-------------'
  ' SPEED TEST  '
  '-------------'

dim i as long
dim t as double
dim td as double
dim tv as double

t=timer
for i=1 to 100000
dval(strptr(s),len(s),v)
next
td=timer-t

t=timer
for i=1 to 100000
v=val(s)
next
tv=timer-t
print
print "for 100000 repeats: "
print "dval time:     ";td
print " val time:     ";tv
print
print "Speed factor:  ";tv/td



Charles Pegge

#1
Here is the PowerBasic equivalent.

However it performs equally as well as Powerbasic's VAL(). So as it stands, there is no advantage in using dval() in a PB program.



'
' DVAL
' text to floating point number conversion in Assembler

' Charles E V Pegge
' 28 June 2007

' PowerBasic  PBWin Ver 8x
' using inline assembler.

#COMPILE EXE
#DIM ALL
#REGISTER NONE


FUNCTION dval(BYVAL p AS BYTE PTR, BYVAL le AS LONG, BYREF v AS DOUBLE) AS LONG
DIM m10  AS LONG: m10=10
DIM m1e4 AS LONG: m1e4=1e4
DIM m1e8 AS LONG: m1e8=1e8
DIM tm1  AS LONG
DIM tm2  AS LONG
DIM sgg  AS LONG
DIM sgx  AS LONG
'

'======================'
!xor eax,eax           ' clear eax
!fldz                  ' load zero to fpu
!mov ebx,le            ' length
!mov ecx,p             ' text pointer
'======================'
a0:                    ' loop for reaching the sign or first digit
!cmp ebx,0             ' is it zero or less?
!jle a2                ' then terminate now with zero
!mov al,[ecx]          ' first char
!cmp al,44             ' is it
!jl aa                 ' if less then .. aa treat as leading space
!jz a2                 ' terminate now with zero
!cmp al,45             ' is it '-' sign?
!jnz a1                ' then
!dec ebx               ' is it last char?
!jle a2                ' then terminate now with zero
!inc ecx               ' next char
!mov dword ptr sgg,1   ' set neg flag
!jmp a1                ' procede to a1
'======================'
aa:                    ' skip space chars
!dec ebx               ' down count chars to go
!inc ecx               ' next char
!jmp a0                ' loop back to a0
'======================'
a1:                    ' begin collecting digits
!mov al,[ecx]          ' load next char
!dec ebx               ' down count
!jl a2                 ' no more digits so goto E section
!inc ecx               ' ready next char
!cmp al,46             ' is this a dot?
!jz bb                 ' if so then goto decimals section
!cmp al,48             ' check lower limit
!jl a2                 ' below '0' char so goto E section
!cmp al,57             ' check upper limit
!jg a2                 ' above '9' so goto E section
!fimul dword ptr m10   ' premultiply the accummulator st
!sub al,48             ' base to 0
!mov tm1,eax           ' store in temp
!fiadd dword ptr tm1   ' add from temp
!jmp a1                ' repeat for next digit
'======================'
a2:                    ' relay to E section
!mov esi,ecx           ' transfer index to esi
!mov cl,al             ' transfer char to cl
!jmp c2                ' go on to E section
'======================'
bb:                    ' decimal point
!cmp ebx,0             ' is this the last char?
!jle c2                ' then finish now
!mov esi,ecx
!xor edx,edx           ' clear edx
!mov eax,1             ' set eax to 10
!xor ecx,ecx           ' clear to act as char reg
!xor edx,edx           ' while edx:eax is used as a digit multiplier
'======================'
!xor edi,edi           ' zero the decimal places tally
b1:                    ' do loop
                       ' start of decimals loop
!dec ebx               ' any more chars?
!jl c1                 ' finish now
!mov cl,[esi]          ' get next char
!inc esi               ' ready for next char
!cmp cl,48             ' range check lower
!jl c1                 ' finish
!cmp cl,57             ' range check upper
!jg c1                 ' check for E numbers
!cmp edi,18            ' limit of decimal places
!jge b1                ' too many decimal places error so ignore rest
!fimul dword ptr m10   ' premultiply accummulator
!mul dword ptr m10     ' multiply eax ready for next loop
!inc edi               ' tally decimal places
!cmp edi,9             ' is this 9 dps done ?
!jnz b2                ' skip if not
!mov tm2,eax           ' move the multiplier to a second stage
!mov eax,1             ' reset the multiplier
b2:                    ' continue
!sub cl,48             ' base  to zero
!mov tm1,ecx           ' store to tm1
!fiadd dword ptr tm1   ' add from tm1
!jmp b1                ' repeat for next digit
'======================'

'======================'
cc:                    '
c1:                    ' decimal place scaling
!mov tm1,eax           ' save eax to tm1
!fidiv dword ptr tm1   ' divide by this factor (up to 9 decimal places)
!cmp dword ptr tm2,0   ' is there a second stage?
!jz c2                 ' skip if not
!fidiv dword ptr tm2   ' divide by this factor (up to 9 more decimal places)
'======================'
c2:                    ' inserted E number checking procedure here:
'======================'
ee:                    ' E & e numbers
!cmp cl,&h45           ' is it E?
!jz e1                 ' okay
!cmp cl,&h65           ' is it e?
!jz e1                 ' okay
!jmp c3                ' else skip E numbers
'----------------------'
e1:                    ' ready to procede with E number
!xor eax,eax           ' clear eax
!mov ch,10             ' x10 multiplier
!dec ebx               ' check if end
!jl c3                 ' finish if at end
!mov cl,[esi]          ' next char
!inc esi               ' increment char pointer
!cmp cl,43             ' is it a '+' sign?
!jz e1a                ' then ignore and get next char
!cmp cl,45             ' it it a '-' sign
!jnz e2                ' skip if not
!mov dword ptr sgx,1   ' set negation flag
'----------------------'
e1a:                   ' get the next digit
!dec ebx               ' check if at end
!jl c3                 ' then finish now
!mov cl,[esi]          ' get a digit
!inc esi               ' increment char pointer
'----------------------'
e2:                    ' first digit is ready
!cmp cl,48             ' is it less then 0?
!jz e1a                ' ignore leading zeros, get next
!jl c3                 ' then finish
!cmp cl,57             ' is it greater than 9?
!jg c3                 ' then finish
!sub cl,48             ' base to zero
!mov al,cl             ' move to accummulator
!dec ebx               ' check at end
!jl e3                 ' if so then procede to process
!mov cl,[esi]          ' next digit
!inc esi               ' next digit pointer
!cmp cl,48             ' check below 0
!jl e3                 ' if so then procede to process
!cmp cl,57             ' check above 9
!jg e3                 ' if so then procede to process
!mul ch                ' multiply accum by 10
!sub cl,48             ' base digit to zero
!add al,cl             ' add it to accum
!dec ebx               ' check if at end
!jl e3                 ' then process
!mov cl,[esi]          ' get the final digit
!inc esi               ' ready for next xhar
!cmp cl,48             ' is it below 0
!jl e3                 ' then process
!cmp cl,57             ' is it above 9
!jg e3                 ' then process
!mul ch                ' multiply accum by 10
!sub cl,48             ' base digit to zero
!add al,cl             ' add to accum
!adc ah,0              ' carry thru to ah
'----------------------'
'                      ' ERROR CHECKS
'cmp eax,307           ' E too great
'jle ee1               '
'mov eax,1             ' error code: E out of range
'jmp xx                '
ee1:                   '
!dec ebx               ' Excess E digits
!jl e3                 '
!mov cl,[esi]          '
!inc esi
!cmp cl,48             '
!jl e3                 '
!cmp cl,57             '
!jg e3                 '
!mov eax,2             ' error code: E overflow
!jmp xx                '
'----------------------'
e3:                    ' E is now in binary form in eax
!cmp dword ptr sgx,1   ' is it negative
!jz e4m                ' if so then go to divider section
'----------------------'
e4:                    ' multiply by 10 for each E number
!cmp eax,8             ' step of 10^8
!jl e5                 ' try smaller step
!fimul dword ptr m1e8  '
!sub eax,8             '
!jmp e4                ' repeat
e5:                    '
!cmp eax,4             ' step of 10^4
!jl e6                 ' try smaller step
!sub eax,4             '
!fimul dword ptr m1e4  '
!jmp e5                ' repeat
e6:                    '
!cmp eax,0             ' step of 10^1
!jle c3                ' done
!dec eax               '
!fimul dword ptr m10   '
!jmp e6                ' repeat till ecx=0
'======================'

'======================'
e4m:                   ' divide by 10 for each negative E number
!cmp eax,8             ' step of 10^8
!jl e5m                ' try smaller step
!fidiv dword ptr m1e8  '
!sub eax,8             '
!jmp e4m               ' repeat
e5m:                   '
!cmp eax,4             ' step of 10^4
!jl e6m                ' try smaller step
!sub eax,4             '
!fidiv dword ptr m1e4  '
!jmp e5m               ' repeat
e6m:                   '
!cmp eax,0             ' step of 10^1
!jle c3                ' done
!dec eax               '
!fidiv dword ptr m10   '
!jmp e6m               ' repeat till ecx=0
'======================'

'======================'
c3:                    '
!cmp dword ptr sgg,1   ' check if sign '-'
!jnz c4                ' skip if not.
!fchs                  ' otherwise change the accummulator sign
'======================'
c4:                    '
!mov eax,v             ' get pointer to result
!fstp qword ptr [eax]    ' store the result and pop the FPU stack                  '
!xor eax,eax           ' no error
'======================'
xx:
!mov function, eax     ' return error code
'======================'

END FUNCTION






  '--------'
  '  TEST  '
  '--------'

GLOBAL ps AS STRING

SUB sprint (s AS STRING)
ps=ps+s+$CR
END SUB

SUB tprint (s AS STRING,d AS STRING)
ps=ps+s+CHR$(8)+CHR$(9)+CHR$(9)+d+$CR
END SUB

FUNCTION PBMAIN() AS LONG


DIM s AS STRING: s="-123456.6789e5"
DIM v AS DOUBLE
DIM erc AS LONG

erc=dval( STRPTR(s),LEN(s),v )
sprint ("input:  "+s)
sprint ("output: "+STR$(v))
sprint ("")
sprint ("Error code: "+STR$(erc))

  '-----------------'
  '  EXTREME TESTS  '
  '-----------------'
sprint("")
sprint ("TESTS AND INTERPRETATIONS")
s=" 0":  dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" ":   dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" ,":  dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" -":  dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" .":  dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" 0,1":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" 1,2":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" 0.1,2":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" !3":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" $3":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" $3$4":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" 3-4":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" 3.4":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" .000456":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" 3.4.5":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" 3e2":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" 3.4e2":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" -.4e2":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" .04e2":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" .04e-2":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" -.04e-2":dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" -.0012345E-10":erc=dval( STRPTR(s),LEN(s),v ): tprint( s,STR$(v))
sprint("")
s=" .123456789012345678E-10":erc=dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" 123456789012345678E+10":erc=dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
s=" 12345678.9012345678E100!?*":erc=dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
's=" 123456789012345678E999":erc=dval( strptr(s),len(s),v ): tprint (s,str$(v))
s=" 123456.789012345678E000300":erc=dval( STRPTR(s),LEN(s),v ): tprint (s,STR$(v))
's=" 1234567890.12345678E300":erc=dval( strptr(s),len(s),v ): tprint (s,str$(v))

sprint("")
sprint ("Error Code: "+STR$(erc))

  '-------------'
  ' SPEED TEST  '
  '-------------'

DIM i AS LONG
DIM t AS DOUBLE
DIM td AS DOUBLE
DIM tv AS DOUBLE

t=TIMER
FOR i=1 TO 100000
dval(STRPTR(s),LEN(s),v)
NEXT
td=TIMER-t

t=TIMER
FOR i=1 TO 100000
v=VAL(s)
NEXT
tv=TIMER-t
sprint("")
sprint( "for 100000 repeats: ")
tprint( "dval time:",STR$(td))
tprint( " val time:",STR$(tv))
sprint("")
tprint( "Speed factor:",STR$(tv/td))

MSGBOX ps

ps=""

END FUNCTION