Pergunta

Eu construí um Perl inline :: C módulo, mas há alguma estranheza com a classificação. Alguém sabe por que ele iria classificar como este? Porque é que a 4.0e-5 não é em primeiro lugar?

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

teste ($ ref);

0.000042
0.000042
0.000042
0,000043
0,000044
0,000044
0,000040
0.000050

Foi útil?

Solução 3

Tenha uma resposta com a ajuda das pessoas mais em http://www.perlmonks.org/ ? node_id = 761015

Eu corri algumas profiling (DProf) e é uma melhoria 4x na velocidade

Total de Tempo decorrido = 0.543205 Segundos
Usuário + Time System = 0.585454 Segundos
Exclusivo vezes | % Tempo ExclSec CumulS #Calls seg / call CSEC / c Nome
100. 0,590 0,490 100000 0,0000 0,0000 test_inline_c_pkg :: percent2

Total de Tempo decorrido = 2.151647 Segundos
Usuário + Time System = 1.991647 Segundos
Exclusivo vezes | % Tempo ExclSec CumulS #Calls seg / call CSEC / c Nome
104. 2,080 1,930 100000 0,0000 0,0000 principal :: percent2

Aqui está o código

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

Outras dicas

Porque você está classificando lexically, Tente este código:

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

Claro, lexically 0.00040 é menor do que 0.00042 bem, mas você não está comparando 0.00040 para 0.00042; você está comparando o 0.00040 número convertido para uma string com o 0.00042 número convertido para uma cadeia. Quando um número fica muito grande ou pequeno, Perl está stringifying resorts lógicas para usando a notação científica. Então você está classificando o conjunto de cordas

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

que estão devidamente ordenados. Perl feliz transforma aquelas cordas de volta para suas números quando você pedir para ele com o formato %f em printf. Você poderia stringify os números mesmo, mas desde que você disse que quer que isso seja mais rápido, que seria um erro. Você não deve estar tentando otimizar o programa antes que você saiba onde lenta (otimização prematura é a raiz de todo evil*). Escreva seu código em seguida, executar Devel :: NYTProf contra ele para descobrir onde ele é lento . Se necessário, as porções em reescrever XS ou Inline::C (I preferem XS). Você vai achar que você obter mais velocidade fora de escolher a estrutura de dados direito de micro-otimizações como este.

* href="http://www-cs-faculty.stanford.edu/~knuth/" rel="nofollow noreferrer"> Knuth, Donald . Programação Estruturada com go às Demonstrações , Surveys ACM Jornal Computing , Vol 6, No. 4, dezembro de 1974. p.268.

Perl_sv_cmp_locale é a sua função de classificação que eu suspeito que é a comparação lexical. Procure numérico de classificação uma ou escrever a sua própria.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top