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 ==========