A looong time ago, on the old qb64.org forums, we discussed rounding numbers, and out of it came some functions:
For rounding type _FLOAT:
FUNCTION Round## (num##, digits%)
FUNCTION RoundUp## (num##, digits%)
FUNCTION RoundDown## (num##, digits%)
FUNCTION RoundScientific## (num##, digits%)
For rounding up (DOUBLE, SINGLE):
FUNCTION RoundUpDouble# (num#, digits%)
FUNCTION RoundUpSingle! (num!, digits%)
Convert to string, getting rid of scientific notation (DOUBLE, SINGLE):
FUNCTION DblToStr$ (n#)
FUNCTION SngToStr$ (n!)
From what I recall, they were all working.
This weekend I dug up the code to use in a new program,
and added the equivalent rounding and convert-to-string for all 3 types (_FLOAT, DOUBLE, SINGLE):
FUNCTION Round## (num##, digits%)
FUNCTION RoundUp## (num##, digits%)
FUNCTION RoundDown## (num##, digits%)
FUNCTION RoundScientific## (num##, digits%)
FUNCTION RoundDouble# (num#, digits%)
FUNCTION RoundUpDouble# (num#, digits%)
FUNCTION RoundDownDouble# (num#, digits%)
FUNCTION RoundScientificDouble# (num#, digits%)
FUNCTION RoundSingle! (num!, digits%) <- not sure this one works: when digits%=3, it rounds .31 to .32
FUNCTION RoundUpSingle! (num!, digits%)
FUNCTION RoundDownSingle! (num!, digits%)
FUNCTION RoundScientificSingle! (num!, digits%)
FUNCTION DblToStr$ (n#)
FUNCTION SngToStr$ (n!)
FUNCTION FloatToStr$ (n##)
Everything seems to work as expected, except for the function RoundUpSingle!, which for some reason rounds 0.31 to 0.32.
I've been comparing code and checking everything and am not seeing what is causing this, or whether the problem is in RoundUpSingle! or SngToStr$.
Maybe a second set of eyes would help...
If someone could spare a couple minutes to look at this and find what's the wrong, it would be most appreciated!
These functions might come in handy for someone.
For rounding type _FLOAT:
FUNCTION Round## (num##, digits%)
FUNCTION RoundUp## (num##, digits%)
FUNCTION RoundDown## (num##, digits%)
FUNCTION RoundScientific## (num##, digits%)
For rounding up (DOUBLE, SINGLE):
FUNCTION RoundUpDouble# (num#, digits%)
FUNCTION RoundUpSingle! (num!, digits%)
Convert to string, getting rid of scientific notation (DOUBLE, SINGLE):
FUNCTION DblToStr$ (n#)
FUNCTION SngToStr$ (n!)
From what I recall, they were all working.
This weekend I dug up the code to use in a new program,
and added the equivalent rounding and convert-to-string for all 3 types (_FLOAT, DOUBLE, SINGLE):
FUNCTION Round## (num##, digits%)
FUNCTION RoundUp## (num##, digits%)
FUNCTION RoundDown## (num##, digits%)
FUNCTION RoundScientific## (num##, digits%)
FUNCTION RoundDouble# (num#, digits%)
FUNCTION RoundUpDouble# (num#, digits%)
FUNCTION RoundDownDouble# (num#, digits%)
FUNCTION RoundScientificDouble# (num#, digits%)
FUNCTION RoundSingle! (num!, digits%) <- not sure this one works: when digits%=3, it rounds .31 to .32
FUNCTION RoundUpSingle! (num!, digits%)
FUNCTION RoundDownSingle! (num!, digits%)
FUNCTION RoundScientificSingle! (num!, digits%)
FUNCTION DblToStr$ (n#)
FUNCTION SngToStr$ (n!)
FUNCTION FloatToStr$ (n##)
Everything seems to work as expected, except for the function RoundUpSingle!, which for some reason rounds 0.31 to 0.32.
I've been comparing code and checking everything and am not seeing what is causing this, or whether the problem is in RoundUpSingle! or SngToStr$.
Maybe a second set of eyes would help...
If someone could spare a couple minutes to look at this and find what's the wrong, it would be most appreciated!
These functions might come in handy for someone.
Code: (Select All)
' ################################################################################################################################################################
' Rounding test
' ################################################################################################################################################################
' BOOLEAN CONSTANTS
CONST FALSE = 0
CONST TRUE = NOT FALSE
' GLOBAL VARIABLES a$=string, i%=integer, L&=long, s!=single, d#=double
DIM ProgramPath$: ProgramPath$ = LEFT$(COMMAND$(0), _INSTRREV(COMMAND$(0), "\"))
DIM ProgramName$: ProgramName$ = MID$(COMMAND$(0), _INSTRREV(COMMAND$(0), "\") + 1)
' START THE MAIN PROGRAM
main ProgramName$
' FINISH UP
SYSTEM ' return control to the operating system
PRINT ProgramName$ + " finished."
END
' /////////////////////////////////////////////////////////////////////////////
' Rounding and math.
' http://www.qb64.net/forum/index_PHPSESSID_gulg2aoa966472fnfhjkgp4i35_topic_14266-0/
'
' Rounding up to n decimal places?
' https://www.qb64.org/forum/index.php?topic=3605.0
' Quote from: SMcNeill on May 16, 2017, 06:57:17 pm
' Can also try:
' INT(number * 100)/100
' Now that worked.
' STR$(INT(myprice * 100) / 100)
' Perfectly drops all the numbers to 2 decimal places.
' What a relief. Thank you so much and everyone else who gave advice. :)
' Quote from: bplus on Today at 02:13:29 PM
' There is round Keyword check Wiki, might be _round
' you have to add 1/2 of 10 ^ DP to x
' EDIT: crap it's .5 * (1/10^DP)
SUB main (ProgName$)
DIM RoutineName AS STRING:: RoutineName = "main"
DIM in$
DIM arrOutput(100, 4) AS STRING
DIM s1!
DIM s2!
DIM d1#
DIM d2#
DIM f1##
DIM f2##
DIM iLine1 AS INTEGER
DIM iLine2 AS INTEGER
DIM iLine3 AS INTEGER
DIM iLine4 AS INTEGER
DIM iColumn AS INTEGER
DIM iMaxLines AS INTEGER
DIM dp% ' # decimal places
Screen _NewImage(1280, 1024, 32)
CLS
iTotal = 0
PRINT "Rounding numbers of type _FLOAT."
PRINT "Thanks to SMcNeill, bplus, and Pete for your help."
PRINT
dp% = 2 ' ROUND TO 2 DECIMAL PLACES
' ROUND FLOAT TO dp% DECIMAL PLACES
iColumn = 1
iLine1 = 1: arrOutput(iLine1, iColumn) = "Round## FLOAT TO " + _TRIM$(STR$(dp%)) + " PLACES"
iLine1 = 2: arrOutput(iLine1, iColumn) = RightPadString$("Original", 10, " ") + " " + RightPadString$("Rounded", 10, " ")
FOR f1## = 0.3 TO 0.4 STEP 0.002
iLine1 = iLine1 + 1
f2## = Round##(f1##, dp%)
arrOutput(iLine1, iColumn) = RightPadString$(FloatToStr$(f1##), 10, " ") + " -> " + RightPadString$(FloatToStr$(f2##), 10, " ")
NEXT f1##
iMaxLines = iLine1
' ROUND FLOAT UP TO 3 DECIMAL PLACES
iColumn = 2
iLine2 = 1: arrOutput(iLine2, iColumn) = "RoundUp## FLOAT TO " + _TRIM$(STR$(dp%)) + " PLACES"
iLine2 = 2: arrOutput(iLine2, iColumn) = RightPadString$("Original", 10, " ") + " " + RightPadString$("Rounded", 10, " ")
FOR f1## = 0.3 TO 0.4 STEP 0.002
iLine2 = iLine2 + 1
f2## = RoundUp##(f1##, dp%)
arrOutput(iLine2, iColumn) = RightPadString$(FloatToStr$(f1##), 10, " ") + " -> " + RightPadString$(FloatToStr$(f2##), 10, " ")
IF iLine2 > iMaxLines THEN
iMaxLines = iLine2
arrOutput(iLine2, 1) = ""
END IF
NEXT f1##
' ROUND FLOAT DOWN TO 3 DECIMAL PLACES
iColumn = 3
iLine3 = 1: arrOutput(iLine3, iColumn) = "RoundDown## FLOAT TO " + _TRIM$(STR$(dp%)) + " PLACES"
iLine3 = 2: arrOutput(iLine3, iColumn) = RightPadString$("Original", 10, " ") + " " + RightPadString$("Rounded", 10, " ")
FOR f1## = 0.3 TO 0.4 STEP 0.002
iLine3 = iLine3 + 1
f2## = RoundDown##(f1##, dp%)
arrOutput(iLine3, iColumn) = RightPadString$(FloatToStr$(f1##), 10, " ") + " -> " + RightPadString$(FloatToStr$(f2##), 10, " ")
IF iLine3 > iMaxLines THEN
iMaxLines = iLine3
arrOutput(iLine3, 1) = ""
END IF
NEXT f1##
' ROUND FLOAT SCIENTIFIC TO 3 DECIMAL PLACES
iColumn = 4
iLine4 = 1: arrOutput(iLine4, iColumn) = "RoundScientific## FLOAT TO " + _TRIM$(STR$(dp%)) + " PLACES"
iLine4 = 2: arrOutput(iLine4, iColumn) = RightPadString$("Original", 10, " ") + " " + RightPadString$("Rounded", 10, " ")
FOR f1## = 0.3 TO 0.4 STEP 0.002
iLine4 = iLine4 + 1
f2## = RoundScientific##(f1##, dp%)
arrOutput(iLine4, iColumn) = RightPadString$(FloatToStr$(f1##), 10, " ") + " -> " + RightPadString$(FloatToStr$(f2##), 10, " ")
IF iLine4 > iMaxLines THEN
iMaxLines = iLine4
arrOutput(iLine4, 1) = ""
END IF
NEXT f1##
FOR iLine1 = 1 TO iMaxLines
PRINT "" + _
RightPadString$(arrOutput(iLine1, 1), 30, " ") + " " + _
RightPadString$(arrOutput(iLine1, 2), 30, " ") + " " + _
RightPadString$(arrOutput(iLine1, 3), 30, " ") + " " + _
RightPadString$(arrOutput(iLine1, 4), 30, " ")
NEXT iLine1
PRINT
INPUT "PRESS <ENTER> TO CONTINUE", in$
CLS
iTotal = 0
PRINT "Rounding numbers of type DOUBLE."
PRINT "Thanks to SMcNeill, bplus, and Pete for your help."
PRINT
dp% = 2 ' ROUND TO 2 DECIMAL PLACES
' ROUND DOUBLE TO dp% DECIMAL PLACES
iColumn = 1
iLine1 = 1: arrOutput(iLine1, iColumn) = "RoundDouble# TO " + _TRIM$(STR$(dp%)) + " PLACES"
iLine1 = 2: arrOutput(iLine1, iColumn) = RightPadString$("Original", 10, " ") + " " + RightPadString$("Rounded", 10, " ")
FOR d1# = 0.3 TO 0.4 STEP 0.002
iLine1 = iLine1 + 1
d2# = RoundDouble#(d1#, dp%)
arrOutput(iLine1, iColumn) = RightPadString$(DblToStr$(d1#), 10, " ") + " -> " + RightPadString$(DblToStr$(d2#), 10, " ")
NEXT d1#
iMaxLines = iLine1
' ROUND DOUBLE UP TO 3 DECIMAL PLACES
iColumn = 2
iLine2 = 1: arrOutput(iLine2, iColumn) = "RoundUpDouble# TO " + _TRIM$(STR$(dp%)) + " PLACES"
iLine2 = 2: arrOutput(iLine2, iColumn) = RightPadString$("Original", 10, " ") + " " + RightPadString$("Rounded", 10, " ")
FOR d1# = 0.3 TO 0.4 STEP 0.002
iLine2 = iLine2 + 1
d2# = RoundUpDouble#(d1#, dp%)
arrOutput(iLine2, iColumn) = RightPadString$(DblToStr$(d1#), 10, " ") + " -> " + RightPadString$(DblToStr$(d2#), 10, " ")
IF iLine2 > iMaxLines THEN
iMaxLines = iLine2
arrOutput(iLine2, 1) = ""
END IF
NEXT d1#
' ROUND DOUBLE DOWN TO 3 DECIMAL PLACES
iColumn = 3
iLine3 = 1: arrOutput(iLine3, iColumn) = "RoundDownDouble# TO " + _TRIM$(STR$(dp%)) + " PLACES"
iLine3 = 2: arrOutput(iLine3, iColumn) = RightPadString$("Original", 10, " ") + " " + RightPadString$("Rounded", 10, " ")
FOR d1# = 0.3 TO 0.4 STEP 0.002
iLine3 = iLine3 + 1
d2# = RoundDownDouble#(d1#, dp%)
arrOutput(iLine3, iColumn) = RightPadString$(DblToStr$(d1#), 10, " ") + " -> " + RightPadString$(DblToStr$(d2#), 10, " ")
IF iLine3 > iMaxLines THEN
iMaxLines = iLine3
arrOutput(iLine3, 1) = ""
END IF
NEXT d1#
' ROUND DOUBLE SCIENTIFIC TO 3 DECIMAL PLACES
iColumn = 4
iLine4 = 1: arrOutput(iLine4, iColumn) = "RoundScientificDouble# TO " + _TRIM$(STR$(dp%)) + " PLACES"
iLine4 = 2: arrOutput(iLine4, iColumn) = RightPadString$("Original", 10, " ") + " " + RightPadString$("Rounded", 10, " ")
FOR d1# = 0.3 TO 0.4 STEP 0.002
iLine4 = iLine4 + 1
d2# = RoundScientificDouble#(d1#, dp%)
arrOutput(iLine4, iColumn) = RightPadString$(DblToStr$(d1#), 10, " ") + " -> " + RightPadString$(DblToStr$(d2#), 10, " ")
IF iLine4 > iMaxLines THEN
iMaxLines = iLine4
arrOutput(iLine4, 1) = ""
END IF
NEXT d1#
FOR iLine1 = 1 TO iMaxLines
PRINT "" + _
RightPadString$(arrOutput(iLine1, 1), 30, " ") + " " + _
RightPadString$(arrOutput(iLine1, 2), 30, " ") + " " + _
RightPadString$(arrOutput(iLine1, 3), 30, " ") + " " + _
RightPadString$(arrOutput(iLine1, 4), 30, " ")
NEXT iLine1
PRINT
INPUT "PRESS <ENTER> TO CONTINUE", in$
CLS
iTotal = 0
PRINT "Rounding numbers of type SINGLE."
PRINT "Thanks to SMcNeill, bplus, and Pete for your help."
PRINT
dp% = 2 ' ROUND TO 2 DECIMAL PLACES
' ROUND SINGLE TO dp% DECIMAL PLACES
iColumn = 1
iLine1 = 1: arrOutput(iLine1, iColumn) = "RoundSingle! TO " + _TRIM$(STR$(dp%)) + " PLACES"
iLine1 = 2: arrOutput(iLine1, iColumn) = RightPadString$("Original", 10, " ") + " " + RightPadString$("Rounded", 10, " ")
FOR s1! = 0.3 TO 0.4 STEP 0.002
iLine1 = iLine1 + 1
s2! = RoundSingle!(s1!, dp%)
arrOutput(iLine1, iColumn) = RightPadString$(SngToStr$(s1!), 10, " ") + " -> " + RightPadString$(SngToStr$(s2!), 10, " ")
NEXT s1!
iMaxLines = iLine1
' ROUND SINGLE UP TO 3 DECIMAL PLACES
iColumn = 2
iLine2 = 1: arrOutput(iLine2, iColumn) = "RoundUpSingle! TO " + _TRIM$(STR$(dp%)) + " PLACES"
iLine2 = 2: arrOutput(iLine2, iColumn) = RightPadString$("Original", 10, " ") + " " + RightPadString$("Rounded", 10, " ")
FOR s1! = 0.3 TO 0.4 STEP 0.002
iLine2 = iLine2 + 1
s2! = RoundUpSingle!(s1!, dp%)
arrOutput(iLine2, iColumn) = RightPadString$(SngToStr$(s1!), 10, " ") + " -> " + RightPadString$(SngToStr$(s2!), 10, " ")
IF iLine2 > iMaxLines THEN
iMaxLines = iLine2
arrOutput(iLine2, 1) = ""
END IF
NEXT s1!
' ROUND SINGLE DOWN TO 3 DECIMAL PLACES
iColumn = 3
iLine3 = 1: arrOutput(iLine3, iColumn) = "RoundDownSingle! TO " + _TRIM$(STR$(dp%)) + " PLACES"
iLine3 = 2: arrOutput(iLine3, iColumn) = RightPadString$("Original", 10, " ") + " " + RightPadString$("Rounded", 10, " ")
FOR s1! = 0.3 TO 0.4 STEP 0.002
iLine3 = iLine3 + 1
s2! = RoundDownSingle!(s1!, dp%)
arrOutput(iLine3, iColumn) = RightPadString$(SngToStr$(s1!), 10, " ") + " -> " + RightPadString$(SngToStr$(s2!), 10, " ")
IF iLine3 > iMaxLines THEN
iMaxLines = iLine3
arrOutput(iLine3, 1) = ""
END IF
NEXT s1!
' ROUND SINGLE SCIENTIFIC TO 3 DECIMAL PLACES
iColumn = 4
iLine4 = 1: arrOutput(iLine4, iColumn) = "RoundScientificSingle! TO " + _TRIM$(STR$(dp%)) + " PLACES"
iLine4 = 2: arrOutput(iLine4, iColumn) = RightPadString$("Original", 10, " ") + " " + RightPadString$("Rounded", 10, " ")
FOR s1! = 0.3 TO 0.4 STEP 0.002
iLine4 = iLine4 + 1
s2! = RoundScientificSingle!(s1!, dp%)
arrOutput(iLine4, iColumn) = RightPadString$(SngToStr$(s1!), 10, " ") + " -> " + RightPadString$(SngToStr$(s2!), 10, " ")
IF iLine4 > iMaxLines THEN
iMaxLines = iLine4
arrOutput(iLine4, 1) = ""
END IF
NEXT s1!
FOR iLine1 = 1 TO iMaxLines
PRINT "" + _
RightPadString$(arrOutput(iLine1, 1), 30, " ") + " " + _
RightPadString$(arrOutput(iLine1, 2), 30, " ") + " " + _
RightPadString$(arrOutput(iLine1, 3), 30, " ") + " " + _
RightPadString$(arrOutput(iLine1, 4), 30, " ")
NEXT iLine1
PRINT
INPUT "PRESS <ENTER> TO CONTINUE", in$
END SUB ' main
' /////////////////////////////////////////////////////////////////////////////
' https://www.qb64.org/forum/index.php?topic=3605.0
' Quote from: SMcNeill on Today at 03:53:48 PM
'
' Sometimes, you guys make things entirely too complicated.
' There ya go! Three functions to either round naturally,
' always round down, or always round up, to whatever number of digits you desire.
' EDIT: Modified to add another option to round scientific,
' since you had it's description included in your example.
' Receives + returns _FLOAT myVar## (-1.18E-4932 to +1.18E+4932)
' =============================================================================
' ROUNDING FUNCTIONS FOR TYPE _FLOAT
FUNCTION Round## (num##, digits%)
Round## = INT(num## * 10 ^ digits% + .5) / 10 ^ digits%
END FUNCTION
FUNCTION RoundUp## (num##, digits%)
RoundUp## = _CEIL(num## * 10 ^ digits%) / 10 ^ digits%
END FUNCTION
FUNCTION RoundDown## (num##, digits%)
RoundDown## = INT(num## * 10 ^ digits%) / 10 ^ digits%
END FUNCTION
FUNCTION RoundScientific## (num##, digits%)
RoundScientific## = _ROUND(num## * 10 ^ digits%) / 10 ^ digits%
END FUNCTION
' =============================================================================
' ROUNDING FUNCTIONS FOR TYPE DOUBLE
FUNCTION RoundDouble# (num#, digits%)
RoundDouble# = INT(num# * 10 ^ digits% + .5) / 10 ^ digits%
END FUNCTION
FUNCTION RoundUpDouble# (num#, digits%)
RoundUpDouble# = _CEIL(num# * 10 ^ digits%) / 10 ^ digits%
END FUNCTION
FUNCTION RoundDownDouble# (num#, digits%)
RoundDownDouble# = INT(num# * 10 ^ digits%) / 10 ^ digits%
END FUNCTION
FUNCTION RoundScientificDouble# (num#, digits%)
RoundScientificDouble# = _ROUND(num# * 10 ^ digits%) / 10 ^ digits%
END FUNCTION
' =============================================================================
' ROUNDING FUNCTIONS FOR TYPE SINGLE
FUNCTION RoundSingle! (num!, digits%)
RoundSingle! = INT(num! * 10 ^ digits% + .5) / 10 ^ digits%
END FUNCTION
' NOTE: not sure this one works: when digits%=3, it rounds .31 to .32
FUNCTION RoundUpSingle! (num!, digits%)
RoundUpSingle! = _CEIL(num! * 10 ^ digits%) / 10 ^ digits%
END FUNCTION
FUNCTION RoundDownSingle! (num!, digits%)
RoundDownSingle! = INT(num! * 10 ^ digits%) / 10 ^ digits%
END FUNCTION
FUNCTION RoundScientificSingle! (num!, digits%)
RoundScientificSingle! = _ROUND(num! * 10 ^ digits%) / 10 ^ digits%
END FUNCTION
' /////////////////////////////////////////////////////////////////////////////
' Integer to string
FUNCTION cstr$ (myValue)
'cstr$ = LTRIM$(RTRIM$(STR$(myValue)))
cstr$ = _TRIM$(STR$(myValue))
END FUNCTION ' cstr$
' /////////////////////////////////////////////////////////////////////////////
' Scientific notation - QB64 Wiki
' https://www.qb64.org/wiki/Scientific_notation
' Example: A string function that displays extremely small or large exponential decimal values.
FUNCTION DblToStr$ (n#)
value$ = UCASE$(LTRIM$(STR$(n#)))
Xpos% = INSTR(value$, "D") + INSTR(value$, "E") 'only D or E can be present
IF Xpos% THEN
expo% = VAL(MID$(value$, Xpos% + 1))
IF VAL(value$) < 0 THEN
sign$ = "-"
valu$ = MID$(value$, 2, Xpos% - 2)
ELSE
valu$ = MID$(value$, 1, Xpos% - 1)
END IF
dot% = INSTR(valu$, ".")
L% = LEN(valu$)
IF expo% > 0 THEN
add$ = STRING$(expo% - (L% - dot%), "0")
END IF
IF expo% < 0 THEN
min$ = STRING$(ABS(expo%) - (dot% - 1), "0")
DP$ = "."
END IF
FOR n = 1 TO L%
IF MID$(valu$, n, 1) <> "." THEN
num$ = num$ + MID$(valu$, n, 1)
END IF
NEXT n
ELSE
DblToStr$ = value$
EXIT FUNCTION
END IF
DblToStr$ = _TRIM$(sign$ + DP$ + min$ + num$ + add$)
END FUNCTION ' DblToStr$
' /////////////////////////////////////////////////////////////////////////////
' Scientific notation - QB64 Wiki
' https://www.qb64.org/wiki/Scientific_notation
' Example: A string function that displays extremely small or large exponential decimal values.
FUNCTION FloatToStr$ (n##)
value$ = UCASE$(LTRIM$(STR$(n##)))
Xpos% = INSTR(value$, "D") + INSTR(value$, "E") 'only D or E can be present
IF Xpos% THEN
expo% = VAL(MID$(value$, Xpos% + 1))
IF VAL(value$) < 0 THEN
sign$ = "-"
valu$ = MID$(value$, 2, Xpos% - 2)
ELSE
valu$ = MID$(value$, 1, Xpos% - 1)
END IF
dot% = INSTR(valu$, ".")
L% = LEN(valu$)
IF expo% > 0 THEN
add$ = STRING$(expo% - (L% - dot%), "0")
END IF
IF expo% < 0 THEN
min$ = STRING$(ABS(expo%) - (dot% - 1), "0")
DP$ = "."
END IF
FOR n = 1 TO L%
IF MID$(valu$, n, 1) <> "." THEN
num$ = num$ + MID$(valu$, n, 1)
END IF
NEXT n
ELSE
FloatToStr$ = value$
EXIT FUNCTION
END IF
FloatToStr$ = _TRIM$(sign$ + DP$ + min$ + num$ + add$)
END FUNCTION ' FloatToStr$
' /////////////////////////////////////////////////////////////////////////////
' Scientific notation - QB64 Wiki
' https://www.qb64.org/wiki/Scientific_notation
' Example: A string function that displays extremely small or large exponential decimal values.
FUNCTION SngToStr$ (n!)
value$ = UCASE$(LTRIM$(STR$(n!)))
Xpos% = INSTR(value$, "D") + INSTR(value$, "E") 'only D or E can be present
IF Xpos% THEN
expo% = VAL(MID$(value$, Xpos% + 1))
IF VAL(value$) < 0 THEN
sign$ = "-"
valu$ = MID$(value$, 2, Xpos% - 2)
ELSE
valu$ = MID$(value$, 1, Xpos% - 1)
END IF
dot% = INSTR(valu$, ".")
L% = LEN(valu$)
IF expo% > 0 THEN
add$ = STRING$(expo% - (L% - dot%), "0")
END IF
IF expo% < 0 THEN
min$ = STRING$(ABS(expo%) - (dot% - 1), "0")
DP$ = "."
END IF
FOR n = 1 TO L%
IF MID$(valu$, n, 1) <> "." THEN
num$ = num$ + MID$(valu$, n, 1)
END IF
NEXT n
ELSE
SngToStr$ = value$
EXIT FUNCTION
END IF
SngToStr$ = _TRIM$(sign$ + DP$ + min$ + num$ + add$)
END FUNCTION ' SngToStr$
' /////////////////////////////////////////////////////////////////////////////
' By sMcNeill from https://www.qb64.org/forum/index.php?topic=896.0
FUNCTION IsNum% (text$)
DIM a$
DIM b$
a$ = _TRIM$(text$)
b$ = _TRIM$(STR$(VAL(text$)))
IF a$ = b$ THEN
IsNum% = TRUE
ELSE
IsNum% = FALSE
END IF
END FUNCTION ' IsNum%
' /////////////////////////////////////////////////////////////////////////////
FUNCTION RightPadString$ (myString$, toWidth%, padChar$)
RightPadString$ = LEFT$(myString$ + STRING$(toWidth%, padChar$), toWidth%)
END FUNCTION ' RightPadString$
' ################################################################################################################################################################
' #REFERENCE
' =============================================================================
' SOME USEFUL STUFF FOR REFERENCE:
' Type Name Type suffix symbol Minimum value Maximum value Size in Bytes
' --------------------- ------------------ ---------------------------- -------------------------- -------------
' _BIT ` -1 0 1/8
' _BIT * n `n -128 127 n/8
' _UNSIGNED _BIT ~` 0 1 1/8
' _BYTE %% -128 127 1
' _UNSIGNED _BYTE ~%% 0 255 1
' INTEGER % -32,768 32,767 2
' _UNSIGNED INTEGER ~% 0 65,535 2
' LONG & -2,147,483,648 2,147,483,647 4
' _UNSIGNED LONG ~& 0 4,294,967,295 4
' _INTEGER64 && -9,223,372,036,854,775,808 9,223,372,036,854,775,807 8
' _UNSIGNED _INTEGER64 ~&& 0 18,446,744,073,709,551,615 8
' SINGLE ! or none -2.802597E-45 +3.402823E+38 4
' DOUBLE # -4.490656458412465E-324 +1.797693134862310E+308 8
' _FLOAT ## -1.18E-4932 +1.18E+4932 32(10 used)
' _OFFSET %& -9,223,372,036,854,775,808 9,223,372,036,854,775,807 Use LEN
' _UNSIGNED _OFFSET ~%& 0 18,446,744,073,709,551,615 Use LEN
' _MEM none combined memory variable type N/A Use LEN
' div: int1% = num1% \ den1%
' mod: rem1% = num1% MOD den1%