2009-04-29 9 views
3

Ich baute ein Perl Inline::C Modul, aber es gibt einige Kuriositäten mit der Sortierung. Weiß jemand, warum es so aussehen würde? Warum ist das 4.0e-5 nicht zuerst?Warum funktioniert Perls Inline :: C 4.0e-5 nach 4.4e-5?

my $ref = [ 5.0e-5,4.2e-5,4.3e-5,4.4e-5,4.4e-5,4.2e-5,4.2e-5,4.0e-5]; 

use Inline C => <<'END_OF_C_CODE'; 

void test(SV* sv, ...) { 

    I32 i; 
    I32 arrayLen; 
    AV* data; 
    float retval; 
    SV** pvalue; 

    Inline_Stack_Vars; 
    data = SvUV(Inline_Stack_Item(0)); 

    /* Determine the length of the array */ 
    arrayLen = av_len(data); 

    // sort 
    sortsv(AvARRAY(data),arrayLen+1,Perl_sv_cmp_locale); 

    for (i = 0; i < arrayLen+1; i++) { 

    pvalue = av_fetch(data,i,0); /* fetch the scalar located at i .*/ 
    retval = SvNV(*pvalue); /* dereference the scalar into a number. */ 

    printf("%f \n",newSVnv(retval)); 
    } 
} 

END_OF_C_CODE 

Test ($ ref);

0,000042
0,000042
0,000042
0,000043
0,000044
0,000044
0,000040
0,000050

Antwort

1

eine Antwort mit Hilfe von den Menschen über bei http://www.perlmonks.org/?node_id=761015

lief ich eine Profilierung (DProf) und es ist eine 4-fach Verbesserung der Geschwindigkeit

insgesamt verstrichene Zeit = 0,543205 Sekunden
Benutzer + Systemzeit = 0.585454 Sekunden
Exklusiv Zeiten
% Zeit ExclSec CumulS #Calls sec/nennen WBK/c-Name
100. 0,590 0,490 100000 0,0000 0,0000 test_inline_c_pkg :: Prozent2

Gesamtlaufzeit = 2,151647 Sekunden
Benutzer + Systemzeit = 1.991.647 Sekunden
Exklusiv Zeiten
% Zeit ExclSec CumulS #Calls sec/nennen WBK/c-Name
104. 2,080 1,930 100000 0,0000 0,0000 main :: Prozent2

Hier ist der Code

use Inline C => <<'END_OF_C_CODE'; 

#define SvSIOK(sv) ((SvFLAGS(sv) & (SVf_IOK|SVf_IVisUV)) == SVf_IOK) 
#define SvNSIV(sv) (SvNOK(sv) ? SvNVX(sv) : (SvSIOK(sv) ? SvIVX(sv) : sv_2nv(sv))) 

static I32 S_sv_ncmp(pTHX_ SV *a, SV *b) { 

    const NV nv1 = SvNSIV(a); 
    const NV nv2 = SvNSIV(b); 
    return nv1 < nv2 ? -1 : nv1 > nv2 ? 1 : 0; 
} 

void test(SV* sv, ...) { 

    I32 i; 
    I32 arrayLen; 
    AV* data; 
    float retval; 
    SV** pvalue; 

    Inline_Stack_Vars; 
    data = SvUV(Inline_Stack_Item(0)); 

    /* Determine the length of the array */ 
    arrayLen = av_len(data); 

    /* sort descending (send numerical sort function S_sv_ncmp) */ 
    sortsv(AvARRAY(data),arrayLen+1, S_sv_ncmp); 

    for (i = 0; i < arrayLen+1; i++) { 

    pvalue = av_fetch(data,i,0); /* fetch the scalar located at i .*/ 
    retval = SvNV(*pvalue); /* dereference the scalar into a number. */ 

    printf("%f \n",newSVnv(retval)); 
    } 
} 

END_OF_C_CODE 
4

Weil Sie lexikalisch werden sortieren, versuchen Sie diesen Code:

#!/usr/bin/perl 

use strict; 
use warnings; 

my $ref = [ 5.0e-5,4.2e-5,4.3e-5,4.4e-5,4.4e-5,4.2e-5,4.2e-5,4.0e-5]; 

print "Perl with cmp\n"; 
for my $val (sort @$ref) { 
    printf "%f \n", $val; 
} 

print "Perl with <=>\n"; 
for my $val (sort { $a <=> $b } @$ref) { 
    printf "%f \n", $val; 
} 

print "C\n"; 

test($ref); 

use Inline C => <<'END_OF_C_CODE'; 

void test(SV* sv, ...) { 

    I32 i; 
    I32 arrayLen; 
    AV* data; 
    float retval; 
    SV** pvalue; 

    Inline_Stack_Vars; 
    data = SvUV(Inline_Stack_Item(0)); 

    /* Determine the length of the array */ 
    arrayLen = av_len(data); 

    // sort 
    sortsv(AvARRAY(data),av_len(data)+1,Perl_sv_cmp_locale); 

    arrayLen = av_len(data); 
    for (i = 0; i < arrayLen+1; i++) { 

    pvalue = av_fetch(data,i,0); /* fetch the scalar located at i .*/ 
    retval = SvNV(*pvalue); /* dereference the scalar into a number. */ 

    printf("%f \n",newSVnv(retval)); 
    } 
} 

END_OF_C_CODE 

Natürlich lexikalisch 0.00040 kleiner als 0.00042 als gut, aber Sie vergleichen nicht 0.00040-0.00042; Sie vergleichen die Zahl 0.00040 konvertiert in eine Zeichenfolge mit der Nummer 0.00042 konvertiert in eine Zeichenfolge. Wenn eine Zahl zu groß oder zu klein wird, greift Perls Stringing-Logik auf die wissenschaftliche Notation zurück. Sie sortieren also die Menge der Zeichenketten

die richtig sortiert sind. Perl wandelt diese Zeichenfolgen glücklicherweise wieder in ihre Zahlen um, wenn Sie es mit dem Format %f in printf anfragen. Sie könnten die Zahlen selbst stringieren, aber da Sie angegeben haben, dass dies schneller sein soll, wäre das ein Fehler. Sie sollten nicht versuchen, das Programm zu optimieren, bevor Sie wissen, wo es langsam ist (vorzeitige Optimierung ist die Wurzel allen Übels *). Schreibe deinen Code und führe dann Devel::NYTProf dagegen aus, um herauszufinden, wo es langsam ist. Falls nötig, schreiben Sie diese Teile in XS oder (ich bevorzuge XS). Sie werden feststellen, dass Sie bei der Auswahl der richtigen Datenstruktur mehr Geschwindigkeit haben als solche Mikrooptimierungen.

*Knuth, Donald. Structured Programming with go to Statements, ACM Journal Computing Surveys, Band 6, Nr. 4, Dezember 1974. S.268.

+0

I möchte die Sortierung im Inline :: C-Bereich für Geschwindigkeit haben. Dies kann das Problem sein, aber wie man sortsv() zum Sortieren numerisch bekommt, ist nicht gut dokumentiert. –

+6

Sie werden keine Geschwindigkeit daraus bekommen. Die Sortierfunktion in Perl ist in C geschrieben. –

+2

Nun, wenn Sie die Funktion, die Sie _passing_ auf die Sortierfunktion bedeuten, dass eine Geschwindigkeitsanhebung erhalten kann, aber es müsste ziemlich kompliziert sein. –

2

Perl_sv_cmp_locale ist Ihre Sortierfunktion, die ich vermute lexikalischen Vergleich ist. Suchen Sie nach numerischer Sortierung oder schreiben Sie Ihre eigene.

+1

Dies ist in der Perl API nicht gut dokumentiert. Selbst versuchen zu versuchen und meine eigene Funktion zu schreiben kein Glück. –

Verwandte Themen