Numbers not acting like numbers

D

D'Anne Asquith

I have subroutine for computing base-10 log. With a recent upgrade from
Perl5.6 to Perl5.8 on both Linux and Solaris systems, a very large program
with a proven track record is not behaving right. The subroutine snippet is
as follows.

use constant logof10 => scalar log(10);
use constant ZERO => scalar 0;
sub log10 {
my $n = shift;
#my $n = &repackit(shift); # HACK HERE
($n <= ZERO) ? undef : log($n)/logof10;
}

On apparently random occurrences the argument (say 0.1) is testing as <= 0
and the subroutine returns undef. Surprize. However, the subroutine might
work for a thousand calls before return undef. I have carefully tracked the
argument upto the subroutine call and inside the subroutine (code not shown)
here and $n is 0.1. The ZERO instead of 0 does not seem to affect the
behavior--still occurs.

If I uncomment the HACK HERE line and comment out the first line, the
subroutine works everytime!

sub repackit {
my $n = shift;
return unpack("d",pack("d",$n));
}

I should not have to do the pack/unpack. It is possible that the argument
is really "0.1" (note double quotes) and not 0.1 deep in the program logic.
Would this be the source of the problem? Unfortunately, when I create a
tiny test program I can not reproduce the problem. The only thing changed
in years of multiple users of the program is use of Perl5.8.

Could someone comment on how a value that looks like 0.1 would test as <=
0--could Perl somehow consider 0.1 as int(0.1) internally?

Thanks,
dasq
 
A

Anno Siegel

D'Anne Asquith said:
I have subroutine for computing base-10 log. With a recent upgrade from
Perl5.6 to Perl5.8 on both Linux and Solaris systems, a very large program
with a proven track record is not behaving right. The subroutine snippet is
as follows.

use constant logof10 => scalar log(10);
use constant ZERO => scalar 0;

"scalar" isn't needed here. "log()" and "0" don't depend on context.
sub log10 {
my $n = shift;
#my $n = &repackit(shift); # HACK HERE
($n <= ZERO) ? undef : log($n)/logof10;
}


Your code isn't wrong, but the use of constants is of no advantage here.
You use named constants if the value you are using could conceivably
change in another version, or if the expression is particularly
complicated. Neither apply to "ZERO" or "logof10".

sub log10 {
my $n = shift;
return unless $n > 0;
log($n)/log(10);
}
On apparently random occurrences the argument (say 0.1) is testing as <= 0
and the subroutine returns undef. Surprize. However, the subroutine might
work for a thousand calls before return undef. I have carefully tracked the
argument upto the subroutine call and inside the subroutine (code not shown)
here and $n is 0.1. The ZERO instead of 0 does not seem to affect the
behavior--still occurs.

If I uncomment the HACK HERE line and comment out the first line, the
subroutine works everytime!

sub repackit {
my $n = shift;
return unpack("d",pack("d",$n));
}

I should not have to do the pack/unpack. It is possible that the argument
is really "0.1" (note double quotes) and not 0.1 deep in the program logic.
Would this be the source of the problem? Unfortunately, when I create a
tiny test program I can not reproduce the problem. The only thing changed
in years of multiple users of the program is use of Perl5.8.

Could someone comment on how a value that looks like 0.1 would test as <=
0--could Perl somehow consider 0.1 as int(0.1) internally?

There is a theoretical possibility for a variable to have independent
string and numeric content ($! is an example). In that case, yes, it
could print as "0.1" and compare negative. But Perl doesn't create such
variables out of the blue, it takes some doing [1].

Anno

[1] use Scalar::Util 'dualvar';
my $foo = dualvar(-1, "0.1");
print "$foo is negative\n" if $foo < 0;
 
H

Heinrich Mislik

I have subroutine for computing base-10 log. With a recent upgrade from
Perl5.6 to Perl5.8 on both Linux and Solaris systems, a very large program
with a proven track record is not behaving right. The subroutine snippet is
as follows.

use constant logof10 => scalar log(10);
use constant ZERO => scalar 0;
sub log10 {
my $n = shift;
#my $n = &repackit(shift); # HACK HERE
($n <= ZERO) ? undef : log($n)/logof10;
}

Could there be some non-printable characters in your data? Consider the
following one-liner:

#perl -e '$_ = "\x080.1";print "$_\n";print "equal\n" if $_ <= 0'
0.1
equal

I couldn't find an example, where the pack/unpack removes such a character,
but this may even be specific to your platform.

hth
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,528
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top