Code archives/Algorithms/Float/Double from Bytes without using a Pointer

This code has been declared by its author to be Public Domain code.

Download source code

Float/Double from Bytes without using a Pointer by beanage2010
Hey,

usually, converting from Bytes to any numeric type is a pretty easy thing to do in BlitzMax:

Local Mem:Byte Ptr=getMyMem()
Local MyFloat:Float = Float Ptr(Mem)[0]

However, it gets really ugly, when you are in an environment
that restricts you from using pointers.
Such an environment is, for example, the OpenGl Shading Language.
This BlitzMax Prototype code shall be a help to anyone
who has to write a converter in any none-pointer supporting language.

Good Sources:
- Wikipedia on the IEEE754 Float Standard
- Wikipedia on the IEEE754 Double Standard
- Awesome online Converter

Use:
Global buffer_:TBank = CreateBank(8)

PokeFloat buffer_, 0, 13.6
Print GetFloat32( buffer_, 0, 0 )
Print ""
PokeDouble buffer_, 0, 14.75
Print GetFloat64( buffer_, 0, 0 )


The code:
SuperStrict

Const	IEEE754_32_0_SIGN:Int = $8000000
Const	IEEE754_32_0_EXPONENT:Int = $7F800000
Const	IEEE754_32_0_FRACTION:Int = $007FFFFF
Const	IEEE754_32_FRACTION_LEN:Int = 23
Const	IEEE754_32_EXPONENT_LEN:Int = 8
Const	IEEE754_32_EXPONENT_BIAS:Int = 127

Const	IEEE754_64_1_SIGN:Int = $80000000
Const	IEEE754_64_1_EXPONENT:Int = $7FF00000
Const	IEEE754_64_1_FRACTION:Int = $000FFFFF
Const	IEEE754_64_0_FRACTION:Int = $FFFFFFFF
Const	IEEE754_64_FRACTION_LEN:Int = 52
Const	IEEE754_64_EXPONENT_LEN:Int = 11
Const	IEEE754_64_EXPONENT_BIAS:Int= 1023

Function _getFloatFromParts:Float( sign_:Byte, exponent_:Int, significand_:Float ) 'exponent already biased here
	If ( significand_< 1 )
		Return ( ( 1.0 - 2.0*Float(sign_) )* significand_ )
	Else
		Return ( ( 1.0 - 2.0*Float(sign_) )* significand_* 2^Float(exponent_) )
	End If
End Function

Function _significandFromFraction:Float( exponent_:Int, fraction_:Int ) 'exponent unbiased here
	If Not ( fraction_|exponent_ ) Then Return .0
	Local ret_:Float = Float(fraction_)/ 2^31.0
	
	ret_:+ ( exponent_<> 0 )
	Return ret_
End Function

Function _getIEEEFloatParts( data_:Int[], sign_:Byte var, exponent_:Int var, significand_:Float var ) 'data must be passed in a big endian order
	Select data_.Length
		Case 1
			sign_ = data_[0]< 0
			exponent_ = ( data_[0]& IEEE754_32_0_EXPONENT ) Shr IEEE754_32_FRACTION_LEN
			significand_ = _significandFromFraction( exponent_, (data_[0]& IEEE754_32_0_FRACTION) Shl IEEE754_32_EXPONENT_LEN ) 'call significand extraction with unbiased exponent
			exponent_:- IEEE754_32_EXPONENT_BIAS 'apply bias
		
		Case 2
'			B B B B B B B B   B B B B B B B B
'			^ ^   ^           ^
'			| |11 |20         |32
'			| |   SIGNIFICAND SIGNIFICAND
'			| EXPONENT        
'			SIGN BIT
			sign_ = ( ( data_[1]& IEEE754_64_1_SIGN )<> 0 )
			exponent_ = Int( ( data_[1]& IEEE754_64_1_EXPONENT ) Shr ( IEEE754_64_FRACTION_LEN- 32 ) )
			significand_ = _significandFromFraction( exponent_, ( ( data_[0] Shr (IEEE754_64_FRACTION_LEN-32+1) ) | ( (data_[1]& IEEE754_64_1_FRACTION) Shl IEEE754_64_EXPONENT_LEN ) ) ) '+1 to avoid shifting into the sign bit
			exponent_:- IEEE754_64_EXPONENT_BIAS 'apply bias
			
	End Select
End Function

'TextureBuffer Value Retreival

Function GetInt32:Int( buffer_:TBank, handle_:Int, idx_:Int ) 'returns int
	Local vec_:Byte
	Local ret_:Int
	
?LittleEndian
	vec_ = PeekByte( buffer_, idx_+ 0 )
	ret_ :| ( Int(vec_) )
	vec_ = PeekByte( buffer_, idx_+ 1 )
	ret_ :| ( Int(vec_) Shl 8 )
	vec_ = PeekByte( buffer_, idx_+ 2 )
	ret_ :| ( Int(vec_) Shl 16 )
	vec_ = PeekByte( buffer_, idx_+ 3 )
	ret_ :| ( Int(vec_) Shl 24 )
?BigEndian
	vec_ = PeekByte( buffer_, idx_+ 3 )
	ret_ :| ( Int(vec_) )
	vec_ = PeekByte( buffer_, idx_+ 2 )
	ret_ :| ( Int(vec_) Shl 8 )
	vec_ = PeekByte( buffer_, idx_+ 1 )
	ret_ :| ( Int(vec_) Shl 16 )
	vec_ = PeekByte( buffer_, idx_+ 0 )
	ret_ :| ( Int(vec_) Shl 24 )
?
	Return ret_
End Function

Function GetFloat32:Float( buffer_:TBank, handle_:Int, idx_:Int ) 'returns float
	Local sign_:Byte
	Local exponent_:Int
	Local significand_:Float
	
	_getIEEEFloatParts( [ GetInt32( buffer_, handle_, idx_ ) ], sign_, exponent_, significand_ );
	Return _getFloatFromParts( sign_, exponent_, significand_ );
End Function

Function GetFloat64:Float( buffer_:TBank, handle_:Int, idx_:Int ) 'converts from IEEE double to IEEE float
	Local sign_:Byte
	Local exponent_:Int
	Local significand_:Float
	
?LittleEndian
	_getIEEEFloatParts( [ GetInt32( buffer_, handle_, idx_ ), GetInt32( buffer_, handle_, idx_+ 4 ) ], sign_, exponent_, significand_ )
?BigEndian
	_getIEEEFloatParts( [ GetInt32( buffer_, handle_, idx_+ 4 ), GetInt32( buffer_, handle_, idx_ ) ], sign_, exponent_, significand_ )
?
	Return _getFloatFromParts( sign_, exponent_, significand_ );
End Function

Comments

N2010
I fail to see why you can't do something like this:

Local data:Int = _buffer.PeekInt(offset)
Local asFloat:Float = Float Ptr(Varptr data)[0]


What exactly prevents you from doing this?


beanage2010
Let my quote from my description, where I actually covered that question:

This BlitzMax Prototype code shall be a help to anyone who has to write a converter in any none-pointer supporting language.


E.g. I wrote this as prototype code for an implementation in GLSL, where I have to read doubles/floats out of a byte texture buffer. Now that propably also explains why the code is so focused on bytes.

I thought others who might encounter the same (or a similar) problem may want to find this prototype before they have to dig into tons and tons of ugly theory.


N2010
That makes more sense when you actually explain that.


Code Archives Forum