in reply to Re: perl inline::c sorting problem
in thread perl inline::c sorting problem

You'll probably have to change Perl_sv_cmp_locale to whatever the constant is for <=> though I'm sorry I can't seem to track that down at the moment

I can't find it either. Is there such a thing ? Or is sortsv() invariably lexical ?

I tried
Perl_sortsv_flags(aTHX_ AvARRAY(data),arrayLen+1,Perl_sv_cmp, flags);
for differing values of 'flags', but it looked like 0 (and any even value) causes a lexical sort in ascending order, and 1 (and any odd value) causes a lexical sort in descending order. I didn't stumble across any value that forces a numeric sort.

The following produces the desired output:
use warnings; use Inline C => Config => CLEAN_AFTER_BUILD => 0, BUILD_NOISY => 1; use Inline C => <<'END_OF_C_CODE'; void test(AV* data) { I32 i; I32 arrayLen; float retval; SV** pvalue; arrayLen = av_len(data); sortsv(AvARRAY(data),arrayLen+1,Perl_sv_cmp); for (i = 0; i < arrayLen+1; i++) { pvalue = av_fetch(data,i,0); printf("%s \n",SvPVX(*pvalue)); } } 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]; for(@$ref) {$_ = sprintf "%f", $_} test($ref);
I don't know if that's helpful in the "real world" application. All it does is stringify the values in the array reference into such a form that the lexical sort produces the desired output. There may be a better way of achieving that stringification.

Cheers,
Rob

Replies are listed 'Best First'.
Re^3: perl inline::c sorting problem
by BrowserUk (Patriarch) on Apr 30, 2009 at 06:47 UTC

    PP_sort.c contains all these routines which appear to be defined such that they could be used as alternatives to Perl_sv_cmp:

    S_sortcv(pTHX_ SV *a, SV *b) S_sortcv_stacked(pTHX_ SV *a, SV *b) S_sortcv_xsub(pTHX_ SV *a, SV *b) S_sv_ncmp(pTHX_ SV *a, SV *b) S_sv_i_ncmp(pTHX_ SV *a, SV *b) S_amagic_ncmp(pTHX_ register SV *a, register SV *b) S_amagic_i_ncmp(pTHX_ register SV *a, register SV *b) S_amagic_cmp(pTHX_ register SV *str1, register SV *str2) S_amagic_cmp_locale(pTHX_ register SV *str1, register SV *str2)

    They are prototyped in proto.h and aliased in embed.h, but even including those explicitly does not allow them to be seen at compile time?


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      The perl api is not very clear here. I have been trying to write my own numberical sort function (for Perl_sv_cmp) and am not sure if I even have the right args. It seems simple enough, but I have not been able to figure it out.
      sortsv(AvARRAY(data), arrayLen+1, Perl_sv_cmp); to sortsv(AvARRAY(data), arrayLen+1, numerical_cmp); ??? I32 numerical_cmp(SV* sv1,SV* sv2) { double num1; double num2; num1 = (double)*sv1; num2 = (double)*sv2; if (num1 == num2) { return 0; } else if (num1 > num2) { return 1; } else { return -1; } }

        I'd just steal the implementation from PP_sort.c. You have to also grab a couple of #defines:

        use warnings; use Inline C => Config => NAME => 'IC_sort', CLEAN_AFTER_BUILD => 0, BUILD_NOISY => 1; 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(AV* data) { I32 i; I32 arrayLen; SV** pvalue; if( SvTYPE( data ) != SVt_PVAV ) croak( "Requires an array ref ( type %d)\n", SvTYPE( data ) ); arrayLen = av_len(data); sortsv(AvARRAY(data),arrayLen+1, S_sv_ncmp); for (i = 0; i < arrayLen+1; i++) { pvalue = av_fetch(data,i,0); printf("%s \n", SvPV_nolen( *pvalue ) ); } } 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]; test($ref);

        That works! However, there is something I do not understand about:

        #define SvNSIV(sv) ( SvNOK(sv) ? SvNVX(sv) : ( SvSIOK(sv) ? SvIVX(sv) +: sv_2nv(sv) ) ) ... const NV nv1 = SvNSIV(a);

        If the value is an NV, it grabs it. But if it is an IV, it grabs the IV and assigns it to the NV without coercion. Seems to work okay for mixed ints and floats and I don't see any warnings, so I guess that's yet another mystery to put down to "the magic of XS".


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.