我构建了一个Perl
Inline::C模块,但排序有些奇怪.有谁知道为什么会这样排序?为什么4.0e-5不是第一个?
my $ref = [ 5.0e-5,4.2e-5,4.3e-5,4.4e-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
test($ref);
0.000042
0.000042
0.000042
0.000043
0.000044
0.000044
0.000040
0.000050
解决方法
因为您正在排序,请尝试以下代码:
#!/usr/bin/perl use strict; use warnings; my $ref = [ 5.0e-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,av_len(data)+1,Perl_sv_cmp_locale); arrayLen = av_len(data); for (i = 0; i < arrayLen+1; i++) { pvalue = av_fetch(data,newSVnv(retval)); } } END_OF_C_CODE
当然,词法0.00040也小于0.00042,但你不是在比较0.00040到0.00042;您正在将转换为字符串的数字0.00040与编号为0.00042的字符串进行比较.当一个数字变得太大或太小时,Perl的字符串逻辑就会采用科学记数法.所以你要对字符串集进行排序
"4.2e-05","4.2e-05","4.3e-05","4.4e-05","4e-05","5e-05"
哪些是正确排序的.当你在printf中使用%f格式询问它时,Perl会愉快地将这些字符串转换回它们的数字.你可以自己对这些数字进行字符串化,但既然你已经说过你希望这个更快,那就错了.你不应该在知道程序变慢之前尝试优化程序(过早的优化是所有邪恶的根源*).编写代码然后针对它运行Devel::NYTProf以找到它的缓慢位置.如有必要,重写XS或Inline :: C中的那些部分(我更喜欢XS).您会发现,与选择微观优化相比,您可以更快地选择正确的数据结构.
* Knuth,Donald. Structured Programming with go to Statements,ACM Journal Computing Surveys,Vol 6,No.4,1974年12月.p.268.