Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"sort { $a <=> $b }" silent on <=> returning non-number #9603

Closed
p5pRT opened this issue Dec 17, 2008 · 10 comments
Closed

"sort { $a <=> $b }" silent on <=> returning non-number #9603

p5pRT opened this issue Dec 17, 2008 · 10 comments

Comments

@p5pRT
Copy link

p5pRT commented Dec 17, 2008

Migrated from rt.perl.org#61448 (status was 'resolved')

Searchable as RT61448$

@p5pRT
Copy link
Author

p5pRT commented Dec 17, 2008

From @ikegami

Created by @ikegami

When the builtin comparison code for "sort { $a <=> $b }" is used,
a warning you'd otherwise get is silenced.

--- BEGIN CODE ---
use strict;
use warnings;

# I don't know how else to generate a NaN in ActivePerl.
my $nan = unpack 'd', scalar reverse pack 'H*', '0x7FFFFFFFFFFFFFFF';

{ print("Builtin​:\n"); my @​a = sort { $a <=> $b } 0, $nan; }
{ print("User supplied​:\n"); my @​a = sort { 1; $a <=> $b } 0, $nan; }
--- END CODE ---

--- BEGIN OUTPUT ---
Builtin​:
User supplied​:
Sort subroutine didn't return a numeric value at bug.pl line 8.
--- END OUTPUT ---

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl 5.10.0:

Configured by SYSTEM at Tue Dec 18 08:45:53 2007.

Summary of my perl5 (revision 5 version 10 subversion 0) configuration:
  Platform:
    osname=MSWin32, osvers=5.00, archname=MSWin32-x86-multi-thread
    uname=''
    config_args='undef'
    hint=recommended, useposix=true, d_sigaction=undef
    useithreads=define, usemultiplicity=define
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=undef, use64bitall=undef, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cl', ccflags ='-nologo -GF -W3 -MD -Zi -DNDEBUG -O1 -DWIN32
-D_CONSOLE -DNO_STRICT -DHAVE_DES_FCRYPT -DUSE_SITECUSTOMIZE
-DPRIVLIB_LAST_IN_INC -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS
-DUSE_PERLIO -DPERL_MSVCRT_READFIX',
    optimize='-MD -Zi -DNDEBUG -O1',
    cppflags='-DWIN32'
    ccversion='12.00.8804', gccversion='', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=undef, longlongsize=8, d_longdbl=define, longdblsize=10
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='__int64',
lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='link', ldflags ='-nologo -nodefaultlib -debug -opt:ref,icf
-libpath:"C:\progs\perl5100\lib\CORE"  -machine:x86'
    libpth=\lib
    libs=  oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib
comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib  netapi32.lib
uuid.lib ws2_32.lib mpr.lib winmm.lib  version.lib odbc32.lib odbccp32.lib
msvcrt.lib
    perllibs=  oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib
comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib  netapi32.lib
uuid.lib ws2_32.lib mpr.lib winmm.lib  version.lib odbc32.lib odbccp32.lib
msvcrt.lib
    libc=msvcrt.lib, so=dll, useshrplib=true, libperl=perl510.lib
    gnulibc_version=''
  Dynamic Linking:
    dlsrc=dl_win32.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' '
    cccdlflags=' ', lddlflags='-dll -nologo -nodefaultlib -debug
-opt:ref,icf  -libpath:"C:\progs\perl5100\lib\CORE"  -machine:x86'

Locally applied patches:
    ACTIVEPERL_LOCAL_PATCHES_ENTRY


@INC for perl 5.10.0:
    c:/progs/perl5100/site/lib
    c:/progs/perl5100/lib
    .


Environment for perl 5.10.0:
    HOME (unset)
    LANG (unset)
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)

PATH=c:\bin;c:\progs\perl5100\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\WBEM
    PERL_BADLANG (unset)
    SHELL (unset)

@p5pRT
Copy link
Author

p5pRT commented Jul 8, 2011

From alex@chmrr.net

Created by alex@chmrr.net

Sorting a list containing NaN leads to odd results​:

  umgah ~ $ perl -wle 'print for sort {$a <=> $b} (4,6,5,2,NaN,3,1);'
  2
  4
  5
  6
  NaN
  1
  3

Given that NaN, and repeated comparisons to it, is involved, this in
itself is not terribly surprising. However, `perldoc -f sort` says on
the topic​:

  Because "<=>" returns "undef" when either operand is "NaN"
  (not-a-number), and because "sort" will trigger a fatal error
  unless the result of a comparison is defined, when sorting with a
  comparison function like "$a <=> $b", be careful about lists that
  might contain a "NaN".

The promised fatal error does not seem to have appeared. It is
unclear if this is to be considered an error in the documentation, or
a regression in the implementation of "sort."

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl v5.8.8:

Configured by Gentoo at Fri Feb 26 02:28:51 EST 2010.

Summary of my perl5 (revision 5 version 8 subversion 8) configuration:
  Platform:
    osname=linux, osvers=2.6.29-gentoo-r5, archname=x86_64-linux
    uname='linux utwig 2.6.29-gentoo-r5 #1 smp sun jul 26 18:16:09 edt 2009 x86_64 intel(r) xeon(tm) cpu 3.60ghz genuineintel gnulinux '
    config_args='-des -Darchname=x86_64-linux -Dcccdlflags=-fPIC -Dccdlflags=-rdynamic -Dcc=x86_64-pc-linux-gnu-gcc -Dprefix=/usr -Dvendorprefix=/usr -Dsiteprefix=/usr -Dlocincpth=  -Doptimize=-O2 -march=nocona -pipe -Duselargefiles -Dd_semctl_semun -Dscriptdir=/usr/bin -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dinstallman1dir=/usr/share/man/man1 -Dinstallman3dir=/usr/share/man/man3 -Dman1ext=1 -Dman3ext=3pm -Dinc_version_list=5.8.0 5.8.0/x86_64-linux 5.8.2 5.8.2/x86_64-linux 5.8.4 5.8.4/x86_64-linux 5.8.5 5.8.5/x86_64-linux 5.8.6 5.8.6/x86_64-linux 5.8.7 5.8.7/x86_64-linux  -Dcf_by=Gentoo -Ud_csh -Dusenm -Di_ndbm -Di_gdbm -Di_db -Dusrinc=/usr/include -Dlibpth=/usr/local/lib64 /lib64 /usr/lib64'
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef
    useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
    use64bitint=define use64bitall=define uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='x86_64-pc-linux-gnu-gcc', ccflags ='-fno-strict-aliasing -pipe -Wdeclaration-after-statement -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2 -march=nocona -pipe',
    cppflags='-fno-strict-aliasing -pipe -Wdeclaration-after-statement'
    ccversion='', gccversion='4.3.4', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='x86_64-pc-linux-gnu-gcc -O2 -march=nocona -pipe', ldflags =' -L/usr/local/lib64'
    libpth=/usr/local/lib64 /lib64 /usr/lib64
    libs=-lpthread -lnsl -lndbm -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc
    perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
    libc=/lib/libc-2.10.1.so, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version='2.10.1'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-rdynamic'
    cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib64'

Locally applied patches:
    


@INC for perl v5.8.8:
    /etc/perl
    /usr/lib64/perl5/vendor_perl/5.8.8/x86_64-linux
    /usr/lib64/perl5/vendor_perl/5.8.8
    /usr/lib64/perl5/vendor_perl/5.8.6
    /usr/lib64/perl5/vendor_perl/5.8.6/x86_64-linux
    /usr/lib64/perl5/vendor_perl/5.8.7
    /usr/lib64/perl5/vendor_perl/5.8.7/x86_64-linux
    /usr/lib64/perl5/vendor_perl
    /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux
    /usr/lib64/perl5/site_perl/5.8.8
    /usr/lib64/perl5/site_perl/5.8.6
    /usr/lib64/perl5/site_perl/5.8.6/x86_64-linux
    /usr/lib64/perl5/site_perl/5.8.7
    /usr/lib64/perl5/site_perl/5.8.7/x86_64-linux
    /usr/lib64/perl5/site_perl
    /usr/lib64/perl5/5.8.8/x86_64-linux
    /usr/lib64/perl5/5.8.8
    /usr/local/lib/site_perl
    .


Environment for perl v5.8.8:
    HOME=/home/chmrr
    LANG=en_US.UTF-8
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/chmrr/bin:/usr/local/bin:/usr/bin:/bin:/opt/bin:/usr/x86_64-pc-linux-gnu/gcc-bin/4.4.4
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Oct 13, 2011

From @cpansprout

On Fri Jul 08 13​:31​:48 2011, alex@​chmrr.net wrote​:

This is a bug report for perl from alex@​chmrr.net,
generated with the help of perlbug 1.35 running under perl v5.8.8.

-----------------------------------------------------------------
[Please enter your report here]

Sorting a list containing NaN leads to odd results​:

umgah ~ $ perl \-wle 'print for sort \{$a \<=> $b\}

(4,6,5,2,NaN,3,1);'
2
4
5
6
NaN
1
3

Given that NaN, and repeated comparisons to it, is involved, this in
itself is not terribly surprising. However, `perldoc -f sort` says on
the topic​:

Because "\<=>" returns "undef" when either operand is "NaN"
\(not\-a\-number\)\, and because "sort" will trigger a fatal error
unless the result of a comparison is defined\, when sorting with a
comparison function like "$a \<=> $b"\, be careful about lists that
might contain a "NaN"\.

The promised fatal error does not seem to have appeared. It is
unclear if this is to be considered an error in the documentation, or
a regression in the implementation of "sort."

The behaviour of sort with regard to undefined values return from
comparison routines changed intentionally in 5.12 (see bug #69384), but
the documentation was never updated. Now it does not die, but produced
an ‘Uninitialized value’ warning for undef, for consistency with other
functions and operators that take numbers.

In previous perl versions, the {$a <=> $b} case is specially optimised
and the optimisation did not take undefs into account (presumably
because the implementor did not think it could happen). It dies with
something more complex, like {($a)[0] <=> $b}, which is not optimised away.

I have just updated the documentation with commit 1bd4e8e.

However, there is still an optimisation bug​:

$ perl5.12.0 -wle 'print for sort {($a)[0] <=> $b} (4,6,5,2,NaN,3,1);'
Use of uninitialized value at -e line 1.
Use of uninitialized value at -e line 1.
Use of uninitialized value at -e line 1.
Use of uninitialized value at -e line 1.
Use of uninitialized value at -e line 1.
Use of uninitialized value at -e line 1.
2
4
5
6
NaN
1
3
$ perl5.12.0 -wle 'print for sort {$a <=> $b} (4,6,5,2,NaN,3,1);'
2
4
5
6
NaN
1
3

I’ve just fixed that with commit f3dab52.

@p5pRT
Copy link
Author

p5pRT commented Oct 13, 2011

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Oct 13, 2011

@cpansprout - Status changed from 'open' to 'resolved'

@p5pRT
Copy link
Author

p5pRT commented Oct 13, 2011

From @cpansprout

I made enough mistakes in my message that it’s confusing.

On Wed Oct 12 23​:29​:54 2011, sprout wrote​:

The behaviour of sort with regard to undefined values return from

s/return\k/ed/

comparison routines changed intentionally in 5.12 (see bug #69384), but
the documentation was never updated. Now it does not die, but produced

s/produce\kd/s/

an ‘Uninitialized value’ warning for undef, for consistency with other
functions and operators that take numbers.

In previous perl versions, the {$a <=> $b} case is specially optimised
and the optimisation did not take undefs into account (presumably

s/undef/nan/

because the implementor did not think it could happen). It dies with
something more complex, like {($a)[0] <=> $b}, which is not optimised
away.

@p5pRT
Copy link
Author

p5pRT commented Oct 13, 2011

From @cpansprout

Aha! This is the same as #94390, which I’ve just fixed.

@p5pRT
Copy link
Author

p5pRT commented Oct 13, 2011

@cpansprout - Status changed from 'new' to 'resolved'

@p5pRT p5pRT closed this as completed Oct 13, 2011
@p5pRT
Copy link
Author

p5pRT commented Oct 13, 2011

From @cpansprout

On Wed Dec 17 14​:35​:52 2008, ikegami@​adaelis.com wrote​:

# I don't know how else to generate a NaN in ActivePerl.
my $nan = unpack 'd', scalar reverse pack 'H*', '0x7FFFFFFFFFFFFFFF';

You can use sin(9**9**9), which produces a negative nan. -sin(...)
produces a positive nan. But in 32-bit ActivePerl, nan breaks if you
try to do anything with it.

(See also <https://rt.cpan.org/Public/Bug/Display.html?id=65876>).

@p5pRT
Copy link
Author

p5pRT commented Oct 13, 2011

From jpl@research.att.com

There's already a comment in perlfunc.pod warning about sort and NaN. I
think I might have put it there. If not, I wish I had put it there. -- jpl

Because C<< <=> >> returns C<undef> when either operand is C<NaN>
(not-a-number), and also because C<sort> raises an exception unless the
result of a comparison is defined, be careful when sorting with a
comparison function like C<< $a <=> $b >> any lists that might contain a
C<NaN>. The following example takes advantage that C<NaN != NaN> to
eliminate any C<NaN>s from the input list.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant