tags:

views:

174

answers:

2

I have this piece of script :

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my @arr = (
    {
        name  => 'foo',
        value => 123,
    },
    {
        name  => 'bar',
        value => 'nan',
    },
    {
        name  => 'foobar',
        value => 456,
    },
);

@arr = sort {$a->{value} <=> $b->{value} } @arr;

print Dumper(\@arr);

I don't have any problems under Windows XP / Strawberry Perl 5.10.1

either Linux 2.6.12-1 i386 / Perl v5.8.5 built for i386-linux-thread-multi,

but under Linux 2.6.18-53 / Perl v5.8.8 built for x86_64-linux-thread-multi, i got the error message :

Sort subroutine didn't return a numeric value at testsort.pl line 21.

What's going wrong and how can i fix it ?

+5  A: 

In some builds, 'nan' is coerced to the number 0 for a <=> comparison and the sort succeeds. In other builds, nan is treated as "not a number" and the return value from <=> is undefined.

For maximum portability, test a value for whether it is a good number of not:

(isnan subroutine from How do I create or test for NaN or infinity in Perl?):

sub isnan { ! defined( $_[0] <=> 9**9**9 ) }

@arr = sort { isnan($a->{value}) ? 0 : $a->{value}
                         <=>  
              isnan($b->{value}) ? 0 : $b->{value} }  @arr;
mobrule
@mobrule: Thanks, i'll try it.
M42
It works. I've surrounded ternary by parenthesis.
M42
nice question and answer. -- except there are two `sub isnan {` in there, might want to delete one
vol7ron
Sorry vol7ron -- fixed.
mobrule
+2  A: 

2 Solutions

  1. mobrule's solution:

    sub isnan { ! defined( $_[0] <=> 9**9**9 ) }
    @arr = sort { isnan($a->{value}) ? 0 : $a->{value}
                                  <=>  
                  isnan($b->{value}) ? 0 : $b->{value} }  @arr;
    
  2. Perldoc's solution:

    @result = sort { $a <=> $b } grep { $_ == $_ } @input;
    

  1. Gives your NaN a 0 value, which should push it to the top of the list.
  2. Takes advantage that NaN != NaN, to eliminate any NaNs from the input list.

As mobrule stated, this is caused by the comparison of NaN between builds.

vol7ron