Domanda

Ho creato un modulo Perl Inline :: C , ma c'è qualche stranezza con l'ordinamento. Qualcuno sa perché dovrebbe ordinare in questo modo? Perché 4.0e-5 non è il primo?

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

È stato utile?

Soluzione 3

Ricevi una risposta con l'aiuto delle persone all'indirizzo http://www.perlmonks.org/ ? NODE_ID = 761.015

Ho eseguito alcuni profili (DProf) ed è un miglioramento di 4x della velocità

Tempo totale trascorso = 0,543205 secondi
  Utente + Ora di sistema = 0,585454 Secondi
Tempi esclusivi
% Time ExclSec CumulS #Call sec / call Csec / c Nome
 100. 0,590 0,490 100000 0,0000 0,0000 test_inline_c_pkg :: percent2

Tempo totale trascorso = 2.151647 Secondi
  Utente + Ora di sistema = 1.991647 Secondi
Tempi esclusivi
% Time ExclSec CumulS #Call sec / call Csec / c Nome
 104. 2.080 1.930 100000 0.0000 0.0000 principale :: percent2

Ecco il codice

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

Altri suggerimenti

Poiché stai ordinando in modo lessicale, prova questo codice:

#!/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

Naturalmente, lessicamente 0.00040 è anche più piccolo di 0.00042 , ma non stai confrontando 0.00040 con 0.00042 ; stai confrontando il numero 0.00040 convertito in una stringa con il numero 0.00042 convertito in una stringa. Quando un numero diventa troppo grande o piccolo, la logica stringente di Perl ricorre all'uso della notazione scientifica. Quindi stai ordinando il set di stringhe

"4.2e-05", "4.2e-05", "4.2e-05", "4.3e-05", "4.4e-05", "4.4e-05", "4e-05", "5e-05"

che sono correttamente ordinati. Perl trasforma felicemente quelle stringhe nei loro numeri quando lo chiedi con il formato % f in printf . Potresti stringere i numeri da solo, ma dal momento che hai dichiarato che vuoi che questo sia più veloce, sarebbe un errore. Non dovresti cercare di ottimizzare il programma prima di sapere dove rallenta (l'ottimizzazione prematura è la radice di tutti i malvagi * ). Scrivi il tuo codice quindi esegui Devel :: NYTProf contro di esso per trovare dove è lento . Se necessario, riscrivi quelle parti in XS o Inline :: C (Preferisco XS). Scoprirai che avrai più velocità nella scelta della giusta struttura di dati rispetto alle micro-ottimizzazioni come questa.

* Knuth, Donald . Programmazione strutturata con andare a Dichiarazioni , ACM Journal Computing Surveys , volume 6, n. 4, dicembre 1974. p.268.

Perl_sv_cmp_locale è la tua funzione di ordinamento che sospetto sia un confronto lessicale. Cerca un ordinamento numerico o scrivine uno tuo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top