dosa dosa - 1 year ago 106
Perl Question

perl bigint not working with regexp matches

I see the following log messages. By looking at the numbers, I have a suspicion that

timeStampLastSeekPoint
is always one plus
timeInNanos
.

% grep -E '^java.lang.IllegalArgumentException.*timeStampLastSeekPoint' messages | head -5
java.lang.IllegalArgumentException: timeInNanos=1500629929661000010, timeStampLastSeekPoint=1500629929661000011
java.lang.IllegalArgumentException: timeInNanos=1500629929661000010, timeStampLastSeekPoint=1500629929661000011
java.lang.IllegalArgumentException: timeInNanos=1500629929661000010, timeStampLastSeekPoint=1500629929661000011
java.lang.IllegalArgumentException: timeInNanos=1500630763150000010, timeStampLastSeekPoint=1500630763150000011
java.lang.IllegalArgumentException: timeInNanos=1500630763150000010, timeStampLastSeekPoint=1500630763150000011


To confirm my suspicion, I pipe into this perl one-liner to extract numbers and show the difference. The differences show all 0s, which can't be true. It is immediately clear that I need higher precision.

% grep -E '^java.lang.IllegalArgumentException.*timeStampLastSeekPoint' messages | \
perl -ne 'if (/timeInNanos=(\d+), timeStampLastSeekPoint=(\d+)/) { printf("%ld %ld %ld\n", $1, $2, $2 - $1) }' | head -5
1500629929661000010 1500629929661000011 0
1500629929661000010 1500629929661000011 0
1500629929661000010 1500629929661000011 0
1500630763150000010 1500630763150000011 0
1500630763150000010 1500630763150000011 0


I googled, found the
bigint
module, and tried it. However, it still doesn't work.

% grep -E '^java.lang.IllegalArgumentException.*timeStampLastSeekPoint' messages | \
perl -Mbigint -ne 'if (/timeInNanos=(\d+), timeStampLastSeekPoint=(\d+)/) { printf("%ld %ld %ld\n", $1, $2, $2 - $1) }' | head -5
1500629929661000010 1500629929661000011 0
1500629929661000010 1500629929661000011 0
1500629929661000010 1500629929661000011 0
1500630763150000010 1500630763150000011 0
1500630763150000010 1500630763150000011 0


After a few attempts, I find that it works only after the regexp matches are assigned to regular variables. As an aside, I now confirm my suspicion that the diff is always 1.

% grep -E '^java.lang.IllegalArgumentException.*timeStampLastSeekPoint' messages | \
perl -Mbigint -ne 'if (/timeInNanos=(\d+), timeStampLastSeekPoint=(\d+)/) { printf("%ld %ld %ld\n", $1, $2, ($b=$2) - ($a=$1)) }' | head -5
1500629929661000010 1500629929661000011 1
1500629929661000010 1500629929661000011 1
1500629929661000010 1500629929661000011 1
1500630763150000010 1500630763150000011 1
1500630763150000010 1500630763150000011 1


All good now that I find the workaround. However, it is not intuitive why the assignments are necessary. Shouldn't
$2 - $1
just work? It feels like a bug. Or, is there an explanation to understand that this is a reasonable behavior? The perl version is v5.14.2.

Answer Source

use bigint; has no effect on your program because it only affects numeric literals, and your program has none.

use bigint; effectively replaces numeric literals with Math::BigInt->new("LITERAL"). This means that

use bigint;

2

is equivalent to

use Math::BigInt qw( );

Math::BigInt->new("2")

This presents a solution:

use Math::BigInt qw( );

Math::BigInt->new($2) - Math::BigInt->new($1)

But thanks to overloaded operators, you could simply use

use Math::BigInt qw( );

Math::BigInt->new($2) - $1

or

use bigint;

0 + $2 - $1

In all cases, you want to use %s (not %d) to have M::BI stringify the num instead of having it numify to an integer.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download