• Support
  • Articles
  • Resources
  • Products

Scientific notation and floating point numbers

Moderator: boris

3 postsPage 1 of 1

IshmaelCallMe
Guru

Posts:
676
Joined: Thu Jan 26, 2006 2:28 am
by IshmaelCallMe » Wed Nov 19, 2008 4:48 pm
Here are some subroutines to handle Scientific notation and floating point numbers encoded in string variables.

Code: Select all

  1.  
  2. s1='999'
  3. s2='-9'
  4. call scimult
  5. call sci2dec
  6. messagebox stmp '-4*-2'
  7.  
  8. s1='-4'
  9. s2='-2'
  10. call scimult
  11. call sci2dec
  12. messagebox stmp '-4*-2'
  13.  
  14. s1='5001'
  15. s2='02'
  16. call scimult
  17. call sci2dec
  18. messagebox stmp '5001*02'
  19.  
  20. s1='5001.001'
  21. s2='02'
  22. call scimult
  23. call sci2dec
  24. messagebox stmp '5001.001*02'
  25.  
  26. s1='-5'
  27. s2='2'
  28. call sciadd
  29. messagebox stmp '-5+2'
  30.  
  31. s1='5001'
  32. s2='02'
  33. call sciadd
  34. messagebox stmp '5001+02'
  35.  
  36. s1='5001.001'
  37. s2='02'
  38. call sciadd
  39. messagebox stmp '5001.001+02'
  40.  
  41. fixbase=5
  42. stmp='5'
  43. call tryit  
  44. stmp='-5'
  45. call tryit  
  46. stmp='-00.050E02'
  47. call tryit
  48. stmp='+5.9999999999999E+001'
  49. call tryit
  50. stmp='+3.2586798E+001'
  51. call tryit
  52. stmp='0'
  53. call tryit
  54. stmp='+9.9E37'
  55. call tryit
  56. stmp='50'
  57. call tryit
  58. stmp='500E-4'
  59. call tryit
  60. stmp='00.05E05'
  61. call tryit
  62. stmp='12.345E02'
  63. call tryit
  64. stmp='12.345600E02'
  65. call tryit
  66. stmp='.5E0'
  67. call tryit
  68. stmp='5E0'
  69. call tryit  
  70. end
  71.  
  72. :tryit
  73.   orig=stmp
  74.   call sci2dec
  75.   messagebox stmp orig
  76.   call fixdp
  77.   messagebox stmp orig
  78.   stmp=orig
  79.   ;orig=stmp
  80.   call dec2sci
  81.   messagebox stmp orig
  82. return
  83.  
  84. :scimult            ;multiply two number strings - gives result in sci
  85.   stmp=s1
  86.   call deconstruct
  87.   len1=result
  88.   numstr1=numstr
  89.   dotpos1=dotpos
  90.   si1=si
  91.   stmp=s2
  92.   call deconstruct
  93.   len=result
  94.   schar=''
  95.   if si=2 schar='-'
  96.   strconcat schar numstr
  97.   str2int inumstr schar
  98.   schar=''
  99.   if si1=2 schar='-'
  100.   strconcat schar numstr1
  101.   str2int inumstr1 schar
  102.   int2str numstr inumstr*inumstr1
  103.   dotpos=dotpos+dotpos1-2
  104.   lenm=len
  105.   if len1>len lenm=len1
  106.   strlen numstr
  107.   ;if result>lenm dotpos=dotpos+1    ;add one to dotpos if mult increased order of magnatude of result
  108.   if result>=len+len1 dotpos=dotpos+1 ;add one to dotpos if mult increased order of magnatude of result
  109.   strcopy numstr 1 1 sstmp
  110.   strscan '+-' sstmp
  111.   si=result
  112.   if si strcopy numstr 2 999 numstr  
  113.   call dec2sci_nd  
  114. return
  115.      
  116. :sciadd         ;add two number strings - gives result in sci
  117.   stmp=s1
  118.   call deconstruct
  119.   numstr1=numstr
  120.   dotpos1=dotpos
  121.   si1=si
  122.   stmp=s2
  123.   call deconstruct
  124.   if dotpos > dotpos1 then  ;add leading zeros till the dotpos are equal
  125.     for k 1 dotpos-dotpos1
  126.       sstmp='0'
  127.       strconcat sstmp numstr1
  128.       numstr1=sstmp
  129.     next
  130.   endif
  131.   if dotpos1 > dotpos then  ;add leading zeros till the dotpos are equal
  132.     for k 1 dotpos1-dotpos
  133.       sstmp='0'
  134.       strconcat sstmp numstr
  135.       numstr=sstmp
  136.     next
  137.     dotpos=dotpos1
  138.   endif
  139.   strlen numstr       ;add zeros on back till length is equal
  140.   len=result
  141.   strlen numstr1
  142.   len1=result
  143.   if len>len1 then
  144.     for k 1 len-len1
  145.       strconcat numstr1 '0'
  146.     next
  147.   endif
  148.   if len1>len then
  149.     for k 1 len1-len
  150.       strconcat numstr '0'
  151.     next
  152.   endif  
  153.   schar=''
  154.   if si=2 schar='-'
  155.   strconcat schar numstr
  156.   str2int inumstr schar
  157.   schar=''
  158.   if si1=2 schar='-'
  159.   strconcat schar numstr1
  160.   str2int inumstr1 schar
  161.   int2str numstr inumstr+inumstr1 
  162.   strcopy numstr 1 1 sstmp
  163.   strscan '+-' sstmp
  164.   si=result
  165.   if si strcopy numstr 2 999 numstr  
  166.   call dec2sci_nd  
  167. return
  168.  
  169. :dec2sci                ;convert any number in string format to scientific notation
  170.   call deconstruct
  171. :dec2sci_nd             ;no deconstruct
  172.   strcopy numstr 1 1 stmp   ;start to construct output
  173.   strconcat stmp '.'
  174.   strcopy numstr 2 999 sstmp
  175.   strconcat stmp sstmp    
  176.   strlen sstmp
  177.   if result=0 strconcat stmp '0'       ;add in one zero after the dp if there is nothing else there
  178.   strconcat stmp 'E'
  179.   int2str sstmp dotpos-2
  180.   strconcat stmp sstmp      
  181.   schar=''
  182.   ;if si=0 schar='+'    ;uncomment this line if you want to add + in front
  183.   ;if si=1 schar='+'    ;uncomment this line if you want to preserve + in front
  184.   if si=2 schar='-'
  185.   strconcat schar stmp
  186.   stmp=schar
  187. return
  188.  
  189. :sci2dec                ;convert scientific notation to decimal format  
  190.   call deconstruct  
  191.   if dotpos<=1 then         ;for moving the dp left from beginning of number string
  192.     stmp='0.'
  193.     k=0-(dotpos-1)
  194.     do while k>0
  195.       strconcat stmp '0'
  196.       k=k-1
  197.     loop
  198.     strconcat stmp numstr
  199.   else                      ;for moving the dp right from beginning of number string
  200.     strlen numstr
  201.     if dotpos > result then
  202.       stmp=numstr
  203.       k=dotpos-result-1
  204.       do while k>0
  205.         strconcat stmp '0'
  206.         k=k-1
  207.       loop
  208.       strconcat stmp '.0'
  209.     else                        ;for moving the dp right into the middle of number string
  210.       strcopy numstr 1 dotpos-1 stmp
  211.       strconcat stmp '.'
  212.       strcopy numstr dotpos 999 sstmp
  213.       strconcat stmp sstmp
  214.     endif
  215.   endif 
  216.   schar=''
  217.   ;if si=0 schar='+'    ;uncomment this line if you want to add + in front
  218.   ;if si=1 schar='+'    ;uncomment this line if you want to preserve + in front
  219.   if si=2 schar='-'
  220.   strconcat schar stmp
  221.   stmp=schar
  222. return
  223.  
  224. :fixdp      ;convert decimal number to fixed decimal position, rounding off if necessary.  fixbase must be set.
  225.   for k 1 fixbase
  226.     strconcat stmp '0'
  227.   next
  228.   strscan stmp '.'
  229.   dotpos=result
  230.   strcopy stmp dotpos+fixbase+1 1 sstmp
  231.   strscan '56789' sstmp
  232.   if result then    ;round up if 5 or greater
  233.     stmp2=''
  234.     remainder=1
  235.     for k dotpos+fixbase 1
  236.       strcopy stmp k 1 sstmp
  237.       strscan sstmp '.'     ;skip the dp when rippling up the round
  238.       if result=0 then
  239.         if remainder then
  240.           str2int itmp sstmp
  241.           remainder=(itmp+1)/10
  242.           if remainder int2str sstmp (itmp+1)-10
  243.           if remainder=0 int2str sstmp (itmp+1)
  244.         endif
  245.       endif
  246.       strconcat sstmp stmp2
  247.       stmp2=sstmp
  248.     next
  249.     stmp=stmp2
  250.   endif
  251.   strcopy stmp 1 dotpos+fixbase stmp
  252. return
  253.  
  254. :deconstruct        ;separates number into numstr, dotpos, si (sign)
  255.   strscan stmp '.'
  256.   dotpos=result
  257.   strscan stmp 'E'      ;will also reformat scientific notation to canonical form
  258.   if result=0 result=999
  259.   strcopy stmp result+1 999 expstr
  260.   strcopy stmp 1 dotpos-1 numstr
  261.   strcopy stmp dotpos+1 result-(dotpos+1) sstmp
  262.   strconcat numstr sstmp
  263.   strcopy numstr 1 1 sstmp
  264.   strlen numstr
  265.   if dotpos<1 dotpos=dotpos+result+1        ;if no decimal point was found
  266.   strscan '+-' sstmp
  267.   si=result
  268.   if si then
  269.     strcopy numstr 2 999 numstr
  270.     dotpos=dotpos-1
  271.   endif
  272.   str2int iexpstr expstr
  273.   dotpos=dotpos+iexpstr
  274.   strlen numstr     ;get rid of leading zeros
  275.   len=result
  276.   for k 1 len
  277.     strcopy numstr k 1 char
  278.     strscan '0' char
  279.     if result=0 break
  280.     dotpos=dotpos-1
  281.   next
  282.   strcopy numstr k 999 numstr  
  283.   strlen numstr ;get rid of trailing zeros
  284.   len=result
  285.   for k len 1
  286.     strcopy numstr k 1 char
  287.     strscan '0' char
  288.     if result<1 break
  289.   next
  290.   if result<1 strcopy numstr 1 k numstr
  291.   strlen numstr     ;leave length in result upon exit
  292. return
  293.  


Original thread here: viewtopic.php?f=3&t=977&p=3647#p3647
Last edited by IshmaelCallMe on Thu Feb 18, 2010 4:20 pm, edited 1 time in total.
shangxi
Newbie

Posts:
1
Joined: Wed Feb 17, 2010 12:11 am
by shangxi » Wed Feb 17, 2010 12:13 am
Hello!

I tried to calculate this:
s1='2.27'
s2='1.213'
call scimult
call sci2dec
messagebox stmp '2.27x1.213'

but the result is not correct.
Any idea where the error is?

Thanks

Edit:
I changed this line:
if result>=len+len1 dotpos=dotpos+1 ;add one to dotpos if mult increased order of magnatude of result

now it seems to run
IshmaelCallMe
Guru

Posts:
676
Joined: Thu Jan 26, 2006 2:28 am
by IshmaelCallMe » Thu Feb 18, 2010 4:25 pm
Fantastic, thanks for the bug fix. I changed the routine in the post above to reflect your change.

But, really, these routines actually need a complete rewrite. While working most of the time, they will fail for a couple special cases. They really need to take into account the number of significant digits, especially during multiplication (too many digits in the number will overflow the teraterm variable). I just don't have the time to do it right now.
Display posts from previous:
Sort by:

3 postsPage 1 of 1

Users browsing this forum: No registered users
cron