Big Endian -> Little Endian

General FreeBASIC programming questions.
BasicScience
Posts: 489
Joined: Apr 18, 2008 4:09
Location: Los Angeles, CA
Contact:

Big Endian -> Little Endian

Post by BasicScience »

Trying to read 32-bit floating point numbers from a binary data file created by LabView. Apparently LabView uses Big Endian since it was originally developed on a Mac OS. Anyone have a fast Big Endian -> Little Endian converter (to work on single float variable or array of single float)?
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Big Endian -> Little Endian

Post by MrSwiss »

Some endian swapping Macros. However, they are geared towards
ULong / ULongInt and not Single ... (if I've correctly interpreted, the question).

This could be solved, with a Union:

Code: Select all

Union DW
    As Single  sdw
    As ULong   uldw
End Union
Last edited by MrSwiss on Jul 24, 2018 20:32, edited 1 time in total.
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Big Endian -> Little Endian

Post by srvaldez »

here some discussion on big endian to little endian conversion viewtopic.php?f=3&t=25857&p=235216&hili ... an#p235216
also more specifically dealing with float https://stackoverflow.com/questions/278 ... tle-endian
the answer by Gregor Brandt converted to FB

Code: Select all

'by Gregor Brandt
function ReverseFloat(byval inFloat as const single) as single
	dim retVal as single
	dim floatToConvert as zstring ptr = cptr(zstring ptr, @inFloat)
	dim returnFloat as zstring ptr = cptr(zstring ptr, @retVal)
	returnFloat[0] = floatToConvert[3]
	returnFloat[1] = floatToConvert[2]
	returnFloat[2] = floatToConvert[1]
	returnFloat[3] = floatToConvert[0]
	return retVal
end function
BasicScience
Posts: 489
Joined: Apr 18, 2008 4:09
Location: Los Angeles, CA
Contact:

Re: Big Endian -> Little Endian

Post by BasicScience »

Thanks for the ideas.

@sarvaldez, I get a segment violation error at this line:

returnFloat[0] = floatToConvert[3]

Is Callocate needed to set aside memory for the arrays?
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Big Endian -> Little Endian

Post by fxm »

Warning:
This above function writes at least 4 additional bytes behind the Single due to a misuse of Zstring.

IMHO, use 'Byte Ptr' instead of 'Zstring Ptr':

Code: Select all

function ReverseFloat(byval inFloat as const single) as single
   dim retVal as single
   dim floatToConvert as byte ptr = cptr(byte ptr, @inFloat)
   dim returnFloat as byte ptr = cptr(byte ptr, @retVal)
   returnFloat[0] = floatToConvert[3]
   returnFloat[1] = floatToConvert[2]
   returnFloat[2] = floatToConvert[1]
   returnFloat[3] = floatToConvert[0]
   return retVal
end function
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Re: Big Endian -> Little Endian

Post by jevans4949 »

Some stuff I wrote a while back, using asm. (To do with MIDI files)

Code: Select all

'***********************************************************************
' Big-endian integer Handling
'***********************************************************************
#include once "jevans4949/bigend/bigend.bi"
'***********************************************************************
' Big-endian Operator Functions
'***********************************************************************
operator be4.cast() as integer
    asm
        mov eax,[This]
        mov eax,[eax]
        bswap eax
        mov [function],eax
    end asm
end operator
'
operator be4.let(byval source as integer)
    asm
        mov ebx,[this]
    	mov eax,[source]
        bswap eax
        mov [ebx],eax
    end asm
end operator
'
operator be2s.cast() as integer
   asm
       mov ebx,[This]
       movsxb eax,Byte Ptr[ebx]
       sal eax,8
       mov al,[ebx+1]
       mov [Function],eax
   end asm
end operator
'
operator be2s.let(byval source as integer)
    asm
        mov ebx,[This]
    	mov eax,[source]
        mov [ebx],ah
        mov [ebx+1],al
    end asm
end operator
'
operator be2u.cast() as integer
   asm
       mov ebx,[This]
       movzx eax,Byte Ptr[ebx]
       sal eax,8
       mov al,[ebx+1]
       mov [Function],eax
   end asm
end operator
'
operator be2u.let(byval source as integer)
    asm
        mov ebx,[This]
    	mov eax,[source]
        mov [ebx],ah
        mov [ebx+1],al
    end asm
end operator
'
operator be3s.cast() as integer
    asm
        mov ebx,[This]
        movsxb eax,Byte ptr[ebx]
        sal eax,16
        mov ah,[ebx+1]
        mov al,[ebx+2]
        mov [Function],eax
   end asm
end operator
'
operator be3s.let(byval source as integer)
    asm
        mov ebx,[This]
    	mov eax,[source]
        mov [ebx+1],ah
        mov [ebx+2],al
        sar eax,8
        mov [ebx],ah
    end asm
end operator
'
operator be3u.cast() as integer
    asm
        mov ebx,[This]
        movzx eax,Byte ptr[ebx]
        sal eax,16
        mov ah,[ebx+1]
        mov al,[ebx+2]
        mov [Function],eax
   end asm
end operator
'
operator be3u.let(byval source as integer)
    asm
        mov ebx,[This]
    	mov eax,[source]
        mov [ebx+1],ah
        mov [ebx+2],al
        sar eax,8
        mov [ebx],ah
    end asm
end operator
Here's the include:

Code: Select all

'***********************************************************************
' Stuff to pull in lib's
'***********************************************************************
#if (__FB_OUT_LIB__ = 0)
#libpath "/freebasic/lib/win32/jevans4949/bigend"
#inclib "bigend"
#endif
'***********************************************************************
' Big-endian Type definitions
'***********************************************************************
type be4 field=1                        '4 byte,assumed signed
    i as integer
    declare operator cast() as integer
    declare operator let(source as integer)
end type
'
type be3s field=1                       '3 byte signed 
    as ubyte h,m,l
    declare operator cast() as integer
    declare operator let(source as integer)
end type
'
type be3u field=1                       '3 byte unsigned 
    as ubyte h,m,l
    declare operator cast() as integer
    declare operator let(source as integer)
end type
'
type be2s field=1                       '2 byte signed 
    i as short
    declare operator cast() as integer
    declare operator let(source as integer)
end type
'
type be2u field=1                       '2 byte unsigned 
    i as ushort
    declare operator cast() as integer
    declare operator let(source as integer)
end type
'
And here's a test driver

Code: Select all

'***********************************************************************
' Big-endian integer Handling
'***********************************************************************
#include once "jevans4949/bigend/bigend.bi"
'***********************************************************************
' Big-Endian Test Harness
'***********************************************************************
dim p as ubyte ptr
dim i as integer
dim j as integer
dim x as be4
dim y as be3s
dim z as be2s
dim w as be2u
dim v as be3u
loop1:
Input "Enter value of type long";i
x = i
y = i
z = i
w = i
v = i
p=@x
print "converted to be4: ";hex(*p,2);hex(*(p+1),2);hex(*(p+2),2);hex(*(p+3),2)
p=@y
print "converted to be3s: ";hex(*p,2);hex(*(p+1),2);hex(*(p+2),2)
p=@v
print "converted to be3u: ";hex(*p,2);hex(*(p+1),2);hex(*(p+2),2)
p=@z
print "converted to be2s: ";hex(*p,2);hex(*(p+1),2)
p=@w
print "converted to be2u: ";hex(*p,2);hex(*(p+1),2)
j = x
print "Converted back from be4:  ";j
j = y
print "Converted back from be3s: ";j
j = v
print "Converted back from be3u: ";j
j = z
print "Converted back from be2s: ";j
j = w
print "Converted back from be2u: ";j
goto loop1

You probably need to define your fields as a Union of Singles and Longs/be4 to get this to work.

Enjoy
BasicScience
Posts: 489
Joined: Apr 18, 2008 4:09
Location: Los Angeles, CA
Contact:

Re: Big Endian -> Little Endian SOLVED

Post by BasicScience »

@fxm, thanks for catching ptr issue with Zstring. With your byte ptr modification, the code runs correctly.

@jevans I'll do some timing tests, and then consider diving into your asm version.

Thanks to all
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Big Endian -> Little Endian

Post by jj2007 »

Didn't know there are "big endian" floats around... but conversion is pretty simple, this snippet converts it twice:

Code: Select all

dim as single MySingle = 123.456

Sub SwitchEndians(TheFloat As Single ptr)
  Asm
	mov edx, [TheFloat]
	mov eax, [edx]
	bswap eax
	mov [edx], eax
  End Asm
End Sub

print "float=";MySingle
SwitchEndians(@MySingle)
print "float=";MySingle
SwitchEndians(@MySingle)
print "float=";MySingle
sleep()
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Big Endian -> Little Endian

Post by MrSwiss »

A simple pure FB Function, using UByte Ptr:

Code: Select all

' eSwpSgl_Func.bas -- 2018-07-24, by MrSwiss
'
' compile: -s console
'

Function eSwpSgl(ByVal si As Const Single) As Single
    Dim As Single   ret

    For i As UInteger = 0 To 3
        CPtr(UByte Ptr, @ret)[3 - i] = CPtr(UByte Ptr, @si)[i]
    Next

    Return ret
End Function


Dim As Single   ts1 = 1.0, ts2 = -5.0, tr1 = 0.0, tr2 = 0.0

Print ts1,, ts2                         ' show start values
tr1 = eSwpSgl(ts1) : tr2 = eSwpSgl(ts2) ' endiannes swap
Print tr1, tr2                          ' show result

ts1 = 0.0 : ts2 = 0.0                   ' clear vars. (for return of reverse operation)
ts1 = eSwpSgl(tr1) : ts2 = eSwpSgl(tr2) ' reverse endiannes swap
Print ts1,, ts2                         ' show reverse result

Sleep
BasicScience
Posts: 489
Joined: Apr 18, 2008 4:09
Location: Los Angeles, CA
Contact:

Re: Big Endian -> Little Endian

Post by BasicScience »

@jj2007 - your ASM conversion is the fastest of the suggested approaches. I suppose this code would work for any 32-bit value (e.g. even for long integer)? It's been a while since I wrote code ASM, what modification would be needed for a 16 bit value (e.g. short integer)?
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Big Endian -> Little Endian

Post by jj2007 »

BasicScience wrote:what modification would be needed for a 16 bit value (e.g. short integer)?

Code: Select all

  bswap eax
  shr eax, 16
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Re: Big Endian -> Little Endian

Post by jevans4949 »

jj2007 has the simplest answer for Singles or 4-byte integers - well done!

My code contains solutions for 2- and 3-byte signed and unsigned integers.

Note, however, that my code assumes a 32-bit compile - assumes sizeof(integer) and sizeof(pointer), and does not include 64-bit integers at all. Obviously it wouldn't work a non-Intel/AMD target either.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Big Endian -> Little Endian

Post by jj2007 »

jevans4949 wrote:jj2007 has the simplest answer for Singles or 4-byte integers - well done!
Thanks.
My code contains solutions for 2- and 3-byte signed and unsigned integers.
Interesting. The FPU can handle 2-byte (as in fild word ptr [esp]), 4-byte and 8-byte integers, but I've never heard of a 3-byte integer. Technically, it can be done, of course:

Code: Select all

  bswap eax
  shr eax, 8
... but is there any IEEE 754 norm about 3-byte integers? Just curious...
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Re: Big Endian -> Little Endian

Post by jevans4949 »

jj2007 wrote:... but I've never heard of a 3-byte integer ...
The MIDI fie specification includes one instance of 3-byte integer, and also wierd variable-length integers - lower 7 bits of each byte are data and top bit indicates another byte follows - e.g &h'8307' decodes to &h'0187'. All integers are big-endian.

EDIT: I once woked for a financial analysis company that had defined a 2-byte compressed float for company accounts data! Can't now remeber the details.
Last edited by jevans4949 on Jul 27, 2018 1:01, edited 1 time in total.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Big Endian -> Little Endian

Post by jj2007 »

Wow, that's funny. Since it's MIDI, I wonder whether the Atari folks were involved. In the meantime I got curious and found out that apparently some graphics cards use a 24-bit float format. I never stop learning ;-)
Post Reply