¿Por qué Perl's Inline :: C clasifica 4.0e-5 después de 4.4e-5?
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
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.