为什么Perl的Inline :: C在4.4e-5之后排序4.0e-5?

前端之家收集整理的这篇文章主要介绍了为什么Perl的Inline :: C在4.4e-5之后排序4.0e-5?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我构建了一个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.

猜你在找的Perl相关文章