Author Topic: Does a Is Number function exist in QB64?  (Read 8240 times)

0 Members and 1 Guest are viewing this topic.

Offline xra7en

  • Seasoned Forum Regular
  • Posts: 284
    • View Profile
Re: Does a Is Number function exist in QB64?
« Reply #15 on: December 29, 2018, 10:41:34 pm »
Like it!
I'll check it out.. and put it in my bag of utils.bi :-)
I just like re-writing old DOS book games into modern QB64 code - weird hobby, I know!

Offline xra7en

  • Seasoned Forum Regular
  • Posts: 284
    • View Profile
Re: Does a Is Number function exist in QB64?
« Reply #16 on: December 29, 2018, 11:16:11 pm »
here is what I did with your code... what do you think?


Code: QB64: [Select]
  1. FUNCTION IS_NUMBER (text AS STRING) ' returns 1 if string is an integer, 0 if not
  2.     IS_NUMBER = 1
  3.     FOR i = 1 TO LEN(text$)
  4.         IF ASC(MID$(text$, i, 1)) < 45 OR ASC(MID$(text$, i, 1)) >= 58 THEN IS_NUMBER = 0
  5.         ' It's not a number, minus sign, / or . character, so goto notanumber
  6.         IF ASC(MID$(text$, i, 1)) = 47 THEN IS_NUMBER = 0
  7.         ' it's a / character, so goto notanumber
  8.     NEXT i
  9.  
I just like re-writing old DOS book games into modern QB64 code - weird hobby, I know!

Offline MWheatley

  • Newbie
  • Posts: 64
    • View Profile
Re: Does a Is Number function exist in QB64?
« Reply #17 on: December 30, 2018, 09:40:47 am »
That looks fine -- glad to have helped.  (Nice to give something back, for a change!)

As I say, it's a bit of code that has worked for me for many, many years.

Malcolm

Offline MWheatley

  • Newbie
  • Posts: 64
    • View Profile
Re: Does a Is Number function exist in QB64?
« Reply #18 on: January 01, 2019, 11:24:30 am »
here is what I did with your code... what do you think?


Code: QB64: [Select]
  1. FUNCTION IS_NUMBER (text AS STRING) ' returns 1 if string is an integer, 0 if not
  2.     IS_NUMBER = 1
  3.     FOR i = 1 TO LEN(text$)
  4.         IF ASC(MID$(text$, i, 1)) < 45 OR ASC(MID$(text$, i, 1)) >= 58 THEN IS_NUMBER = 0
  5.         ' It's not a number, minus sign, / or . character, so goto notanumber
  6.         IF ASC(MID$(text$, i, 1)) = 47 THEN IS_NUMBER = 0
  7.         ' it's a / character, so goto notanumber
  8.     NEXT i
  9.  

Out of interest, I'd be interested in seeing a piece of code that used this function.  As I've just typed elsewhere, I almost never use functions, and would appreciate seeing an example using a bit of code I know and understand.

(If you're wondering why, it's chiefly that early BASICs made functions difficult (to me, anyway), and by the time QB45 came along, I'd got out of the habit.  Plus, the QB45 IDE doesn't exactly make the experience all that user-friendly, either.)

Malcolm


Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Does a Is Number function exist in QB64?
« Reply #19 on: January 01, 2019, 12:29:03 pm »
Hi Malcohm,

Here is a quick demo showing the use of the function:
Code: QB64: [Select]
  1.     PRINT: INPUT "Please enter a number or not to test the IS_NUMBER function > ", test$
  2.  
  3.    'the next line uses the function
  4.     IF IS_NUMBER(test$) = 1 THEN PRINT "Is a number" ELSE PRINT " NOT a number."
  5.  
  6.     INPUT "Test function again? y for yes ", again$
  7. LOOP UNTIL again$ <> "y"
  8.  
  9. FUNCTION IS_NUMBER (text AS STRING) ' returns 1 if string is an integer, 0 if not
  10.     IS_NUMBER = 1
  11.     FOR i = 1 TO LEN(text$)
  12.         IF ASC(MID$(text$, i, 1)) < 45 OR ASC(MID$(text$, i, 1)) >= 58 THEN IS_NUMBER = 0
  13.         ' It's not a number, minus sign, / or . character, so goto notanumber
  14.         IF ASC(MID$(text$, i, 1)) = 47 THEN IS_NUMBER = 0
  15.         ' it's a / character, so goto notanumber
  16.     NEXT i
  17.  

BTW the function fails for numbers like
Code: QB64: [Select]
  1. n = 23E29

Also thinks 23-. is a number!
« Last Edit: January 01, 2019, 12:43:10 pm by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Does a Is Number function exist in QB64?
« Reply #20 on: January 01, 2019, 04:26:25 pm »
here is what I did with your code... what do you think?

Out of interest, I'd be interested in seeing a piece of code that used this function.  As I've just typed elsewhere, I almost never use functions, and would appreciate seeing an example using a bit of code I know and understand.

(If you're wondering why, it's chiefly that early BASICs made functions difficult (to me, anyway), and by the time QB45 came along, I'd got out of the habit.  Plus, the QB45 IDE doesn't exactly make the experience all that user-friendly, either.)

Malcolm

You use FUNCTIONs all the time in your code.  Your original code is chock full of them...

FOR i = 1 TO LEN(text$)
IF ASC(MID$(text$, i, 1)) < 45 OR ASC(MID$(text$, i, 1)) >= 58 GOTO notanumber

Of the above, we have 2 lines of code and 3 functions:  LEN(), ASC(), MID$()

At its base, all a FUNCTION is, is a routine which gives you a return value.  A SUB on the other hand, doesn’t.

CLS — this is a SUB.
PRINT — this is a SUB.
ASC() — This returns a value, so is a FUNCTION.
CHR$() — Function.
SIN(), COS(), TAN() — all FUNCTIONs.

If it’s a routine which gives you a return value, which you can use from the right side of an equal sign, it’s a FUNCTION:

X = whatever(), and whatever() is a FUNCTION.

IF your command is a stand-alone procedure which can’t go to the right side of an equal sign, it’s a SUB:

X = PRINT “Hello World” — for example.



You’ve used functions all the time in your code.  You just haven’t been creating any CUSTOM functions of your own, from the way your post sounds.  When you do, you just end up using them like you have been, with all usual rules and syntax applying.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

FellippeHeitor

  • Guest
Re: Does a Is Number function exist in QB64?
« Reply #21 on: January 05, 2019, 03:38:16 pm »
This isnumber() function is present in source/qb64.bas and I've adapted it recently to recognise scientific notation as well:

Code: QB64: [Select]
  1. FUNCTION isnumber (a$)
  2.     IF LEN(a$) = 0 THEN EXIT FUNCTION
  3.     FOR i = 1 TO LEN(a$)
  4.         a = ASC(MID$(a$, i, 1))
  5.         IF a = 45 THEN
  6.             IF (i = 1 AND LEN(a$) > 1) OR (i > 1 AND (d = i - 1 OR E = i - 1)) THEN _CONTINUE
  7.             EXIT FUNCTION
  8.         END IF
  9.         IF a = 46 THEN
  10.             IF dp = 1 THEN EXIT FUNCTION
  11.             dp = 1
  12.             _CONTINUE
  13.         END IF
  14.         IF a = 100 OR a = 68 THEN 'D
  15.             IF d > 1 OR E > 1 THEN EXIT FUNCTION
  16.             d = i
  17.             _CONTINUE
  18.         END IF
  19.         IF a = 101 OR a = 69 THEN 'E
  20.             IF d > 0 OR E > 1 THEN EXIT FUNCTION
  21.             E = i
  22.             _CONTINUE
  23.         END IF
  24.         IF a = 43 THEN '+
  25.             IF d = i - 1 OR E = i - 1 THEN _CONTINUE
  26.             EXIT FUNCTION
  27.         END IF
  28.  
  29.         IF a >= 48 AND a <= 57 THEN _CONTINUE
  30.         EXIT FUNCTION
  31.     NEXT
  32.     isnumber = 1

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Does a Is Number function exist in QB64?
« Reply #22 on: January 05, 2019, 08:08:32 pm »
I just wanted to waste some time on something this evening, so I decided to toss my hat into the ring and over-engineer a number checker...  Here's what I came up with; feel free to test it and point out any glitches which I produced.

Code: QB64: [Select]
  1. DIM test(10) AS STRING
  2. DATA "123a.3","-123.456","--234","1.23E15","123","dogfood","678.965","54678","-987134","23.4.5"
  3.  
  4. FOR i = 1 TO 10
  5.     READ test(i)
  6.  
  7. FOR i = 1 TO 10
  8.     PRINT "TEST #"; i; ": "; test(i) + " "
  9.     result = NumberType(test(i))
  10.     IF result = 0 THEN PRINT "INVALID: "; NumErr$
  11.     IF result AND 1 THEN PRINT "Valid Unsigned Byte.  ";
  12.     IF result AND 2 THEN PRINT "Valid Unsigned Integer.  ";
  13.     IF result AND 4 THEN PRINT "Valid Unsigned Long.  ";
  14.     IF result AND 8 THEN PRINT "Valid Unsigned Integer64.  ";
  15.     IF result AND 16 THEN PRINT "Valid Signed Byte.  ";
  16.     IF result AND 32 THEN PRINT "Valid Signed Integer.  ";
  17.     IF result AND 64 THEN PRINT "Valid Signed Long.  ";
  18.     IF result AND 128 THEN PRINT "Valid Signed Integer64.  ";
  19.     IF result AND 256 THEN PRINT "Valid Single.  ";
  20.     IF result AND 512 THEN PRINT "Valid Double.  ";
  21.     IF result AND 1024 THEN PRINT "Valid Float.  ";
  22.     PRINT
  23.     PRINT
  24.     SLEEP
  25.  
  26.  
  27. FUNCTION NumberType~% (text$)
  28.     SHARED NumErr$
  29.     temp$ = UCASE$(_TRIM$(text$))
  30.     NumErr$ = "" 'reset the error message
  31.  
  32.     'First check for negative values; flag for invalid cases of multiple negation.
  33.     IF MID$(temp$, 1, 1) = "-" THEN negative = -1
  34.     FOR i = 1 TO LEN(temp$)
  35.         IF MID$(temp$, i, 1) = "-" THEN minus = minus + 1
  36.         IF MID$(temp$, i, 1) = "." THEN period = period + 1 'Go ahead and check for multiple periods while we're at it.
  37.     NEXT
  38.     IF minus > 1 THEN NumErr$ = _TRIM$(STR$(minus)) + " negative signs (-) encountered, rendering string not to be a valid number.  "
  39.     IF negative THEN temp$ = MID$(temp$, 2) 'strip off the minus
  40.  
  41.     'Check for integer values if no period is present
  42.     IF period = 0 THEN 'we don't have to worry about any sort of float values, so check for just numbers
  43.         FOR i = 1 TO LEN(temp$)
  44.             t$ = MID$(temp$, i, 1)
  45.             IF t$ < "0" OR t$ > "9" THEN NumErr$ = NumErr$ + "Invalid Character (" + t$ + ") encountered.  "
  46.         NEXT
  47.     ELSEIF period = 1 THEN 'We have a single period; it may be a valid SINGLE/DOUBLE/FLOAT
  48.         FOR i = 1 TO LEN(temp$)
  49.             t$ = MID$(temp$, i, 1)
  50.             IF t$ = "E" OR t$ > "D" THEN Exponent = Exponent + 1
  51.             IF t$ < "0" OR t$ > "9" THEN
  52.                 IF (t$ = "E" OR t$ = "D") AND Exponent > 1 THEN NumErr$ = NumErr$ + "Invalid Character (" + t$ + ") encountered.  "
  53.                 IF t$ <> "E" AND t$ <> "D" AND t$ <> "." THEN NumErr$ = NumErr$ + "Invalid Character (" + t$ + ") encountered.  "
  54.             END IF
  55.         NEXT
  56.         IF Exponent > 1 THEN
  57.             NumErr$ = NumErr$ + _TRIM$(STR$(Exponent)) + " Exponential Characters, rendering REAL values impossible.  "
  58.         ELSEIF Exponent = 1 THEN
  59.             IF MID$(temp$, 2, 1) <> "." THEN NumErr$ = NumErr$ + "Rejected for non-standard numeric value; too many digits before Exponnential Character."
  60.         END IF
  61.     ELSE 'We have too many periods to be a valid number
  62.         NumErr$ = NumErr$ + _TRIM$(STR$(period)) + " periods (.) encountered, rendering string not to be a valid number.  "
  63.     END IF
  64.  
  65.     IF NumErr$ = "" THEN
  66.         'It's a valid number
  67.         t## = VAL(temp$)
  68.         IF period = 0 THEN 'integer
  69.             IF t## >= -128 AND t## <= 127 THEN NumberType = NumberType OR 16 'signed byte
  70.             IF t## >= -32768 AND t## <= 32767 THEN NumberType = NumberType OR 32 'signed integer
  71.             IF t## >= -2147483648 AND t## <= 2147483647 THEN NumberType = NumberType OR 64 'signed long
  72.             IF t## >= -9223372036854775808 AND t## <= 9223372036854775807 THEN NumberType = NumberType OR 128 'signed integer64
  73.             IF negative = 0 THEN 'unsigned
  74.                 IF t## <= 255 THEN NumberType = NumberType OR 1 'unsigned byte
  75.                 IF t## <= 65535 THEN NumberType = NumberType OR 2 'unsigned integer
  76.                 IF t## <= 4294967295 THEN NumberType = NumberType OR 4 'unsigned long
  77.                 IF t## <= 18446744073709551615 THEN NumberType = NumberType OR 8 'unsigned integer64
  78.             END IF
  79.         END IF
  80.         IF t## >= -2.802597E-45 AND t## <= 3.402823E+38 THEN NumberType = NumberType OR 256 'single
  81.         IF t## >= -4.490656458412465E-324 AND t## <= 1.797693134862310E+308 THEN NumberType = NumberType OR 512 'double
  82.         IF t## >= -1.18E-4932 AND t## <= 1.18E+4932 THEN NumberType = NumberType OR 1024 'float
  83.     END IF
  84.  

Singles/doubles/floats might be a little glitchy, as I don't usually find myself using scientific notation for ANYTHING, really...  I may have some of the basic rules of the format wrong, and if so, I'll go in and adjust them later and correct them.

For example, is 1E15 a valid number?  Or does it need to be 1.0E15 with that decimal in there?   Currently, it flags as INVALID, as I was thinking the decimal was required -- but I freely admit, I may be wrong guessing that...   It happens sometimes.  :P
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

FellippeHeitor

  • Guest
Re: Does a Is Number function exist in QB64?
« Reply #23 on: January 05, 2019, 11:28:24 pm »

Offline luke

  • Administrator
  • Seasoned Forum Regular
  • Posts: 324
    • View Profile
Re: Does a Is Number function exist in QB64?
« Reply #24 on: January 06, 2019, 12:17:50 am »
QB64 unfortunately doesn't have any functions for using regular expressions, but here's one that'll match numbers:
Code: QB64: [Select]
  1. /^-?(&h[\da-f]+|&o[0-7]+|&b[01]+|(\d+\.?\d*|\.?\d+)([ed][-+]?\d*)?)$/i

This allows for &H/&O/&B numbers, regular integers, floating point numbers, and even decimals with leading/trailing decimal points like ".23" or "23." which are valid in QB64.

You can play with it here: https://regex101.com/r/2EP3G2/1
« Last Edit: January 06, 2019, 12:21:38 am by luke »