Pregunta

Construí un módulo Perl Inline :: C , pero hay algunas rarezas Con la clasificación. ¿Alguien sabe por qué se ordenaría así? ¿Por qué el 4.0e-5 no es el primero?

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
  

prueba ($ ref);

0.000042
0.000042
0.000042
0.000043
0.000044
0.000044
0.000040
0.000050

¿Fue útil?

Solución 3

Obtenga una respuesta con la ayuda de las personas que se encuentran en http://www.perlmonks.org/ ? node_id = 761015

Ejecuté algunos perfiles (DProf) y es una mejora 4x en velocidad

Tiempo total transcurrido = 0.543205 segundos
  Usuario + Tiempo del sistema = 0.585454 segundos
Tiempos exclusivos
% Time ExclSec CumulS #Call sec / call Csec / c Name
 100. 0.590 0.490 100000 0.0000 0.0000 test_inline_c_pkg :: percent2

Tiempo total transcurrido = 2.151647 segundos
  Usuario + Tiempo del sistema = 1.991647 segundos
Tiempos exclusivos
% Time ExclSec CumulS #Call sec / call Csec / c Name
 104. 2.080 1.930 100000 0.0000 0.0000 principal :: percent2

Aquí está el 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

Otros consejos

Debido a que estás clasificando léxicamente, prueba 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
Por supuesto, 0.00040 también es menor que 0.00042 , pero no está comparando 0.00040 con 0.00042 ; está comparando el número 0.00040 convertido en una cadena con el número 0.00042 convertido en una cadena. Cuando un número se vuelve demasiado grande o demasiado pequeño, la lógica restrictiva de Perl recurre al uso de la notación científica. Así que estás clasificando el conjunto de cadenas

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

que están correctamente ordenados. Perl felizmente convierte esas cadenas de nuevo en sus números cuando lo solicitas con el formato % f en printf . Usted podría encadenar los números usted mismo, pero ya que ha declarado que quiere que esto sea más rápido, eso sería un error. No debe intentar optimizar el programa antes de saber dónde está lento (la optimización prematura es la raíz de todo el mal * ). Escriba su código y luego ejecute Devel :: NYTProf en su contra para encontrar dónde está lento . Si es necesario, vuelva a escribir esas partes en XS o Inline :: C (Prefiero XS). Descubrirá que obtiene más velocidad al elegir la estructura de datos correcta que las microoptimizaciones como esta.

* Knuth, Donald . Programación estructurada con ir a Declaraciones , ACM Journal Computing Surveys , Vol. 6, No. 4, diciembre de 1974. p.268.

Perl_sv_cmp_locale es su función de clasificación que sospecho que es una comparación léxica. Busque una clasificación numérica o escriba la suya.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top