Sujet : Re: Top 10 most common hard skills listed on resumes...
De : bc (at) *nospam* freeuk.com (Bart)
Groupes : comp.lang.cDate : 08. Sep 2024, 22:01:10
Autres entêtes
Organisation : A noiseless patient Spider
Message-ID : <vbl3am$228vv$1@dont-email.me>
References : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
User-Agent : Mozilla Thunderbird
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;
Then I removed some casts that I thought were not necessary. 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.
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.
I didn't take the C version further, but I did port it to my syntax to see what it might look like; that is shown below.
That uses 64-bits, but the arrays are still 32 bits (and here passed by reference and are actual arrays, not pointer). I rearranged the parameters for clarity.
This is now 20 non-blank lines vs 38 of your original, and has a 60% smaller character count. But this is more about keeping clutter away from the main body of the function.
Then it becomes easier to reason about it, something you also seem to claim. For example, I probably don't need 'c'; I can set pp := 0 then use pp.[32] as needed; two more lines gone. Now however, pp needs to have function-scope.
Now please post a version in Forth!
---------------------------
proc do_bgi_add(ref[]u32 dest, xp, yp, int xlen, ylen)=
u64 xext, yext, c, pp, i
if ylen < xlen then
swap(xlen, ylen)
swap(xp, yp)
fi
xext := xp[xlen].[31]
yext := yp[ylen].[31]
c := 0
i := 1
while i <= xlen, ++i do
dst[i] := pp := xp[i] + yp[i] + c
c := pp.[32]
od
while i <= ylen, ++i do
dst[i] := pp := xext + yp[i] + c
c := pp.[32]
od
dst[i] := xext + yext + c
end
---------------------------
(Special features: X.[i] is bit indexing. While-loops can have an option incremental (left over from a suggestion for C where 'for' was over-used); as written, the arrays are 1-based. 'swap' is a built-in op.)