Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.sys.acorn.programmer > #2042 > unrolled thread

Unsigned integer comparison in Basic V

Started byRichard Porter <dontusethis@address.uk.invalid>
First post2012-08-09 18:06 +0100
Last post2012-08-13 16:19 +0100
Articles 11 — 7 participants

Back to article view | Back to comp.sys.acorn.programmer


Contents

  Unsigned integer comparison in Basic V Richard Porter <dontusethis@address.uk.invalid> - 2012-08-09 18:06 +0100
    Re: Unsigned integer comparison in Basic V Martin Bazley <martin.bazley@blueyonder.co.uk> - 2012-08-09 23:56 +0100
      Re: Unsigned integer comparison in Basic V Richard Porter <dontusethis@address.uk.invalid> - 2012-08-10 12:12 +0100
        Re: Unsigned integer comparison in Basic V "Ste (news)" <steve@revi11.plus.com> - 2012-08-10 14:10 +0100
          Re: Unsigned integer comparison in Basic V Jeremy Nicoll - news posts <jn.nntp.scrap007@wingsandbeaks.org.uk> - 2012-08-10 14:58 +0100
            Re: Unsigned integer comparison in Basic V "Ste (news)" <steve@revi11.plus.com> - 2012-08-13 16:14 +0100
          Re: Unsigned integer comparison in Basic V Steve Drain <steve@kappa.me.uk> - 2012-08-10 16:11 +0100
        Re: Unsigned integer comparison in?Basic V Justin Fletcher <gerph@gerph.org> - 2012-08-10 15:25 +0100
      Re: Unsigned integer comparison in Basic V jgh@arcade.demon.co.uk - 2012-08-10 15:49 -0700
        Re: Unsigned integer comparison in Basic V Martin Bazley <martin.bazley@blueyonder.co.uk> - 2012-08-11 19:44 +0100
        Re: Unsigned integer comparison in Basic V Richard Porter <dontusethis@address.uk.invalid> - 2012-08-13 16:19 +0100

#2042 — Unsigned integer comparison in Basic V

FromRichard Porter <dontusethis@address.uk.invalid>
Date2012-08-09 18:06 +0100
SubjectUnsigned integer comparison in Basic V
Message-ID<9d64a2bc52.news@user.minijem.plus.com>
In the latest update to SiteMatch I needed to compare timestamps which 
are 40-bit integers held in two words. Unfortunately comparing the 
bottom word went wrong because it was treated as being signed. As a 
result I had to write a little function to do an unsigned comparison 
which involved testing whether each integer was less than zero or not.

I was wondering if anyone has a neater solution to this problem, which 
has no doubt been encountered many times.

-- 
Richard Porter
rich@ / www. richardporter.me.uk
"You can't have Windows without pains."

[toc] | [next] | [standalone]


#2044

FromMartin Bazley <martin.bazley@blueyonder.co.uk>
Date2012-08-09 23:56 +0100
Message-ID<2e75c2bc52.martin@blueyonder.co.uk>
In reply to#2042
The following bytes were arranged on 9 Aug 2012 by Richard Porter :

> In the latest update to SiteMatch I needed to compare timestamps which
> are 40-bit integers held in two words. Unfortunately comparing the
> bottom word went wrong because it was treated as being signed. As a
> result I had to write a little function to do an unsigned comparison
> which involved testing whether each integer was less than zero or not.
>
> I was wondering if anyone has a neater solution to this problem, which
> has no doubt been encountered many times.

BASIC doesn't have unsigned integers, and this is extremely annoying.
(What, for example, will happen when the file size limit is increased
from 2GB to 4GB in the near future?)

The way I would probably have done it is with an assembler routine such
as the following:

codelimit%=64
DIM code% codelimit%-1
FOR pass%=8 TO 10 STEP 2
P%=code%:L%=code%+codelimit%
[OPT pass%
.unsigned_le%
CMP R0,R1
MOV R0,#0
MVNLS R0,#0
MOV PC,R14
.unsigned_lt%
CMP R0,R1
MOV R0,#0
MVNLO R0,#0
MOV PC,R14
.unsigned_ge%
CMP R0,R1
MOV R0,#0
MVNHS R0,#0
MOV PC,R14
.unsigned_gt%
CMP R0,R1
MOV R0,#0
MVNHI R0,#0
MOV PC,R14
]
NEXT

...And then, to make it a bit nicer, you could have veneers like these:

DEF FNunsigned_le(A%,B%)=USR(unsigned_le%)
DEF FNunsigned_lt(A%,B%)=USR(unsigned_lt%)
DEF FNunsigned_ge(A%,B%)=USR(unsigned_ge%)
DEF FNunsigned_gt(A%,B%)=USR(unsigned_gt%)

So, instead of writing "IF filesize1%<filesize2%", you'd write "IF
FNunsigned_lt(filesize1%,filesize2%)".

A bit unwieldy, I know, but that's BASIC for you.  Generally speaking,
mathematical operations with a large number of bits are easier to do in
assembler, which has features like unsigned comparisons and the carry
flag to help you.

By the way, if you want to compare two numbers of more than 32 bits each
(such as, say, 40-bit datestamps), you could try the following
(completely untested!) extension:

.unsigned_lt64%
CMP R1,R3
CMPEQ R0,R2
MOV R0,#0
MVNLO R0,#0
MOV PC,R14

DEF FNunsigned_lt64(A%,B%,C%,D%)=USR(unsigned_lt64%)

IF FNunsigned_lt64(lowbits1%,highbits1%,lowbits2%,highbits2%)...

-- 
  __<^>__
 / _   _ \           It is written that Geeks shall inherit the Earth.
( ( |_| ) )
 \_>   <_/  ======================= Martin Bazley ==========================

[toc] | [prev] | [next] | [standalone]


#2045

FromRichard Porter <dontusethis@address.uk.invalid>
Date2012-08-10 12:12 +0100
Message-ID<cfd705bd52.news@user.minijem.plus.com>
In reply to#2044
The date being 9 Aug 2012, Martin Bazley 
<martin.bazley@blueyonder.co.uk> decided to write:

> By the way, if you want to compare two numbers of more than 32 bits each
> (such as, say, 40-bit datestamps), you could try the following
> (completely untested!) extension:

> .unsigned_lt64%
> CMP R1,R3
> CMPEQ R0,R2
> MOV R0,#0
> MVNLO R0,#0
> MOV PC,R14

> DEF FNunsigned_lt64(A%,B%,C%,D%)=USR(unsigned_lt64%)

> IF FNunsigned_lt64(lowbits1%,highbits1%,lowbits2%,highbits2%)...

Thanks. Yes, if I'm going to do it in assembler then I might as well 
do the whole 40-bit comparison in one go.

Cheers,
-- 
Richard Porter
rich@ / www. richardporter.me.uk
"You can't have Windows without pains."

[toc] | [prev] | [next] | [standalone]


#2046

From"Ste (news)" <steve@revi11.plus.com>
Date2012-08-10 14:10 +0100
Message-ID<52bd10a2f3steve@revi11.plus.com>
In reply to#2045
In article <cfd705bd52.news@user.minijem.plus.com>,
   Richard Porter <dontusethis@address.uk.invalid> wrote:
> Thanks. Yes, if I'm going to do it in assembler then I might as well do
> the whole 40-bit comparison in one go.

Or, with !Routines from www.7thsoftware.co.uk/software.htm

  LIBRARY "<Routines$Linker>"
  PROC`library("maths.int64")

  REM Unsigned 64 bit comparison
  CASE SGN FN`ucmp64(lo_t0%,hi_t1%, lo_t1%,hi_t1%) OF
    WHEN -1
      REM t0 < t1
    WHEN +1
      REM t0 > t1
    OTHERWISE
      REM t0 = t1
  ENDCASE

where lo_ is the least-significant word (bottom 32 bits) and hi_ the most
significant (top 32 bits).

Ta,

Steve

-- 
Steve Revill @ Home
Note: All opinions expressed herein are my own.

[toc] | [prev] | [next] | [standalone]


#2050

FromJeremy Nicoll - news posts <jn.nntp.scrap007@wingsandbeaks.org.uk>
Date2012-08-10 14:58 +0100
Message-ID<mpro.m8jlhs007kw0f02oo@wingsandbeaks.org.uk.invalid>
In reply to#2046
"Ste (news)" <steve@revi11.plus.com> wrote:


>  REM Unsigned 64 bit comparison
>  CASE SGN FN`ucmp64(lo_t0%,hi_t1%, lo_t1%,hi_t1%) OF

Should that be               hi_t0%   ?   



-- 
Jeremy C B Nicoll - my opinions are my own.

Email sent to my from-address will be deleted. Instead, please reply
to newsreplyaaa@wingsandbeaks.org.uk replacing "aaa" by "284".  

[toc] | [prev] | [next] | [standalone]


#2076

From"Ste (news)" <steve@revi11.plus.com>
Date2012-08-13 16:14 +0100
Message-ID<52bea7821asteve@revi11.plus.com>
In reply to#2050
In article <mpro.m8jlhs007kw0f02oo@wingsandbeaks.org.uk.invalid>,
   Jeremy Nicoll - news posts <jn.nntp.scrap007@wingsandbeaks.org.uk> wrote:
> "Ste (news)" <steve@revi11.plus.com> wrote:
> >  REM Unsigned 64 bit comparison
> >  CASE SGN FN`ucmp64(lo_t0%,hi_t1%, lo_t1%,hi_t1%) OF
>
> Should that be               hi_t0%   ?   

Yes. It wouldn't be usenet if I'd got my example right... ;)

Steve

-- 
Steve Revill @ Home
Note: All opinions expressed herein are my own.

[toc] | [prev] | [next] | [standalone]


#2055

FromSteve Drain <steve@kappa.me.uk>
Date2012-08-10 16:11 +0100
Message-ID<Rx9Vr.738315$gC5.518647@fx10.am4>
In reply to#2046
Ste (news) wrote:
> Richard Porter wrote:
>> Thanks. Yes, if I'm going to do it in assembler then I might as well do
>> the whole 40-bit comparison in one go.
> Or, with !Routines from www.7thsoftware.co.uk/software.htm

I did announce a long integer library back in December:

   http://www.kappa.me.uk/longs.htm

This creates long integers using normal integer variables and can do 
most operations on them, including comparisons.

The functionality will eventually get included in Basalt, but it might 
be worth a look.

Steve

[toc] | [prev] | [next] | [standalone]


#2054 — Re: Unsigned integer comparison in?Basic V

FromJustin Fletcher <gerph@gerph.org>
Date2012-08-10 15:25 +0100
SubjectRe: Unsigned integer comparison in?Basic V
Message-ID<alpine.DEB.1.10.1208101436530.6010@buttercup.gerph.org>
In reply to#2045
On Fri, 10 Aug 2012, Richard Porter wrote:

> The date being 9 Aug 2012, Martin Bazley
> <martin.bazley@blueyonder.co.uk> decided to write:
>
>> By the way, if you want to compare two numbers of more than 32 bits each
>> (such as, say, 40-bit datestamps), you could try the following
>> (completely untested!) extension:
>
>> .unsigned_lt64%
>> CMP R1,R3
>> CMPEQ R0,R2
>> MOV R0,#0
>> MVNLO R0,#0
>> MOV PC,R14
>
>> DEF FNunsigned_lt64(A%,B%,C%,D%)=USR(unsigned_lt64%)
>
>> IF FNunsigned_lt64(lowbits1%,highbits1%,lowbits2%,highbits2%)...
>
> Thanks. Yes, if I'm going to do it in assembler then I might as well
> do the whole 40-bit comparison in one go.

But not like that - that function may return with VS and would therefore 
trigger an error.

Personaly, I'd not be passing the values around in pairs of integers, but 
as pointers to a block of memory that contained them, as that's easier
to manipulate. And then you can avoid using assembler at all. Dropping to 
assembler to solve a problem is probably only sensible once you've got a 
working algorithm already - it's a form of premature optimisation to 
start writing assembler when you don't need to:

REM Compare two 40bit values, little endian.
REM v1p% pointer to first of 5 bytes in value
REM v2p% pointer to second of 5 bytes in value
REM returns -ve if v1p% < v2p%
REM         +ve if v1p% > v2p%
REM         0 if v1p% = v2p%
DEF FNcompare40bit(v1p%, v2p%)
LOCAL o%
o%=v1p%?4 - v2p%?4:IF o%<>0 THEN=o%
o%=v1p%?3 - v2p%?3:IF o%<>0 THEN=o%
o%=v1p%?2 - v2p%?2:IF o%<>0 THEN=o%
o%=v1p%?1 - v2p%?1:IF o%<>0 THEN=o%
o%=v1p%?0 - v2p%?0
=o%

It might not be as fast, but it's easy to read and debug.
And has the bonus of not requiring any understanding of BASIC or the 
calling conventions for assembler routines, at the expense of using 
indirection operators - they're not that hard though.

-- 
Gerph <http://gerph.org/>
... I was confused, and I live it all out to find
     That I'm not the only person with these things in mind

[toc] | [prev] | [next] | [standalone]


#2062

Fromjgh@arcade.demon.co.uk
Date2012-08-10 15:49 -0700
Message-ID<32103cbc-f143-4d45-8204-3f0de6ee1616@googlegroups.com>
In reply to#2044
Martin Bazley wrote:
> By the way, if you want to compare two numbers of more than 32 bits each
> (such as, say, 40-bit datestamps), you could try the following
> (completely untested!) extension:

As they're 40-bit they're going to be in memory anyway, so just
deal with them in memory (untested):

int40a%=address of 40-bit integer A
int40b%=address of 40-bit integer B

DEFFNcmp40(int40a%, int40b%)
IF int40a%!1 > int40b%!1 THEN =1
IF int40a%!1 = int40b%!1 THEN IF int40a%?0 = int40b%?0 THEN =0
=-1

Similarly for any other size of integer
DEFFNcmp64(int64a%, int64b%)
IF int64a%!4 > int64b%!4 THEN =1
IF int64a%!4 = int64b%!4 THEN IF int64a%!0 = int64b%!0 THEN =0
=-1

JGH

[toc] | [prev] | [next] | [standalone]


#2065

FromMartin Bazley <martin.bazley@blueyonder.co.uk>
Date2012-08-11 19:44 +0100
Message-ID<c30eb3bd52.martin@blueyonder.co.uk>
In reply to#2062
The following bytes were arranged on 10 Aug 2012 by jgh@arcade.demon.co.uk:

> Martin Bazley wrote:
> > By the way, if you want to compare two numbers of more than 32 bits each
> > (such as, say, 40-bit datestamps), you could try the following
> > (completely untested!) extension:
>
> As they're 40-bit they're going to be in memory anyway, so just
> deal with them in memory (untested):

Not necessarily; the usual case is reading load and exec addresses via
OS_File, where the datestamp is returned in two separate registers (one
of which also contains the filetype).  From a purely academic viewpoint
it's faster not to have to save them to memory and then load them back
again, although since the OP is using BASIC I don't suppose he's too
worried about that.

-- 
  __<^>__   "Did you know that polar bears stay white all year round? ...The
 / _   _ \  white colour makes them less visible to the seals and penguins
( ( |_| ) ) they hunt."  - Nelson Thornes AQA-endorsed GCSE science textbook
 \_>   <_/  ======================= Martin Bazley ==========================

[toc] | [prev] | [next] | [standalone]


#2077

FromRichard Porter <dontusethis@address.uk.invalid>
Date2012-08-13 16:19 +0100
Message-ID<f4fda7be52.news@user.minijem.plus.com>
In reply to#2062
The date being 10 Aug 2012, jgh@arcade.demon.co.uk decided to write:

> Martin Bazley wrote:
>> By the way, if you want to compare two numbers of more than 32 bits each
>> (such as, say, 40-bit datestamps), you could try the following
>> (completely untested!) extension:

> As they're 40-bit they're going to be in memory anyway, so just
> deal with them in memory (untested):

> int40a%=address of 40-bit integer A
> int40b%=address of 40-bit integer B

> DEFFNcmp40(int40a%, int40b%)
> IF int40a%!1 > int40b%!1 THEN =1
> IF int40a%!1 = int40b%!1 THEN IF int40a%?0 = int40b%?0 THEN =0
> =-1

I don't think that quite does what I want. I need to return TRUE if 
40-bit integer A is greater than 40-bit integer B, otherwise FALSE.

If the top bytes are different than they determine the result; if they 
are equal then it is necessary to compare the bottom 4 bytes which I 
think should be int40a%!4 and int40b%!4.

If only one of the integers is negative (as BASIC sees them) then the 
result needs to be inverted (the negative one must be the greater), 
otherwise a straight comparison works.

As regards Martin's point, although both stamps came from OS_File in a 
buffer, at this point they are stored in a 2-dimensional integer array 
including the file type.

Anyway I have decided to stick with the BASIC solution though I was 
tempted by the libraries 'routines' or 'longs' which I'd forgotten all 
about. Thanks for the suggestions.

-- 
Richard Porter
rich@ / www. richardporter.me.uk
"You can't have Windows without pains."

[toc] | [prev] | [standalone]


Back to top | Article view | comp.sys.acorn.programmer


csiph-web