The IEEE754 double format is made up of a 1-bit sign, 11-bit exponent and 52-bit mantissa:
7 6 5 4 3 2 1 0
seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm
Due to the vagaries of endianness, that most significant byte on the left is actually ieee(7)
, the least significant on the right is ieee(0)
- this is the same for mbf()
below.
The exponent gives you a value of 0
through 2047
(211-1) some of which are used to represent special values like +/-inf
(infinity) and nan
(not a number).
The mantissa bits represent, from left to right, 1/2
, 1/4
, 1/8
and so on. In order to get the number, you calculate n = (-1)s x 2e-bias x 1.m
Microsoft double binary format is:
7 6 5 4 3 2 1 0
eeeeeeee smmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm
The code you see is simply transferring (and slightly changing) the values from MBF to IEEE754 double precision format.
To answer your specific questions:
Dim sign As Byte = mbf(6) And ToByte(&H80)
What is the reason for 'And &H80'?
Hex 80 (&H80
) is the binary pattern 1000 0000
.
When you AND
a value with that, you get &H80
if that bit was set or 0
otherwise.
This basically just records what the sign of the number was and you can simply transfer it as-is from mbf(6)
to ieee(7)
.
Dim exp As Int16 = mbf(7) - 128S - 1S + 1023S
Why 1152 (128+1+1023)?
Exponents in IEEE754 are biased exponents. In other words, the values stored may be 0
thru 255
but the actual values represented by those may be -128
thru 127
(disregarding the special values for now).
This allows you to have negative exponents for very small values and positive exponents for large values.
MBF exponents are also biased but they're biased on 128
for both single and double types whereas IEEE754 double precision exponents have their 0-point at 1023
.
The reason for the extra -1
is because of the differences between MBF and IEEE754 regarding where the implicit 1
goes. IEEE754 puts it before the binary point, MBF after. That means the exponent must be adjusted by one.
ieee(7) = ieee(7) Or sign
Why don't we just save sign to ieee(7)?
That's a slight mystery since ieee(7)
hasn't been explicitly set at that point. I can only assume that ieee()
has been initialised to zero upon creation, otherwise you may get into trouble since just about every transfer operation here is done with an OR
.
You're right that it makes more sense to just use ieee(7) = sign
. The actual OR
ing to combine the exponent bits are on the next line.
ieee(7) = ieee(7) Or ToByte(exp >> 4 And &HFF)
What is the reason for shifting by 4?
Because the IEEE754 exponent crosses two bytes and you want only part of that exponent in the most significant one. Seven bits of the exponent go into the most significant byte, the other four go into the next byte.
This is handled by the two lines:
ieee(7) = ieee(7) Or ToByte(exp >> 4 And &HFF) ' upper 7 bits '
ieee(6) = ieee(6) Or ToByte(exp << 4 And &HFF) ' lower 4 bits '
Given the 16-bit value 00000abcdefghijk
, the two are calculated:
>> 4 and &hff : 0abcdefg (s will go at the left)
<< 4 and &hff : hijk0000 (m will go at the right)