Raku operator for 2's complement arithmetic?

Viewed 129

I sometimes use this:

$ perl -e "printf \"%d\", ((~18446744073709551592)+1)"
24

I can't seem to do it with Raku. The best I could get is:

$ raku -e "say +^18446744073709551592"
-18446744073709551593

So: how can I make Raku give me the same answer as Perl ?

2 Answers

Gotta go with (my variant¹ of) Liz's custom op (in her comment below).

sub prefix:<²^>(uint $a) { (+^ $a) + 1 }

say ²^ 18446744073709551592; # 24

My original "semi-educated wild guess"² that turned out to be acceptable to @zentrunix and the basis for Liz's op:

say (+^ my uint $ = 18446744073709551592) + 1; # 24

\o/ It works!³

Footnotes

¹ I flipped the two character op because I wanted to follow the +^ form, have it sub-vocalize as "two's complement", and avoid it looking like ^2.

² One line of thinking was about the particular integer. I saw that 18446744073709551592 is close to 2**64. Another was that integers are limited precision in Perl unless you do something to make them otherwise, whereas in Raku they are arbitrary precision unless you do something to make them otherwise. A third line of thinking came from reading the doc for prefix +^ which says "converts the number to binary using as many bytes as needed" which I interpreted as meaning that the representation is somehow important. Hmm. What if I try an int variable? Overflow. (Of course.) uint? Bingo.

³ I've no idea if this solution is right for the wrong reasons. Or even worse. One thing that's concerning is that uint in Raku is defined to correspond to the largest native unsigned integer size supported by the Raku compiler used to compile the Raku code. (Iirc.) In practice today this means Rakudo and whatever underlying platform is being targeted, and I think that almost certainly means C's uint64_t in almost all cases. I imagine perl has some similar platform dependent definition. So my solution, if it is a reasonable one, is presumably only portable to the degree that the Raku compiler (which in practice today means Rakudo) agrees with the perl binary (which in practice today means P5P's perl) when run on some platform. See also @p6steve's comment below.

'Long-hand' answer:

raku -e 'put ( (18446744073709551592.base(2) - 0b1).comb.map({!$_.Int+0}).join.parse-base(2));'

OR

raku -e 'say 18446744073709551592.base(2).comb.map({!$_.Int+0}).join.parse-base(2) + 1;'

Sample Output: 24

The answers above (should?) implement "Two's-Complement" encoding directly. Neither uses Raku's +^ twos-complement operator. The first one subtracts one from the binary representation, then inverts. The second one inverts first, then adds one. Neither answer feels truly correct, yet the same answer as Perl5 is obtained (24).

Looking at the Raku Docs page, one would conclude that the "twos-complement" of a positive number would be negative, hence it's not clear what the Perl (and now Raku) answers represent. Hopefully the foregoing is somewhat useful.

https://docs.raku.org/routine/+$CIRCUMFLEX_ACCENT

Related