Meta Project

The Unofficial Meta Documentation

Converting formats to and from Binary arrays

What is it?

As you might have noticed, the use of arrays of things is somehow limited. To be precise it is limited to BYTE! arrays.

Why?

Yes why should you be limited to this fact? Exactly! As sure as everything inside the computer is only either a zero or a one, those ones and zeroes are combined into BYTE!s and every one or zero only means one or zero until we decide what it really means for us.

So the BYTE! arrays we get in Meta can mean many things to us as programmers or users. We only need to learn how to deal with them to let them have the meaning we want them to have.

Is it an easy solution?

No. Or yes. We do the extra steps of convertion that other languages do for us. That seems like more work and yes it is, but it means also more control and freedom from all the superfluous extra's that are added otherwise and we do not have any control ov er.

The basic working

A BYTE! is 8 bits. Eight little digits of a value of either 0 or 1. Possible values are thus 0 up to 2 to the power of 8 minus 1, that is 0 to and including 255.

As a WHOLE8! type this is interpreted as -128 up to 127.

Here is a table of standard types:

Format Type Bitsize Minimum value Maximum value
WHOLE8! Signed 8-bit -128 127
BYTE! Unsigned 8-bit 0 255
WHOLE16! Signed 16-bit -32,768 32,767
NATURAL16! Unsigned 16-bit 0 65,535
WHOLE32! Signed 32-bit -2,147,483,648 2,147,483,647
NATURAL32! Unsigned 32-bit 0 4,294,967,295
WHOLE64! Signed 64-bit -9,223,372,036,854,775,808 9,223,372,036,854,775,807
NATURAL64! Unsigned 64-bit 0 18,446,744,073,709,551,615

AAdditional to these there is FLOATER32! to BYTE! array and Character to BYTE! array to be shown.

Show some conversions!

WHOLE8! to BYTE! array

A straightforward case. A WHOLE8! is nothing else than a signed BYTE! so we can store it directly.

let array binary! 32
WHOLE8! number
number: -2
poke array 1 number
what-is-in-the-array-now: pick array 1
write/line what-is-in-the-array-now

Result is now

254

BYTE! array to WHOLE8!

This is a straightforward case also. So the conversion here is trivial too.

let array binary! 32
poke array 1 254
number: to whole8! pick array 1
write/line number

Result is obviously

-2

NATURAL16! to BYTE! array

Now we get into the more interesting cases. Let's see...

let array binary! 32
NATURAL16! number
number: 65500
poke array 1 number
what-is-in-the-array-now: pick array 1
write/line what-is-in-the-array-now

And for sure this is not what you want in general.

220

Now let us use some convenience functions to determine what should go where

NATURAL16! number
number: 65500
write/line first-of number
write/line second-of number
write/line (to natural16! second-of number) * 256 + first-of number

If I get to choose how to store this into an array of BYTE! values then I say the thing that is returned as FIRST-OF goes in first, and the thing that gets returned from SECOND-OF goes into the second place.

But all experts might disagree with me on this.

For the recalculation says that the SECOND-OF part is taken, then multiplied by the base of 256 and after that the next thing is added, which is the FIRST-OF part.

You can see this as a choice between two algorithms to read a number say 1234.

First algorithm reads left to right:

numberstring: "1234"
base= 10
result: 0
while not is-empty numberstring [
    cipher: to whole! copy cut numberstring 1
    result: result * base + cipher
    advance numberstring
]
write/line result

And the other algorithm reads from right to left, and this would look something like the following that I am sure can use some cleanup.

numberstring: "1234"
base= 10
factor: 1
result: 0
length: count numberstring
while length [
    cipher: to whole! copy cut at numberstring length 1
    result: cipher * factor + result
    factor: factor * base
    decrement length
    numberstring: copy cut numberstring length
]
write/line result

In my not so humble little opinion (imnshlo) the first is more elegant.

And that calls for the reverse order :-(

let array binary! 32
NATURAL16! number
number: 65500
poke array 2 FIRST-OF number
poke array 1 SECOND-OF number
for index 2 [
    write/line to string! pick array index
]

255
220

BYTE! array to NATURAL16!

The other way around as discussed.

let array binary! 32
poke array 1 220
poke array 2 255

base= 256
NATURAL16! number
number: 0

for index 2 [
    number: base * number + pick array (3 - index)
]
write/line number

With result

65500

As it should be.

WHOLE16! to BYTE! array

BYTE! array to WHOLE16!

NATURAL32! to BYTE! array

BYTE! array to NATURAL32!

WHOLE32! to BYTE! array

BYTE! array to WHOLE32!

NATURAL64! to BYTE! array

BYTE! array to NATURAL64!

WHOLE64! to BYTE! array

By now I guess you get the drill.

BYTE! array to WHOLE64!

+++Floating point conversion

FLOATER32! to BYTE! array

According to some 'random' 32-bit floating point calculator is the number 123.456 equal to

123.456
01000010111101101110100101111001

The conversion is on the fourth line in the next piece of code.

let memory binary! 4
floater32! fp
fp: to floater32! 123.456
unportable change/binary memory fp
for index 4 [
    write/line number: to whole! pick memory index
    binary-string: ""
    repeat 8 [
        either is-odd number [
            binary-string: join/with "1" binary-string
        ][
            binary-string: join/with "0" binary-string
        ]
        number: number >> 1
    ]
    write/line binary-string
]

Results in

121
01111001
233
11101001
246
11110110
66
01000010

Which is the correct (little endian) result.

The CHANGE/BINARY just takes the thing to store and places it in the offered location and takes as much space as needed.

BYTE! array to FLOATER32!

The other way around: We fill value in the memory array and see what the result is.

let memory binary! 4
poke memory 1 139
poke memory 2 148
poke memory 3 35
poke memory 4 68
write/line unportable as floater32! memory

Instead of drectly writing the value, we can fill a variable with its value

floater32! fp
fp: as floater32! memory
write/line fp

The result we find is

654.32098388671875

And this is close the value of 654.321 that I have plugged in into the previous example to construct this one.

+++Character conversion

Characters to BYTE! array

BYTE! array to Characters