Making a 64-bit number from two 32-bit numbers

Discussions related to mathematics, numerical methods, graph plotting etc.
Hated Moron

Making a 64-bit number from two 32-bit numbers

Post by Hated Moron »

This is really silly, but I just can't figure it out. I want to do what sounds like an extremely simple thing: make a 64-bit number out of two 32-bit numbers, one (e.g. L%) representing the LS 32-bits and the other (e.g. H%) the MS 32-bits; it's a requirement that it works in both the (default) *HEX 32 mode and the *HEX 64 mode.

Trivial surely? But not, by all accounts. Here are some of the things I've tried:

Code: Select all

r%% = L% OR H% << 32
Doesn't work when L% is negative, because after sign-extension to 64-bits the MS 32-bits will be &FFFFFFFF which will force the MS 32-bits of the result to be &FFFFFFFF too!

Code: Select all

r%% = L% AND &FFFFFFFF OR H% << 32
Doesn't work because the &FFFFFFFF is sign-extended to &FFFFFFFFFFFFFFFF and the AND does nothing!

Code: Select all

r%% = L% AND &00000000FFFFFFFF OR H% << 32
Doesn't work because the MS 32-bits of the hexadecimal constant are discarded, so it's the same as the previous example!

Code: Select all

r%% = (L% << 32) >> 32 OR H% << 32
Doesn't work because the << operator sign-extends into the 32 MS bits!

Code: Select all

r%% = (L% <<< 32) >>> 32 OR H% <<< 32
Doesn't work because the >>> 32 ignores the MS 32-bits!

In fact the only thing I've tried which does work is this, which is messy (and triggers a warning from the Cross-Reference Utility that Y% isn't used):

Code: Select all

X% = L%
Y% = H%
r%% = ]^X%
Am I missing something obvious, or is this seemingly trivial task more difficult than you might think? Can you find a better way to do it?
Hated Moron

Re: Making a 64-bit number from two 32-bit numbers

Post by Hated Moron »

On 16/10/2023 19:18, Geoff Webb wrote (cross-posted from the Discussion Group):
Forgive my niaivity, but, why does multiplying H% by 2^32 and adding L% not work?
Perhaps I can best illustrate that by example. Suppose:

Code: Select all

      L% = &FEDCBA98
      H% = &76543210
You propose multiplying H% by 2^32:

Code: Select all

       &7654321000000000
and then adding it to L%. Remember that in BBC BASIC integers are signed so the sum becomes:

Code: Select all

       &7654321000000000
     + &FFFFFFFFFEDCBA98
     = &7654320FFEDCBA98
But the answer we wanted was:

Code: Select all

       &76543210FEDCBA98
Close, but no cigar!
p_m21987
Posts: 177
Joined: Mon 02 Apr 2018, 21:51

Re: Making a 64-bit number from two 32-bit numbers

Post by p_m21987 »

Hello,
Does this work?

Code: Select all

r%%=L% OR (&FFFFFFFF<<<32) EOR ((NOT H%)<<<32)
Regards,
PM
Hated Moron

Re: Making a 64-bit number from two 32-bit numbers

Post by Hated Moron »

On 16/10/2023 23:17, Daniel Bingamon wrote (cross-posted from the Discussion Group):
I did this with the consideration that the left shift operation simply doesn't work for 64-bits.
Huh? You're going to have to explain that comment; there are no known bugs in the working of the shift operators with 64-bit integers, given the compatibility constraints.
First I tried this:

Code: Select all

      L% = &AAAAAAAA
      H% = &55555555
      t%% = L%
      t%% = t%% * 65536
      t%% = t%% * 65536
      
      r%% = H%
      r%% = r%% + t%%
      PRINT r%%
For a start this tries to put L% (Low) in the high 32-bits and H% (High) in the low 32-bits! :roll:

If we correct that reversal:

Code: Select all

      L% = &AAAAAAAA
      H% = &55555555
      t%% = H%
      t%% = t%% * 65536
      t%% = t%% * 65536
      
      r%% = L%
      r%% = r%% + t%%
      
      *HEX 64
      PRINT ~r%%
We get &55555554AAAAAAAA which is wrong (what should have been a 5 has changed into a 4).

Irrespective of it not even working, I wonder why you would think you would get a different result from multiplying something by 2^16 twice rather than by 2^32 once.
This also worked:

Code: Select all

      L% = &AAAAAAAA
      H% = &55555555
      t%% = L%
      t%% = t%% <<< 16
      t%% = t%% <<< 16

      r% = H%
      r%% = r%% + t%%
      PRINT r%%
Again correcting the silly low/high reversal:

Code: Select all

      L% = &AAAAAAAA
      H% = &55555555
      t%% = H%
      t%% = t%% <<< 16
      t%% = t%% <<< 16

      r%% = L%
      r%% = r%% + t%%
      
      *HEX 64
      PRINT ~r%%
which gives the same incorrect value as before (not surprising as you've simply replaced a multiplication by a power-of-two with the equivalent bit shift). :(

And a similar question to the one above: why would you think shifting something by 16 bits twice would give a different result from shifting it by 32 bits once?

I must admit I'm surprised and disappointed that somebody would submit code which doesn't even get the answer right!
Hated Moron

Re: Making a 64-bit number from two 32-bit numbers

Post by Hated Moron »

p_m21987 wrote: Mon 16 Oct 2023, 22:16 Hello,
Does this work?

Code: Select all

r%%=L% OR (&FFFFFFFF<<<32) EOR ((NOT H%)<<<32)
On a quick test it seems to in *HEX 32 mode, but in *HEX 64 mode it is failing with a 'Number too big' error:

Code: Select all

      *HEX 64
      L% = &FEDCBA98
      H% = &76543210

      r%%=L% OR (&FFFFFFFF<<<32) EOR ((NOT H%)<<<32)

      *HEX 64
      PRINT ~r%%
So given that a stated requirement was that "it works in both the (default) *HEX 32 mode and the *HEX 64 mode" I'm afraid it doesn't qualify. It should score high marks in a code obfuscation contest though! :lol:
p_m21987
Posts: 177
Joined: Mon 02 Apr 2018, 21:51

Re: Making a 64-bit number from two 32-bit numbers

Post by p_m21987 »

Hated Moron wrote: Tue 17 Oct 2023, 17:00 On a quick test it seems to in *HEX 32 mode, but in *HEX 64 mode it is failing with a 'Number too big' error:
It seems like the "number too big" error is being raised by the assignment to L%, on this line:

Code: Select all

L% = &FEDCBA98
It seems to work if we change the way we assign the value to L%, like this:

Code: Select all

      *HEX 64
      L% = (&FEDCBA98<<32)>>32
      H% = &76543210

      r%%=L% OR (&FFFFFFFF<<<32) EOR ((NOT H%)<<<32)

      *HEX 64
      PRINT ~r%%
Hated Moron

Re: Making a 64-bit number from two 32-bit numbers

Post by Hated Moron »

p_m21987 wrote: Wed 18 Oct 2023, 00:05 It seems like the "number too big" error is being raised by the assignment to L%
Fair point, I ought not to penalise the initial assignment. The easiest way of fixing that is to write the constant in full:

Code: Select all

      *HEX 64
      L% = &FFFFFFFFFEDCBA98
      H% = &76543210

      r%%=L% OR (&FFFFFFFF<<<32) EOR ((NOT H%)<<<32)

      *HEX 64
      PRINT ~r%%
This is what I settled on for my application:

Code: Select all

      r%% = L% AND (2^32-1) OR H% <<< 32
User avatar
hellomike
Posts: 184
Joined: Sat 09 Jun 2018, 09:47
Location: Amsterdam

Re: Making a 64-bit number from two 32-bit numbers

Post by hellomike »

The requirement does not say that the 'concatination' has to be done in a single assignment line so, what is wrong with this?

Code: Select all

      r%% = 0
      L% = &FEDCBA98
      H% = &76543210
      P% = ^r%%
      P%!0 = H%
      P%!4 = L%
      *HEX 64
      PRINT ~r%%
Hated Moron

Re: Making a 64-bit number from two 32-bit numbers

Post by Hated Moron »

hellomike wrote: Thu 19 Oct 2023, 10:31 The requirement does not say that the 'concatination' has to be done in a single assignment line so, what is wrong with this?

Code: Select all

      r%% = 0
      L% = &FEDCBA98
      H% = &76543210
      P% = ^r%%
      P%!0 = H%
      P%!4 = L%
      *HEX 64
      PRINT ~r%%
There are two things wrong with it, that I can see. Firstly you've swapped L% and H% (as did a previous respondent); although I didn't expressly say so, I intended L% and H% to represent the Low and High words respectively, hence the choice of variable names. They do in the code I listed.

Secondly you've used a 32-bit variable P% to hold a pointer, oops! Those two faults can easily be remedied as follows:

Code: Select all

      L% = &FEDCBA98
      H% = &76543210
      p%% = ^r%%
      p%%!0 = L%
      p%%!4 = H%
      *HEX 64
      PRINT ~r%%
As I posted above, this is what I ended up using:

Code: Select all

      r%% = L% AND (2^32-1) OR H% <<< 32
I eventually realised (it took much longer than it should have) that the trick to making it work was not to use a hexadecimal constant &FFFFFFFF but to represent the same value in 'decimal'. It ticks all the boxes: short, simple and easy to understand.
User avatar
hellomike
Posts: 184
Joined: Sat 09 Jun 2018, 09:47
Location: Amsterdam

Re: Making a 64-bit number from two 32-bit numbers

Post by hellomike »

Fair points and eventually your solution indeed is the most elegant.