Qbasicnews.com

Full Version: hi-/lowbyte -> integer function
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
hi, i'm on a late night coding spree again, and i found i had to make a function that turns two values in the byte range to an integer, producing on bit level what would have been the unsigned integer but looks signed to QB. err.. yeah, can't describe it very well right now, but i think you can tell from the code what i mean.
Code:
DEFINT A-Z
FUNCTION word (hibyte, lowbyte)
    IF (hibyte AND 128) THEN
        word = -(256 * ((128 - hibyte) AND 127)) + lowbyte
    ELSE
        word = (256 * hibyte) OR lowbyte
    END IF
END FUNCTION
That's what my tired brain came up with. Please, if you know a faster way of doing it, post it. I tried another method - POKEing the hibyte - but that's slower, at least on somewhat modern CPUs that can perform those calculations fast. Oh yeah, and I'm talking about PureQB ways of doing it, of course.
Quote:hi, i'm on a late night coding spree again, and i found i had to make a function that turns two values in the byte range to an integer, producing on bit level what would have been the unsigned integer but looks signed to QB. err.. yeah, can't describe it very well right now, but i think you can tell from the code what i mean.
Code:
DEFINT A-Z
FUNCTION word (hibyte, lowbyte)
    IF (hibyte AND 128) THEN
        word = -(256 * ((128 - hibyte) AND 127)) + lowbyte
    ELSE
        word = (256 * hibyte) OR lowbyte
    END IF
END FUNCTION
That's what my tired brain came up with. Please, if you know a faster way of doing it, post it. I tried another method - POKEing the hibyte - but that's slower, at least on somewhat modern CPUs that can perform those calculations fast. Oh yeah, and I'm talking about PureQB ways of doing it, of course.

Hey...I did something similar some time back. I was turning text strings into arrays of 32-bit integers. eg, I would take the first 4 bytes of the string and use them as the first 32-bit integer in the array...the next 4-bytes would make the second integer...etc.

Code:
SUB passtolongint (a$, passarray&())
DIM textarray(1 TO LEN(a$) \ 4) AS STRING * 4
  
  FOR x = 1 TO LEN(a$) \ 4         'splits a$ into 4 byte chunks
    textarray(x) = MID$(a$, 1 + ((x - 1) * 4), 4)    'the (1 + ((x - 1) * 4) is is to make the string posistioner go 1, 5, 9, etc.
  NEXT x
  FOR p = 1 TO LEN(a$) \ 4                 'p is which 4-byte chunk
    FOR x = 1 TO 4                         'x is which digit
     digit$ = MID$(textarray(p), x, 1)
     digit = ASC(digit$)
      IF x = 1 THEN               'this deals with the fact that the binarys are represented as signed integer (4byte, 32 bit)
        IF digit > 127 THEN                'if greater than 128, call it negative and make num smaller than 128
         sign = -1
         digit = digit - 128
        ELSE sign = 1
        END IF
      END IF
     bytevalue& = digit * (256 ^ (4 - x))          'converts base 256 place
     passarray&(p) = passarray&(p) + bytevalue&  'adds base to present value
    NEXT x
   passarray&(p) = sign * passarray&(p)          'signs the number
  NEXT p
END SUB

This code uses some really unfortunate names try substituting the following:

passtolongint stringToLongArray
a$ inputString$
textarray fourBytes
digit$ aByte$
digit aByte

Anyway...I don't think any of this helps you, because we both used basically the same logic...

Looking at your code, it occurs to me...why not change the lines:

IF (hibyte AND 128) THEN
word = -(256 * ((128 - hibyte) AND 127)) + lowbyte


to

IF (hibyte AND 128) THEN
word = (-256 * (hibyte AND 127)) + lowbyte
Not sure if this is faster, but it also works:

Code:
word = CVI(CHR$(lowbyte) + CHR$(hibyte))
This is shorter than the original, and doesn't use strings. But Plasma's is probably faster because there's no IF in his.
[syntax="qbasic"]word = (hiByte * 256& + lowByte) AND &H7FFF&
IF hiByte AND &H80 THEN word = word OR &H8000[/syntax]
Quote:This is shorter than the original, and doesn't use strings. But Plasma's is probably faster because there's no IF in his.
[syntax="qbasic"]word = (hiByte * 256& + lowByte) AND &H7FFF&
IF hiByte AND &H80 THEN word = word OR &H8000[/syntax]
You can rewrite this without if:

[syntax="qbasic"]word = (hiByte * 256& + lowByte) AND &H7FFF&
word = word OR (((hiByte AND &H80) \ (2 ^ 7)) * (2& ^ 15))[/syntax]
Didn't test though Smile (should work theorethically)
Code:
'
'BYTES to INTEGER
'
lo = I AND &HFF
IF I < 0  THEN
hi = ((I AND &H7F00) \ &H100) + &H80
ELSE
hi=(I AND &H7F00) \ &H100
END IF
'
'

Code:
'
'INTEGER to BYTES
'
IF hi > &H7F THEN
I = lo + (hi - &H100) * &H100
ELSE
I = lo + hi * &H100
END IF
'
'

Those rotuines used a signed integer, but if you need unsigned
integers just convert it.
Very fast, and pure QB Smile

Nemesis
*blink, blink* *justwokeup*
great, thanks guys, i'm gonna speed-test them in a minute! Big Grin

Edit:

OK.. eww, i found an error in mine, it gives wrong results when hibyte = 128 Tongue corrected version:
Code:
FUNCTION word (hibyte, lowbyte)
    IF (hibyte AND 128) THEN
        IF hibyte = 128 THEN
            word = &H8000 OR lowbyte
        ELSE
            word = -(256 * ((128 - hibyte) AND 127)) + lowbyte
        END IF
    ELSE
        word = (256 * hibyte) OR lowbyte
    END IF
END FUNCTION

I used a slightly modified version of Nemesis's for testing:
Code:
FUNCTION word.nemesis (hibyte, lowbyte)
    IF (hibyte AND 128) THEN
        word.nemesis = lowbyte + (hibyte - 256) * 256
    ELSE
        word.nemesis = lowbyte + hibyte * 256
    END IF
END FUNCTION

The results I got.. *drumroll*

#1 Nemesis
#2 myself
#3 Sterling
#4 Plasma

Those apply to both interpreted and compiled. Oh, and on a Celeron 1GHz. Maybe Plasma's would be faster on a 286, dunno.
Without testing I would've assumed Sterling's method to be faster than mine, but the use of longs apparently drags it down quite a bit.
All routines had to perform exactly the same calculations, and those involved all cases of hibyte (>128, =128, <128). The ranking is based on several runs.

Btw, @Mango: (b AND 127) != ((128 - b) AND 127)
Wink
Btw, how about this?

[syntax="qbasic"]
'//////////////////////////////////////////////
'Only do this part once
DIM word AS INTEGER

DEF SEG = VARSEG(word)
offs% = VARPTR(word)
'/////////////////////////////////////////////
'This can be done multiple times
POKE offs%, loByte
POKE offs% + 1, hiByte
'//////////////////////////////////////////////[/syntax]
Should work theorethically and should be really fast (perhaps even faster than anything that's posted here) Wink
Quote:Should work theorethically and should be really fast (perhaps even faster than anything that's posted here) Wink
Argh, I don't feel like running the tests again Big Grin I'll just stick with Nemesis's version. Besides, I think for the lowbyte part it would be faster to just write
Code:
word = lowbyte
Like Neo said:
[syntax="qbasic"]
DIM SHARED IntSeg As Integer, IntOffs As Integer

Variable% = 0
IntSeg = VarSeg(Variable%)
IntOffs = VarPtr(Variable%)

addHiLo 1, 1
Print Variable%

addHiLo 0, 1
Print Variable%


SUB addHiLo(hiByte, loByte)
DEF SEG = IntSeg
POKE IntOffs, loByte
POKE IntOffs + 1, hiByte
END SUB[/syntax]
Pages: 1 2