[bmx] Float/Double from Bytes without using a Pointer by beanage [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:42

Previous topic - Next topic

BlitzBot

Title : Float/Double from Bytes without using a Pointer
Author : beanage
Posted : 1+ years ago

Description : 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:
- <a href="http://en.wikipedia.org/wiki/Single_precision" target="_blank">Wikipedia on the IEEE754 Float Standard</a>
- <a href="http://en.wikipedia.org/wiki/Double_precision_floating-point_format" target="_blank">Wikipedia on the IEEE754 Double Standard</a>
- <a href="http://www.binaryconvert.com/convert_unsigned_int.html" target="_blank">Awesome online Converter</a>

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: [/i]

Code :
Code (blitzmax) Select
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 :


N(Posted 1+ years ago)

 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?


beanage(Posted 1+ years ago)

 Let my quote from my description, where I actually covered that question:<div class="quote"> This BlitzMax Prototype code shall be a help to anyone who has to write a converter in any none-pointer supporting language. </div>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.


N(Posted 1+ years ago)

 That makes more sense when you actually explain that. [/i]