As you might have noticed, the use of arrays of things is somehow limited. To be precise it is limited to BYTE! arrays.
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.
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.
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.
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
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
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
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.
By now I guess you get the drill.
+++Floating point conversion
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.
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