I have a sensor here that spits out four bytes in IEEE 754 floating point format. I remembered Kyle muttering that he didn’t use this particulate floating point format and with zero examples of float variables in the sample files, I wrote my own procedures. Both work. Both have obvious errors, which I don’t understand.
Floating point mantissa is a number between 1 and 2, where the 1 before the decimal point is conveniently removed. The bits store the 1/2, 1/4, 1/8.. values.
I needed to go to decimal, so I used 5_000_000 and shifted that to the right (2_500_000, 1_250_000, etc) which should add up to 1e7 max if all mantissa bits are 1.
In my opinion 1.5xxx * 2^y is very different from 0.5xxx * 2^y, but the result is correct?
Also, when divided by 1e7, this doesn’t work? For some reason my value is 10x too small. Easy fix.
I also used the 23rd bit of the mantissa, counting from 1. Jal counts from 0, so this should be bit 22. Yet, it works.
For the dword variant I corrected the 23 to 22 (the mantissa formally needs no mask from the fp input value, since I only use one bit) but this gave a result that was 4 times too large. Easy fix, but even less understandable.
Any ideas about the sample that I should make for this? Are there typical IEEE 754 numbers that I should use as an example? I am also a bit worried about the limited exponent range in my code. For larger exponents I could shift leftward one bit and a time and catch the overflow in a separate byte, so I can cover the full dword range.
I’m also not sure about the way how the conversion works the other way. After all, 1/2 * 2^1, 1/4 * 2^2 and 1/8 * 2^3 are all 1. There must be a preferred format.
-- -------------------------------------------------------------------
-- IEE 754 floating point conversion: 1 sign bit, 8 exponent bits, 23 mantissa bits
-- max 4 digits after decimal point
-- Original: Eur van Andel
-- -------------------------------------------------------------------
function ieee754_to_sdword(byte in fp3, byte in fp2, byte in fp1, byte in fp0, byte in digits) return sdword is
var bit sign at fp3:7 -- 1 bit sign
var byte exponent -- 8 bits exponent
var dword mantissa -- 23 bits mantissa, 32 bits here
var bit sig_bit at mantissa:23 -- most significant bit
var dword value = 0
var dword fraction = 5_000_000 -- 7 digits
exponent = (fp3 << 1) + (fp2 >> 7)
mantissa = dword(fp2 & 0b0111_1111)
mantissa = mantissa << 15 -- only 7 bits, 8th is for exponent
mantissa = mantissa + (word(fp1) << 8) + fp0
exponent = exponent - 127 -- exponent bias, fake sbyte
for 22 loop
if sig_bit then
value = value + fraction
end if
mantissa = mantissa << 1
fraction = fraction >> 1 -- add 1/2, 1/4, etc of 10^7
end loop
value = value << exponent -- exponent max 8 here, not that much
if digits == 0 then
value = value / 1_000_000 -- should be 10^7? this works, dunno why
elsif digits == 1 then
value = value / 100_000
elsif digits == 2 then
value = value / 10_000
elsif digits == 3 then
value = value / 1_000
elsif digits == 4 then
value = value / 100
end if -- more digits too slow
if sign then
return - sdword(value)
else
return sdword(value)
end if
end function
-- -------------------------------------------------------------------
-- IEE 754 floating point conversion: 1 sign bit, 8 exponent bits, 23 mantissa bits
-- max 4 digits after decimal point
-- Original: Eur van Andel
-- -------------------------------------------------------------------
function ieee754_to_sdword2(dword in fp, byte in digits) return sdword is
var bit sign at fp:31 -- 1 bit sign
var byte exponent = byte((fp & 0x7F_80_00_00) >> 23) -- 8 bits exponent
var dword mantissa = fp & 0x00_7F_FF_FF -- 23 bits mantissa
var bit sig_bit at mantissa:22 -- most significant bit
var dword value = 0
var dword fraction = 5_000_000 -- 7 digits
exponent = exponent - 127 -- exponent bias, fake sbyte
for 22 loop
if sig_bit then
value = value + fraction
end if
mantissa = mantissa << 1
fraction = fraction >> 1 -- add 1/2, 1/4, etc of 10^7
end loop
if exponent > 2 then
exponent = exponent -2 -- dafuq?
value = value << exponent -- exponent max 8 here, not that much
else
value = value << exponent
value = value >> 2
end if
if digits == 0 then
value = value / 1_000_000 -- should be 10^7? this works, dunno why
elsif digits == 1 then
value = value / 100_000
elsif digits == 2 then
value = value / 10_000
elsif digits == 3 then
value = value / 1_000
elsif digits == 4 then
value = value / 100
end if -- more digits too slow
if sign then
return - sdword(value)
else
return sdword(value)
end if
end function
---
Fiwihex B.V. Wierdensestraat 74, NL7604BK Almelo, Netherlands
tel+31-653-286573