[32909] in Perl-Users-Digest

home help back first fref pref prev next nref lref last post

Perl-Users Digest, Issue: 4187 Volume: 11

daemon@ATHENA.MIT.EDU (Perl-Users Digest)
Mon Apr 7 05:17:28 2014

Date: Mon, 7 Apr 2014 02:17:05 -0700 (PDT)
From: Perl-Users Digest <Perl-Users-Request@ruby.OCE.ORST.EDU>
To: Perl-Users@ruby.OCE.ORST.EDU (Perl-Users Digest)

Perl-Users Digest           Mon, 7 Apr 2014     Volume: 11 Number: 4187

Today's topics:
        pack/unpack help please <No-Spam@deezee.org>
    Re: pack/unpack help please <No-Spam@deezee.org>
    Re: pack/unpack help please <rweikusat@mobileactivedefense.com>
    Re: pack/unpack help please <rweikusat@mobileactivedefense.com>
    Re: pack/unpack help please <No-Spam@deezee.org>
    Re: pack/unpack help please <rweikusat@mobileactivedefense.com>
    Re: pack/unpack help please <No-Spam@deezee.org>
        Digest Administrivia (Last modified: 6 Apr 01) (Perl-Users-Digest Admin)

----------------------------------------------------------------------

Date: Sat, 5 Apr 2014 15:14:00 +0000 (UTC)
From: "Dave Saville" <No-Spam@deezee.org>
Subject: pack/unpack help please
Message-Id: <fV45K0OBJxbE-pn2-ZptoCme8xcH5@paddington.bear.den>

I am using perl on a Rasberry pi to read an i2c device using the hipi 
library.

@temp = $dev->bus_read( MPU6050_TEMP_OUT_H, 2 ); 

Returns two bytes as an array of two values. High byte, low byte.

For example I may get:

$temp[0] = 244; # 0xFD
$temp[1] = 224; # 0xE0

Which is -2848. I (eventually) came up with this

$temp = unpack 's', pack 'CC', reverse @temp;

Is there a better method? Also why does 

$temp = unpack 'n', pack 'CC',  @temp;

Not give the same value?

TIA
-- 
Regards
Dave Saville


------------------------------

Date: Sat, 5 Apr 2014 15:45:24 +0000 (UTC)
From: "Dave Saville" <No-Spam@deezee.org>
Subject: Re: pack/unpack help please
Message-Id: <fV45K0OBJxbE-pn2-Bq6ZOeCtKyST@paddington.bear.den>

On Sat, 5 Apr 2014 15:14:00 UTC, "Dave Saville" <No-Spam@deezee.org> 
wrote:

> $temp = unpack 'n', pack 'CC',  @temp;
> 
> Not give the same value?

Ah, n is unsigned.

$temp = unpack 's>', pack 'CC', @temp;

Does the trick.
-- 
Regards
Dave Saville


------------------------------

Date: Sat, 05 Apr 2014 20:25:51 +0100
From: Rainer Weikusat <rweikusat@mobileactivedefense.com>
Subject: Re: pack/unpack help please
Message-Id: <8761mn7f40.fsf@sable.mobileactivedefense.com>

"Dave Saville" <No-Spam@deezee.org> writes:
> I am using perl on a Rasberry pi to read an i2c device using the hipi 
> library.
>
> @temp = $dev->bus_read( MPU6050_TEMP_OUT_H, 2 ); 
>
> Returns two bytes as an array of two values. High byte, low byte.
>
> For example I may get:
>
> $temp[0] = 244; # 0xFD

This is 0xf4, not 0xfd.

> $temp[1] = 224; # 0xE0
>
> Which is -2848. I (eventually) came up with this
>
> $temp = unpack 's', pack 'CC', reverse @temp;
>
> Is there a better method?

What's you definition of 'better' here? You can generally build the
number by 'putting the bytes in the right place', ie

$temp[0] << 8 | $temp[1]

If you want it to be interpreted as signed, two ways to achieve that
would be

($temp[0] << 8 | $temp[1]) - ($temp[0] & 0x80 && 0x1000)

and

use integer;
($temp[0] << 8 | $temp[1]) ^ ($temp[0] & 0x80 && HIBITS)

with HIBITS defined as

use constant HIBITS => -1 & ~0xffff;

both are faster (for me) than your approach, OTOH, you'll very likely
freak out people to whom it never occured that computers actually work
with binary numbers and that the bit operators are useful.

sample code:
-------------
use Benchmark;

use constant HIBITS => -1 & ~0xffff;

@t = (0xf4, 0xe0);

timethese(-3,
	  {
	   pack => sub {
	       return unpack('s', pack('CC', reverse(@t)));
	   },
	   
	   calc => sub {
	       use integer;
	      return ($t[0] << 8 | $t[1]) ^ ($t[0] & 0x80 && HIBITS);
	  }});


------------------------------

Date: Sat, 05 Apr 2014 20:49:44 +0100
From: Rainer Weikusat <rweikusat@mobileactivedefense.com>
Subject: Re: pack/unpack help please
Message-Id: <871txbmu93.fsf@sable.mobileactivedefense.com>

Rainer Weikusat <rweikusat@mobileactivedefense.com> writes:
> "Dave Saville" <No-Spam@deezee.org> writes:
>> I am using perl on a Rasberry pi to read an i2c device using the hipi 
>> library.
>>
>> @temp = $dev->bus_read( MPU6050_TEMP_OUT_H, 2 ); 
>>
>> Returns two bytes as an array of two values. High byte, low byte.

[...]

> use integer;
> ($temp[0] << 8 | $temp[1]) ^ ($temp[0] & 0x80 && HIBITS)
>
> with HIBITS defined as
>
> use constant HIBITS => -1 & ~0xffff;

The xor is somewhat out-of-place here because there are no overlapping
1-bits in both numbers. | can be used as well.


------------------------------

Date: Sun, 6 Apr 2014 12:58:13 +0000 (UTC)
From: "Dave Saville" <No-Spam@deezee.org>
Subject: Re: pack/unpack help please
Message-Id: <fV45K0OBJxbE-pn2-YdGSMxfn5bkG@paddington.bear.den>

On Sat, 5 Apr 2014 19:25:51 UTC, Rainer Weikusat 
<rweikusat@mobileactivedefense.com> wrote:

> "Dave Saville" <No-Spam@deezee.org> writes:
> > I am using perl on a Rasberry pi to read an i2c device using the hipi 
> > library.
> >
> > @temp = $dev->bus_read( MPU6050_TEMP_OUT_H, 2 ); 
> >
> > Returns two bytes as an array of two values. High byte, low byte.
> >
> > For example I may get:
> >
> > $temp[0] = 244; # 0xFD
> 
> This is 0xf4, not 0xfd.

Yup - typo and/or brain to keyboard. :-)

> 
> > $temp[1] = 224; # 0xE0
> >
> > Which is -2848. I (eventually) came up with this
> >
> > $temp = unpack 's', pack 'CC', reverse @temp;
> >
> > Is there a better method?
> 
> What's you definition of 'better' here? You can generally build the
> number by 'putting the bytes in the right place', ie
> 
> $temp[0] << 8 | $temp[1]
> 

That's what I thought at first, but the sign stumped me.

> If you want it to be interpreted as signed, two ways to achieve that
> would be
> 
> ($temp[0] << 8 | $temp[1]) - ($temp[0] & 0x80 && 0x1000)
> 
> and
> 
> use integer;
> ($temp[0] << 8 | $temp[1]) ^ ($temp[0] & 0x80 && HIBITS)
> 
> with HIBITS defined as
> 
> use constant HIBITS => -1 & ~0xffff;

Hmm I see how the second one works but the first doesn't :

use strict;
use warnings;

my @temp;
$temp[0] = 244; # 0xF4
$temp[1] = 224; # 0xE0
printf "%X %X\n", @temp;
printf "%X\n", $temp[0] & 0x80;
printf "%X\n", $temp[0] & 0x80 && 0x1000;
printf "%X\n", ($temp[0] << 8 | $temp[1]) - ($temp[0] & 0x80 && 
0x1000);
printf "%d\n", ($temp[0] << 8 | $temp[1]) - ($temp[0] & 0x80 && 
0x1000);
use integer;
use constant HIBITS => -1 & ~0xffff;
printf "%X\n", HIBITS;
printf "%X\n", $temp[0] & 0x80;
printf "%X\n", $temp[0] & 0x80 && HIBITS;
printf "%X\n", ($temp[0] << 8 | $temp[1]) ^ ($temp[0] & 0x80 && 
HIBITS);
printf "%d\n", ($temp[0] << 8 | $temp[1]) ^ ($temp[0] & 0x80 && 
HIBITS);

[T:\tmp]try.pl
F4 E0
80
1000
E4E0
58592
FFFF0000
80
FFFF0000
FFFFF4E0
-2848


-- 
Regards
Dave Saville


------------------------------

Date: Sun, 06 Apr 2014 15:36:40 +0100
From: Rainer Weikusat <rweikusat@mobileactivedefense.com>
Subject: Re: pack/unpack help please
Message-Id: <87a9by1q4n.fsf@sable.mobileactivedefense.com>

"Dave Saville" <No-Spam@deezee.org> writes:
> On Sat, 5 Apr 2014 19:25:51 UTC, Rainer Weikusat 
> <rweikusat@mobileactivedefense.com> wrote:
>> "Dave Saville" <No-Spam@deezee.org> writes:
>> > I am using perl on a Rasberry pi to read an i2c device using the hipi 
>> > library.
>> >
>> > @temp = $dev->bus_read( MPU6050_TEMP_OUT_H, 2 ); 
>> >
>> > Returns two bytes as an array of two values. High byte, low byte.
>> >
>> > For example I may get:
>> >
>> > $temp[0] = 244; # 0xFD

[...]

>> If you want it to be interpreted as signed, two ways to achieve that
>> would be
>> 
>> ($temp[0] << 8 | $temp[1]) - ($temp[0] & 0x80 && 0x1000)

[...]

> Hmm I see how the second one works but the first doesn't :

My bad. The final number in the second term should be 0x10000 (65536),
not 0x1000 (4096).

perl -e 'print((0xf4 << 8 | 0xe0) - (0xf4 & 0x80 && 0x10000))'

Both rely on negative integers being represented as two's complement. In
this case, a negative n-bit integer is encoded as 'distance' from 2**n,
ie 0xffff aka 65535 is -1.


------------------------------

Date: Sun, 6 Apr 2014 15:22:09 +0000 (UTC)
From: "Dave Saville" <No-Spam@deezee.org>
Subject: Re: pack/unpack help please
Message-Id: <fV45K0OBJxbE-pn2-Uy1Fd0H4p8Hi@paddington.bear.den>

On Sun, 6 Apr 2014 14:36:40 UTC, Rainer Weikusat 
<rweikusat@mobileactivedefense.com> wrote:

> My bad. The final number in the second term should be 0x10000 (65536),
> not 0x1000 (4096).
>

What's a factor of 16 between friends? :-)
 
> perl -e 'print((0xf4 << 8 | 0xe0) - (0xf4 & 0x80 && 0x10000))'
> 
> Both rely on negative integers being represented as two's complement. In
> this case, a negative n-bit integer is encoded as 'distance' from 2**n,
> ie 0xffff aka 65535 is -1.
>  

I am happy playing with bits - I just could not see what you were 
trying to do there. Whereas your second method was obvious what it 
did.

Just for fun I added another I dreamed up to your benchmark

kalk => sub {
    my $x = $t[0] << 8 | $t[1];
    return $t[0] & 0x80 ? ~(~$x & 0xffff) : $x;

Which sits between the two.

Thanks.

-- 
Regards
Dave Saville


------------------------------

Date: 6 Apr 2001 21:33:47 GMT (Last modified)
From: Perl-Users-Request@ruby.oce.orst.edu (Perl-Users-Digest Admin) 
Subject: Digest Administrivia (Last modified: 6 Apr 01)
Message-Id: <null>


Administrivia:

To submit articles to comp.lang.perl.announce, send your article to
clpa@perl.com.

Back issues are available via anonymous ftp from
ftp://cil-www.oce.orst.edu/pub/perl/old-digests. 

#For other requests pertaining to the digest, send mail to
#perl-users-request@ruby.oce.orst.edu. Do not waste your time or mine
#sending perl questions to the -request address, I don't have time to
#answer them even if I did know the answer.


------------------------------
End of Perl-Users Digest V11 Issue 4187
***************************************


home help back first fref pref prev next nref lref last post