Page 1 of 1
writefloat calc question
Posted: Thu Feb 02, 2006 2:56 pm
by Fable Fox
i need to know something not important, but intriguing:
writefloat(5) and writefloat(6) is written as 00 00 a0 40 and 00 00 c0 40 (in the file, read using hex editor)? can someone explain it to me? this is because everything else byte, word, etc get written as their hex equivalent?, for example 10 = 0A. Does someone know how computer calculated that it arrive at 0000a040 and 0000c040?
does someone who good at comp math explain how you store point value, such as 3.5 or 5.8 in hex? thanks.
Posted: Thu Feb 02, 2006 4:11 pm
by Dare2
Big question, that.
Floats are stored using a standard called IEEE-754. This approximates the value, which is why floats are not always absolutely 100% accurate.
Floats have a sign bit, an exponent, and a mantissa (and some implied values) and these are used together to calculate the value.
This code (more or less shows) how a 32 float is handled.
Code: Select all
Structure single_TYPE
StructureUnion
flt.f
int.l
cha.b[4]
EndStructureUnion
EndStructure
sng.single_TYPE
Procedure.s zLeft(valu,dgt)
ProcedureReturn Right("00000000000000000000000000000000000000000000000000000000000000000"+Bin(valu),dgt)
EndProcedure
; Format of a 32 bit IEEE-754 float;
; Bits: Seeeeeee eMMMMMMM MMMMMMMM MMMMMMMM
; Where S = Sign
; e = exponent
; M = Mantissa (or fraction or significand, your call)
Procedure calcIEEEsingle(vlu.f)
Debug ""
Debug "-------------------"
Debug "ORIGINAL = " + StrF(vlu)
Debug ""
;Stick the original value into our structure
sng.single_TYPE\flt=vlu
; Because of endian-ness, use reverse order
; in processing the 4 bytes
signIs=(sng\cha[3] & $80) >> 7
If signIs
signIs=-1
Debug "Value is NEGATIVE"
Else
signIs=1
Debug "Value is POSITIVE"
EndIf
;Next 8 bits are the exponent.
; Need to give them a little shift to the left
exponent=((sng\cha[3] & $7F) << 1) + ((sng\cha[2] & $80) >> 7)
Debug "Raw exponent = "+Bin(exponent)
;Mantissa is next 23 bits (base 2)
; Do some shuffle, using several code lines for readability.
mantissa=(sng\cha[2] & $7F) : mantissa << 8
mantissa+(sng\cha[1] & $FF) : mantissa << 8
mantissa+(sng\cha[0] & $FF) : mantissa * 2
Debug "Raw Mantissa = "+zLeft(mantissa,24)+" ("+Str(mantissa)+")"
Debug "This is ..."
If exponent=255 And mantissa<>0
Debug "... NaN"
ElseIf exponent=255 And mantissa=0
If signIs=-1
Debug "... Negative Infinity"
Else
Debug "... Infinity"
EndIf
ElseIf exponent=0 And mantissa=0
If signIs=-1
Debug "... Negative zero (-0)"
Else
Debug "... Zero"
EndIf
ElseIf exponent=0 And mantissa<>0
Debug "... a Denormalised number"
Else
Debug "... a Normalised number"
; Calculate the mantissa as a "binary decimal"
man.f=1.0 ; There is an invisible or implied one
flag=$00800000 ; This flag used to check the bits
adj.f=1.0 ; This value halved for each bit
For i=1 To 23 ; Check each bit for mantissa bits
adj / 2.0 ; Halve our value
If mantissa & flag ; If the bit is set
man + adj ; add value to mantissa
EndIf ;
flag >> 1 ; Shift the bit one place right
Next ;
; Test the result:
; Note - exponent here adjusted by -127 (the "bias")
; However, this should be checked earlier as it can
; change this, for example whether the
; "decimal binary" starts with 1. or 0.
; But who cares!
; Make everything a float.
; Not absolutely needed, but ...
fSign.f = signIs
fExp.f = exponent
IEEE754val.f= fSign * Pow(2.0,(fExp-127.0)) * man
Debug StrF(IEEE754val) + " is the IEEE-754 value"
Debug StrF(vlu) + " is the original value."
EndIf
EndProcedure
odds.single_TYPE
odds\int=$0 : calcIEEEsingle(odds\flt)
odds\int=$80000000 : calcIEEEsingle(odds\flt)
odds\int=$7F800000 : calcIEEEsingle(odds\flt)
odds\int=$FF800000 : calcIEEEsingle(odds\flt)
odds\int=$80 : calcIEEEsingle(odds\flt)
calcIEEEsingle(1.0)
calcIEEEsingle(-1.0)
calcIEEEsingle(123.45)
calcIEEEsingle(-123.45)
calcIEEEsingle(0.1)
calcIEEEsingle(-0.1)
calcIEEEsingle(1.0/3.0)
calcIEEEsingle(22.0/7.0)
calcIEEEsingle(123.456)
calcIEEEsingle(123.4567)
The above is for a single precision float. These are reasonably accurately represented up to about 7 digits.
A double precision float (64 bits) pushes it around 15 digits, when the wheels start to wobble badly again.
Note that the exponent determines things like 0, -0 (which it appears PureBasic kindly sorts out for us, saving us some heartache), NaN (not a number) and Infinity.
Note also that the reason it is stored back to front (hex 00 00 a0 40 and not 40 0a 00 00) is nothing to do with the float and everything to do with the endian-ness of the computer.
lol. Having just typed all that, I hope that was what you were looking for.

Posted: Thu Feb 02, 2006 11:42 pm
by Hatonastick
Yeah and this is a bit of a gotcha to those who don't know this - as Dare2 showed me a day or so ago.

Posted: Fri Feb 03, 2006 2:14 am
by SFSxOI
i've discovered that too....
I guess they are called floats for a reason, cause they are kinda - almost - but not really

Posted: Fri Feb 03, 2006 10:13 am
by MrMat
Nice explanation Dare2

Posted: Fri Feb 03, 2006 1:15 pm
by Dare2
Thanks MrMat!
I must have had one brain cell actually in synch with another when I wrote that.
thanks.
Posted: Sat Feb 04, 2006 1:58 pm
by Fable Fox
wow - nice explanation. i do know about that backward thing. i'm an experienced (dos days) save game hacker. it just that i never learn hex past that mantissa thing.
thank you very much.