Author Topic: and another one for your toolbox...  (Read 46696 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: and another one for your toolbox...
« Reply #45 on: December 02, 2019, 11:03:49 am »
For sure, I'd like it too, if each function would add its respective prefix, but it would break compatiblity with legacy code. But on the other side HEX$, OCT$ and now BIN$ belong to the same type of function and should behave the same way, that's why I didn't add the &B prefix.

From a different point of view, &B is a new addition added in or after v1.0, that's basically the reason why QB64 misses the built-in BIN$ function. So if BIN$ is QB64 specific, shouldn't it be _BIN$ intead? And what do we do with the binary prefix then, _&B ??


Of course _&B is silly but hmm... _HEX$, _OCT$, _BIN$ that use prefixes all! not terrible ;)
« Last Edit: December 02, 2019, 11:06:51 am by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: and another one for your toolbox...
« Reply #46 on: December 02, 2019, 01:30:12 pm »
Reconsidered again, I use the string all the time without the &B (we have the number value already when we call the function so not likely need to convert back Plus it is easier to add than to remove, so
Code: QB64: [Select]
  1. FUNCTION BIN$ (integerBase10 AS _INTEGER64) 'no more &B because easier to add than to remove
  2.     DIM j AS INTEGER
  3.     IF integerBase10 = 0 THEN BIN$ = "0": EXIT FUNCTION
  4.     WHILE 2 ^ j <= integerBase10
  5.         IF (integerBase10 AND 2 ^ j) > 0 THEN BIN$ = "1" + BIN$ ELSE BIN$ = "0" + BIN$
  6.         j = j + 1
  7.     WEND
  8.  

The function just needs 1 variable, so I use something of Rho's

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: and another one for your toolbox...
« Reply #47 on: December 02, 2019, 03:47:23 pm »
And finally ... a speed test:

Code: QB64: [Select]
  1. _TITLE "BIN$ speed test..."
  2. PRINT "BIN$ speed test ... System: "; _OS$: PRINT
  3. PRINT "TB = current version from Toolbox board"
  4. PRINT "BP = latest version from B+"
  5. PRINT "RS = version from RhoSigma"
  6.  
  7. '--- for a fair test we need the same numbers for all
  8. '--- functions, so we first fill an array with numbers
  9. REDIM num&(1000000)
  10. FOR i& = 0 TO 1000000
  11.     num&(i&) = INT(RND(1) * 1000000000) + 1000000000
  12. NEXT i&
  13.  
  14. '--- Toolbox ---
  15. st# = TIMER(0.001)
  16. PRINT "TB-Start:"; st#
  17. FOR i& = 0 TO 1000000
  18.     b$ = BIN_TB$(num&(i&))
  19. NEXT i&
  20. et# = TIMER(0.001)
  21. IF et# = st# THEN et# = et# + 0.001 'avoid div by zero below
  22. PRINT "TB-End..:"; et#
  23. PRINT "Run-Time:"; et# - st#; "sec."
  24. PRINT "Speed...:"; 1000000 / (et# - st#); "LONGs/sec."
  25.  
  26. '--- bplus ---
  27. st# = TIMER(0.001)
  28. PRINT "BP-Start:"; st#
  29. FOR i& = 0 TO 1000000
  30.     b$ = BIN_BP$(num&(i&))
  31. NEXT i&
  32. et# = TIMER(0.001)
  33. IF et# = st# THEN et# = et# + 0.001 'avoid div by zero below
  34. PRINT "BP-End..:"; et#
  35. PRINT "Run-Time:"; et# - st#; "sec."
  36. PRINT "Speed...:"; 1000000 / (et# - st#); "LONGs/sec."
  37.  
  38. '--- RhoSigma ---
  39. st# = TIMER(0.001)
  40. PRINT "RS-Start:"; st#
  41. FOR i& = 0 TO 1000000
  42.     b$ = BIN_RS$(num&(i&))
  43. NEXT i&
  44. et# = TIMER(0.001)
  45. IF et# = st# THEN et# = et# + 0.001 'avoid div by zero below
  46. PRINT "RS-End..:"; et#
  47. PRINT "Run-Time:"; et# - st#; "sec."
  48. PRINT "Speed...:"; 1000000 / (et# - st#); "LONGs/sec."
  49. '--- cleanup & wait ---
  50. PRINT "...done, press any key"
  51. ERASE num&
  52.  
  53. '================================
  54. '=== AND HERE COMES THE MAGIC ===
  55. '================================
  56.  
  57. FUNCTION BIN_TB$ (integerBase10 AS _INTEGER64)
  58.     DIM i AS _INTEGER64, pow AS INTEGER, b$
  59.     IF integerBase10 = 0 THEN BIN_TB$ = "&B0": EXIT FUNCTION
  60.     i = integerBase10 'copy
  61.     pow = 0
  62.     WHILE i > 0
  63.         IF i AND 2 ^ pow THEN
  64.             b$ = "1" + b$
  65.             i = i - 2 ^ pow
  66.         ELSE
  67.             b$ = "0" + b$
  68.         END IF
  69.         pow = pow + 1
  70.     WEND
  71.     BIN_TB$ = "&B" + b$
  72.  
  73. FUNCTION BIN_BP$ (integerBase10 AS _INTEGER64) 'no more &B because easier to add than to remove
  74.     DIM j AS INTEGER
  75.     IF integerBase10 = 0 THEN BIN_BP$ = "0": EXIT FUNCTION
  76.     WHILE 2 ^ j <= integerBase10
  77.         IF (integerBase10 AND 2 ^ j) > 0 THEN BIN_BP$ = "1" + BIN_BP$ ELSE BIN_BP$ = "0" + BIN_BP$
  78.         j = j + 1
  79.     WEND
  80.  
  81. FUNCTION BIN_RS$ (value&&)
  82.     DIM v&&, vi&&
  83.     BIN_RS$ = "": v&& = value&&
  84.     DO
  85.         vi&& = INT(v&& / 2)
  86.         IF v&& / 2 = vi&& THEN BIN_RS$ = "0" + BIN_RS$: ELSE BIN_RS$ = "1" + BIN_RS$
  87.         v&& = vi&&
  88.     LOOP UNTIL v&& = 0
  89.  
  90.  
« Last Edit: December 16, 2019, 05:32:15 am by RhoSigma »
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: and another one for your toolbox...
« Reply #48 on: December 02, 2019, 04:39:25 pm »
And here is my final one,
it's even twice as fast as my first one (which is in the speed test) by simply avoiding the temporary string operations done under the QB64 hood when adding the "0" or "1" into an existing string. It cuts the times to approx. 3.05 sec. with the x86 build and 2.54 sec. with x64.

Code: QB64: [Select]
  1. FUNCTION BIN$ (value&&)
  2.     'chp% = char position, msp% = most significant position
  3.     'tlv&& = temporary loop value, ivq&& = integer value quotient
  4.     DIM chp%, msp%, tlv&&, ivq&&
  5.     tlv&& = value&&
  6.     BIN$ = STRING$(64, "0"): chp% = 64: msp% = 64
  7.     DO
  8.         ivq&& = INT(tlv&& / 2)
  9.         IF tlv&& / 2 <> ivq&& THEN MID$(BIN$, chp%, 1) = "1": msp% = chp%
  10.         chp% = chp% - 1: tlv&& = ivq&&
  11.     LOOP UNTIL tlv&& = 0
  12.     BIN$ = MID$(BIN$, msp%)
  13.  
  14.  
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: and another one for your toolbox...
« Reply #49 on: December 02, 2019, 07:25:43 pm »
Dang now I have to revise mine! OK very nice lesson about concatenation!

Here is my new version (and NOT final version) against RhoSigma's, had to add another 0 to the test and dump the time consuming array:
Code: QB64: [Select]
  1. _TITLE "BIN$ speed test..." 'Bplus mod of RhoSigma's 2019-12-03
  2. PRINT "BIN$ speed test ... System: "; _OS$: PRINT
  3. PRINT "BP = latest version from B+"
  4. PRINT "RS = latest from RhoSigma"
  5.  
  6. '--- for a fair test we need the same numbers for all
  7. '--- functions, so we first fill an array with numbers
  8.  
  9. PRINT "First test print BIN$ of 0:"
  10. PRINT "Bplus has "; bpBIN$(0)
  11. PRINT "RhoSigma has "; rsBIN$(0)
  12. PRINT "Press key to continue... "
  13. FOR i = 1 TO 7
  14.     r = INT(RND * 10 ^ i)
  15.     PRINT "For random number r = "; r
  16.     PRINT "   Bplus has "; bpBIN$(r)
  17.     PRINT "RhoSigma has "; rsBIN$(r)
  18. PRINT "Press key to continue... "
  19. '--- bplus ---
  20. st# = TIMER(0.001)
  21. PRINT "BP-Start:"; st#
  22. FOR i&& = 0 TO 10000000
  23.     b$ = bpBIN$(i&&)
  24. et# = TIMER(0.001)
  25. IF et# = st# THEN et# = et# + 0.001 'avoid div by zero below
  26. PRINT "BP-End..:"; et#
  27. PRINT "Run-Time:"; et# - st#; "sec."
  28.  
  29. '--- RhoSigma ---
  30. st# = TIMER(0.001)
  31. PRINT "RS-Start:"; st#
  32. FOR i&& = 0 TO 10000000
  33.     b$ = rsBIN$(i&&)
  34. et# = TIMER(0.001)
  35. IF et# = st# THEN et# = et# + 0.001 'avoid div by zero below
  36. PRINT "RS-End..:"; et#
  37. PRINT "Run-Time:"; et# - st#; "sec."
  38. '--- cleanup & wait ---
  39. PRINT "...done, press any key"
  40.  
  41.  
  42. '================================
  43. '=== AND HERE COMES THE MAGIC ===
  44. '================================
  45.  
  46. FUNCTION rsBIN$ (value&&)
  47.     'chp% = char position, msp% = most significant position
  48.     'tlv&& = temporary loop value, ivq&& = integer value quotient
  49.     DIM chp%, msp%, tlv&&, ivq&&
  50.     tlv&& = value&&
  51.     rsBIN$ = STRING$(64, "0"): chp% = 64: msp% = 64
  52.     DO
  53.         ivq&& = INT(tlv&& / 2)
  54.         IF tlv&& / 2 <> ivq&& THEN MID$(rsBIN$, chp%, 1) = "1": msp% = chp%
  55.         chp% = chp% - 1: tlv&& = ivq&&
  56.     LOOP UNTIL tlv&& = 0
  57.     rsBIN$ = MID$(rsBIN$, msp%)
  58.  
  59. FUNCTION bpBIN$ (integerBase10 AS _INTEGER64) 'no more &B because easier to add than to remove
  60.     DIM j AS _INTEGER64, place AS INTEGER
  61.     j = 1: place = 64: bpBIN$ = STRING$(64, "0")
  62.     WHILE j <= integerBase10
  63.         IF (integerBase10 AND j) > 0 THEN MID$(bpBIN$, place, 1) = "1" ELSE MID$(bpBIN$, place, 1) = "0"
  64.         j = j * 2: place = place - 1
  65.     WEND
  66.     bpBIN$ = MID$(bpBIN$, place + 1)
  67.     IF bpBIN$ = "" THEN bpBIN$ = "0"
  68.  
  69.  
Speed test review.PNG

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: and another one for your toolbox...
« Reply #50 on: December 03, 2019, 04:56:24 am »
The really final one ??? :)

used bitshift instead of division, and unrolled the loop for the smallest integer type (_BYTE). Have also tweaked yours a bit B+, j=j+j (instead j*2) and removed the "0" (ELSE) branch from your condition. Your string consists of zeros, no need to write them for each tested bit.

Make sure your QB64 version is recent enough to have the _SHR instruction...

Code: QB64: [Select]
  1. _TITLE "BIN$ speed test..." 'Bplus mod of RhoSigma's 2019-12-03
  2. PRINT "BIN$ speed test ... System: "; _OS$: PRINT
  3. PRINT "BP = latest version from B+"
  4. PRINT "RS = latest from RhoSigma"
  5.  
  6. '--- for a fair test we need the same numbers for all
  7. '--- functions, so we first fill an array with numbers
  8.  
  9. PRINT "First test print BIN$ of 0:"
  10. PRINT "Bplus has "; bpBIN$(0)
  11. PRINT "RhoSigma has "; rsBIN$(0)
  12. PRINT "Press key to continue... "
  13. FOR i = 1 TO 7
  14.     r = INT(RND * 10 ^ i)
  15.     PRINT "For random number r = "; r
  16.     PRINT "   Bplus has "; bpBIN$(r)
  17.     PRINT "RhoSigma has "; rsBIN$(r)
  18. PRINT "Press key to continue... "
  19. '--- bplus ---
  20. st# = TIMER(0.001)
  21. PRINT "BP-Start:"; st#
  22. FOR i&& = 0 TO 10000000
  23.     b$ = bpBIN$(i&&)
  24. et# = TIMER(0.001)
  25. IF et# = st# THEN et# = et# + 0.001 'avoid div by zero below
  26. PRINT "BP-End..:"; et#
  27. PRINT "Run-Time:"; et# - st#; "sec."
  28.  
  29. '--- RhoSigma ---
  30. st# = TIMER(0.001)
  31. PRINT "RS-Start:"; st#
  32. FOR i&& = 0 TO 10000000
  33.     b$ = rsBIN$(i&&)
  34. et# = TIMER(0.001)
  35. IF et# = st# THEN et# = et# + 0.001 'avoid div by zero below
  36. PRINT "RS-End..:"; et#
  37. PRINT "Run-Time:"; et# - st#; "sec."
  38. '--- cleanup & wait ---
  39. PRINT "...done, press any key"
  40.  
  41.  
  42. '================================
  43. '=== AND HERE COMES THE MAGIC ===
  44. '================================
  45.  
  46. FUNCTION rsBIN$ (value&&)
  47.     'tlv&& = temporary loop value
  48.     'chp% = char position, msp% = most significant position
  49.     DIM tlv&&, chp%, msp%
  50.     tlv&& = value&&
  51.     rsBIN$ = STRING$(64, "0"): chp% = 64: msp% = 64
  52.     DO
  53.         IF (tlv&& AND 1) THEN MID$(rsBIN$, chp%, 1) = "1": msp% = chp%
  54.         IF (tlv&& AND 2) THEN MID$(rsBIN$, chp% - 1, 1) = "1": msp% = chp% - 1
  55.         IF (tlv&& AND 4) THEN MID$(rsBIN$, chp% - 2, 1) = "1": msp% = chp% - 2
  56.         IF (tlv&& AND 8) THEN MID$(rsBIN$, chp% - 3, 1) = "1": msp% = chp% - 3
  57.         IF (tlv&& AND 16) THEN MID$(rsBIN$, chp% - 4, 1) = "1": msp% = chp% - 4
  58.         IF (tlv&& AND 32) THEN MID$(rsBIN$, chp% - 5, 1) = "1": msp% = chp% - 5
  59.         IF (tlv&& AND 64) THEN MID$(rsBIN$, chp% - 6, 1) = "1": msp% = chp% - 6
  60.         IF (tlv&& AND 128) THEN MID$(rsBIN$, chp% - 7, 1) = "1": msp% = chp% - 7
  61.         chp% = chp% - 8
  62.         tlv&& = _SHR(tlv&&, 8)
  63.     LOOP UNTIL tlv&& = 0
  64.     rsBIN$ = MID$(rsBIN$, msp%)
  65.  
  66. FUNCTION bpBIN$ (integerBase10 AS _INTEGER64) 'no more &B because easier to add than to remove
  67.     DIM j AS _INTEGER64, place AS INTEGER
  68.     j = 1: place = 64: bpBIN$ = STRING$(64, "0")
  69.     WHILE j <= integerBase10
  70.         IF (integerBase10 AND j) > 0 THEN MID$(bpBIN$, place, 1) = "1"
  71.         j = j + j: place = place - 1
  72.     WEND
  73.     bpBIN$ = MID$(bpBIN$, place + 1)
  74.     IF bpBIN$ = "" THEN bpBIN$ = "0"
  75.  
  76.  
« Last Edit: December 16, 2019, 05:30:19 am by RhoSigma »
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: and another one for your toolbox...
« Reply #51 on: December 03, 2019, 08:20:56 am »
And now my really really really FINAL one, yes REALLY :)

improved using _MEM and CHECKING:OFF

Once again, make sure your QB64 version is recent enough to have the _SHR instruction...

Code: QB64: [Select]
  1. _TITLE "BIN$ speed test..." 'Bplus mod of RhoSigma's 2019-12-03
  2. PRINT "BIN$ speed test ... System: "; _OS$: PRINT
  3. PRINT "BP = latest version from B+"
  4. PRINT "RS = latest from RhoSigma"
  5.  
  6. '--- for a fair test we need the same numbers for all
  7. '--- functions, so we first fill an array with numbers
  8.  
  9. PRINT "First test print BIN$ of 0:"
  10. PRINT "Bplus has "; bpBIN$(0)
  11. PRINT "RhoSigma has "; rsBIN$(0)
  12. PRINT "Press key to continue... "
  13. FOR i = 1 TO 7
  14.     r = INT(RND * 10 ^ i)
  15.     PRINT "For random number r = "; r
  16.     PRINT "   Bplus has "; bpBIN$(r)
  17.     PRINT "RhoSigma has "; rsBIN$(r)
  18. PRINT "Press key to continue... "
  19. '--- bplus ---
  20. st# = TIMER(0.001)
  21. PRINT "BP-Start:"; st#
  22. FOR i&& = 0 TO 10000000
  23.     b$ = bpBIN$(i&&)
  24. et# = TIMER(0.001)
  25. IF et# = st# THEN et# = et# + 0.001 'avoid div by zero below
  26. PRINT "BP-End..:"; et#
  27. PRINT "Run-Time:"; et# - st#; "sec."
  28.  
  29. '--- RhoSigma ---
  30. st# = TIMER(0.001)
  31. PRINT "RS-Start:"; st#
  32. FOR i&& = 0 TO 10000000
  33.     b$ = rsBIN$(i&&)
  34. et# = TIMER(0.001)
  35. IF et# = st# THEN et# = et# + 0.001 'avoid div by zero below
  36. PRINT "RS-End..:"; et#
  37. PRINT "Run-Time:"; et# - st#; "sec."
  38. '--- cleanup & wait ---
  39. PRINT "...done, press any key"
  40.  
  41.  
  42. '================================
  43. '=== AND HERE COMES THE MAGIC ===
  44. '================================
  45.  
  46. FUNCTION rsBIN$ (value&&)
  47.     'tlv&& = temporary loop value, b$64 = fixed length temporary string
  48.     'chp% = char position mem offset, msp% = most significant string position
  49.     'one% = ascii code of "1", mp = memory pointer to b$64
  50.     DIM tlv&&, b$64, chp%, msp%, mp AS _MEM
  51.     tlv&& = value&&
  52.     b$64 = STRING$(64, "0"): chp% = 63: msp% = 64: one% = 49
  53.     mp = _MEM(b$64)
  54.     DO
  55.         IF (tlv&& AND 1) THEN _MEMPUT mp, mp.OFFSET + chp%, one% AS _BYTE: msp% = chp% + 1
  56.         IF (tlv&& AND 2) THEN _MEMPUT mp, mp.OFFSET + chp% - 1, one% AS _BYTE: msp% = chp%
  57.         IF (tlv&& AND 4) THEN _MEMPUT mp, mp.OFFSET + chp% - 2, one% AS _BYTE: msp% = chp% - 1
  58.         IF (tlv&& AND 8) THEN _MEMPUT mp, mp.OFFSET + chp% - 3, one% AS _BYTE: msp% = chp% - 2
  59.         IF (tlv&& AND 16) THEN _MEMPUT mp, mp.OFFSET + chp% - 4, one% AS _BYTE: msp% = chp% - 3
  60.         IF (tlv&& AND 32) THEN _MEMPUT mp, mp.OFFSET + chp% - 5, one% AS _BYTE: msp% = chp% - 4
  61.         IF (tlv&& AND 64) THEN _MEMPUT mp, mp.OFFSET + chp% - 6, one% AS _BYTE: msp% = chp% - 5
  62.         IF (tlv&& AND 128) THEN _MEMPUT mp, mp.OFFSET + chp% - 7, one% AS _BYTE: msp% = chp% - 6
  63.         chp% = chp% - 8
  64.         tlv&& = _SHR(tlv&&, 8)
  65.     LOOP UNTIL tlv&& = 0
  66.     _MEMFREE mp
  67.     rsBIN$ = MID$(b$64, msp%)
  68.  
  69. FUNCTION bpBIN$ (integerBase10 AS _INTEGER64) 'no more &B because easier to add than to remove
  70.     DIM j AS _INTEGER64, place AS INTEGER
  71.     j = 1: place = 64: bpBIN$ = STRING$(64, "0")
  72.     WHILE j <= integerBase10
  73.         IF (integerBase10 AND j) > 0 THEN MID$(bpBIN$, place, 1) = "1"
  74.         j = j + j: place = place - 1
  75.     WEND
  76.     bpBIN$ = MID$(bpBIN$, place + 1)
  77.     IF bpBIN$ = "" THEN bpBIN$ = "0"
  78.  
  79.  
« Last Edit: December 16, 2019, 05:29:04 am by RhoSigma »
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: and another one for your toolbox...
« Reply #52 on: December 03, 2019, 09:20:39 am »
I still like this version, for myself:

Code: QB64: [Select]
  1. n$ = bin$(12, 1)
  2. PRINT n$, VAL(n$)
  3.  
  4. n$ = bin$(-2, 1) 'byte
  5. PRINT n$, VAL(n$)
  6.  
  7. n$ = bin$(-2, 2) 'integer
  8. PRINT n$, VAL(n$)
  9.  
  10. FUNCTION bin$ (n AS _INTEGER64, Rbytes AS _BYTE)
  11.     STATIC m AS _MEM
  12.     DIM b AS _BYTE, i AS INTEGER, l AS LONG, i64 AS _INTEGER64
  13.     IF n < 1 THEN 'the user needs to tell us how many return bytes they expect
  14.         SELECT CASE Rbytes 'assign the value to the proper mem type
  15.             CASE 1: m = _MEM(b): b = n '1 for a byte
  16.             CASE 2: m = _MEM(i): i = n '2 for an integer
  17.             CASE 4:: m = _MEM(l): l = n '4 for a long
  18.             CASE 8: m = _MEM(i64): i64 = n '8 for an integer64
  19.             CASE ELSE: bin$ = "WRONG RETURN TYPE!": EXIT FUNCTION
  20.         END SELECT
  21.     ELSE
  22.         m = _MEM(n): l = 8 'just use the number as we passed it
  23.     END IF
  24.  
  25.     FOR i1 = 0 TO Rbytes - 1
  26.         FOR j = 0 TO 7 '8 bytes per length and 8 bits in each byte
  27.             IF _MEMGET(m, m.OFFSET + i1, _BYTE) AND 2 ^ j THEN b$ = "1" + b$ ELSE b$ = "0" + b$
  28.     NEXT j, i1
  29.     bin$ = "&B" + MID$(b$, INSTR(b$, "1"))
  30.  

Unlike all the rest, this is isn't built with speed being it's deciding factor -- flexibility is.  It returns BIN$ for both positive and negative values, and for various variable types.  I don't usually find myself needing to be concerned with "how fast can I turn a number into a binary string", so this is designed more for "how useful can it be, when turning a number into a binary string". 

n$ = bin$(-2, 1) <--- This would return the binary value of -2, if I was dealing with bytes.
n$ = bin$(-2, 4) <--- This would return the binary value of -2, if I was dealing with longs.

Not only does it work for positive numbers, but it also works with negative ones, and returns them back to us for whatever variable type which we might want it to.
« Last Edit: December 03, 2019, 10:01:52 am by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: and another one for your toolbox...
« Reply #53 on: December 03, 2019, 10:57:33 am »
Yeah I suspected this was going to get into bit shifting and MEM but did not expect for Type variables, ha ;-))

And agree it's getting kind of crazy to be completely focused on speed. (Specially since I don't think I am going to get a faster one than RhoSigma. LOL)

@Steve, you really have an actual use for binary strings for different variable types or are you going to make one up now? ;) Even for MEM stuff I would think you need number values not strings?
« Last Edit: December 03, 2019, 12:17:57 pm by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: and another one for your toolbox...
« Reply #54 on: December 03, 2019, 11:07:36 am »
Yeah I suspected this was going to get into bit shifting and MEM but did not expect for Type variables, ha ;-))

And agree it's getting kind of crazy to be completely focused on speed.

@Steve, you really have an actual use for binary strings for different variable types or are you going to make one up now? Even for MEM stuff I would think you need number values not strings?

Mainly for teaching purposes, to help explain to people why COLOR -1 in 32-bit is the same as color &HFFFFFFFF.   (A shortcut I use all the time!)

As you say, normally you use AND bit_value, rather than AND VAL(MID$(BIN$(number), position,1)).  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: and another one for your toolbox...
« Reply #55 on: December 03, 2019, 12:21:04 pm »
I put this in edit but decided it's best in full reply to RhoSigma's efforts:
Update: oh heck I missed the ELSE replace with "0" thing, nice catch.

RhoSigma, really, really nice work! you make my version better and then cut that time in half or so... :)

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: and another one for your toolbox...
« Reply #56 on: December 04, 2019, 03:50:20 am »
Thanks B+,

I saw it already in your edit. And yes, in general I do also prefer readability end elegance over speed (GuiTools is the best prove), but nevertheless it was a nice brain training to see what's possible and what you can do to take out as many as possible of the time consuming "under the hood" operations, which regulary nobody even think of.
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: and another one for your toolbox...
« Reply #57 on: December 05, 2019, 11:06:49 pm »
Added a much needed line to InputG function when _DISPLAY is activated.
https://www.qb64.org/forum/index.php?topic=1511.msg110651#msg110651
« Last Edit: December 05, 2019, 11:22:56 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: and another one for your toolbox...
« Reply #58 on: December 16, 2019, 10:39:30 pm »
A number of tools have been updated or added, here is best versions of some routines discussed earlier in this thread.

8 routines added or improved to my toolbox today 2019-12-16, what a day!
Code: QB64: [Select]
  1. ' 2019-12-16 updates to my Toolbox Listing
  2.  
  3. '2019-12-16 fix by Steve saves some time with STATIC and saves and restores last dest
  4. SUB ftri (x1, y1, x2, y2, x3, y3, K AS _UNSIGNED LONG)
  5.     DIM D AS LONG
  6.     STATIC a&
  7.     D = _DEST
  8.     IF a& = 0 THEN a& = _NEWIMAGE(1, 1, 32)
  9.     _DEST a&
  10.     _DONTBLEND a& '  '<<<< new 2019-12-16 fix
  11.     PSET (0, 0), K
  12.     _BLEND a& '<<<< new 2019-12-16 fix
  13.     _DEST D
  14.     _MAPTRIANGLE _SEAMLESS(0, 0)-(0, 0)-(0, 0), a& TO(x1, y1)-(x2, y2)-(x3, y3)
  15.  
  16. 'update 2019-12-16 needs updated fTri 2019-12-16  I like this ordering of points better
  17. 'need 4 non linear points (not all on 1 line) list them clockwise so x2, y2 is opposite of x4, y4
  18. SUB fquad (x1, y1, x2, y2, x3, y3, x4, y4, K AS _UNSIGNED LONG)
  19.     ftri x1, y1, x2, y2, x3, y3, K
  20.     ftri x3, y3, x4, y4, x1, y1, K
  21.  
  22. ' 2019-12-16 this should have been in here earlier
  23. SUB EllipseFill (CX AS INTEGER, CY AS INTEGER, a AS INTEGER, b AS INTEGER, C AS _UNSIGNED LONG)
  24.     ' CX = center x coordinate
  25.     ' CY = center y coordinate
  26.     '  a = semimajor axis
  27.     '  b = semiminor axis
  28.     '  C = fill color
  29.     IF a = 0 OR b = 0 THEN EXIT SUB
  30.     DIM h2 AS _INTEGER64
  31.     DIM w2 AS _INTEGER64
  32.     DIM h2w2 AS _INTEGER64
  33.     DIM x AS INTEGER
  34.     DIM y AS INTEGER
  35.     w2 = a * a
  36.     h2 = b * b
  37.     h2w2 = h2 * w2
  38.     LINE (CX - a, CY)-(CX + a, CY), C, BF
  39.     DO WHILE y < b
  40.         y = y + 1
  41.         x = SQR((h2w2 - y * y * w2) \ h2)
  42.         LINE (CX - x, CY + y)-(CX + x, CY + y), C, BF
  43.         LINE (CX - x, CY - y)-(CX + x, CY - y), C, BF
  44.     LOOP
  45.  
  46. 'thanks STxAxTIC from Toolbox
  47. SUB EllipseTilt (CX, CY, a, b, ang, C AS _UNSIGNED LONG)
  48.     DIM k, i, j
  49.     '  CX = center x coordinate
  50.     '  CY = center y coordinate
  51.     '   a = semimajor axis  major radius
  52.     '   b = semiminor axis  minor radius
  53.     ' ang = clockwise orientation of semimajor axis in radians (0 default)
  54.     '   C = fill color
  55.     FOR k = 0 TO 6.283185307179586 + .025 STEP .025 'not sure about the stepper it should depend on a and b
  56.         i = a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  57.         j = -a * COS(k) * SIN(ang) + b * SIN(k) * COS(ang)
  58.         i = i + CX
  59.         j = -j + CY
  60.         IF k <> 0 THEN
  61.             LINE -(i, j), C
  62.         ELSE
  63.             PSET (i, j), C
  64.         END IF
  65.     NEXT
  66.  
  67. 'relace toolbox code  2019-12-16
  68. 'this needs RotoZoom3 to rotate image and EllipseFill to make the image BUT it can now scale it also!
  69. SUB fTiltEllipse (destH AS LONG, ox AS INTEGER, oy AS INTEGER, majorRadius AS INTEGER, minorRadius AS INTEGER, radianAngle AS SINGLE, c AS _UNSIGNED LONG)
  70.     'setup isolated area, draw fFlatEllipse and then RotoZoom the image into destination
  71.     'ox, oy is center of ellipse
  72.     'majorRadius is 1/2 the lonest axis
  73.     'minorRadius is 1/2 the short axis
  74.     'radianAngle is the Radian Angle of Tilt
  75.     'c is of course color
  76.     DIM sd&, temp&
  77.     sd& = _DEST
  78.     temp& = _NEWIMAGE(2 * majorRadius, 2 * minorRadius, 32)
  79.     _DEST temp&
  80.     _DONTBLEND temp& '<< test 12-16
  81.     'fEllipse majorRadius, minorRadius, majorRadius, minorRadius, c
  82.     EllipseFill majorRadius, minorRadius, majorRadius, minorRadius, c
  83.     _BLEND temp& '<< test 12-16
  84.     _DEST destH
  85.     RotoZoom3 ox, oy, temp&, 1, 1, radianAngle
  86.     _FREEIMAGE temp&
  87.     _DEST sd&
  88.  
  89. SUB RotoZoom3 (X AS LONG, Y AS LONG, Image AS LONG, xScale AS SINGLE, yScale AS SINGLE, radianRotation AS SINGLE)
  90.     ' this assumes you have set your drawing location with _dest or default to screen
  91.     ' X, Y is where you want to put the middle of the image
  92.     ' Image is the handle assigned with _LOADIMAGE
  93.     ' xScale, yScale are shrinkage < 1 or magnification > 1 on the given axis
  94.     ' radianRotation is the Angle in Radian units to rotate the image
  95.  
  96.     DIM px(3) AS SINGLE: DIM py(3) AS SINGLE ' simple arrays for x, y to hold the 4 corners of image
  97.     DIM W&, H&, sinr!, cosr!, i&, x2&, y2& '   variables for image manipulation
  98.     W& = _WIDTH(Image&): H& = _HEIGHT(Image&)
  99.     px(0) = -W& / 2: py(0) = -H& / 2 'left top corner
  100.     px(1) = -W& / 2: py(1) = H& / 2 ' left bottom corner
  101.     px(2) = W& / 2: py(2) = H& / 2 '  right bottom
  102.     px(3) = W& / 2: py(3) = -H& / 2 ' right top
  103.     sinr! = SIN(-radianRotation): cosr! = COS(-radianRotation) ' rotation helpers
  104.     FOR i& = 0 TO 3 ' calc new point locations with rotation and zoom
  105.         x2& = xScale * (px(i&) * cosr! + sinr! * py(i&)) + X: y2& = yScale * (py(i&) * cosr! - px(i&) * sinr!) + Y
  106.         px(i&) = x2&: py(i&) = y2&
  107.     NEXT
  108.     _MAPTRIANGLE _SEAMLESS(0, 0)-(0, H& - 1)-(W& - 1, H& - 1), Image TO(px(0), py(0))-(px(1), py(1))-(px(2), py(2))
  109.     _MAPTRIANGLE _SEAMLESS(0, 0)-(W& - 1, 0)-(W& - 1, H& - 1), Image TO(px(0), py(0))-(px(3), py(3))-(px(2), py(2))
  110.  
  111. '=================================================================================================================== String stuff
  112. '---------------------------------------------------------------------
  113. 'RhoSigma keeps saying final version but then...
  114. 'here is reference: https://www.qb64.org/forum/index.php?topic=1933.msg112096#msg112096
  115. 'Function:  Convert any given dec/hex/oct number into a binary string.
  116. '           Can handle positive and negative values and works in that
  117. '           similar to the QB64 built-in HEX$ and OCT$ functions.
  118. '
  119. 'Synopsis:  binary$ = BIN$ (value&&)
  120. '
  121. 'Result:    binary$ --> the binary representation string of the given
  122. '                       number without leading zeros for positive values
  123. '                       and either 8/16/32 or 64 chars for negatives,
  124. '                       depending on the input size
  125. '
  126. 'Inputs:    value&& --> the pos./neg. number to convert, may also be
  127. '                       given as &H or &O prefixed value
  128. '
  129. 'Notes:     You may also pass in floating point values, as long as its
  130. '           represented value fits into the _INTEGER64 (&&) input, hence
  131. '           approx. -9.223372036854776E+18 to 9.223372036854776E+18.
  132. '           Different from HEX$ and OCT$, BIN$ won't throw an overflow
  133. '           error, if this range is exceeded, but the result is probably
  134. '           wrong in such a case.
  135. '---------------------------------------------------------------------
  136. FUNCTION BIN$ (value&&)
  137. '--- option _explicit requirements ---
  138. DIM temp~&&, charPos%, highPos%
  139. '--- init ---
  140. temp~&& = value&&
  141. BIN$ = STRING$(64, "0"): charPos% = 64: highPos% = 64
  142. '--- convert ---
  143.     IF (temp~&& AND 1) THEN MID$(BIN$, charPos%, 1) = "1": highPos% = charPos%
  144.     charPos% = charPos% - 1: temp~&& = temp~&& \ 2
  145. LOOP UNTIL temp~&& = 0
  146. '--- adjust negative size ---
  147. IF value&& < 0 THEN
  148.     IF -value&& < &HFFFFFFFF~& THEN highPos% = 33
  149.     IF -value&& < &H0000FFFF~& THEN highPos% = 49
  150.     IF -value&& < &H000000FF~& THEN highPos% = 57
  151.     IF -value&& < &H00000000~& THEN highPos% = 1
  152. '--- set result ---
  153. BIN$ = MID$(BIN$, highPos%)
  154.  
  155. 'update 2019-12-16 in ...test\graphics\fTri tests.bas  SLEEP with a click
  156. SUB cSleep (secsWait AS DOUBLE) 'wait for keypress or mouseclick, solves midnight problem nicely I think
  157.     DIM wayt AS INTEGER, oldMouse AS INTEGER, k AS LONG, startTime AS DOUBLE
  158.     oldMouse = -1 '2019-12-16 2nd fix today assume an old mouse click is still active
  159.     startTime = TIMER
  160.     wayt = 1
  161.     _KEYCLEAR
  162.     WHILE wayt
  163.         WHILE _MOUSEINPUT: WEND
  164.         IF _MOUSEBUTTON(1) AND oldMouse = 0 THEN wayt = 0
  165.         oldMouse = _MOUSEBUTTON(1) ' <<< this is Steve's cool way to get clear of mouse click
  166.         k = _KEYHIT: IF k > 0 THEN _KEYCLEAR: wayt = 0
  167.         IF TIMER - startTime < 0 THEN 'past midnight
  168.             IF TIMER + 24 * 60 * 60 - startTime > secsWait THEN wayt = 0
  169.         ELSE
  170.             IF TIMER - startTime >= secsWait THEN wayt = 0
  171.         END IF
  172.         _LIMIT 30
  173.     WEND
  174.  
  175.  

EDIT: 2019-12-17 RhoSigma changed final version of BIN$ again

EDIT: 2020-03-03 Discovered big error in revised RotoZoom3 now fixed
« Last Edit: March 03, 2020, 01:28:30 pm by bplus »

FellippeHeitor

  • Guest
Re: and another one for your toolbox...
« Reply #59 on: December 16, 2019, 10:41:16 pm »
Quote
8 routines added or improved to my toolbox today 2019-12-16, what a day!

It is wholesome to see this community so active and going so strong. Moment of appreciation here.