Displaying binary representations of Floats

Share your advanced PureBasic knowledge/code with the community.
Kale
PureBasic Expert
PureBasic Expert
Posts: 3000
Joined: Fri Apr 25, 2003 6:03 pm
Location: Lincoln, UK
Contact:

Displaying binary representations of Floats

Post by Kale »

Code updated for 5.20+

I've been playing around with floating point numbers and trying to understand how they are stored using binary. I think i've got a pretty good handle on it now and come up with this code. It allows you to input a number in the 'DecimalNumber.s' var to examine, then display usefull info in the Debug Output window.

Code: Select all

;For all 32 bit floating point numbers encoded in the IEEE 754 standard,
;the bits are arranged like this:
;
;Sign bit   Exponent   Significand (Mantissa)
;0          00000000   00000000000000000000000
;
;31         30----23   22-----bit index------0
;
;1 bit for the sign, 8 bits for the exponent and 23 bits for the significand.
;

;]=============================================================================
;-CONSTANTS
;[=============================================================================

#SIZE_OF_SIGN = 1 ;bit
#SIZE_OF_EXPONENT = 8 ;bits
#SIZE_OF_SIGNIFICAND = 23 ;bits
#EXPONENT_BIAS = 127

;]=============================================================================
;-PROCEDURES
;[=============================================================================

Procedure.q ValB(String.s)
   Protected Result.q
   Protected Pointer.l = @String
   For x.l = 1 To Len(String)
      Result = (Result << 1) + PeekC(Pointer) - 48
      Pointer + SizeOf(Character)
   Next x
   ProcedureReturn Result
EndProcedure

;]=============================================================================
;-MAIN
;[=============================================================================

;Type a decimal floating point number here to examine:
DecimalNumber.s = "0.1"

;Examinations:
FloatingPointNumber.f = ValF(DecimalNumber)
BinaryString.s = RSet(Bin(PeekL(@FloatingPointNumber)), 32, "0")
SignBitString.s = Mid(BinaryString, 1, #SIZE_OF_SIGN)
ExponentString.s = Mid(BinaryString, 1 + #SIZE_OF_SIGN, #SIZE_OF_EXPONENT)
SignificandString.s = Mid(BinaryString, 1 + #SIZE_OF_SIGN + #SIZE_OF_EXPONENT, #SIZE_OF_SIGNIFICAND)

Debug "Original Decimal Floating Point Number: "
Debug DecimalNumber
Debug ""
Debug "-----------------------------------------------------------------------"
Debug "Internal Binary Representation:"
Debug StrF(FloatingPointNumber, 18) + "  -  (" + BinaryString + ")"
Debug ""
Debug "Sign bit: " + SignBitString
Debug "Exponent: " + ExponentString + "  (" + Str(ValB(ExponentString) - #EXPONENT_BIAS) + ")"
Debug "Significand: " + "(1.)" + SignificandString
Debug "-----------------------------------------------------------------------"
Debug ""

;Read the floating point number from its binary source:

Exponent.q = ValB(ExponentString) - #EXPONENT_BIAS
If Exponent < 0
   SignificandString = RSet("1" + SignificandString, #SIZE_OF_SIGNIFICAND + -Exponent, "0")
   IntegerPart.q = 0
   FractionalPart.q = ValB(SignificandString)
Else
   IntegerPart.q = ValB("1" + Mid(SignificandString, 1, Exponent))
   FractionalPart.q = ValB(Mid(SignificandString, Exponent + 1, #SIZE_OF_SIGNIFICAND - Exponent))
EndIf

;Display the floating point number read from binary:
Debug "The floating point number re-read from binary is:"
If SignBitString = "1"
   Debug "-" + StrF(IntegerPart + FractionalPart / Pow(2, #SIZE_OF_SIGNIFICAND - Exponent), 18)
Else
   Debug StrF(IntegerPart + FractionalPart / Pow(2, #SIZE_OF_SIGNIFICAND - Exponent), 18)
EndIf
Debug ""
Debug ""
I'm pretty sure this code can handle any number to be stored in a float but i keep reading things about 'Denormal Numbers'! I can't seem to find a source which can explain these to me other than stuff that looks like a rocket science manual. So if any one can fill me in to what they are i would be grateful. ;)
--Kale

Image
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

That's what I call doing it the hard way. :wink:

Code: Select all

Float.f = 0.1
Long.l = PeekL(@Float)

Debug "Original number:"
Debug Float
Debug "Internal binary representation:"
Debug RSet(Bin(Long), 8*4, "0")
Debug "Float, re-read from binary:"
Float = 0
Float = PeekF(@Long)
Debug Float
Kale
PureBasic Expert
PureBasic Expert
Posts: 3000
Joined: Fri Apr 25, 2003 6:03 pm
Location: Lincoln, UK
Contact:

Post by Kale »

Trond wrote:That's what I call doing it the hard way. :wink:

Code: Select all

Float.f = 0.1
Long.l = PeekL(@Float)

Debug "Original number:"
Debug Float
Debug "Internal binary representation:"
Debug RSet(Bin(Long), 8*4, "0")
Debug "Float, re-read from binary:"
Float = 0
Float = PeekF(@Long)
Debug Float
Yes your code is a little bit shorter but it doesn't do what mine does, ;) and that is read and decode 32 bit binary to extrapolate the floating point number contained within. In mine i read the sign, the exponent and the significand and process these in order to give me the stored float.

I've done it this way to show how it is done while i was learning how to do it. :)
--Kale

Image
dioxin
User
User
Posts: 97
Joined: Thu May 11, 2006 9:53 pm

Post by dioxin »

Kale,
Normalised 32 bit FP numbers are of this format:

Code: Select all

sEEEEEEEEfffffffffffffffffffffff   s=sign, E=exponent (biased by adding 127), f=fractional part and there is an implied 1 ahead of the fractional part so the mantissa actually has 24 bits, not the 23 you may expect. i.e. the number is really:

<S> 1.fffffffffffffffffffffff x 2^(EEEEEEEE - 127)

	The Exponent range for normalised numbers is -126 to +127 (EEEEEEEE= 1 to 254)
	If EEEEEEEE = 255 then the number is infinite or Not A Number.
	If EEEEEEEE = 0   then the number is either zero or denormalised.
 
Denormalized numbers are the range of numbers which are too small to be represented in the normalised format because the exponent can't go below 1, but which can still be usefully represented in the bits available, although at lower precision.

You can recognise a denormalised number from EEEEEEEE.
If the EEEEEEEE is zero AND ff..ff is zero then the number represented is zero
If the EEEEEEEE is zero AND ff..ff is non-zero then the number represented is denormalised.
The denormalised number has an implied leading 0 rather than the implied leading 1 of normalised numbers.
The exponent of the denormalised number is always -126 as the smaller size of smaller numbers is taken into account by shifting the bits right in the mantissa rather than by decrementing the exponent further.

The smallest number that can be held normalised is:

Code: Select all

sEEEEEEEEfffffffffffffffffffffff
s0000000100000000000000000000000
which represents <s>1.0 x 2^-126

If we decrease the number by 1 count in the LSB we get:

Code: Select all

sEEEEEEEEfffffffffffffffffffffff
s0000000011111111111111111111111
which is the biggest denormalised number.
It's value is <s>0.11111111111111111111111 x 2^-126 (note the exponent of denormalised numbers is always -126)
Normalised this would be <s>1.11111111111111111111110 x 2^-127 but -127 is out of range for EEEEEEEE


If we divide its value by 8 we get:

Code: Select all

sEEEEEEEEfffffffffffffffffffffff
s0000000000011111111111111111111
It's value is <s>0.00011111111111111111111 x 2^-126 (note the exponent of denormalised numbers is always -126)
Normalised this would be <s>1.11111111111111111110000 x 2^-130 but -130 is out of range for EEEEEEEE



So, for an example, take the following number:

Code: Select all

sEEEEEEEEfffffffffffffffffffffff
s0000000000000111000000000000000
It is a denormalised number since EEEEEEEE is zero and the fracional part is non-zero.
Its value is:
<s> 0.00000111000000000000000 x 2^-126

=<s> 1.11000000 x 2^-132 Normalised.. but the exponent of -132 is beyond the range that will allow this number to be stored in a normalised format.


Paul.
Kale
PureBasic Expert
PureBasic Expert
Posts: 3000
Joined: Fri Apr 25, 2003 6:03 pm
Location: Lincoln, UK
Contact:

Post by Kale »

Thanks Dioxin, thats cleared it up for me. :)

I'm guessing my code probably won't handle denormalised number then, as i always add the implied '1' at the front of all significands. Mind you, i'm guessing denormalised numbers in floats is pretty rare?
--Kale

Image
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

But why exactly would anyone want to know this?
Kale
PureBasic Expert
PureBasic Expert
Posts: 3000
Joined: Fri Apr 25, 2003 6:03 pm
Location: Lincoln, UK
Contact:

Post by Kale »

Trond wrote:But why exactly would anyone want to know this?
Education.
--Kale

Image
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Kale wrote:
Trond wrote:But why exactly would anyone want to know this?
Education.
:D
I'd not call it education, but information :wink:
("Education" is a very subjetive concept)

BTW Thanks, Dioxin, nice info
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
Post Reply