|
Posted by t.x.michaels@gmail.com on July 8, 2007, 5:37 pm
Please log in for more thread options
>
> > Hello all - I am considering creating a simple module which allows a
> > user to read/write big-endian floats or doubles.
>
> The name "Data::Endian" doesn't reflect that purpose.
>
> > The "read_float" subroutine is as follows:
>
> > #Receives a four-byte binary chunk containing a floating point number
> > # if platform is little-endian - do byte swapping
> > # if big-endian - just unpack as float
> > sub read_float {
> > my $SPF_binary_number = shift;
> > my $arch_is_little_endian = unpack("h*", pack("s", 1)) =~ /^1/;
> > my $float;
>
> > if ( $arch_is_little_endian ) {
> > my $bit_string = unpack("B32", $SPF_binary_number);
> > my ($b0, $b1, $b2, $b3) = unpack("A8" x 4, $bit_string);
> > my $flipped_bit_string = $b3 . $b2 . $b1 . $b0;
> > $float = unpack("f", pack("B32", $flipped_bit_string));
>
> That seems like a an awfully complicated way to me. How about:
>
> $float = unpack("f", pack("L", unpack("N", $SPF_binary_number)));
>
> > }
> > else { #Big-endian
> > $float = unpack("f", $SPF_binary_number);
> > }
> > return $float;
> > }
>
> In fact, the oneliner above works on both little- and big-endian
> machines (the pack("L", unpack("N", ...)) sequence takes care of that)
> and is almost four times faster than your version on my computer (an
> Intel Core2) and still about twice as fast on two big-endian machines I
> tried (a PA-RISC and a SPARC machine).
>
> #!/usr/bin/perl
> use warnings;
> use strict;
> use Config;
> use Benchmark qw(:all);
>
> sub read_float {
> my $SPF_binary_number = shift;
> my $arch_is_little_endian = unpack("h*", pack("s", 1)) =~ /^1/;
> my $float;
>
> if ( $arch_is_little_endian ) {
> my $bit_string = unpack("B32", $SPF_binary_number);
> my ($b0, $b1, $b2, $b3) = unpack("A8" x 4, $bit_string);
> my $flipped_bit_string = $b3 . $b2 . $b1 . $b0;
> $float = unpack("f", pack("B32", $flipped_bit_string));
> }
> else { #Big-endian
> $float = unpack("f", $SPF_binary_number);
> }
> return $float;
>
> }
>
> sub read_float2 {
> my $SPF_binary_number = shift;
> my $arch_is_little_endian = unpack("h*", pack("s", 1)) =~ /^1/;
> my $float;
>
> if ( $arch_is_little_endian ) {
> $float = unpack("f", pack("L", unpack("N", $SPF_binary_number)));
> }
> else { #Big-endian
> $float = unpack("f", $SPF_binary_number);
> }
> return $float;
>
> }
>
> sub read_float3 {
> my $SPF_binary_number = shift;
> my $float;
>
> if ( substr($Config, 0, 1) eq '1' ) {
> $float = unpack("f", pack("L", unpack("N", $SPF_binary_number)));
> }
> else { #Big-endian
> $float = unpack("f", $SPF_binary_number);
> }
> return $float;
>
> }
>
> sub read_float4 {
> my $SPF_binary_number = shift;
> return unpack("f", pack("L", unpack("N", $SPF_binary_number)));
>
> }
>
> sub dummy {
> my $SPF_binary_number = shift;
> return 1.0;
>
> }
>
> cmpthese(-3,
> {
> michaels => sub { my $float = read_float('1234') },
> use_L_N => sub { my $float = read_float2('1234') },
> use_Config => sub { my $float = read_float3('1234') },
> simple => sub { my $float = read_float4('1234') },
> dummy => sub { my $float = dummy('1234') },
> }
> );
> __END__
>
> Results on an Intel Core2:
>
> Rate michaels use_Config use_L_N simple dummy
> michaels 129505/s -- -12% -55% -80% -90%
> use_Config 147082/s 14% -- -49% -77% -88%
> use_L_N 287865/s 122% 96% -- -55% -77%
> simple 633616/s 389% 331% 120% -- -50%
> dummy 1260230/s 873% 757% 338% 99% --
>
> Results on an UltraSparc IIi:
>
> Rate use_Config michaels use_L_N simple dummy
> use_Config 6913/s -- -57% -58% -80% -89%
> michaels 16006/s 132% -- -3% -54% -76%
> use_L_N 16432/s 138% 3% -- -53% -75%
> simple 34941/s 405% 118% 113% -- -47%
> dummy 65749/s 851% 311% 300% 88% --
>
> (also note that the call overhead is about 100% - as can be seen by
> comparing the times of simple and dummy)
>
> Given that your problem can be solved in a single line of perl I don't
> really see the need for module to do that.
>
> hp
>
> --
> _ | Peter J. Holzer | I know I'd be respectful of a pirate
> |_|_) | Sysadmin WSR | with an emu on his shoulder.
> | | | h...@hjp.at |
> __/ |http://www.hjp.at/| -- Sam in "Freefall"
Peter,
Thank you for your insightful commentary, it is very much
appreciated.
Your solution for converting single precision floating point numbers
between big and little endian formats is certainly
faster and easier than the one I presented.
It would appear that the solution presented, would be limited to
single precision (32-bit) floating point numbers.
What would you suggest for the double precision (64-bit) floating
point number conversions?
My solution would have been pretty much the same as the one I
offered for the SPF numbers, extended to 64-bits
(byte-swapping and unpacking as double).
Again, thank you for taking the time to share your insights, it is
really very much appreciated.
Sincerely,
Terry Michaels
|