Deutsch   English   Français   Italiano  
<vblfgb$2dkij$1@paganini.bofh.team>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: ...!feeds.phibee-telecom.net!2.eu.feeder.erje.net!feeder.erje.net!newsfeed.bofh.team!paganini.bofh.team!not-for-mail
From: Waldek Hebisch <antispam@fricas.org>
Newsgroups: comp.lang.c
Subject: Re: Top 10 most common hard skills listed on resumes...
Date: Mon, 9 Sep 2024 00:29:01 -0000 (UTC)
Organization: To protect and to server
Message-ID: <vblfgb$2dkij$1@paganini.bofh.team>
References: <vab101$3er$1@reader1.panix.com>   <87v7zjuyd8.fsf@bsb.me.uk> <20240829084851.962@kylheku.com> <87mskvuxe9.fsf@bsb.me.uk> <vaq9tu$1te8$1@dont-email.me> <vbci8r$1c9e8$1@paganini.bofh.team> <vbcs65$eabn$1@dont-email.me> <vbekut$1kd24$1@paganini.bofh.team> <vbepcb$q6p2$1@dont-email.me> <vbgb5q$1ruv8$1@paganini.bofh.team> <vbhbbb$1blt4$1@dont-email.me> <vbipp5$24kl5$1@paganini.bofh.team> <vbk0d9$1tajm$1@dont-email.me> <vbkpfc$27l2o$1@paganini.bofh.team> <vbl3am$228vv$1@dont-email.me>
Injection-Date: Mon, 9 Sep 2024 00:29:01 -0000 (UTC)
Injection-Info: paganini.bofh.team; logging-data="2544211"; posting-host="WwiNTD3IIceGeoS5hCc4+A.user.paganini.bofh.team"; mail-complaints-to="usenet@bofh.team"; posting-account="9dIQLXBM7WM9KzA+yjdR4A";
User-Agent: tin/2.6.2-20221225 ("Pittyvaich") (Linux/6.1.0-9-amd64 (x86_64))
X-Notice: Filtered by postfilter v. 0.9.3
Bytes: 9012
Lines: 196

Bart <bc@freeuk.com> wrote:
> On 08/09/2024 19:13, Waldek Hebisch wrote:
>> Bart <bc@freeuk.com> wrote:
> 
>>> Like being able define anonymous structs always anywhere, or allowing
>>> multiple declarations of the same module-level variables and functions.
>> 
>> Look at this C code:
>> 
>> void
>> do_bgi_add(unsigned int * dst, int xlen, unsigned int * xp,
>>       int ylen, unsigned int * yp) {
>>      if (ylen < xlen) {
>>          int tmp = xlen;
>>          xlen = ylen;
>>          ylen = tmp;
>>          unsigned int * tmpp = xp;
>>          xp = yp;
>>          yp = tmpp;
>>      }
>>      unsigned int xext = (unsigned int)(((int)(xp[xlen - 1])) >> 31);
>>      unsigned int yext = (unsigned int)(((int)(yp[ylen - 1])) >> 31);
>>      unsigned int c = 0;
>>      int i = 0;
>>      while(i < xlen) {
>>          unsigned long long pp = (unsigned long long)(xp[i])
>>                                + (unsigned long long)(yp[i])
>>                                + (unsigned long long)c;
>>          dst[i] = pp;
>>          c = (pp >> (32ULL));
>>          i++;
>>      }
>>      while(i < ylen) {
>>          unsigned long long pp = (unsigned long long)xext
>>                                + (unsigned long long)(yp[i])
>>                                + (unsigned long long)c;
>>          dst[i] = pp;
>>          c = (pp >> (32ULL));
>>          i++;
>>      }
>>      {
>>          unsigned long long pp = (unsigned long long)xext
>>                                + (unsigned long long)yext
>>                                + (unsigned long long)c;
>>          dst[i] = pp;
>>      }
>> }
>> 
>> 
>> I claim that is is better than what could be done in early Pascal.
>> Temporary variables are declared exactly in scopes where they are
>> needed, I reuse the same name for 'pp' but scoping makes clear
>> that different 'pp' are different variables.  All variables
>> are initialised at declaration time with sensible values.  Only
>> parameters, 'i' and 'c' are common to various stages, they have
>> to.  Note that 'xext' and 'yext' are declared at point where I
>> can compute initial value.  Also note that among ordinary
>> variables only 'i' and 'c' are reassigned (I need to swap parameters
>> to simplify logic and 'dst' array entries are assigned as part of
>> function contract).  Fact that variables are not reassigned could
>> be made clearer by declaring them as 'const'.
> 
> I had a problem with this code because it was so verbose. The first 
> thing I did was to define aliases u64 and u32 for those long types:
> 
>  typedef unsigned long long u64;
>  typedef unsigned long u32;

This code runs in 33 bit i386, 32 bit ARM and 64 bit x86-64, in
all cases under Linux.  As Keith noticed, most popular of those
has 64-bit long.  So your definition would break it.  You need

typedef unsigned int u32;

> Then I removed some casts that I thought were not necessary.

I want to be warned about mixing signed and unsigend when
I do not intend so.  Casts make clear to compiler (and reader)
that I really want this.

> The first 
> result looks like this:
> 
> ---------------------------
> void do_bgi_add(u32 * dst, int xlen, u32 * xp, int ylen, u32 * yp) {
>     u32 xext, yext, c;
>     u64 pp;
>     int i;
> 
>     if (ylen < xlen) {
>         int tmp = xlen;
>         xlen = ylen;
>         ylen = tmp;
>         u32 * tmpp = xp;
>         xp = yp;
>         yp = tmpp;
>     }
> 
>     xext = ((int)(xp[xlen - 1])) >> 31;
>     yext = ((int)(yp[ylen - 1])) >> 31;
> 
>     c = 0;
>     i = 0;
>     while(i < xlen) {
>         pp = (u64)(xp[i]) + (u64)yp[i] + c;
>         dst[i] = pp;
>         c = pp >> 32;
>         i++;
>     }
> 
>    while(i < ylen) {
>         pp = (u64)xext  + (u64)yp[i]  + c;
>         dst[i] = pp;
>         c = pp >> 32;
>         i++;
>     }
>     pp = (u64)xext + (u64)yext + c;
>     dst[i] = pp;
> }
> ---------------------------
> 
> Things actually fit onto one line! It's easier now to grasp what's going 
> on. There are still quite a few casts; it would be better if xext/yext/c 
> were all u64 type instead of u32.

No.  It is essential for efficiency to have 32-bit types.  On 32-bit
machines doing otherwise would add useless instructions to object
code.  More precisly, really stupid compiler will generate useless
intructions even with my declarations, really smart one will
notice that variables fit in 32-bits and optimize accordingly.
But at least some gcc versions needed such declarations.  Note 
also that my version makes clear that there there is
symmetry (everything should be added using 64-bit precision),
you depend on promotion rules which creates visual asymetry
are requires reasoning to realize that meaning is symetric.

> pp seems to used for the same purpose throughout, so I can't see the 
> point in declaring three separate versions of the same thing.

My version can be checked for correctenss in one resonably fast
pass other source.  Your changes require multiple passes or much
slower single pass (because with single pass you need to keep
more info in your head compared to my version).

Your version obscures important fact that there is truncation
is assigment

    dst[i] = pp;

In my version type of pp is clearly visible, together with casts
this gives string hint what is happening: this is 32-bit addition
producing carry in 'c'.  And this is version of code intended for
32-bit machines, so everthing can be done using 32-bit instructions
(and on 32-bit machine there is no need for real shift).  Your
remark above indicates that you missed this, but I think that
this is much easier to infer from my version than from your
changed one.

Another thing, I gave this example because most my functions
are very short.  This one was longer and in longer function
benfits of keeping variable local are bigger.  And that
function happend to have casts, but casts are actually
were a distraction to my main point.

Also, note that I plan to change this code so that it uses
64-bit arithmetic on 64-bit machines.  Then I will have
something like 'host_word' (unsigned 32-bit on 32-bit
machine and 64-bit on 64-bit machine), 'signed_host_word'
(the same number of bit, but signed) and 'double_host_word'
(128-bit on 64-bit machine, 64-bit on 32-bit machine).
I wait with this change because ATM there is still piece of
code elsewere which can not handle 64-bit parts.  So, while
your u64 and u32 change is acceptable for current version
it would be misleading about future intent.

Note, I did not intend to post a trap for you, but in your
egerness to shorten the code you removed important information.
And while this code is unlikely to change much (basically
upgrade to 64-bit version on 64-bit machines in the only likely
change), normally code evolves and your version is harder
to change.

More generally, my aim is to make code obviously correct
(I not saying that I was fully successful in this case).
I consider your version worse, because with your version
========== REMAINDER OF ARTICLE TRUNCATED ==========