Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange behaviour of sort

Tags:

sorting

perl

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 ?

like image 632
Toto Avatar asked Jul 09 '10 14:07

Toto


2 Answers

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;
like image 144
mob Avatar answered Oct 31 '22 17:10

mob


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.

like image 42
vol7ron Avatar answered Oct 31 '22 18:10

vol7ron