为什么Perl';s内联::C在4.4e-5之后排序4.0e-5?
我构建了一个Perl模块,但排序有些奇怪。有人知道为什么会这样吗?为什么4.0e-5不是第一款为什么Perl';s内联::C在4.4e-5之后排序4.0e-5?,perl,sorting,Perl,Sorting,我构建了一个Perl模块,但排序有些奇怪。有人知道为什么会这样吗?为什么4.0e-5不是第一款 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**
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
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];
使用内联C=>因为您是按词汇排序的,请尝试以下代码:
#!/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
它们被正确地分类了。当您使用printf
中的%f
格式要求Perl将这些字符串转换回数字时,Perl会很高兴地将它们转换回数字。你可以自己把数字串起来,但既然你说你想让它更快,那就错了。你不应该在知道程序慢到哪里之前就尝试优化程序(过早优化是万恶之源*
)。编写您的代码,然后对其运行,以找出其速度较慢的地方。如有必要,在或Inline::C
(我更喜欢XS)中重写这些部分。您会发现,选择正确的数据结构比这样的微优化更快
*
,第6卷,第4期,1974年12月。p、 268.Perl\u sv\u cmp\u locale
是您的排序函数,我怀疑它是词汇比较。找一个数字排序,或者自己写一个。在上面的人的帮助下有一个答案
我运行了一些评测(DProf),速度提高了4倍
总运行时间=0.543205秒
用户+系统时间=0.585454秒
独家时代
%时间排除秒累积#呼叫秒/呼叫Csec/c名称
1000.590 0.490 100000 0.0000 0.0000测试内嵌c_包装::百分比2
总运行时间=2.151647秒
用户+系统时间=1.991647秒
独家时代
%时间排除秒累积#呼叫秒/呼叫Csec/c名称
1042.080 1.930 100000 0.0000 0.0000主要::百分比2
这是代码
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
use Inline C=>我希望在Inline::C部分进行排序以提高速度。这可能是个问题,但如何让sortsv()进行数字排序并没有很好的文档记录。您无法从中获得任何速度。Perl中的sort函数是用C编写的。现在,如果您指的是传递给sort函数的函数,那么这可能会提高速度,但它必须非常复杂。Perl api中没有很好的说明。即使试着写我自己的函数也没有运气。
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