Author Topic: More matrix fun  (Read 4750 times)

0 Members and 1 Guest are viewing this topic.

Offline david_uwi

  • Newbie
  • Posts: 71
    • View Profile
More matrix fun
« on: May 19, 2021, 02:35:56 pm »
As we seem to be looking at matrix manipulation...
Here's a program I wrote nearly 30 years ago. It diagonalizes a real symmetric matrix. This gives (in maths-speak) the eigenvalues and eigenvectors. It''s only set up for a 3x3 (which is read from a data file in the order 1,1 2,2 3,3 1,2 1,3 2,3),
but it will do any size (but note the time taken is approx N cubed where N is the size of the matrix). Enjoy...
Code: QB64: [Select]
  1. 5 DEFINT I-N
  2. n2 = 3
  3. DIM e(n2, n2), X(n2, n2)
  4. OPEN "c:\cw1\mymatrix.txt" FOR INPUT AS #1
  5. INPUT #1, e(1, 1), e(2, 2), e(3, 3), e(1, 2), e(1, 3), e(2, 3)
  6. e(2, 1) = e(1, 2): e(3, 2) = e(2, 3): e(3, 1) = e(1, 3)
  7. PRINT "input matrix"
  8. FOR i = 1 TO n2
  9.     FOR J = 1 TO n2
  10.         PRINT USING "####.#####"; e(i, J);
  11.     NEXT J
  12.     PRINT
  13.  
  14. GOSUB 4000
  15. PRINT "EIGENVALUES"
  16. FOR i = 1 TO n2
  17.     FOR J = 1 TO n2
  18.         PRINT USING "####.#####"; e(i, J);
  19.     NEXT J
  20.     PRINT
  21. PRINT "EIGENVECTORS"
  22. FOR i = 1 TO n2
  23.     FOR J = 1 TO n2
  24.         PRINT USING "####.#####"; X(i, J);
  25.     NEXT J
  26.     PRINT
  27.  
  28. GOTO 130
  29. 100 PRINT "*********************"
  30. 110 PRINT "INCORRECT INPUT!!!!!"
  31. 120 PRINT "*********************"
  32. 130 END
  33. 4000 REM DIAGONALISATION USING JACOBI'S METHOD (D.S. 1993)
  34. 4005 M = (n2 * n2 - n2) / 2
  35. 4010 TRA = M * .00001
  36. FOR i = 1 TO n2
  37.     FOR J = 1 TO n2
  38.         X(i, J) = 0!
  39.     NEXT J
  40.     X(i, i) = 1!
  41. 4090 FOR L = 1 TO M * 10
  42.    4100 Q = 0: AM = -1
  43.    4110 FOR J = 1 TO n2 - 1
  44.        4120 FOR i = J + 1 TO n2
  45.            4130 Z = ABS(e(i, J))
  46.            4140 Q = Q + Z
  47.            4150 IF Z < AM GOTO 4170
  48.            4160 AM = Z: IX = i: JX = J
  49.        4170 NEXT i
  50.    4180 NEXT J
  51.    4190 IF Q < TRA THEN RETURN
  52.    4200 A1 = e(IX, IX) - e(JX, JX)
  53.    4210 A5 = e(IX, JX)
  54.    4220 IF ABS(A5) * 50 > ABS(A1) GOTO 4270
  55.    4230 A6 = 2 * A1 * A1 + 3 * A5 * A5
  56.    4240 C = -2 * A1 * A5 / A6
  57.    4250 s = 1 - A5 * A5 / A6
  58.    4260 GOTO 4320
  59.    4270 A2 = SQR(A1 * A1 + 4 * A5 * A5)
  60.    4280 IF A1 > 0 THEN A2 = -A2
  61.    4290 A3 = (A1 + A2) / (2 * A5)
  62.    4300 s = 1 / SQR(A3 * A3 + 1)
  63.    4310 C = A3 * s
  64.    4320 FOR J = 1 TO n2
  65.        4330 TM = e(JX, J) * s + e(IX, J) * C
  66.        4340 e(IX, J) = e(IX, J) * s - e(JX, J) * C
  67.        4350 e(JX, J) = TM
  68.        4360 TM = X(JX, J) * s + X(IX, J) * C
  69.        4370 X(IX, J) = X(IX, J) * s - X(JX, J) * C
  70.        4380 X(JX, J) = TM
  71.    4390 NEXT J
  72.    4400 FOR J = 1 TO n2
  73.        4410 TM = e(J, JX) * s + e(J, IX) * C
  74.        4420 e(J, IX) = e(J, IX) * s - e(J, JX) * C
  75.        4430 e(J, JX) = TM
  76.    4440 NEXT J
  77. 4450 NEXT L
  78. 4460 PRINT "CONVERGENCE FAILURE": CLOSE #1
  79. 4490 END

Offline david_uwi

  • Newbie
  • Posts: 71
    • View Profile
Re: More matrix fun
« Reply #1 on: May 20, 2021, 02:57:09 am »
That's amazing the Jacobi diagonalization is very similar to mine. Maybe I was influenced by "Numerical Methods" though some of the programs in the book are very poor efforts.
I would claim that mine is better as it avoids rounding errors by moving from using a square root solution as the off-diagonals get small (notice I only use single precision). There is also a problem with the solution "stagnating" and oscillating around a solution which mine overcomes. I often diagonalize several thousand matrices and I can't afford for some to not converge or converge very slowly. Oh and mine has the bonus of line numbers and GOTOs.
I'm looking at the "Hermitian routine" (that does matrices with a+ib on one side and a-ib on the other side of the diagonal).
The trick is that the result (eigenvalues) has to be real so you can initially reduce the matrix to a real symmetric and go from there.
« Last Edit: May 20, 2021, 03:21:54 am by david_uwi »

Offline david_uwi

  • Newbie
  • Posts: 71
    • View Profile
Re: More matrix fun
« Reply #2 on: May 20, 2021, 02:37:01 pm »
If you want a real world example of this routine in action. Here is my NMR (nuclear magnetic resonance) spectrum calculator. In NMR you are primarily looking at hydrogen and their resonance frequency depends on the surrounding atoms (this is called chemical shift) there is also interaction between the hydrogens (so called spin-spin coupling). It is this spin-spin coupling that produces off-diagonal elements in the matrix -that need to be removed. I have given a small demo data file for 1,2-dichlorobenzene a very simple molecule that surprisingly produces a rather complex spectrum.
This is the data file (if you look at the program this is expected in c:\cw1\o-dichlorobenzene.txt). Almost forgot the program is also expecting to be able to load fonts from c:\windows\fonts.

dichlorobenzene
4,100
6.0,6.5,6.5,6.0
5,1,0,5,1,5
5.5,7.0,.5,0

line one is just the title
line 2 is the number of hydrogens(4), and the spectrometer operating frequency (100 MHz)
line 3 is the chemical shifts (4 hydrogens 4 shifts, but 1 and 4 are the same as are 2 and 3)
then come the couplings in the order 1,2 1,3 1,4 2,3 2,4 3,4
line 4 is for the output low chemical shift, high, line broadening factor, integration (which is set off)
Code: QB64: [Select]
  1. DEFINT I-N
  2. DEFDBL A-H, O-Z
  3. OPEN "I", #1, "c:\cw1\o-dichlorobenzene.txt"
  4. INPUT #1, b$
  5. INPUT #1, n, spop
  6. IM = 2 ^ n
  7. DIM AH(IM, n) AS INTEGER, AX(IM, IM) AS INTEGER
  8. DIM TP(4096), F(4096), X(IM, IM), E(IM, IM)
  9. DIM aj(28, 28), VH(n), XX(4000), Y(4000), YD(30), XD(40)
  10. LINE INPUT #1, Z$ 'INPUT OF CHEMICAL SHIFTS
  11. GOSUB charsep1
  12. REM INPUT OF SPIN-SPIN COUPLING J12,J13...J23,J24..etc
  13. LINE INPUT #1, Z$
  14. GOSUB charsep2
  15. REM freq min,freq max, line width,integration (0/1)
  16. INPUT #1, fmin, fmax, t2, itg
  17. fmin = fmin * spop: fmax = fmax * spop
  18. TK = TIMER
  19. REM CALCULATING ELEMENTS IN HAMILTONIAN MATRIX
  20. xsca = 960: ysca = 480 'spectrum size
  21. N2 = IM
  22. FOR i = 0 TO N2 - 1
  23.     II = i
  24.     FOR IN = n - 1 TO 0 STEP -1
  25.         JJ = 2 ^ IN
  26.         IF (II - JJ) < 0 THEN TJ = -1 ELSE TJ = 1
  27.         IF TJ = 1 THEN II = II - JJ
  28.         AH(i + 1, IN + 1) = TJ
  29.     NEXT IN
  30. FOR i = 1 TO N2
  31.     E(i, i) = 0: AX(i, i) = 0
  32.     FOR L = 1 TO n
  33.         E(i, i) = E(i, i) + VH(L) * .5 * AH(i, L)
  34.         TD = AH(i, L) * .25
  35.         FOR k = L + 1 TO n
  36.             E(i, i) = E(i, i) + aj(L, k) * TD * AH(i, k)
  37.         NEXT k
  38.     NEXT L
  39. FOR i = 1 TO N2
  40.     X(i, i) = 1
  41.     FOR L = i + 1 TO N2
  42.         MA = 0: MB = 0: K1 = 0: K2 = 0
  43.         X(i, L) = 0: X(L, i) = 0
  44.         FOR k = 1 TO n
  45.             TG = AH(i, k) * AH(L, k) - 1
  46.             MA = MA + TG
  47.             MB = MB + TG * AH(L, k)
  48.             IF TG <> 0 THEN
  49.                 IF K1 > 0 THEN K2 = k ELSE K1 = k
  50.             END IF
  51.         NEXT k
  52.         IF MA = -4 AND MB = 0 THEN
  53.             E(i, L) = .5 * aj(K1, K2)
  54.             E(L, i) = E(i, L)
  55.         END IF
  56.     NEXT L
  57. GOSUB jacobi
  58. 'E matrix has the eigenvalues (energies)
  59. 'X matrix has the eigenvectors (wavefunction mixtures)
  60. IAY = 0
  61. FOR i = 1 TO N2
  62.     FOR j = i + 1 TO N2
  63.         FOR k = 1 TO n
  64.             IAY = IAY + AH(i, k) * AH(j, k)
  65.         NEXT k
  66.         IF IAY = n - 2 THEN AX(i, j) = 1 ELSE AX(i, j) = 0
  67.         AX(j, i) = AX(i, j)
  68.         IAY = 0
  69.     NEXT j
  70. m = 0
  71. FOR L = 1 TO N2 - 1 'we have 4 nested loops - this is slow!
  72.     FOR k = L + 1 TO N2
  73.         ff = ABS(E(k, k) - E(L, L)) 'frequencies
  74.         IF ABS(ff) > 50000 GOTO 10
  75.         tpp = 0
  76.         FOR j = 1 TO N2
  77.             IF ABS(X(L, j)) > .01 THEN
  78.                 FOR i = 1 TO N2
  79.                     IF AX(j, i) <> 0 THEN tpp = tpp + X(k, i) * X(L, j)
  80.                 NEXT i
  81.             END IF
  82.         NEXT j
  83.         IF ABS(tpp) > .02 THEN
  84.             m = m + 1
  85.             F(m) = ff
  86.             TP(m) = tpp * tpp 'transition probabilities
  87.         END IF
  88.    10 NEXT k
  89. GOSUB sort
  90. GOSUB lorentz
  91. GOSUB outscr
  92. END 'end of main
  93. sort:
  94. FOR i = 1 TO m - 1
  95.     FM = F(i): JM = i
  96.     FOR j = i + 1 TO m
  97.         IF F(j) > FM THEN FM = F(j): JM = j
  98.     NEXT j
  99.     F(JM) = F(i): F(i) = FM
  100.     TPT = TP(JM)
  101.     TP(JM) = TP(i): TP(i) = TPT
  102. lorentz:
  103. REM CONSTRUCTING LORENTZIANS
  104. 'lineshapes are lorentzian
  105. SW = fmax - fmin
  106. MM = 3600
  107. AI = SW / MM
  108. FOR N5 = 1 TO MM + 1
  109.     XX(N5) = fmin + AI * (N5 - 1)
  110.     Y(N5) = 0
  111. NEXT N5
  112. WID = 4 / t2
  113. TA = 4 * 3.14159 * 3.14159 * t2 * t2
  114. TB = WID / AI
  115. FOR N5 = 1 TO m
  116.     C2 = (F(N5) - fmin) / AI
  117.     IF ABS(F(N5)) > 10000 GOTO 100 'this really needs to include spop
  118.     IF ABS(C2 - TB) > 30000 THEN IJC = 30000
  119.     IF IJC <> 30000 THEN IJC = INT(C2 - TB)
  120.     IF IJC < 1 THEN IJC = 1
  121.     IF IJC < MM THEN
  122.         IJD = INT(C2 + TB)
  123.         IF IJD > MM THEN IJD = MM
  124.         C1 = 2 * t2 * TP(N5)
  125.         FOR MI = IJC TO IJD
  126.             C3 = F(N5) - XX(MI)
  127.             Y(MI) = Y(MI) + C1 / (1 + TA * C3 * C3)
  128.         NEXT MI
  129.     END IF
  130. 100 NEXT N5
  131. jacobi:
  132. REM DIAGONALISATION USING JACOBI'S METHOD (D.S.)
  133. 'removes biggest off-diagonal elements first
  134. m = (N2 * N2 - N2) / 2
  135. TRA = m * .001
  136. FOR L = 1 TO m * 2
  137.     Q = 0: AM = -1
  138.     FOR j = 1 TO N2 - 1
  139.         FOR i = j + 1 TO N2
  140.             Z = ABS(E(i, j))
  141.             Q = Q + Z
  142.             IF Z > AM THEN AM = Z: IX = i: JX = j
  143.         NEXT i
  144.     NEXT j
  145.     IF Q < TRA THEN RETURN
  146.     A1 = E(IX, IX) - E(JX, JX)
  147.     A5 = E(IX, JX)
  148.     IF ABS(A5) * 50 < ABS(A1) THEN
  149.         A6 = 2 * A1 * A1 + 3 * A5 * A5
  150.         C = -2 * A1 * A5 / A6 'this is not the best approx.
  151.         s = 1 - A5 * A5 / A6 'but it stops the routine stagnating
  152.     ELSE
  153.         A2 = SQR(A1 * A1 + 4 * A5 * A5)
  154.         IF A1 > 0 THEN A2 = -A2
  155.         A3 = (A1 + A2) / (2 * A5)
  156.         s = 1 / SQR(A3 * A3 + 1)
  157.         C = A3 * s
  158.     END IF
  159.     FOR j = 1 TO N2
  160.         TM = E(JX, j) * s + E(IX, j) * C
  161.         E(IX, j) = E(IX, j) * s - E(JX, j) * C
  162.         E(JX, j) = TM
  163.         TM = X(JX, j) * s + X(IX, j) * C
  164.         X(IX, j) = X(IX, j) * s - X(JX, j) * C
  165.         X(JX, j) = TM
  166.     NEXT j
  167.     FOR j = 1 TO N2
  168.         TM = E(j, JX) * s + E(j, IX) * C
  169.         E(j, IX) = E(j, IX) * s - E(j, JX) * C
  170.         E(j, JX) = TM
  171.     NEXT j
  172. 'program ends up here if the matrix does not
  173. 'diagonalize in 2M iterations
  174. PRINT "CONVERGENCE FAILURE": CLOSE #1
  175. charsep1:
  176. REM SEPARATING INPUT CHARACTER INTO NUMBERS
  177. FOR L = 1 TO n - 1
  178.     II = LEN(Z$)
  179.     JJ = INSTR(Z$, ",")
  180.     VH(L) = VAL(LEFT$(Z$, JJ - 1)) * spop
  181.     Z$ = RIGHT$(Z$, II - JJ)
  182. VH(n) = VAL(Z$) * spop
  183. charsep2:
  184. REM SEPARATING INPUT CHARACTER INTO NUMBERS
  185. FOR i = 1 TO n - 2
  186.     FOR j = i + 1 TO n
  187.         II = LEN(Z$)
  188.         JJ = INSTR(Z$, ",")
  189.         aj(i, j) = VAL(LEFT$(Z$, JJ - 1))
  190.         Z$ = RIGHT$(Z$, II - JJ)
  191.     NEXT j
  192. aj(n - 1, n) = VAL(Z$)
  193. outscr:
  194. SCREEN _NEWIMAGE(xsca + 100, ysca + 120, 2)
  195. font1& = _LOADFONT("c:\windows\fonts\times.ttf", 32, "bold")
  196. _FONT font1&
  197.  
  198. YMIN = 5000!: YMAX = -1!: xmin = 5000!: xmax = 0!
  199. C1 = (fmax - fmin) / 3600: i = 3600
  200. YQM = 0
  201. FOR k = 1 TO i
  202.     IF YMIN > Y(k) THEN YMIN = Y(k)
  203.     IF YMAX < Y(k) THEN KMAX = k
  204.     IF YMAX < Y(k) THEN YMAX = Y(k)
  205.     XX(k) = (C1 * k + fmin) / spop
  206.     IF xmin > XX(k) THEN xmin = XX(k)
  207.     IF xmax < XX(k) THEN xmax = XX(k)
  208.     YQM = YQM + Y(k)
  209. XO = XX(i): YO = Y(i)
  210. XO = ((xmax - XX(i)) / (xmax - xmin) * xsca) + 40
  211. YO = ((Y(i) - YMIN) / (YMAX - YMIN) * ysca) - 20
  212. REM XO = INT(XO + .5): YO = INT(YO + .5)
  213. YYO = 100: YYY = 100
  214. FOR k = i - 1 TO 1 STEP -1
  215.     XX = ((xmax - XX(k)) / (xmax - xmin) * xsca) + 40
  216.     YY = ((Y(k) - YMIN) / (YMAX - YMIN) * ysca) - 20
  217.     YN = (YY + YO * TC) / (1 + TC)
  218.     REM XX = INT(XX + .5): YY = INT(YN + .5)
  219.     LINE (XO, ysca - YO)-(XX, ysca - YY)
  220.     YYY = YYY + Y(k) * ysca * .8 / YQM
  221.     'integration line
  222.     IF itg = 1 THEN LINE (XO, ysca - YYO)-(XX, ysca - YYY)
  223.     YYYO = YYY
  224.     XO = XX: YO = YN: YYO = YYY
  225. LINE (40, 10)-(40, ysca + 40)
  226. LINE (40, ysca + 40)-(xsca + 40, ysca + 40)
  227. LINE (40, 10)-(xsca + 40, 10)
  228. LINE (xsca + 40, ysca + 40)-(xsca + 40, 10)
  229. kg = -1
  230. 20 k = 0
  231. kg = kg + 1
  232. g(0) = .05: g(1) = .1: g(2) = .2: g(3) = .5: g(4) = 1: g(6) = 20: g(7) = 50: g(8) = 100: g(9) = 200
  233. IF xmin = 0 THEN xs = -g(kg)
  234. IF xmin <> 0 THEN xs = xmin - g(kg)
  235. xi = xs
  236. 30 xi = xi + g(kg)
  237. 'PRINT xi; g(kg); k; xmin; xmax; xs; kg: INPUT sa$
  238. IF xi <= xmax + .001 THEN
  239.     k = k + 1
  240.     IF k > 10 GOTO 20
  241.     XD(k) = xi
  242.     GOTO 30
  243. XD(k + 1) = xi
  244. FOR i = 1 TO k + 1
  245.     XXD = (((xmax - XD(i)) / (xmax - xmin)) * xsca) + 40
  246.     XC = INT(((XXD - 10) / xsca) * xsca)
  247.     XXD = INT(XXD + .5)
  248.     cc$ = LTRIM$(STR$((INT(XD(i) * 100 + .5) / 100)))
  249.     IF LEN(cc$) = 1 THEN cc$ = cc$ + ".0"
  250.     _PRINTSTRING (XC, ysca + 50), cc$
  251.     LINE (XXD, ysca + 40)-(XXD, ysca + 50)
  252. 40 NEXT i
  253. A$ = "Chemical Shift ë (ppm)"
  254. _PRINTSTRING (xsca / 2 - 100, ysca + 85), A$
  255. ypos = (ytop - ysca) / 8
  256. xpos = xsca / 12
  257. LOCATE 1, xpos + 10
  258.     h$ = INKEY$
  259. LOOP WHILE h$ = ""
  260. IF UCASE$(h$) = "P" THEN GOSUB onebit
  261. 'input p to store as a bitmap
  262. 7510 RETURN
  263.  
  264. onebit:
  265. '1-bit bitmap loader
  266. OPEN b$ + ".bmp" FOR BINARY AS #1
  267. pow2%(0) = 1
  268. FOR j% = 1 TO 7
  269.     pow2%(j%) = pow2%(j% - 1) + pow2%(j% - 1)
  270. NEXT j%
  271. filetype$ = "BM"
  272. offset& = 62&
  273. pixwidth& = 1600&
  274. pixht& = 820&
  275. ppbyte& = 8&
  276. header& = 40&
  277. datsize& = (pixwidth& * pixht& / ppbyte&)
  278. filesize& = datsize& + offset&
  279. reserved% = 0
  280. planes% = 1
  281. bpp% = 1
  282. compress& = 0&
  283. ppm& = 3880&
  284. numcol& = 2&
  285. impcol& = 0&
  286. 'storing file header
  287. PUT #1, , filetype$
  288. PUT #1, , filesize&
  289. PUT #1, , reserved%
  290. PUT #1, , reserved%
  291. PUT #1, , offset&
  292. 'storing DIB header
  293. PUT #1, , header&
  294. PUT #1, , pixwidth&
  295. PUT #1, , pixht&
  296. PUT #1, , planes%
  297. PUT #1, , bpp%
  298. PUT #1, , compress&
  299. PUT #1, , datsize&
  300. PUT #1, , ppm&
  301. PUT #1, , ppm&
  302. PUT #1, , numcol&
  303. PUT #1, , impcol&
  304. 'storing black and white
  305. black$ = CHR$(0) + CHR$(0) + CHR$(0) + CHR$(0)
  306. white$ = CHR$(255) + CHR$(255) + CHR$(255) + CHR$(0)
  307. PUT #1, , black$
  308. PUT #1, , white$
  309. 'storing bitmap
  310. FOR yvalue% = CINT(pixht&) - 1 TO 0 STEP -1
  311.     FOR xvalue% = 0 TO CINT(pixwidth&) - 1 STEP CINT(ppbyte&)
  312.         FOR bits% = 0 TO 7
  313.             pix% = POINT(xvalue% + bits%, yvalue%)
  314.             'change to pix% > 0 to get white on black
  315.             IF pix% = 0 THEN pixel% = (pixel% OR pow2%(7 - bits%))
  316.         NEXT bits%
  317.         qpix$ = CHR$(pixel%)
  318.         pixel% = 0
  319.         PUT #1, , qpix$
  320.     NEXT xvalue%
  321. NEXT yvalue%
  322.  
  323.  
  324.  
« Last Edit: May 20, 2021, 02:40:54 pm by david_uwi »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: More matrix fun
« Reply #3 on: May 20, 2021, 03:40:21 pm »
Quote
Oh and mine has the bonus of line numbers and GOTOs.

I find it amusing to consider it a bonus. I have to ask, sorry inquiring minds have to know, why is that better?

To me GOTO is completely neutral thing (because I am an enlightened being LOL) and line numbers a nuisance for coding, but maybe I will get insight or find out you are joking around a little :-)
« Last Edit: May 20, 2021, 03:43:34 pm by bplus »

Offline david_uwi

  • Newbie
  • Posts: 71
    • View Profile
Re: More matrix fun
« Reply #4 on: May 21, 2021, 11:57:33 am »
I am just amazed at the backward compatibility. All other programming languages there is a good chance you code will stop working following every upgrade.
I used to do a bit of FORTRAN (when I was but a young lad) , but modern FORTRAN is totally different (and to me indecipherable). You would even struggle to get an old quickbasic program to run on freebasic (but not on QB64).
Notice in the second program the GOTOs have gone (and most of the line numbers) -Mac (rip) showed me the error of my ways.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: More matrix fun
« Reply #5 on: May 21, 2021, 12:09:48 pm »
Ah for backwards compatibility, OK yes, saves allot of work updating old working programs.

Can't see anyone wanting to make new programs requiring line numbers.

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: More matrix fun
« Reply #6 on: May 23, 2021, 12:18:51 am »
Was it GWBASIC that had GOTO line number?

Did GWBASIC have labels?   I can't remember

Offline david_uwi

  • Newbie
  • Posts: 71
    • View Profile
Re: More matrix fun
« Reply #7 on: May 23, 2021, 03:25:52 am »
Yes GWBasic had it all, but it was surprisingly slow. I believe the WHILE..WEND is also for back compatibility (when you could easily use a DO..LOOP).

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: More matrix fun
« Reply #8 on: May 23, 2021, 03:40:08 am »
Only line numbers, no line labels (strings)
http://www.antonis.de/qbebooks/gwbasman/index.html