PerlのInline :: Cが4.0e-5を4.4e-5の後にソートするのはなぜですか?

StackOverflow https://stackoverflow.com/questions/804810

  •  03-07-2019
  •  | 
  •  

質問

Perl Inline :: C モジュールを作成しましたが、奇妙な点がありますソート付き。なぜこのように分類されるのか誰にもわかりますか? 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** 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

役に立ちましたか?

解決 3

http://www.perlmonks.org/で、人々の助けを借りて回答を得る?node_id = 761015

プロファイリング(DProf)を実行したところ、速度が4倍向上しました

合計経過時間= 0.543205秒
  ユーザー+システム時間= 0.585454秒
限定タイム
%Time ExclSec CumulS #Calls sec / call Csec / c Name
 100. 0.590 0.490 100000 0.0000 0.0000 test_inline_c_pkg :: percent2

合計経過時間= 2.151647秒
  ユーザー+システム時間= 1.991647秒
限定タイム
%Time ExclSec CumulS #Calls sec / call Csec / c Name
 104. 2.080 1.930 100000 0.0000 0.0000 main :: percent2

コードは次のとおりです

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

他のヒント

レキシカルにソートしているため、次のコードを試してください:

#!/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

もちろん、字句的には 0.00040 0.00042 よりも小さいですが、 0.00040 0.00042 ;文字列に変換された数字 0.00040 と文字列に変換された数字 0.00042 を比較しています。数値が大きすぎたり小さすぎたりすると、Perlの文字列化ロジックは科学表記法を使用します。したがって、文字列のセットをソートしています

"4.2e-05", "4.2e-05", "4.2e-05", "4.3e-05", "4.4e-05", "4.4e-05", "4e-05", "5e-05"

適切にソートされています。 Perlは、 printf %f 形式で要求すると、それらの文字列を喜んで数字に戻します。自分で数字を文字列化することもできますが、これをもっと高速にしたいと述べているので、それは間違いです。プログラムがどこで遅くなるかを知る前に、プログラムを最適化しようとすべきではありません(早すぎる最適化がすべての悪 * の根本です)。コードを記述し、 Devel :: NYTProf を実行して、どこが遅いかを見つけます。 。必要に応じて、 XS または Inline :: C の部分を書き換えます(XSが好きです)。このようなマイクロ最適化よりも、適切なデータ構造を選択するほうがより高速になります。

* クヌース、ドナルド go toステートメントを使用した構造化プログラミング ACM Journal Computing Surveys 、Vol 6、No。4、1974年12月。p.268。

Perl_sv_cmp_locale は、語彙比較と思われるソート関数です。数値の並べ替えを探すか、独自に作成します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top