Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
ConvertTo
#1
A simple function so we can make certain that we convert a value to the type that we want it to be when doing math stuffs.  

Code: (Select All)
PRINTConvertTo("bit", -1)
PRINT ConvertTo("unsigned bit", -1)
PRINT ConvertTo("byte", -1)
PRINT ConvertTo("~ byte", -1)
PRINT ConvertTo("integer", -1)
PRINT ConvertTo("unsigned integer", -1)
PRINT ConvertTo("&", -1)
PRINT ConvertTo("~&", -1)

PRINT
PRINT "And here's why this type of stuff is needed:"
DIM UL AS _UNSIGNED LONG: UL = 1
PRINT -1 * UL, ConvertTo("&", -1 * UL), "const * unsigned long = unsigned long"
PRINT -1` * UL, ConvertTo("&", -1` * UL), "bit * unsigned long = unsigned long"
PRINT -1%% * UL, ConvertTo("&", -1%% * UL), "byte * unsigned long = unsigned long"
PRINT -1% * UL, ConvertTo("&", -1% * UL), "integer * unsigned long = unsigned long"
PRINT -1& * UL, ConvertTo("&", -1& * UL), "long * unsigned long = unsigned long"
PRINT -1&& * UL, ConvertTo("&", -1&& * UL), "integer64 * unsigned long = integer64"


FUNCTION ConvertTo## (type$, num##)
    temp$ = _TRIM$(UCASE$(type$))

    'check for some unsigned indicators
    IF LEFT$(temp$, 1) = "~" THEN Unsigned = -1: temp$ = _TRIM$(MID$(temp$, 2))
    IF LEFT$(temp$, 8) = "UNSIGNED" THEN Unsigned = -1: temp$ = _TRIM$(MID$(temp$, 9))
    IF LEFT$(temp$, 1) = "U" THEN Unsigned = -1: temp$ = _TRIM$(MID$(temp$, 2))

    'convert to the desired type
    SELECT CASE UCASE$(temp$)
        CASE "LONG", "&"
            IF Unsigned THEN
                temp~& = num##
                ConvertTo = temp~&
            ELSE
                temp& = num##
                ConvertTo = temp&
            END IF
        CASE "BIT", "`"
            IF Unsigned THEN
                temp~` = num##
                ConvertTo = temp~`
            ELSE
                temp` = num##
                ConvertTo = temp`
            END IF
        CASE "BYTE", "%%"
            IF Unsigned THEN
                temp~%% = num##
                ConvertTo = temp~%%
            ELSE
                temp%% = num##
                ConvertTo = temp%%
            END IF
        CASE "INT", "INTEGER", "%"
            IF Unsigned THEN
                temp~% = num##
                ConvertTo = temp~%
            ELSE
                temp% = num##
                ConvertTo = temp%
            END IF
        CASE "INT64", "INTEGER64", "_INTEGER64", "&&"
            IF Unsigned THEN
                temp~&& = num##
                ConvertTo = temp~&&
            ELSE
                temp&& = num##
                ConvertTo = temp&&
            END IF
        CASE "SINGLE", "!"
            temp! = num##
            ConvertTo = temp!
        CASE "DOUBLE", "#"
            temp# = num##
            ConvertTo = temp#
        CASE "FLOAT", "_FLOAT", "##"
            temp! = num##
            ConvertTo = temp!
    END SELECT
END FUNCTION

QB64 tries to assign math to the largest type that is involved in the math, and this can sometimes lead to some rather odd results.

DIM UL AS _UNSIGNED LONG
UL = -1
PRINT -1 * UL

Now, most folks would think that -1 * -1 would, of course, be 1.   

It's NOT.

The reason is we're multiplying a const value of -1 (which, I think defaults to a LONG type) times an UNSIGNED LONG type, so the return value becomes and UNSIGNED LONG type for us...  and who here wants to tell us what the value of -1 is, with an UNSIGNED LONG??  (Hint:  It's not 1.  Big Grin )

So add in a simple ConvertTo command in there, make certain that the result is the type that you'd expect to get back, and you can happily do math stuffs forevermore without this type of issue biting you in the butt.

PRINT ConvertTo("Long", -1 * UL)   <-- and this would print the LONG value of the result and not the UNSIGNED LONG value.

Simple enough, right?  Wink
Reply
#2
Nice, but you're explanation was a little too "&".

Pete
Reply
#3
hello SMcNeill Smile 
you have a good idea, so why not instead of one ConvertTo  function have separate functions for each type AND add them to QB64pe?
so your example would be: PRINT Long( -1 * UL) 
this would agree with how other programming languages work
Reply
#4
It's just a personal preference.  I'd personallu rather just have a single command than have to have a different one for each type out there.

bit, byte, integer, long,  integer64 -- all signed and unsigned
single, double, float
offset -- signed and unsigned

15 new commands just to convert a value to the proper type.  (If I'm counting right at 4AM in the morning.  Big Grin )

If one was to go that route, I think I'd personally prefer a very simple number type system:

Int1, Int8, Int16, Int32,Int64 -- all integers, with the number being the number of bits in them.
UInt1, UInt8, UInt16, UInt32, UInt64 -- all unsigned integers, with the numbers representing bits in them.
Float32, Float64, Float256 -- same here for floating point values.

Short names, with less typing involved, and which would all group closely together and be easily to see/highlight in the wiki for learning purposes.  (Personally, I think having to type _Unsigned_Integer64(-1 * UL) would end up breaking my fingers after pasting it into the machine 1000 times. )
Reply




Users browsing this thread: 1 Guest(s)