Por que do Perl inline :: C tipo 4.0e-5 após 4.4e-5?
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
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.