Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #143374 > unrolled thread

qsort() standard functions

Started byrick.c.hodgin@gmail.com
First post2019-04-24 09:08 -0700
Last post2019-05-04 05:53 -0700
Articles 20 on this page of 103 — 26 participants

Back to article view | Back to comp.lang.c


Contents

  qsort() standard functions rick.c.hodgin@gmail.com - 2019-04-24 09:08 -0700
    Re: qsort() standard functions gazelle@shell.xmission.com (Kenny McCormack) - 2019-04-24 16:12 +0000
      Re: qsort() standard functions rick.c.hodgin@gmail.com - 2019-04-24 09:18 -0700
        Re: qsort() standard functions Chad <cdalten@gmail.com> - 2019-05-02 12:02 -0700
      Re: qsort() standard functions Real Troll <real.troll@trolls.com> - 2019-04-24 22:30 -0400
        Re: qsort() standard functions "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2019-04-24 19:32 -0700
          Re: qsort() standard functions Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-04-25 10:19 +0000
            Re: qsort() standard functions rick.c.hodgin@gmail.com - 2019-04-25 04:09 -0700
              Re: qsort() standard functions Richard Damon <Richard@Damon-Family.org> - 2019-04-25 08:13 -0400
                Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-25 06:39 -0700
                Re: qsort() standard functions already5chosen@yahoo.com - 2019-04-25 07:23 -0700
        Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-25 00:39 -0700
          Re: qsort() standard functions Real Troll <Real.Troll@Trolls.com> - 2019-04-25 23:27 +0100
    Re: qsort() standard functions John Bode <jfbode1029@gmail.com> - 2019-04-24 09:34 -0700
      Re: qsort() standard functions "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2019-04-24 09:47 -0700
      Re: qsort() standard functions John Bode <jfbode1029@gmail.com> - 2019-04-24 09:47 -0700
        Re: qsort() standard functions "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2019-04-24 12:54 -0400
          Re: qsort() standard functions John Bode <jfbode1029@gmail.com> - 2019-04-24 11:33 -0700
            Re: qsort() standard functions "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2019-04-24 14:41 -0400
              Re: qsort() standard functions John Bode <jfbode1029@gmail.com> - 2019-04-24 11:52 -0700
                Re: qsort() standard functions gazelle@shell.xmission.com (Kenny McCormack) - 2019-04-24 19:12 +0000
                Re: qsort() standard functions "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2019-04-24 16:05 -0400
                  Re: qsort() standard functions queequeg@trust.no1 (Queequeg) - 2019-04-24 20:39 +0000
              Re: qsort() standard functions James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-04-24 16:33 -0700
        Re: qsort() standard functions gazelle@shell.xmission.com (Kenny McCormack) - 2019-04-24 19:18 +0000
          Re: qsort() standard functions Bart <bc@freeuk.com> - 2019-04-24 20:28 +0100
            Re: qsort() standard functions gazelle@shell.xmission.com (Kenny McCormack) - 2019-04-24 21:27 +0000
          Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-24 12:31 -0700
          Re: qsort() standard functions John Bode <jfbode1029@gmail.com> - 2019-04-24 13:02 -0700
            Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-24 13:41 -0700
              Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-24 14:00 -0700
                Re: qsort() standard functions Anton Shepelev <anton.txt@gmail.com> - 2019-04-25 00:22 +0300
                  Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-24 15:04 -0700
                    Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-24 15:20 -0700
                      Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-24 15:40 -0700
                        Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-24 15:57 -0700
                          Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-24 16:06 -0700
                            Re: qsort() standard functions Anton Shepelev <anton.txt@gmail.com> - 2019-04-25 23:49 +0300
                              Re: qsort() standard functions Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-04-25 22:45 +0100
                                Re: qsort() standard functions Bart <bc@freeuk.com> - 2019-04-25 23:00 +0100
                                  Re: qsort() standard functions Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-04-25 23:24 +0100
                                Re: qsort() standard functions Real Troll <Real.Troll@Trolls.com> - 2019-04-25 23:20 +0100
                                Re: qsort() standard functions Anton Shepelev <anton.txt@g{oogle}mail.com> - 2019-04-26 13:06 +0300
                                  Re: qsort() standard functions Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-04-26 13:38 +0100
                                    Re: qsort() standard functions Anton Shepelev <anton.txt@g{oogle}mail.com> - 2019-04-26 16:43 +0300
                                      Re: qsort() standard functions Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-04-26 17:46 +0100
                                        Re: qsort() standard functions Anton Shepelev <anton.txt@gmail.com> - 2019-04-27 14:55 +0300
                                          Re: qsort() standard functions Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-04-27 14:59 +0100
                                            Re: qsort() standard functions Robert Wessel <robertwessel2@yahoo.com> - 2019-04-27 11:41 -0500
                                              Re: qsort() standard functions Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-05-02 09:46 -0700
                                                Re: qsort() standard functions Anton Shepelev <anton.txt@gmail.com> - 2019-05-02 20:35 +0300
                                                  Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-05-02 15:35 -0700
                                                    Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-05-05 04:39 -0700
                                                  Re: qsort() standard functions Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-05-04 07:35 -0700
                                                    Re: qsort() standard functions Anton Shepelev <anton.txt@gmail.com> - 2019-05-05 00:01 +0300
                                            Re: qsort() standard functions Anton Shepelev <anton.txt@gmail.com> - 2019-05-02 15:11 +0300
                                              Re: qsort() standard functions Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-05-02 16:36 +0100
                                Re: qsort() standard functions Anton Shepelev <anton.txt@gmail.com> - 2019-04-27 14:47 +0300
                                  Re: qsort() standard functions Robert Wessel <robertwessel2@yahoo.com> - 2019-04-27 08:30 -0500
                                    Re: qsort() standard functions Anton Shepelev <anton.txt@gmail.com> - 2019-05-02 14:52 +0300
                                      Re: qsort() standard functions Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-05-04 07:13 -0700
                                        Re: qsort() standard functions Anton Shepelev <anton.txt@gmail.com> - 2019-05-05 22:57 +0300
                                          Re: qsort() standard functions David Brown <david.brown@hesbynett.no> - 2019-05-06 10:09 +0200
                                          Re: qsort() standard functions Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-06-01 05:22 -0700
                              Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-25 17:09 -0700
                                Re: qsort() standard functions Bart <bc@freeuk.com> - 2019-04-26 10:58 +0100
                                  Re: qsort() standard functions mark.bluemel@gmail.com - 2019-04-26 03:59 -0700
                                  Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-26 06:34 -0700
                                    Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-26 07:16 -0700
                                      Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-26 07:45 -0700
                                        Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-26 08:29 -0700
                                Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-26 12:06 -0700
                                  Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-26 13:09 -0700
                                    Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-26 13:37 -0700
                                      Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-26 14:05 -0700
                      Re: qsort() standard functions Anton Shepelev <anton.txt@gmail.com> - 2019-04-27 14:59 +0300
                        Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-27 06:19 -0700
                          Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-27 06:32 -0700
    Re: qsort() standard functions Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2019-04-24 10:54 -0600
      Re: qsort() standard functions "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2019-04-24 10:10 -0700
      Re: qsort() standard functions Anton Shepelev <anton.txt@gmail.com> - 2019-04-25 00:06 +0300
    Re: qsort() standard functions scott@slp53.sl.home (Scott Lurndal) - 2019-04-24 17:37 +0000
      Re: qsort() standard functions "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2019-04-24 10:56 -0700
        Re: qsort() standard functions Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2019-04-24 12:12 -0600
          Re: qsort() standard functions "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2019-04-24 14:27 -0400
            Re: qsort() standard functions John Bode <jfbode1029@gmail.com> - 2019-04-24 11:44 -0700
              Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-24 11:57 -0700
                Re: qsort() standard functions fir <profesor.fir@gmail.com> - 2019-04-24 12:04 -0700
              Re: qsort() standard functions nobody@example.org (Scott) - 2019-04-25 01:16 +0000
                Re: qsort() standard functions James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-04-24 21:38 -0400
    Re: qsort() standard functions "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2019-04-24 14:42 -0400
      Re: qsort() standard functions David Brown <david.brown@hesbynett.no> - 2019-04-24 22:13 +0200
      Re: qsort() standard functions queequeg@trust.no1 (Queequeg) - 2019-04-24 20:46 +0000
    Re: qsort() standard functions jadill33@gmail.com - 2019-04-24 14:01 -0700
    Re: qsort() standard functions "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2019-04-24 15:41 -0700
    Re: qsort() standard functions "Mr. Man-wai Chang" <toylet.toylet@gmail.com> - 2019-04-26 22:24 +0800
      Re: qsort() standard functions Anton Shepelev <anton.txt@gmail.com> - 2019-05-02 15:05 +0300
        Re: qsort() standard functions "Mr. Man-wai Chang" <toylet.toylet@gmail.com> - 2019-05-03 17:02 +0800
          Re: qsort() standard functions Chad <cdalten@gmail.com> - 2019-05-03 10:10 -0700
            Re: qsort() standard functions "Mr. Man-wai Chang" <toylet.toylet@gmail.com> - 2019-05-04 01:22 +0800
              Re: qsort() standard functions Chad <cdalten@gmail.com> - 2019-05-03 15:14 -0700
                [OT]Eternal.... programmer? "Mr. Man-wai Chang" <toylet.toylet@gmail.com> - 2019-05-04 06:20 +0800
                  Re: [OT]Eternal.... programmer? Chad <cdalten@gmail.com> - 2019-05-04 05:53 -0700

Page 3 of 6 — ← Prev page 1 2 [3] 4 5 6  Next page →


#143443

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-04-25 23:24 +0100
Message-ID<878svxu3je.fsf@bsb.me.uk>
In reply to#143441
Bart <bc@freeuk.com> writes:

> On 25/04/2019 22:45, Ben Bacarisse wrote:
>> Anton Shepelev <anton.txt@gmail.com> writes:
>
>> I don't want to be overly negative -- you are one of the few people who
>> posts actual code here.  I really liked your sort function.
>
> Did you get the main sort module to work?

Yes.

> I couldn't get it to do that, either with my own test code, or the
> code that was posted an hour ago.

I also wrote a small driver and everything worked, though I did not test
that much.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#143442

FromReal Troll <Real.Troll@Trolls.com>
Date2019-04-25 23:20 +0100
Message-ID<q9tbsg$1jei$1@gioia.aioe.org>
In reply to#143440
On 25/04/2019 22:45, Ben Bacarisse wrote:
>
> you are one of the few people who
> posts actual code here.

but we also have that Peter Popoff look alike who keeps telling us (here 
on C & C++ newsgroups) that Jesus will solve all the problems of the 
world without getting out your bed!!!!.

<https://www.youtube.com/watch?v=x_NuZDaR46I>



>

[toc] | [prev] | [next] | [standalone]


#143448

FromAnton Shepelev <anton.txt@g{oogle}mail.com>
Date2019-04-26 13:06 +0300
Message-ID<20190426130638.ee2504b98c14cb6c666f95b8@g{oogle}mail.com>
In reply to#143440
Ben Bacarisse:

>You play fast and loose with types here!  One case prevents
>compilation and there is also an int overflow bug that
>really matters.

Thanks for your comments.  I wrote it in a hurry and shall
have to post a fixed corrected version.  It is a shame,
though, that the compiler did not report any errors.

>> /* comparison function: */
>> int comp( void * data, int i, int j )
>> {  return ( (int*)data )[i] -
>>           ( (int*)data )[j];
>> }
>
>Your header specifies a fourth parameter:
>
>  typedef int  (*comp_f)( void * data, int i, int j, const void * extra );

Yes, it is missing.

>Also, did you mean for the "const"s to be the other way
>round?
>  typedef int (*comp_f)(const void *data, int i, int j, void * extra);

No.  The extra data (`extra') should not be modified in the
process of sorting, whereas the data to sort (`data')
should.  This `extra' parameter may point to whatever
additional information the user wants to supply.  When
sorting a table, for example, it may contain the column by
which to sort and the order (ascending or descending).

>(I'd use size_t for all the offsets but not doing that is
>presumably a deliberate decision on your part.)

Yes, the temptation to use int universally for all integer
values.

>>/* comparison function for standard qsort: */
>>compar(const void * a, void * b)
>>{  return *((int*)a) - *((int*)b);
>>}
>
>qsort wants both pointers to point to const void.  Also,
>this declaration uses implicit int, but I think you said
>you write C90.  Mind you, adding the return type is, to my
>mind, good practise even in C90.

Don't know why I wrote it so carelessly.  Of course, the
arguments are symmetrical and should both be modified by
`const'.  The lack of a return type is also just an error on
my part.

>>/* swap function: */
>>void swap( void * data, int i, int j )
>>{  int buf;
>>   buf = ( (int[])data )[i];
>>   ( (int*)data )[i] = ( (int*)data )[j];
>>   ( (int*)data )[j] = buf;
>>}
>
>You can't cast to an array type, nor to an incomplete type;
>int [] is both!

Therefore,

  buf = (int*)data )[i]

In a hurry I forgot that outside parameter declarations,
int[] is different from int*.

>Subtracting ints can lead to unintended behaviour when the
>result overflows, even when the actual behaviour is the
>expected "wrap-around" one.

True, and that seemed the laziest (and efficient) way to
implement a comparison function.  I will reconsider.

>I don't want to be overly negative -- you are one of the
>few people who posts actual code here.  I really liked your
>sort function.

No, I am greateful for your reply, and will be back.

-- 
()  ascii ribbon campaign - against html e-mail
/\  http://preview.tinyurl.com/qcy6mjc [archived]

[toc] | [prev] | [next] | [standalone]


#143453

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-04-26 13:38 +0100
Message-ID<87mukdrler.fsf@bsb.me.uk>
In reply to#143448
Anton Shepelev <anton.txt@g{oogle}mail.com> writes:

> Ben Bacarisse:
<cut>
>> ... did you mean for the "const"s to be the other way
>> round?
>>  typedef int (*comp_f)(const void *data, int i, int j, void * extra);
>
> No.  The extra data (`extra') should not be modified in the
> process of sorting, whereas the data to sort (`data')
> should.  This `extra' parameter may point to whatever
> additional information the user wants to supply.  When
> sorting a table, for example, it may contain the column by
> which to sort and the order (ascending or descending).

Hmm... I think that's wrong (about what's const and what isn't).  The
data items should /not/ be modified simply by the act of comparing one
to another, but the extra data might very well be.  For example, I've
done collection of statistics via the 'extra' data pointer.

<cut>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#143458

FromAnton Shepelev <anton.txt@g{oogle}mail.com>
Date2019-04-26 16:43 +0300
Message-ID<20190426164329.8cd319730cce76ab734f5ac6@g{oogle}mail.com>
In reply to#143453
Ben Bacarisse:

>>>Also, did you mean for the "const"s to be the other way
>>>round?
>>>  typedef int (*comp_f)(const void *data, int i, int j, void * extra);
>>
>>No.  The extra data (`extra') should not be modified in
>>the process of sorting, whereas the data to sort (`data')
>>should.  This `extra' parameter may point to whatever
>>additional information the user wants to supply.  When
>>sorting a table, for example, it may contain the column by
>>which to sort
>
>Hmm... I think that's wrong (about what's const and what
>isn't).  The data items should /not/ be modified simply by
>the act of comparing one to another,

But they are modified in swap_f, and I intended to make the
parameter type the same throughout.  It is better to accept
a `void *' and pass on as `const void *' to the comparison
function.

>but the extra data might very well be.  For example, I've
>done collection of statistics via the 'extra' data pointer.

This is the only case of modifying `extra' that I could
think of, but it belongs more to debugging than to actual
use, so I didn't provide it.  Not a big deal if I do,
though, except if one is a devotee of const correctness...

-- 
()  ascii ribbon campaign - against html e-mail
/\  http://preview.tinyurl.com/qcy6mjc [archived]

[toc] | [prev] | [next] | [standalone]


#143467

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-04-26 17:46 +0100
Message-ID<87ef5osoib.fsf@bsb.me.uk>
In reply to#143458
Anton Shepelev <anton.txt@g{oogle}mail.com> writes:

> Ben Bacarisse:
>
>>>>Also, did you mean for the "const"s to be the other way
>>>>round?
>>>>  typedef int (*comp_f)(const void *data, int i, int j, void * extra);
>>>
>>>No.  The extra data (`extra') should not be modified in
>>>the process of sorting, whereas the data to sort (`data')
>>>should.  This `extra' parameter may point to whatever
>>>additional information the user wants to supply.  When
>>>sorting a table, for example, it may contain the column by
>>>which to sort
>>
>>Hmm... I think that's wrong (about what's const and what
>>isn't).  The data items should /not/ be modified simply by
>>the act of comparing one to another,
>
> But they are modified in swap_f, and I intended to make the
> parameter type the same throughout.

That, to me, is a false consistency.  The two functions are not the
same.  A swap function has to modify the pointer targets, a comparison
function should not.

> It is better to accept
> a `void *' and pass on as `const void *' to the comparison
> function.

I don't understand this.

>>but the extra data might very well be.  For example, I've
>>done collection of statistics via the 'extra' data pointer.
>
> This is the only case of modifying `extra' that I could
> think of, but it belongs more to debugging than to actual
> use, so I didn't provide it.

I think it's better to consider what's logical rather than what you (or
I) can think of.  But there are certainly other uses of non-const target
extra data.

> Not a big deal if I do,
> though, except if one is a devotee of const correctness...

Again, I'm not side what you mean here.  It seems as if you are saying
that if you did make 'extra' a 'const void *', that would annoy devotees
of const correctness.  Seems like the other way round to me, but many
I've missed your meaning.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#143485

FromAnton Shepelev <anton.txt@gmail.com>
Date2019-04-27 14:55 +0300
Message-ID<20190427145541.4f9f1d28cc434e9136029307@gmail.com>
In reply to#143467
Ben Bacarisse to Anton Shepelev:

> > > Hmm... I think that's wrong (about what's const and
> > > what isn't).  The data items should /not/ be modified
> > > simply by the act of comparing one to another,
> >
> > But they are modified in swap_f, and I intended to make
> > the parameter type the same throughout.
>
> That, to me, is a false consistency.  The two functions
> are not the same.  A swap function has to modify the
> pointer targets, a comparison function should not.

Agreed (and fixed).

> > It is better to accept a `void *' and pass on as `const
> > void *' to the comparison function.
>
> I don't understand this.

I meant: "and pass *it* on as `const void *'".

> > This is the only case of modifying `extra' that I could
> > think of, but it belongs more to debugging than to
> > actual use, so I didn't provide it.
>
> I think it's better to consider what's logical rather than
> what you (or I) can think of.  But there are certainly
> other uses of non-const target extra data.

If so, you might want to have `extra' not only in the
comparison function but also in the swap function, in order
for example to gather statistics about the number of swap
operations.

> > Not a big deal if I do, though, except if one is a
> > devotee of const correctness...
>
> Again, I'm not side what you mean here.  It seems as if
> you are saying that if you did make 'extra' a 'const void
> *', that would annoy devotees of const correctness.  Seems
> like the other way round to me, but many I've missed your
> meaning.

I meant avoiding `const' before `extra' for the rare case of
debugging and gathering statistics whereas in actual use
`extra' is very unlikely to change.

-- 
()  ascii ribbon campaign -- against html e-mail
/\  http://preview.tinyurl.com/qcy6mjc [archived]

[toc] | [prev] | [next] | [standalone]


#143492

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-04-27 14:59 +0100
Message-ID<878svvsg52.fsf@bsb.me.uk>
In reply to#143485
Anton Shepelev <anton.txt@gmail.com> writes:

> Ben Bacarisse to Anton Shepelev:
<cut>
>> I think it's better to consider what's logical rather than
>> what you (or I) can think of.  But there are certainly
>> other uses of non-const target extra data.
>
> If so, you might want to have `extra' not only in the
> comparison function but also in the swap function, in order
> for example to gather statistics about the number of swap
> operations.

That's an interesting thought.  Yes, in a language without first-class
functions it is probably wise to pass some context pointer to every
call-back at least in general-purpose utilities like sorting.

>> > Not a big deal if I do, though, except if one is a
>> > devotee of const correctness...
>>
>> Again, I'm not [sure] what you mean here.  It seems as if
>> you are saying that if you did make 'extra' a 'const void
>> *', that would annoy devotees of const correctness.  Seems
>> like the other way round to me, but many I've missed your
>> meaning.
>
> I meant avoiding `const' before `extra' for the rare case of
> debugging and gathering statistics whereas in actual use
> `extra' is very unlikely to change.

I can see you won't be persuaded, but it's not about 'avoiding' const,
it's about const being, in my opinion, wrong.  To take another example,
if the comparison is expensive, you might want to store some derived key
in the extra data.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#143494

FromRobert Wessel <robertwessel2@yahoo.com>
Date2019-04-27 11:41 -0500
Message-ID<c919ce5osb9vloiag3ugnusnjf40191gr2@4ax.com>
In reply to#143492
On Sat, 27 Apr 2019 14:59:37 +0100, Ben Bacarisse
<ben.usenet@bsb.me.uk> wrote:

>Anton Shepelev <anton.txt@gmail.com> writes:
>
>> Ben Bacarisse to Anton Shepelev:
><cut>
>>> I think it's better to consider what's logical rather than
>>> what you (or I) can think of.  But there are certainly
>>> other uses of non-const target extra data.
>>
>> If so, you might want to have `extra' not only in the
>> comparison function but also in the swap function, in order
>> for example to gather statistics about the number of swap
>> operations.
>
>That's an interesting thought.  Yes, in a language without first-class
>functions it is probably wise to pass some context pointer to every
>call-back at least in general-purpose utilities like sorting.
>
>>> > Not a big deal if I do, though, except if one is a
>>> > devotee of const correctness...
>>>
>>> Again, I'm not [sure] what you mean here.  It seems as if
>>> you are saying that if you did make 'extra' a 'const void
>>> *', that would annoy devotees of const correctness.  Seems
>>> like the other way round to me, but many I've missed your
>>> meaning.
>>
>> I meant avoiding `const' before `extra' for the rare case of
>> debugging and gathering statistics whereas in actual use
>> `extra' is very unlikely to change.
>
>I can see you won't be persuaded, but it's not about 'avoiding' const,
>it's about const being, in my opinion, wrong.  To take another example,
>if the comparison is expensive, you might want to store some derived key
>in the extra data.


I don't really have a strong opinion either way, but since the "extra"
area is provided and used (only) by the user of the sort function, I'm
not so sure that requiring the user to cast away the const-ness, if
the user wants that, is really all that wrong.  This is in keeping
with the not uncommon practice of objects that have hidden state still
being treated as "const" in many contexts.

[toc] | [prev] | [next] | [standalone]


#143572

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2019-05-02 09:46 -0700
Message-ID<86h8acg5y5.fsf@mailhub.linuxsc.com>
In reply to#143494
Robert Wessel <robertwessel2@yahoo.com> writes:

> On Sat, 27 Apr 2019 14:59:37 +0100, Ben Bacarisse
> <ben.usenet@bsb.me.uk> wrote:
>
>> Anton Shepelev <anton.txt@gmail.com> writes:
>>
>>> Ben Bacarisse to Anton Shepelev:
>>
>> <cut>
>>
>>>> I think it's better to consider what's logical rather than
>>>> what you (or I) can think of.  But there are certainly
>>>> other uses of non-const target extra data.
>>>
>>> If so, you might want to have `extra' not only in the
>>> comparison function but also in the swap function, in order
>>> for example to gather statistics about the number of swap
>>> operations.
>>
>> That's an interesting thought.  Yes, in a language without
>> first-class functions it is probably wise to pass some context
>> pointer to every call-back at least in general-purpose utilities
>> like sorting.
>>
>>>>> Not a big deal if I do, though, except if one is a
>>>>> devotee of const correctness...
>>>>
>>>> Again, I'm not [sure] what you mean here.  It seems as if
>>>> you are saying that if you did make 'extra' a 'const void
>>>> *', that would annoy devotees of const correctness.  Seems
>>>> like the other way round to me, but many I've missed your
>>>> meaning.
>>>
>>> I meant avoiding `const' before `extra' for the rare case of
>>> debugging and gathering statistics whereas in actual use
>>> `extra' is very unlikely to change.
>>
>> I can see you won't be persuaded, but it's not about 'avoiding'
>> const, it's about const being, in my opinion, wrong.  To take
>> another example, if the comparison is expensive, you might want to
>> store some derived key in the extra data.
>
> I don't really have a strong opinion either way, but since the
> "extra" area is provided and used (only) by the user of the sort
> function, I'm not so sure that requiring the user to cast away the
> const-ness, if the user wants that, is really all that wrong.  This
> is in keeping with the not uncommon practice of objects that have
> hidden state still being treated as "const" in many contexts.

My reaction is very much the opposite.  The point of providing the
'extra' parameter is for the convenience of the client, and so
should accommodate as wide a range of use cases as it reasonably
can.  We do not know that a client data area will be used only
with calls to the sort function - it might be used in conjunction
with several different callback functions, for all sorts (no pun
intended) of purposes.  Furthermore the combination of a function
pointer and a void * pointer is a common idiom in C to provide the
functionality of a closure.  Surely the idiom expects that data
in the "closure" might be modified, and so a 'void *' type rather
than a 'const void *' type is more usual, and more appropriate.
Since the 'extra' parameter (almost always) needs to be converted
by the callback function, that function can choose a 'const Foo *'
type if const-ness is important there.  Forcing client code to put
in an unnecessary cast says in effect the sort routine knows better
than its callers.  Service routines such as sort should accommodate
their callers, not the other way around.

[toc] | [prev] | [next] | [standalone]


#143574

FromAnton Shepelev <anton.txt@gmail.com>
Date2019-05-02 20:35 +0300
Message-ID<20190502203521.9f93e01e3aa66851ce1ebfd3@gmail.com>
In reply to#143572
Tim Rentsch:

> My reaction is very much the opposite.  The point of
> providing the 'extra' parameter is for the convenience of
> the client, and so should accommodate as wide a range of
> use cases as it reasonably can.  We do not know that a
> client data area will be used only with calls to the sort
> function - it might be used in conjunction with several
> different callback functions, for all sorts (no pun
> intended) of purposes.

You mean the data to which a pointer is passed to the sort
routing as the `extra' parameter can also be used elsewhere
in the program outside the sort routine?  If so, the `const'
modifier in the sort routine does not in any away affect
these other usages, does it?

> Furthermore the combination of a function pointer and a
> void * pointer is a common idiom in C to provide the
> functionality of a closure.  Surely the idiom expects that
> data in the "closure" might be modified, and so a 'void *'
> type rather than a 'const void *' type is more usual, and
> more appropriate.  Since the 'extra' parameter (almost
> always) needs to be converted by the callback function,
> that function can choose a 'const Foo *' type if const-
> ness is important there.  Forcing client code to put in an
> unnecessary cast says in effect the sort routine knows
> better than its callers.  Service routines such as sort
> should accommodate their callers, not the other way
> around.

I understand your appeal to generality but miss your point
about the unnecessary cast.  The cast is always there,
whether to `Foo *' or to `const Foo *'.  I should say it is
unavoidable rather than unnecessary.

-- 
()  ascii ribbon campaign -- against html e-mail
/\  http://preview.tinyurl.com/qcy6mjc [archived]

[toc] | [prev] | [next] | [standalone]


#143576

Fromfir <profesor.fir@gmail.com>
Date2019-05-02 15:35 -0700
Message-ID<d48f64fe-d394-44cc-95df-c655a62cb7fb@googlegroups.com>
In reply to#143574
W dniu czwartek, 2 maja 2019 19:35:32 UTC+2 użytkownik Anton Shepelev napisał:
> Tim Rentsch:
> 
> > My reaction is very much the opposite.  The point of
> > providing the 'extra' parameter is for the convenience of
> > the client, and so should accommodate as wide a range of
> > use cases as it reasonably can.  We do not know that a
> > client data area will be used only with calls to the sort
> > function - it might be used in conjunction with several
> > different callback functions, for all sorts (no pun
> > intended) of purposes.
> 
> You mean the data to which a pointer is passed to the sort
> routing as the `extra' parameter can also be used elsewhere
> in the program outside the sort routine?  If so, the `const'
> modifier in the sort routine does not in any away affect
> these other usages, does it?
> 
> > Furthermore the combination of a function pointer and a
> > void * pointer is a common idiom in C to provide the
> > functionality of a closure.  Surely the idiom expects that
> > data in the "closure" might be modified, and so a 'void *'
> > type rather than a 'const void *' type is more usual, and
> > more appropriate.  Since the 'extra' parameter (almost
> > always) needs to be converted by the callback function,
> > that function can choose a 'const Foo *' type if const-
> > ness is important there.  Forcing client code to put in an
> > unnecessary cast says in effect the sort routine knows
> > better than its callers.  Service routines such as sort
> > should accommodate their callers, not the other way
> > around.
> 
> I understand your appeal to generality but miss your point
> about the unnecessary cast.  The cast is always there,
> whether to `Foo *' or to `const Foo *'.  I should say it is
> unavoidable rather than unnecessary.
> 
it would be do to make real contest based on sorting - like what i said sort array of milion integer values 

when comparing real implementations not just staying at the "use quicksortt"

but as usual users here most often prefer talking something non important instead of focusing on core things

(and thats pity for me as i could learn something or tell something)

[toc] | [prev] | [next] | [standalone]


#143606

Fromfir <profesor.fir@gmail.com>
Date2019-05-05 04:39 -0700
Message-ID<f2be0c91-1069-4b57-8279-8a8b719f0b71@googlegroups.com>
In reply to#143576
W dniu piątek, 3 maja 2019 00:35:51 UTC+2 użytkownik fir napisał:
> W dniu czwartek, 2 maja 2019 19:35:32 UTC+2 użytkownik Anton Shepelev napisał:
> > Tim Rentsch:
> > 
> > > My reaction is very much the opposite.  The point of
> > > providing the 'extra' parameter is for the convenience of
> > > the client, and so should accommodate as wide a range of
> > > use cases as it reasonably can.  We do not know that a
> > > client data area will be used only with calls to the sort
> > > function - it might be used in conjunction with several
> > > different callback functions, for all sorts (no pun
> > > intended) of purposes.
> > 
> > You mean the data to which a pointer is passed to the sort
> > routing as the `extra' parameter can also be used elsewhere
> > in the program outside the sort routine?  If so, the `const'
> > modifier in the sort routine does not in any away affect
> > these other usages, does it?
> > 
> > > Furthermore the combination of a function pointer and a
> > > void * pointer is a common idiom in C to provide the
> > > functionality of a closure.  Surely the idiom expects that
> > > data in the "closure" might be modified, and so a 'void *'
> > > type rather than a 'const void *' type is more usual, and
> > > more appropriate.  Since the 'extra' parameter (almost
> > > always) needs to be converted by the callback function,
> > > that function can choose a 'const Foo *' type if const-
> > > ness is important there.  Forcing client code to put in an
> > > unnecessary cast says in effect the sort routine knows
> > > better than its callers.  Service routines such as sort
> > > should accommodate their callers, not the other way
> > > around.
> > 
> > I understand your appeal to generality but miss your point
> > about the unnecessary cast.  The cast is always there,
> > whether to `Foo *' or to `const Foo *'.  I should say it is
> > unavoidable rather than unnecessary.
> > 
> it would be do to make real contest based on sorting - like what i said sort array of milion integer values 
> 
> when comparing real implementations not just staying at the "use quicksortt"
> 
> but as usual users here most often prefer talking something non important instead of focusing on core things
> 
> (and thats pity for me as i could learn something or tell something)

anyway thios thread will back in future, i guess (becouse it is worth it)

(i mean topic of specifical array sorting codes in c with micro/milisecond ime measures, that beats other solutions)

so if not now - then later (i could discuss it right now but maybe some need to grow up to it, and im not enough 'motivated' to do it alone on my site and public results then (i got strong problems with 'motivation anyway, as i said))

[toc] | [prev] | [next] | [standalone]


#143592

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2019-05-04 07:35 -0700
Message-ID<86zho2i8yt.fsf@mailhub.linuxsc.com>
In reply to#143574
Anton Shepelev <anton.txt@gmail.com> writes:

> Tim Rentsch:
>
>> My reaction is very much the opposite.  The point of
>> providing the 'extra' parameter is for the convenience of
>> the client, and so should accommodate as wide a range of
>> use cases as it reasonably can.  We do not know that a
>> client data area will be used only with calls to the sort
>> function - it might be used in conjunction with several
>> different callback functions, for all sorts (no pun
>> intended) of purposes.
>
> You mean the data to which a pointer is passed to the sort
> routing as the `extra' parameter can also be used elsewhere
> in the program outside the sort routine?

Yes, and in particular with other callback functions.

> If so, the `const'
> modifier in the sort routine does not in any away affect
> these other usages, does it?

My point is that one bears on the other and so, yes, it
can affect other code that needs the same callback data.


>> Furthermore the combination of a function pointer and a
>> void * pointer is a common idiom in C to provide the
>> functionality of a closure.  Surely the idiom expects that
>> data in the "closure" might be modified, and so a 'void *'
>> type rather than a 'const void *' type is more usual, and
>> more appropriate.  Since the 'extra' parameter (almost
>> always) needs to be converted by the callback function,
>> that function can choose a 'const Foo *' type if const-
>> ness is important there.  Forcing client code to put in an
>> unnecessary cast says in effect the sort routine knows
>> better than its callers.  Service routines such as sort
>> should accommodate their callers, not the other way
>> around.
>
> I understand your appeal to generality but miss your point
> about the unnecessary cast.  The cast is always there,
> whether to `Foo *' or to `const Foo *'.  I should say it is
> unavoidable rather than unnecessary.

When the parameter is const void * (but the use is not):

    int
    some_callback_1( const void *vdata  /*, other parameters */ ){
        Foo *data = (void *)vdata;
        /* ... rest of function ... */
        return  0;
    }

When the parameter is just void *, with no const (but the use is
const):

    int
    some_callback_2( void *vdata  /*, other parameters */ ){
        const Foo *data = vdata;
        /* ... rest of function ... */
        return  0;
    }

The first case needs a cast.  The second case doesn't need one,
and doesn't have one (and still wouldn't if the declaration were
'Foo *data = ...' without the 'const').

[toc] | [prev] | [next] | [standalone]


#143602

FromAnton Shepelev <anton.txt@gmail.com>
Date2019-05-05 00:01 +0300
Message-ID<20190505000109.359cbff1ce49cfb959796539@gmail.com>
In reply to#143592
Tim Rentsch:

> When the parameter is const void * (but the use is not):
>
>     int
>     some_callback_1( const void *vdata  /*, other parameters */ ){
>         Foo *data = (void *)vdata;
>         /* ... rest of function ... */
>         return  0;
>     }
>
> When the parameter is just void *, with no const (but the
> use is const):
>
>     int
>     some_callback_2( void *vdata  /*, other parameters */ ){
>         const Foo *data = vdata;
>         /* ... rest of function ... */
>         return  0;
>     }
>
> The first case needs a cast.  The second case doesn't need
> one, and doesn't have one (and still wouldn't if the
> declaration were 'Foo *data = ...' without the 'const').

Ah, I had simply forgot about this automatic pointer
conversion because of lack of practice in C.

-- 
()  ascii ribbon campaign -- against html e-mail
/\  http://preview.tinyurl.com/qcy6mjc [archived]

[toc] | [prev] | [next] | [standalone]


#143569

FromAnton Shepelev <anton.txt@gmail.com>
Date2019-05-02 15:11 +0300
Message-ID<20190502151101.f8fce60bdd5749bc6a1c1fc7@gmail.com>
In reply to#143492
Ben Bacarisse to Anton Shepelev:

> > I meant avoiding `const' before `extra' for the rare
> > case of debugging and gathering statistics whereas in
> > actual use `extra' is very unlikely to change.
>
> I can see you won't be persuaded, but it's not about
> 'avoiding' const, it's about const being, in my opinion,
> wrong.  To take another example, if the comparison is
> expensive, you might want to store some derived key in the
> extra data.

But I have already removed `const' and added one to `data',
exactly as you suggested:

   typedef int  (*comp_f)( const void * data, int i, int j, void * extra );
   [ http://al.howardknight.net/msgid.cgi?ID=155679895900 ]

-- 
()  ascii ribbon campaign -- against html e-mail
/\  http://preview.tinyurl.com/qcy6mjc [archived]

[toc] | [prev] | [next] | [standalone]


#143571

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-05-02 16:36 +0100
Message-ID<877eb8euli.fsf@bsb.me.uk>
In reply to#143569
Anton Shepelev <anton.txt@gmail.com> writes:

> Ben Bacarisse to Anton Shepelev:
>
>> > I meant avoiding `const' before `extra' for the rare
>> > case of debugging and gathering statistics whereas in
>> > actual use `extra' is very unlikely to change.
>>
>> I can see you won't be persuaded, but it's not about
>> 'avoiding' const, it's about const being, in my opinion,
>> wrong.  To take another example, if the comparison is
>> expensive, you might want to store some derived key in the
>> extra data.
>
> But I have already removed `const' and added one to `data',
> exactly as you suggested:
>
>    typedef int  (*comp_f)( const void * data, int i, int j, void * extra );
>    [ http://al.howardknight.net/msgid.cgi?ID=155679895900 ]

I must have missed your agreement on this matter.  I seem to have got
lost in the words somewhere.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#143484

FromAnton Shepelev <anton.txt@gmail.com>
Date2019-04-27 14:47 +0300
Message-ID<20190427144733.63852ec695135de51c951373@gmail.com>
In reply to#143440
Here is a corrected version of my generic QuickSort implementation:

---------------------------------- sort.h --------------------------------------

/* ----------------------- A generic sorting routine ------------------------ */
/* Comparison function:
    > 0 <=> data[i] > data[j]
    < 0 <=> data[i] < data[j]
   == 0 <=> data[i] = data[j] */
typedef int  (*comp_f)( const void * data, int i, int j, void * extra );

/* Exchange ith and jth elements: */
typedef void (*swap_f)( void * data, int i, int j );

void sort
(  void * data, /* pointer to data to sort         */
   int    len,  /* length of data to sort          */
   comp_f comp, /* comparison function             */
   swap_f swap, /* swap function                   */
   void * extra /* user-supplied parameter to comp */
);

---------------------------------- sort.c --------------------------------------
#include <stdio.h>
#include <limits.h>
#include "sort.h"

/* Partition an array [l..r] around a "pivot" member so that */
/* the elements of the left sub-array do not exceed, and the ones */
/* of the right sub-array are not less than, the pivot. */
static int /* returns the right boundary of the left sub-array */
partition
(  void * data, /* pointer to the full array              */
   int    l,    /* left  boundary of the sub-array        */
   int    r,    /* right boundary of the sub-array, l < r */
   comp_f comp,
   swap_f swap,
   void * extra
)
{  int p; /* index of the pivot, element */
   p = ( l + r ) / 2; /* Chose the middle element as pivot */

   while( 1 )
   {  /* advance cursors until they stop at a pair of elements */
      /* that should be swapped or meet or go past each other.  */
      /* The pivot element serves as a sentinel.                */
      while( comp( data, l, p, extra ) < 0 ) l += 1;
      while( comp( data, r, p, extra ) > 0 ) r -= 1;
      if( l >= r ) break;

      swap( data, l, r );      /* Swap the pair found         */
           if( l == p ) p = r; /* Update pivot location if it */
      else if( r == p ) p = l; /* was changed during the swap */

      /* Advance the cursors. If they are adjecent they will cross: */
      l += 1; r -= 1;
   }
   return r;
}

void sort
(  void * data,
   int    len,
   comp_f comp,
   swap_f swap,
   void * extra
)
{  /* In this algorithm, minimun sufficient stack size is Log(len) */
   int sl[sizeof(int) * CHAR_BIT]; /* left  sub-array boundaries on the stack */
   int sr[sizeof(int) * CHAR_BIT]; /* right sub-array boundaries nn the stack */

   int d;          /* stack depth */
   int l, r;       /* left and right boundaries of a sub-array */
   int lpos, rpos; /* positions of the left and right new sub-arrays on the stack */
   int newr;       /* the right boundary of the new left sub-array */

   d     = 1; /* Put the initial sub-array onto the stack */
   sl[0] = 0; sr[0] = len - 1;   
   while( d > 0 )
   {  d -= 1; /* Take an element from the stack */
      l = sl[d]; r = sr[d];
      if( l >= r ) continue; /* Skip a subarray shorter than two */
      
      newr = partition( data, l , r, comp, swap, extra );

      /* process the shorter sub-array first to ease the stack: */
      lpos = d; rpos = d; 
      if( newr - l > r - newr - 1 ) rpos += 1;
      else                          lpos += 1;

      /* Put partiioned sub-arrays onto the stack: */
      sl[lpos] = l;        sr[lpos] = newr;
      sl[rpos] = newr + 1; sr[rpos] = r;
      d += 2;
   }
}

---------------------------------- test.c --------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "sort.h"

static void print( int * a, int n )
{  int i;
   for( i = 0; i < n; i++ )
      printf("%i ", a[i] );
   printf("\n");
}

static int intcomp( int a, int b )
{  if( a > b ) return  1;
   if( a < b ) return -1;
               return  0;
}

static int comp( const void * data, int i, int j, void * extra )
{  return intcomp( ( (int*)data )[i], ( (int*)data )[j] );  }

/* comparison for qsort: */
static int qscomp(const void * a, const void * b)
{  return intcomp( *(int*)a, *(int*)b );  }

static void swap( void * data, int i, int j )
{  int buf;
   buf = ( (int*)data )[i];
   ( (int*)data )[i] = ( (int*)data )[j];
   ( (int*)data )[j] = buf;
}

#define TESTLEN 5000
/* performance test with a random array: */
static void test()
{  int     a[TESTLEN], c[TESTLEN];
   int     i, j;
   clock_t start, total;

   total = 0;
   for( i = 0; i < 1000; i++ )
   {  for( j = 0; j < TESTLEN; j++ )
      {  a[j] = rand() % 5;
         c[j] = a[j];
      }
      start = clock();
      /*qsort( a, testlen, sizeof(int), &qscomp );*/
      sort( a, TESTLEN, &comp, &swap, NULL );
      total += clock() - start;  
      for( j = 0; j < TESTLEN-1; j++ )
      {  if( a[j] > a[j+1] )
         {  print( c, TESTLEN );
            print( a, TESTLEN );
            return;
         }
      }
   }
   printf("Time: %f\n", (float)total / CLOCKS_PER_SEC );
}

/* test with a small hard-coded array: */
#define TMLEN 3
static void testman( void )
{  int ta[TMLEN] = {3,2,1};
   print( ta, TMLEN );
   sort ( ta, TMLEN, &comp, &swap, NULL );
   print( ta, TMLEN );
}

int main( int argc, char** argv )
{  /*testman();
   return 0;*/

   test();
   return 0;
}

[toc] | [prev] | [next] | [standalone]


#143490

FromRobert Wessel <robertwessel2@yahoo.com>
Date2019-04-27 08:30 -0500
Message-ID<pvk8cedubu1tmovs4vhndi1k5nmc2oqjtv@4ax.com>
In reply to#143484
On Sat, 27 Apr 2019 14:47:33 +0300, Anton Shepelev
<anton.txt@gmail.com> wrote:

>Here is a corrected version of my generic QuickSort implementation:
>
>---------------------------------- sort.h --------------------------------------
>
>/* ----------------------- A generic sorting routine ------------------------ */
>/* Comparison function:
>    > 0 <=> data[i] > data[j]
>    < 0 <=> data[i] < data[j]
>   == 0 <=> data[i] = data[j] */
>typedef int  (*comp_f)( const void * data, int i, int j, void * extra );
>
>/* Exchange ith and jth elements: */
>typedef void (*swap_f)( void * data, int i, int j );
>
>void sort
>(  void * data, /* pointer to data to sort         */
>   int    len,  /* length of data to sort          */
>   comp_f comp, /* comparison function             */
>   swap_f swap, /* swap function                   */
>   void * extra /* user-supplied parameter to comp */
>);
>
>---------------------------------- sort.c --------------------------------------
>#include <stdio.h>
>#include <limits.h>
>#include "sort.h"
>
>/* Partition an array [l..r] around a "pivot" member so that */
>/* the elements of the left sub-array do not exceed, and the ones */
>/* of the right sub-array are not less than, the pivot. */
>static int /* returns the right boundary of the left sub-array */
>partition
>(  void * data, /* pointer to the full array              */
>   int    l,    /* left  boundary of the sub-array        */
>   int    r,    /* right boundary of the sub-array, l < r */
>   comp_f comp,
>   swap_f swap,
>   void * extra
>)
>{  int p; /* index of the pivot, element */
>   p = ( l + r ) / 2; /* Chose the middle element as pivot */
>
>   while( 1 )
>   {  /* advance cursors until they stop at a pair of elements */
>      /* that should be swapped or meet or go past each other.  */
>      /* The pivot element serves as a sentinel.                */
>      while( comp( data, l, p, extra ) < 0 ) l += 1;
>      while( comp( data, r, p, extra ) > 0 ) r -= 1;
>      if( l >= r ) break;
>
>      swap( data, l, r );      /* Swap the pair found         */
>           if( l == p ) p = r; /* Update pivot location if it */
>      else if( r == p ) p = l; /* was changed during the swap */
>
>      /* Advance the cursors. If they are adjecent they will cross: */
>      l += 1; r -= 1;
>   }
>   return r;
>}
>
>void sort
>(  void * data,
>   int    len,
>   comp_f comp,
>   swap_f swap,
>   void * extra
>)
>{  /* In this algorithm, minimun sufficient stack size is Log(len) */
>   int sl[sizeof(int) * CHAR_BIT]; /* left  sub-array boundaries on the stack */
>   int sr[sizeof(int) * CHAR_BIT]; /* right sub-array boundaries nn the stack */
>
>   int d;          /* stack depth */
>   int l, r;       /* left and right boundaries of a sub-array */
>   int lpos, rpos; /* positions of the left and right new sub-arrays on the stack */
>   int newr;       /* the right boundary of the new left sub-array */
>
>   d     = 1; /* Put the initial sub-array onto the stack */
>   sl[0] = 0; sr[0] = len - 1;   
>   while( d > 0 )
>   {  d -= 1; /* Take an element from the stack */
>      l = sl[d]; r = sr[d];
>      if( l >= r ) continue; /* Skip a subarray shorter than two */
>      
>      newr = partition( data, l , r, comp, swap, extra );
>
>      /* process the shorter sub-array first to ease the stack: */
>      lpos = d; rpos = d; 
>      if( newr - l > r - newr - 1 ) rpos += 1;
>      else                          lpos += 1;
>
>      /* Put partiioned sub-arrays onto the stack: */
>      sl[lpos] = l;        sr[lpos] = newr;
>      sl[rpos] = newr + 1; sr[rpos] = r;
>      d += 2;
>   }
>}
>
>---------------------------------- test.c --------------------------------------
>
>#include <stdio.h>
>#include <stdlib.h>
>#include <time.h>
>#include "sort.h"
>
>static void print( int * a, int n )
>{  int i;
>   for( i = 0; i < n; i++ )
>      printf("%i ", a[i] );
>   printf("\n");
>}
>
>static int intcomp( int a, int b )
>{  if( a > b ) return  1;
>   if( a < b ) return -1;
>               return  0;
>}
>
>static int comp( const void * data, int i, int j, void * extra )
>{  return intcomp( ( (int*)data )[i], ( (int*)data )[j] );  }
>
>/* comparison for qsort: */
>static int qscomp(const void * a, const void * b)
>{  return intcomp( *(int*)a, *(int*)b );  }
>
>static void swap( void * data, int i, int j )
>{  int buf;
>   buf = ( (int*)data )[i];
>   ( (int*)data )[i] = ( (int*)data )[j];
>   ( (int*)data )[j] = buf;
>}
>
>#define TESTLEN 5000
>/* performance test with a random array: */
>static void test()
>{  int     a[TESTLEN], c[TESTLEN];
>   int     i, j;
>   clock_t start, total;
>
>   total = 0;
>   for( i = 0; i < 1000; i++ )
>   {  for( j = 0; j < TESTLEN; j++ )
>      {  a[j] = rand() % 5;
>         c[j] = a[j];
>      }
>      start = clock();
>      /*qsort( a, testlen, sizeof(int), &qscomp );*/
>      sort( a, TESTLEN, &comp, &swap, NULL );
>      total += clock() - start;  
>      for( j = 0; j < TESTLEN-1; j++ )
>      {  if( a[j] > a[j+1] )
>         {  print( c, TESTLEN );
>            print( a, TESTLEN );
>            return;
>         }
>      }
>   }
>   printf("Time: %f\n", (float)total / CLOCKS_PER_SEC );
>}
>
>/* test with a small hard-coded array: */
>#define TMLEN 3
>static void testman( void )
>{  int ta[TMLEN] = {3,2,1};
>   print( ta, TMLEN );
>   sort ( ta, TMLEN, &comp, &swap, NULL );
>   print( ta, TMLEN );
>}
>
>int main( int argc, char** argv )
>{  /*testman();
>   return 0;*/
>
>   test();
>   return 0;
>}


I may have lost track, but is this intended to be a generally usable
implementation at the end of the day, or a demonstration of letting
the compiler properly specialize a sort implementation?

If the former, I'd offer a few suggestions on the Quicksort
implementation.

First, just swap the pivot to the first location (or last) in the
partition after picking it, and adjust the edge of the subarray you're
partitioning.  That way you don't have to keep checking if you've
moved it.

The usual Quicksort optimizations, median-of-three for pivot
selection, insertion sorting small partitions (you have a choice of a
single insertion sort pass over the entire input, or insertion sorts
of the individual small partitions - given cache effects, the latter
is usually recommended today), are worthwhile optimizations, with
minimal complexity.  You've already dealt with the stack issue
(although I personally prefer the semi-recursive form, it's not a big
difference).

Introsort is a significant upgrade to basic Quicksort, and bounds
performance to O(n log n).  The basic idea is to keep an eye on the
efficiency of the partitioning process, and switch to Heapsort if it's
performing poorly.  More or less you look at the size of the partition
relative to it depth - after (depth) three partitioning operations,
partitions should be about an eighth the size of the input - if you
are showing considerably larger than that, give up and Heapsort the
partition instead.  It does add significant complexity - the Heapsort
implementation will be about as big as the rest of the (optimized)
Quicksort.

Musser's original Introsort paper is rather interesting reading, not
so much for the algorithm (which is one of those obvious-in-hind-sight
things), but for his discussion of just how easy it is to generate
pathological inputs for Quicksort.  And given that this is 2019, you
pretty much have to assume that inputs will be constructed in an
actively malicious manner, unless you can specifically prove
otherwise.

[toc] | [prev] | [next] | [standalone]


#143567

FromAnton Shepelev <anton.txt@gmail.com>
Date2019-05-02 14:52 +0300
Message-ID<20190502145240.03216d54fb7c1449b1f2fff7@gmail.com>
In reply to#143490
Robert Wessel:

> I may have lost track, but is this intended to be a
> generally usable implementation at the end of the day, or
> a demonstration of letting the compiler properly
> specialize a sort implementation?

It is generally usable for my purposes because pathological
cases are improbable.  It is not the compiler, but the
programmer that specialises an implementation.  How can a
compiler do it?

> If the former, I'd offer a few suggestions on the
> Quicksort implementation.
>
> First, just swap the pivot to the first location (or last)
> in the partition after picking it, and adjust the edge of
> the subarray you're partitioning.  That way you don't have
> to keep checking if you've moved it.

Then the pivot will no loger work as sentinel and I shall
have to use a complex stop condition in:

   while( comp( data, l, p, extra ) < 0 ) l += 1;
   while( comp( data, r, p, extra ) > 0 ) r -= 1;

> The usual Quicksort optimizations, median-of-three for
> pivot selection, insertion sorting small partitions (you
> have a choice of a single insertion sort pass over the
> entire input, or insertion sorts of the individual small
> partitions - given cache effects, the latter is usually
> recommended today), are worthwhile optimizations, with
> minimal complexity.

Agreed.

I have tried switching to insertion sort when the subarray
becomes shorter than a specified legth, but found little
benefit on random arrays with TCC for some reason.  Notice
that insertion sort using swaps is by a constant factor
slower than the more optimal but non-generic implementation.

> You've already dealt with the stack issue (although I
> personally prefer the semi-recursive form, it's not a big
> difference).

You mean reliance of tail-call optimisation?  I dislike it
for readability.  Recursive code is compiled into iterative
machine code.  This is misleading.

> Introsort is a significant upgrade to basic Quicksort, and
> bounds performance to O(n log n).  The basic idea is to
> keep an eye on the efficiency of the partitioning process,
> and switch to Heapsort if it's performing poorly.  More or
> less you look at the size of the partition relative to it
> depth - after (depth) three partitioning operations,
> partitions should be about an eighth the size of the input
> - if you are showing considerably larger than that, give
> up and Heapsort the partition instead.  It does add
> significant complexity - the Heapsort implementation will
> be about as big as the rest of the (optimized) Quicksort.

In that case, I think, using Heapsort all through is
simpler.  I should refer to avoid a compound sorting
algorithm, be it QuickSort + Insertion sort or QuickSort +
HeapSort.

> Musser's original Introsort paper is rather interesting
> reading, not so much for the algorithm (which is one of
> those obvious-in-hind-sight things), but for his
> discussion of just how easy it is to generate pathological
> inputs for Quicksort.  And given that this is 2019, you
> pretty much have to assume that inputs will be constructed
> in an actively malicious manner, unless you can
> specifically prove otherwise.

A simple solution would be to select a random pivot.

-- 
()  ascii ribbon campaign -- against html e-mail
/\  http://preview.tinyurl.com/qcy6mjc [archived]

[toc] | [prev] | [next] | [standalone]


Page 3 of 6 — ← Prev page 1 2 [3] 4 5 6  Next page →

Back to top | Article view | comp.lang.c


csiph-web