develooper Front page | perl.perl5.porters | Postings from June 2015

Re: Coverity finding: shift by negative

Thread Previous | Thread Next
From:
Ricardo Signes
Date:
June 23, 2015 12:55
Subject:
Re: Coverity finding: shift by negative
Message ID:
20150623125505.GA16140@cancer.codesimply.com
* Abigail <abigail@abigail.be> [2015-06-23T07:00:19]
> > At the very minimum, I would suggest undef for the negative shift case.
> > (To get Coverity off our case.)
> 
> Changing direction seems, to me, the logical thing to do. 

Agreed.

> What to do with left shifting "too many bits" means picking an evil;
> in order of my preference:
> 
>    1) Promote the IV to an NV; that is, treat "<< $n" as "* 2 ** $n".
>       Of course, if $n gets too large, we first start to lose precision,
>       and then we'll get an overflow. 

I thought #1 was most preferable to me, too.  It preserves, more or less, the
doubling property of left shifting, and leaves us open to moving to higher
precision math in the future...

...but for what reason are programmers left shifting so darn far?

Why, for example, aren't they just multiplying by a power of two?  I tend to do
it for the same reason I use => instead of a comma.  That is, for the benefit
of a later reader (in expressing the idea of the code, not just its effect),
and maybe to save some typing.  If that's the case for everybody else, then it
should act just like multiple doubling.

Maybe it's just for precedence.  Again, should act like doubling.

...except how does this translate back to right shifting?  That's *integer*
division by two.  And left shifting is already *integer* multiplication.
1.8<<1 is 2, not 3 or 3.6 or 4.  And in perl's integer semantics, when $x
repeatedly doubled, you eventually hit zero... but not before hitting
-9223372036854775808 at the 64th doubling, on 64-bit.

  DB<33> p do { use integer; my $x = 1; for (1..63) { $x *= 2 }  $x }
  -9223372036854775808

  DB<37> p do { use integer; my $x = 1; $x << 63 }
  -9223372036854775808

  DB<38> p 1 << 63
  9223372036854775808

So in the end, I don't think we're shooting for consistency, because the things
we'd be consistent with are not worth emulating.  The more I look into this,
the more I think we're picking at a scab, and the less sure I feel about any
particular suggestion.  My tentative thinking is:

  * right shifting by "a whole lot" gets you to zero
  * shifting by a negative number reverses the direction of the shift
  * left shifting by a large enough value warns and keeps its current behavior

I can't think of semantics other than "bigint everywhere" that are worth
breaking anything for.  The current semantics are bizarre, but they're there.
If we change them, it should be to something worth the trouble.  I don't think
I've seen anything compelling.

How big is big enough to warn?  Either 32, because your program would be
affected if run on a 32-bit perl (even though you aren't) or maxbits, because
it is affected in this runtime.

> Well, ideally, I'd like option 0): do what Python and Ruby does:
> automatically start using bigints, but that would require a lot of
> changes.

Agreed.

-- 
rjbs

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About