21

I no longer have my ZX81 or Spectrum, nor their manuals, but I do remember that both floating-point and integer values are stored as 40-bit values (and the motivation for that is addressed in Why does Sinclair BASIC have two formats for storing numbers in the same structure? - that question addresses the why rather than the how).

What I don't remember is the layout of the values. In particular, does it follow¹ the IEEE-754 principles, or is it a "Sinclair special", in the same way that ZX81 character encoding is unlike any standard? I'm also interested to see how the integers are encoded within the value space - if I were doing this within an IEEE-754 encoding, I'd probably co-opt the (otherwise unused) NaNs for this purpose.

Supplementary question that might fall within the same scope: does the format support subnormal numbers?


¹ I guess "presage" might be more accurate, as I think IEEE hadn't completed that standardisation activity at that time.

15
  • 3
    Quick remark: Isn't the format described in chapter 24 of the manual, mentioned in the selected answer to the linked question?Mightneed to scroll down all the way. (Secondary Q: Every normal FP format can do subnormal - it's part of teh way it is.) Commented Feb 26 at 8:38
  • 1
    @pndc - I've already explained how it's different - the question I linked is about the motivation and doesn't ask about the representation. Commented Feb 26 at 10:34
  • 1
    In other words, that question is the why, and this is the how. Commented Feb 26 at 10:40
  • 1
    @Raffzahn DEC floats before IEEE-754 couldn't do subnormal. If you have a hidden MSB, you have to reserve an exponent to designate denormalized numbers. DEC didn't do this. Commented Feb 26 at 16:27
  • 1
    @tofro SGN PI, please! Commented Feb 28 at 1:02

2 Answers 2

19

The 'how' can be found in the ZX Spectrum user manual.

Chapter 24 'The Memory' details the various memory areas maintained by ZX BASIC, including the memory format of a BASIC line and of the various types of variables.

The relevant text is below, very slightly modified for clarity here:

Any number (except 0) can be written uniquely as:

  • +/- m x 2e

where

  • +/- is the sign
  • m is the mantissa, and lies between 0.5 and 1 (it cannot be 1),
  • e is the exponent, a whole number (possibly negative).

Suppose you write m in the binary scale. Because it is a fraction, it will have a binary point (like the decimal point in the scale of ten) and then a binary fraction (like a decimal fraction); so in binary:

  • a half is written .1
  • a quarter is written .01
  • three quarters is written .11
  • a tenth is written .000110011001100110011

...and so on. With our number m, because it is less than 1, there are no bits before the binary point, and because it is at least 0.5, the bit immediately after the binary point is a 1.

To store the number in the computer, we use five bytes, as follows:

  • Write the first eight bits (b31:24) of the mantissa into the second byte (we know that the first bit, b31, is 1)
  • Write the second eight bits (b23:16) into the third byte
  • Write the third eight bits (b15:8) into the fourth byte
  • Write the fourth eight bits (b7:0) into the fifth byte.
  • Replace the first bit in the second byte (b31, which we know is 1) by the sign: 0 for plus, 1 for minus.
  • Write the exponent plus 128 into the first byte.

For instance, suppose our number is 1/10. 1/10 = 4/5x2-3

Thus the mantissa m is .11001100110011001100110011001100 in binary (since the 33rd bit is 1, we shall round the 32nd up from 0 to 1), and the exponent e is 3.

Applying our three rules gives the five bytes.

There is an alternative way of storing whole numbers between -65535 and +65535:

  • the first byte is 0.
  • the second byte is 0 for a positive number, FFh for a negative one.
  • the third and fourth bytes are the less (b7:0) and more (b15:8) significant bytes of the number (or the number +131072 if it is negative).
  • the fifth byte is 0.
4
  • That looks an awful lot like standard 40-bit Microsoft Binary Format. Commented Feb 26 at 22:34
  • 2
    @Mark, that must be some new meaning of "standard" with which I wasn't previously familiar. Who standardised it? Commented Feb 27 at 8:07
  • 6
    @TobySpeight, actually I think it's just an old meaning you're very familiar with :-), here describing 'typical' or 'familiar'. (standard (adjective). Used or accepted as normal or average e.g. "the standard rate of income tax") Commented Feb 27 at 10:41
  • 1
    Note that some routines tried to store -65536 using the small integer format with hilarious results such as INT -65536 resulting in -1. Commented Feb 28 at 1:06
12

For floating-point numbers, we use a 8-bit exponent and 31-bit mantissa.

Like IEEE-754, the exponent is in biased form, so 0000001 represents 2⁻¹²⁷, 1000000 represents 2⁰, and 1111111 represents 2⁺¹²⁷.

Unlike IEEE-754, the sign bit is stored after the exponent, not before¹.

Unusually for a Z80 system, the mantissa bytes are stored in big-endian order.

Visually:

39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
e₇ e₆ e₅ e₄ e₃ e₂ e₁ e₀ s m₃₀ m₂₉ m₂₈ m₂₇ m₂₆ m₂₅ m₂₄ m₂₃ m₂₂ m₂₁ m₂₀ m₁₉ m₁₈ m₁₇ m₁₆ m₁₅ m₁₄ m₁₃ m₁₂ m₁₁ m₁₀ m₉ m₈ m₇ m₆ m₅ m₄ m₃ m₂ m₁ m₀
39 … 32 31 30 … 0
exponent sign mantissa
8 bits 1 bit 31 bits

The unused exponent value of 0000000 is not used for denormal numbers (which are not supported in ZX Basic); instead it signals that an integer value is stored. Integers use a two's-complement representation for -65536 to +65535, sign-extended to 24 bits:

39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 s s s s s s s s i₇ i₆ i₅ i₄ i₃ i₂ i₁ i₀ i₁₅ i₁₄ i₁₃ i₁₂ i₁ i₁₀ i₉ i₈ 0 0 0 0 0 0 0 0
39 … 32 31 … 24 23 … 8 7 … 0
flag sign bits value unused
8 bits 8 bits 16 bits 8 bits
00 00 or FF little-endian 00

Combined graphic:

bit 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
float e₇ e₆ e₅ e₄ e₃ e₂ e₁ e₀ s m₃₀ m₂₉ m₂₈ m₂₇ m₂₆ m₂₅ m₂₄ m₂₃ m₂₂ m₂₁ m₂₀ m₁₉ m₁₈ m₁₇ m₁₆ m₁₅ m₁₄ m₁₃ m₁₂ m₁₁ m₁₀ m₉ m₈ m₇ m₆ m₅ m₄ m₃ m₂ m₁ m₀
integer 0 0 0 0 0 0 0 0 s s s s s s s s i₇ i₆ i₅ i₄ i₃ i₂ i₁ i₀ i₁₅ i₁₄ i₁₃ i₁₂ i₁ i₁₀ i₉ i₈ 0 0 0 0 0 0 0 0

¹ Although this adds complexity when ordering values, it simplifies access to the exponent's bits. It also means that a simple test of bit 31 finds the sign of both floating-point and integer values.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.