Using the IEEE 754 specification link in #2 above, and using those primitive tools, a pencil and paper, made an attempt at viewing the bits that are used to create the floating point representation of our discovered value that appears to be problematic.

GOAL: Make a determination if the issue is with the functions that are performing the conversion, or isolate if the underlying floating point math is problematic.

Using our initial value, we split into the fractional and the integer parts. Using the integer value, convert that to base 2 using a calculator, and also the hex equivalent for reference. The fractional part uses a iterative process of simple multiplication, and records the carry value, either a one or zero.

Step A
Convert the Integer part to it's equivalent in base 2

var kwh = 1234.505;
Convert to F.P.
Step A Integral part 1234 base 10 = 0100 1101 0010 base 2 == 0x04D2
Fractional Part 0.505
0.505 x 2 = 1.01 1
0.01 x 2 = 0.02 0
0.02 x 2 = 0.04 0
0.04 x 2 = 0.08 0
0.08 x 2 = 0.16 0
0.16 x 2 = 0.32 0
0.32 x 2 = 0.64 0
0.64 x 2 = 1.28 1
0.28 x 2 = 0.56 0
0.56 x 2 = 1.12 1
0.12 x 2 = 0.24 0
0.24 x 2 = 0.48 0
0.48 x 2 = 0.96 0
0.96 x 2 = 1.92 1
0.92 x 2 = 1.84 1
0.84 x 2 = 1.68 1

I only manually calculated 16 places as we really don't know how many bits will be required and quite frankly, is a tedious process.

Step B
Normalize that integer part (move the D.P. in this case left) so we have a value of one multiplied by it's base 2 power equivalent. We are after the resultant power which is used as an index.

0100 1101 0010
Step B Normalize - move D.P. left 10 places
// we drop the leading zero in the initial value
1.00 1101 0010 base2 x 2 ^10
We moved the D.P. ten places left which is the equivalent of multiplying one and the fractional part by 2 ^ 10

We mentally save ten, the base 2 power and record both to use in subsequent calculations. Looking back at the @valderman Feb 2012 stackoverflow.com getNumberParts(x) function from #2 above, we now can validate that the power 10 does match.

Step C
Now we may start to assemble our F.P. register value. Bit 31 is the sign. B23-B30 is the exponent. Bit0-B22 holds the mantissa

1 bit sign 8 bit exponent 23 bit mantissa
reg 0 00000000 0000000000.....bit0
31 30 22 0
msb lsb msb lsb

Assemble the base 2 fractional part. Using the manual calculations from step 2

mantissa is formed using the original adjusted exponent
00 1101 0010 followed by
1000 0001 0100 0111
23 bits mantissa
reg 0 10001001 0011010010.....bit0
31 30 22 0
msb lsbmsb lsb

Step D
Convert the stream of bits into the base we understand in hex notation

F.P. 0 1000 1001 0011 0100 1010 0000 0101 000
Separating by four bits, 0xF we now have
0100 0100 1001 1010 0101 0000 0010 1000
we can easily see the hex equivalent of
0x449A 5028
// this is our Floating Point equivalent value in hex for
// our base 10 value of 1234.505
// that is the value used in the register performing F.P. calculations
// make sure not to confuse with the human readable
// hex equivalent 0x04d2 or 1234
which when converted to human readable form is
0x449A 5028 base 16
equiv - as a floating point value not the original number 1234.505
1150963752 base 10

Now off to hand calculate the reverse process and build a simple snippet to check our work.

Espruino is a JavaScript interpreter for low-power Microcontrollers. This site is both a support community for Espruino and a place to share what you are working on.

RobinWed 2019.08.21

Using the IEEE 754 specification link in #2 above, and using those primitive tools, a pencil and paper, made an attempt at viewing the bits that are used to create the floating point representation of our discovered value that appears to be problematic.

GOAL: Make a determination if the issue is with the functions that are performing the conversion, or isolate if the underlying floating point math is problematic.

Using our initial value, we split into the fractional and the integer parts. Using the integer value, convert that to base 2 using a calculator, and also the hex equivalent for reference. The fractional part uses a iterative process of simple multiplication, and records the carry value, either a one or zero.

Step A

Convert the Integer part to it's equivalent in base 2

I only manually calculated 16 places as we really don't know how many bits will be required and quite frankly, is a tedious process.

Step B

Normalize that integer part

(move the D.P. in this case left)so we have a value of one multiplied by it's base 2 power equivalent. We are after the resultant power which is used as an index.We mentally save ten, the base 2 power and record both to use in subsequent calculations. Looking back at the @valderman Feb 2012 stackoverflow.com

`getNumberParts(x)`

function from #2 above, we now can validate that the power 10 does match.Step C

Now we may start to assemble our F.P. register value. Bit 31 is the sign. B23-B30 is the exponent. Bit0-B22 holds the mantissa

Assemble the base 2 fractional part. Using the manual calculations from step 2

Step D

Convert the stream of bits into the base we understand in hex notation

Now off to hand calculate the reverse process and build a simple snippet to check our work.

Back in a bit

(a long while)