Rocksolid Light

Welcome to novaBBS (click a section below)

mail  files  register  newsreader  groups  login

Message-ID:  

"The medium is the massage." -- Crazy Nigel


devel / comp.lang.c / Re: portable way to get highest bit set?

SubjectAuthor
* portable way to get highest bit set?candycanearter07
+* Re: portable way to get highest bit set?Anton Shepelev
|+* Re: portable way to get highest bit set?David Brown
||`* Re: portable way to get highest bit set?Anton Shepelev
|| `* Re: portable way to get highest bit set?David Brown
||  `* Re: portable way to get highest bit set?Anton Shepelev
||   `* Re: portable way to get highest bit set?David Brown
||    +- Re: portable way to get highest bit set?Anton Shepelev
||    `* Re: portable way to get highest bit set?Ben Bacarisse
||     `- Re: portable way to get highest bit set?David Brown
|`* Re: portable way to get highest bit set?candycanearter07
| +- Re: portable way to get highest bit set?David Brown
| +* Re: portable way to get highest bit set?Ian C
| |+- Re: portable way to get highest bit set?Tim Rentsch
| |`- Re: portable way to get highest bit set?candycanearter07
| +* Re: portable way to get highest bit set?Tim Rentsch
| |+* Re: portable way to get highest bit set?David Brown
| ||+* Re: portable way to get highest bit set?Ben Bacarisse
| |||+* Re: portable way to get highest bit set?David Brown
| ||||`* Re: portable way to get highest bit set?Ben Bacarisse
| |||| `- Re: portable way to get highest bit set?David Brown
| |||`- Re: portable way to get highest bit set?Tim Rentsch
| ||+* Re: portable way to get highest bit set?Michael S
| |||`* Re: portable way to get highest bit set?Michael S
| ||| `- Re: portable way to get highest bit set?Anton Shepelev
| ||+- Re: portable way to get highest bit set?Michael S
| ||+- Re: portable way to get highest bit set?Michael S
| ||`- Re: portable way to get highest bit set?Michael S
| |`* Re: portable way to get highest bit set?Anton Shepelev
| | +- Re: portable way to get highest bit set?Michael S
| | `* Re: portable way to get highest bit set?Tim Rentsch
| |  `* Re: portable way to get highest bit set?Anton Shepelev
| |   `* Re: portable way to get highest bit set?Tim Rentsch
| |    +* Re: portable way to get highest bit set?Scott Lurndal
| |    |`- Re: portable way to get highest bit set?Tim Rentsch
| |    +* Re: portable way to get highest bit set?Michael S
| |    |`* Re: portable way to get highest bit set?Tim Rentsch
| |    | +* Re: portable way to get highest bit set?Michael S
| |    | |`* Re: portable way to get highest bit set?Tim Rentsch
| |    | | +* Re: portable way to get highest bit set?Michael S
| |    | | |`* Re: portable way to get highest bit set?Tim Rentsch
| |    | | | +- Re: portable way to get highest bit set?Branimir Maksimovic
| |    | | | `* Re: portable way to get highest bit set?Michael S
| |    | | |  `* Re: portable way to get highest bit set?Michael S
| |    | | |   `* Re: portable way to get highest bit set?Tim Rentsch
| |    | | |    `* Re: portable way to get highest bit set?Michael S
| |    | | |     +- Re: portable way to get highest bit set?Chris M. Thomasson
| |    | | |     `* Re: portable way to get highest bit set?Tim Rentsch
| |    | | |      `* Re: portable way to get highest bit set?Keith Thompson
| |    | | |       `- Re: portable way to get highest bit set?Tim Rentsch
| |    | | `* Re: portable way to get highest bit set?jak
| |    | |  `* Re: portable way to get highest bit set?Tim Rentsch
| |    | |   `* Re: portable way to get highest bit set?jak
| |    | |    `* Re: portable way to get highest bit set?Tim Rentsch
| |    | |     `* Re: portable way to get highest bit set?jak
| |    | |      +* Re: portable way to get highest bit set?Tim Rentsch
| |    | |      |`* Re: portable way to get highest bit set?jak
| |    | |      | `- Re: portable way to get highest bit set?Tim Rentsch
| |    | |      `* Re: portable way to get highest bit set?Kaz Kylheku
| |    | |       `* Re: portable way to get highest bit set?Bart
| |    | |        `* Re: portable way to get highest bit set?Michael S
| |    | |         `* Re: portable way to get highest bit set?Ben Bacarisse
| |    | |          `- Re: portable way to get highest bit set?Michael S
| |    | +* Re: portable way to get highest bit set?Anton Shepelev
| |    | |+* Re: portable way to get highest bit set?Tim Rentsch
| |    | ||`* Re: portable way to get highest bit set?Anton Shepelev
| |    | || +- Re: portable way to get highest bit set?Tim Rentsch
| |    | || `* Re: portable way to get highest bit set?Anton Shepelev
| |    | ||  +- Re: portable way to get highest bit set?Bart
| |    | ||  `* Re: portable way to get highest bit set?Tim Rentsch
| |    | ||   `* Re: portable way to get highest bit set?Anton Shepelev
| |    | ||    `- Re: portable way to get highest bit set?Tim Rentsch
| |    | |`* Re: portable way to get highest bit set?Tim Rentsch
| |    | | +* Re: portable way to get highest bit set?Michael S
| |    | | |+* Re: portable way to get highest bit set?Tim Rentsch
| |    | | ||`- Re: portable way to get highest bit set?Michael S
| |    | | |`* Re: portable way to get highest bit set?Anton Shepelev
| |    | | | `- Re: portable way to get highest bit set?Tim Rentsch
| |    | | `- Re: portable way to get highest bit set?David Brown
| |    | `* Re: portable way to get highest bit set?Michael S
| |    |  +- Re: portable way to get highest bit set?Michael S
| |    |  +- False positives in spam filter? (was: Re: portable way to getRay Banana
| |    |  +- Re: portable way to get highest bit set?Anton Shepelev
| |    |  `- Re: portable way to get highest bit set?Ben Bacarisse
| |    `* Re: portable way to get highest bit set?Anton Shepelev
| |     `* Re: portable way to get highest bit set?Tim Rentsch
| |      `* Re: portable way to get highest bit set?Anton Shepelev
| |       `- Re: portable way to get highest bit set?Tim Rentsch
| +* Re: portable way to get highest bit set?Richard Harnden
| |`* Re: portable way to get highest bit set?candycanearter07
| | `* Re: portable way to get highest bit set?Bart
| |  +- Re: portable way to get highest bit set?Keith Thompson
| |  `- Re: portable way to get highest bit set?candycanearter07
| `- Re: portable way to get highest bit set?Tim Rentsch
+- Re: portable way to get highest bit set?Ben Bacarisse
+* Re: portable way to get highest bit set?Lew Pitcher
|`* Re: portable way to get highest bit set?Lew Pitcher
| `* Re: portable way to get highest bit set?Lew Pitcher
|  `* Re: portable way to get highest bit set?Tim Rentsch
|   `* Re: portable way to get highest bit set?Bart
|    `* Re: portable way to get highest bit set?Tim Rentsch
+- Re: portable way to get highest bit set?Kaz Kylheku
+* Re: portable way to get highest bit set?jak
+* Re: portable way to get highest bit set?Blue-Maned_Hawk
`* Re: portable way to get highest bit set?Kaz Kylheku

Pages:12345678
Re: portable way to get highest bit set?

<86o7gp4ytq.fsf@linuxsc.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30044&group=comp.lang.c#30044

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: tr.17...@z991.linuxsc.com (Tim Rentsch)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Sun, 22 Oct 2023 23:50:25 -0700
Organization: A noiseless patient Spider
Lines: 83
Message-ID: <86o7gp4ytq.fsf@linuxsc.com>
References: <ug5gvh$1jkar$3@dont-email.me> <20231011102714.44a870af4dfe68f756974953@g{oogle}mail.com> <ug6huc$1rvp1$1@dont-email.me> <86h6mxawqq.fsf@linuxsc.com> <20231012111100.272c96b3209baad26a150e55@g{oogle}mail.com> <86cyxkb2ka.fsf@linuxsc.com> <20231012141719.99f5a10ec921db3ee6f7d948@g{oogle}mail.com> <864jiwaqic.fsf@linuxsc.com> <20231012173021.0000149c@yahoo.com> <86v8bbanjv.fsf@linuxsc.com> <20231012191641.00007493@yahoo.com> <865y346qvs.fsf@linuxsc.com> <ugp766$3ppas$1@dont-email.me> <86wmvj5gkc.fsf@linuxsc.com> <ugqm71$7e0u$1@dont-email.me> <86y1fu4rfm.fsf@linuxsc.com> <uh43ee$2lgq1$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: dont-email.me; posting-host="1a209718dd30b1f4c336e16106c8461e";
logging-data="3139589"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/pIdos5n5+GaROqqAjYhOVSc1Ztfub/9k="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:tEwZU2YyatSrOQiYeDVY+7Zbhck=
sha1:TkdR1jV1HJevBuoPglDccyDAGtk=
 by: Tim Rentsch - Mon, 23 Oct 2023 06:50 UTC

jak <nospam@please.ty> writes:

> Tim Rentsch ha scritto:

[considering the problems of non-powers-of-two sizes]

> #include <limits.h>
>
> typedef unsigned long T;
>
> T h_bit(T val)
> {
> int tbits = 0, bits = (sizeof(val) * CHAR_BIT) / 2;
> for(; bits > 0; bits /= 2)
> if((((T)-1) << bits) & val)
> {
> val >>= bits;
> tbits += bits;
> }
> for(; val > 1; val /= 2, tbits++);
> return val << tbits;
> }
>
> In this way it also works with char_bit == 12 and for any value it
> performs:
> 3 Interactions per data 1 byte wide.
> +1 When the width doubles (e.g. 6 for 8 bytes).
> +1 if CHAR_BIT == 12.
> If there is no something that halves these timing, given its
> simplicity I remain happy.

Two problems: it isn't obvious what the performance costs of
this scheme are, and clearly it may do more shifts than it
needs to. The problem is easy to fix, so let's just fix it.

T
h_bit( T v ){
T ones = -1;
unsigned w = ALL_ONES_WIDTH( ones );
unsigned shift = largest_power_of_two_less_than( w );
T mask = ones >> w-shift;
unsigned total_shift = 0;

do {
if( v > mask ){
v >>= shift;
total_shift += shift;
}
} while( shift /= 2, mask >>= shift, shift > 0 );

return v << total_shift;
}

Here ALL_ONES_WIDTH is just a different name for the MASK_WIDTH
macro I showed before (and is better than multiplying CHAR_BIT
times sizeof (T), which might not give the right answer):

#define ALL_ONES_WIDTH( m ) ( 0U + (unsigned)+( \
(m) /((m)%32767 +1) /32767 %32767 *15 \
+ (m) %32767 /((m)%31 +1) /31 %31 *5 \
+ 4 - 12 / ((m)%31 + 3) \
))

Yes, it's complicated, but the point of abstraction is it isn't
necessary to understand how something works when it is abstracted
away.

All that's left is the largest_power_of_two_less_than() function:

unsigned
largest_power_of_two_less_than( unsigned n ){
unsigned s, t = 1;

do s = t, t <<= 1; while( t < n );

return n > 1 ? s : 0;
}

Easy as falling off a log. Also it isn't hard to write a macro
that does the same thing, at compile time, for all practical
values of widths (corresponding to the parameter n). Doing
that means the initialization of 'shift' is done with a
compile-time constant.

Re: portable way to get highest bit set?

<87lebtbkft.fsf@fatphil.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30056&group=comp.lang.c#30056

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: pc+use...@asdf.org (Phil Carmody)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Mon, 23 Oct 2023 15:19:18 +0300
Organization: A noiseless patient Spider
Lines: 21
Message-ID: <87lebtbkft.fsf@fatphil.org>
References: <ug5gvh$1jkar$3@dont-email.me>
<pan$e0805$faa9a91a$a60476dc$4a90cfa8@invalid.invalid>
<87h6mwu9rk.fsf@nosuchdomain.example.com>
<pan$325f3$70a576a8$3150c04a$26db7b31@invalid.invalid>
<ugagv6$2vs64$1@dont-email.me>
<pan$21acb$49c8a2a6$a1bbf038$1e40c8f0@invalid.invalid>
<ugck5i$3faav$1@dont-email.me>
<pan$19122$eaff5f26$f64222cd$d70e555c@invalid.invalid>
<ugd37f$3ln97$2@dont-email.me>
<pan$c64d0$8c0ed5b8$62596621$789ec9e7@invalid.invalid>
<86zg0k8u3l.fsf@linuxsc.com>
<pan$b29a$e4923427$117477d2$1f9519d0@invalid.invalid>
MIME-Version: 1.0
Content-Type: text/plain
Injection-Info: dont-email.me; posting-host="fb0d125bdad8fe799150db7ddadb0503";
logging-data="3288653"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/5kHwa+fRy4vWxR1avIMpb"
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux)
Cancel-Lock: sha1:vMjCR6EPHvUIFbax6aww3QGHLH8=
sha1:hiE2PfqujZLZfUMmy1SVRvSvpkk=
 by: Phil Carmody - Mon, 23 Oct 2023 12:19 UTC

Blue-Maned_Hawk <bluemanedhawk@invalid.invalid> writes:
> Tim Rentsch wrote:
>
>> The word obsolete means no longer used or no longer useful. If someone
>> is still using it then by definition it is not obsolete.
>
> That is not my definition. I consider something obsolete when it has been
> replaced.

If someone is still using it, then it has not been replaced, and thus by
your definition it's not obsolete.

You are confusing "has been replaced" with "newer alternatives
exist". They are different concepts.

Phil
--
We are no longer hunters and nomads. No longer awed and frightened, as we have
gained some understanding of the world in which we live. As such, we can cast
aside childish remnants from the dawn of our civilization.
-- NotSanguine on SoylentNews, after Eugen Weber in /The Western Tradition/

Re: portable way to get highest bit set?

<86jzrd4i1n.fsf@linuxsc.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30058&group=comp.lang.c#30058

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: tr.17...@z991.linuxsc.com (Tim Rentsch)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Mon, 23 Oct 2023 05:52:52 -0700
Organization: A noiseless patient Spider
Lines: 62
Message-ID: <86jzrd4i1n.fsf@linuxsc.com>
References: <ug5gvh$1jkar$3@dont-email.me> <20231011102714.44a870af4dfe68f756974953@g{oogle}mail.com> <ug6huc$1rvp1$1@dont-email.me> <86h6mxawqq.fsf@linuxsc.com> <20231012111100.272c96b3209baad26a150e55@g{oogle}mail.com> <86cyxkb2ka.fsf@linuxsc.com> <20231012141719.99f5a10ec921db3ee6f7d948@g{oogle}mail.com> <864jiwaqic.fsf@linuxsc.com> <20231012173021.0000149c@yahoo.com> <86v8bbanjv.fsf@linuxsc.com> <20231012191641.00007493@yahoo.com> <865y346qvs.fsf@linuxsc.com> <20231018174110.00003717@yahoo.com> <86sf675fir.fsf@linuxsc.com> <20231020001455.00006ea4@yahoo.com> <20231021225010.00001606@yahoo.com> <86ttqi4oae.fsf@linuxsc.com> <20231023011138.000078ba@yahoo.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: dont-email.me; posting-host="1a209718dd30b1f4c336e16106c8461e";
logging-data="3311987"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19laU9scZwy9yMT6/oUE0lSfHBKqkg0NiI="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:Jrfk8vEwdwqzTflQXZ5NBEpw7ec=
sha1:tXXoGnaLlkqLK5QjriZk+N5jfUg=
 by: Tim Rentsch - Mon, 23 Oct 2023 12:52 UTC

Michael S <already5chosen@yahoo.com> writes:

> On Sun, 22 Oct 2023 09:25:45 -0700
> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

[...]

>> Incidentally, I found the default number of iterations in the tool
>> to be too low to give reliable indicators of performance. I ended
>> up using about 2000 iterations, which gave pretty steady results.
>
> Most likely, you computer was heavily loaded with other jobs.
> On idle computer median should stabilaze much sooner.

The processor is not otherwise loaded. Remember, I am looking
for the effects of small changes, where the difference may be
noticeably less than 10%. At 13 iterations it isn't unusual to
see fluctuations of more than 20%.

[...]

>> End result, my sense is that the fastest method is likely to be
>> platform specific, and probably needs to be coded in assembly.
>
> Intrinsic functions should be as fast as asm.
> With gcc - __builtin_clz() family. It does not belong to the
> realm of portable C, but still is much more portable than asm.
> And arguably still on topic in this group, if not in this thread.

I tend to think of intrinsics like __builtin_clz() as assembler
in disguise. However it is true that they are more portable
than assembler, when and where they are available, and depending
on what types are supported.

[...]

>> My comment upthread is about scaling. As the size gets bigger,
>> the method of oring with ever-increasing shift amounts is doomed,
>> because it's an O(N*log(N)) algorithm, but the problem can be
>> solved in O(N). My sense is that 128 bits is close to the
>> crossover, and maybe even is the crossover if we were writing in
>> assembly rather than C. And now that I've said that, it's time
>> to abandon the discussion, since it is now no longer topical in
>> a C newsgroup. :)
>
> As to your suggestion that the problem can be solved in O(N) time,
> right now, at night, I can only think of sort of O(N) solutions
> that exploit knowledge of internal representation of wide integer
> number, e.g. knowledge of its endiannes, either Little or Big.
> Which is not exactly portable.

If we wait until you have the benefit of some daylight thinking
hours I expect you will see how this can be done. (Disclaimer
and possible spoiler alert: strictly speaking there may be some
issues on implementations with integer types that have trap
representations. These days though I don't think any machines
even have any padding bits, let alone trap representations. Oh,
I have to take that back - I know of one contemporary machine
where unsigned types don't use the sign bit, and so have one
padding bit. In that case though there is enough information
so the padding bit is known, and potential trap representations
can be avoided.)

Re: portable way to get highest bit set?

<pan$b13ec$1bcd72f4$63d47bc0$6e56a14e@invalid.invalid>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30061&group=comp.lang.c#30061

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!bluemanedhawk.eternal-september.org!.POSTED!not-for-mail
From: bluemane...@invalid.invalid (Blue-Maned_Hawk)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Mon, 23 Oct 2023 13:51:06 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 9
Message-ID: <pan$b13ec$1bcd72f4$63d47bc0$6e56a14e@invalid.invalid>
References: <ug5gvh$1jkar$3@dont-email.me>
<pan$e0805$faa9a91a$a60476dc$4a90cfa8@invalid.invalid>
<87h6mwu9rk.fsf@nosuchdomain.example.com>
<pan$325f3$70a576a8$3150c04a$26db7b31@invalid.invalid>
<ugagv6$2vs64$1@dont-email.me>
<pan$21acb$49c8a2a6$a1bbf038$1e40c8f0@invalid.invalid>
<ugck5i$3faav$1@dont-email.me>
<pan$19122$eaff5f26$f64222cd$d70e555c@invalid.invalid>
<ugd37f$3ln97$2@dont-email.me>
<pan$c64d0$8c0ed5b8$62596621$789ec9e7@invalid.invalid>
<86zg0k8u3l.fsf@linuxsc.com>
<pan$b29a$e4923427$117477d2$1f9519d0@invalid.invalid>
<87lebtbkft.fsf@fatphil.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Injection-Date: Mon, 23 Oct 2023 13:51:06 -0000 (UTC)
Injection-Info: bluemanedhawk.eternal-september.org; posting-host="d2809c405464370864b61fc53d86b8e5";
logging-data="3339537"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19AMUnOmniDOMSYGS/JD0nl/55YSDaKxCw="
User-Agent: Pan/0.154 (Izium; 517acf4)
Cancel-Lock: sha1:/ywod8fRoPmYtVTI5ujumkOeXzM=
X-Face: Llanfair­pwllgwyngyll­gogery­c
hwyrn­
drobwll­llan­tysilio­gogo­g
och
Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAACh0lEQVRYw71Z21bD
MAzzevbfkr4cHjrSXJyL044+MDa6WLEl2SkvkrZ1AbAvXO+bUGSCPYnsuIVGMpm
ZLnjX718GhAKNsp8lON2F9VrhELwIgJlBepkZjA78rVK+FkmNhEJK76UsJlz8+E
rJsjrpYouhLo/SC6qPHgakFOR8wV9+8rCfO/I/oVnmUZUp42/LW2XkLj9TCFNM9
jp5g2EmHZgpYZjCOkYU7sXVogRylJqpdggoFLG1g09Flah/7kErCxzR9HgXPYsq
0glb9cxjIz2Vsk9AmAoCSxECpD713joMKjQqLAtmMqJmXjdVvlMnMQCVITotJd1
z+fh1f1NNo+vuc1KnhWUmY7t03vydTud9BbXCtN3L2PL3bK7JCNG0GHzuZxafyB
fxevCxpm1vrwZltqw6SILCcdoCE6PGQC8wZWDA9Or7Qp5s3lAZezys0nDazs9S9
R0TjwEiksRxLkNPC1NMMWPs1bj0Ei0Yuo+JVtFLuzP1NRJ16qXWN8DhhtmS4PDg
O6mqRxs4bEJrYt087mSIow/1VzW2oFlMQuiuIy/KsUagvhdw6hSjJGlIavbLF8x
j3X47bccLcUSi0dkWh1nUZNhANT1tHKUXrNxNLbd9KPb9wDDVrKwmPQMOPQ1oy6
k5I1DwzDeRJd3jVIhDAUxq3ngzJG4CCkNXZxZVMcjefoK2J0gUY2S3rxz/RuTFx
2zHd9U+obimJXMG4edsk/2j5pTU5G1MmzbRLxkfq5EiT1GGsidvMGzi+1goGb2l
GCrN+nGnV8xj3q3JLRDVPL96vUc7Z4aJ3TN1mVqWAMJMfG+Jxh6TQqP+92iZkCU
xtglds1AB6r0aiSHKcnFck+p/c/0CbacFLQcajGcAAAAASUVORK5CYII=
 by: Blue-Maned_Hawk - Mon, 23 Oct 2023 13:51 UTC

Phil Carmody wrote:

> You are confusing "has been replaced" with "newer alternatives exist".

You are confusing alternatives with replacements.

--

Re: portable way to get highest bit set?

<20231022155123.253@kylheku.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30066&group=comp.lang.c#30066

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!rocksolid2!news.neodome.net!news.mixmin.net!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: 864-117-...@kylheku.com (Kaz Kylheku)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Mon, 23 Oct 2023 17:22:15 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 120
Message-ID: <20231022155123.253@kylheku.com>
References: <ug5gvh$1jkar$3@dont-email.me>
<20231011102714.44a870af4dfe68f756974953@g{oogle}mail.com>
<ug6huc$1rvp1$1@dont-email.me> <86h6mxawqq.fsf@linuxsc.com>
<20231012111100.272c96b3209baad26a150e55@g{oogle}mail.com>
<86cyxkb2ka.fsf@linuxsc.com>
<20231012141719.99f5a10ec921db3ee6f7d948@g{oogle}mail.com>
<864jiwaqic.fsf@linuxsc.com> <20231012173021.0000149c@yahoo.com>
<86v8bbanjv.fsf@linuxsc.com> <20231012191641.00007493@yahoo.com>
<865y346qvs.fsf@linuxsc.com> <ugp766$3ppas$1@dont-email.me>
<86wmvj5gkc.fsf@linuxsc.com> <ugqm71$7e0u$1@dont-email.me>
<86y1fu4rfm.fsf@linuxsc.com> <uh43ee$2lgq1$1@dont-email.me>
Injection-Date: Mon, 23 Oct 2023 17:22:15 -0000 (UTC)
Injection-Info: dont-email.me; posting-host="5c204f9608c1b51964379badb88b6534";
logging-data="3449286"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/mVuGUwgc+NKTVCKL4VVnd3YRCSVFw9sA="
User-Agent: slrn/pre1.0.4-9 (Linux)
Cancel-Lock: sha1:kdaDFAh0GGdmRiVEBfKjCHGgIrk=
 by: Kaz Kylheku - Mon, 23 Oct 2023 17:22 UTC

On 2023-10-22, jak <nospam@please.ty> wrote:
> #include <limits.h>
>
> typedef unsigned long T;
>
> T h_bit(T val)
> {
> int tbits = 0, bits = (sizeof(val) * CHAR_BIT) / 2;
> for(; bits > 0; bits /= 2)
> if((((T)-1) << bits) & val)
> {
> val >>= bits;
> tbits += bits;
> }
> for(; val > 1; val /= 2, tbits++);
> return val << tbits;
> }

This is a nice approach if we are interested in the tbits value.

GCC does a good job of unrolling the looping. Only problem is, there
are branches:

E.g. x86 code with gcc 7.5:

h_bit:
movl 4(%esp), %eax
xorl %ecx, %ecx
testl $-65536, %eax
je .L2
shrl $16, %eax
movl $16, %ecx
..L2:
testl $-256, %eax
je .L3
shrl $8, %eax
addl $8, %ecx
..L3:
testl $-16, %eax
je .L4
shrl $4, %eax
addl $4, %ecx
..L4:
testl $-4, %eax
je .L5
shrl $2, %eax
addl $2, %ecx
..L5:
testl $-2, %eax
je .L6
addl $1, %ecx
movl $1, %eax
..L6:
sall %cl, %eax
ret

(Also, note that the translated code shows that you have some
unnecessary details in the C code. If you reverse engineer
the code back to C, you will get better C. Your second for
loop disappeared entirely.)

Let's look at the code I posted a while ago:

unsigned long fill_mask_down(unsigned long x)
{
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;

#if UINT_MAX == UINT32_MAX
x |= x >> 16;
#elif UINT_MAX == UINT64_MAX
x |= x >> 16;
x |= x >> 32;
#elif UINT_MAX != UINT16_MAX
#error port me!
#endif

return x;
}

unsigned long isolate_highest_bit(unsigned long x)
{
unsigned long m = fill_mask_down(x);
return m ^ (m >> 1);
}

This leads to a single branch-free basic block:

isolate_highest_bit:
movl 4(%esp), %edx
movl %edx, %eax
shrl %eax
orl %edx, %eax
movl %eax, %edx
shrl $2, %edx
orl %edx, %eax
movl %eax, %edx
shrl $4, %edx
orl %edx, %eax
movl %eax, %edx
shrl $8, %edx
orl %edx, %eax
movl %eax, %edx
shrl $16, %edx
orl %edx, %eax
movl %eax, %edx
shrl %edx
xorl %edx, %eax
ret

This doesn't require branch prediction or speculative execution to go
fast.

--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazinator@mstdn.ca
NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.

Re: portable way to get highest bit set?

<20231023102308.140@kylheku.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30067&group=comp.lang.c#30067

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!rocksolid2!news.neodome.net!news.mixmin.net!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: 864-117-...@kylheku.com (Kaz Kylheku)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Mon, 23 Oct 2023 17:39:37 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 84
Message-ID: <20231023102308.140@kylheku.com>
References: <ug5gvh$1jkar$3@dont-email.me>
<pan$e0805$faa9a91a$a60476dc$4a90cfa8@invalid.invalid>
<87h6mwu9rk.fsf@nosuchdomain.example.com>
<pan$325f3$70a576a8$3150c04a$26db7b31@invalid.invalid>
<ugagv6$2vs64$1@dont-email.me>
<pan$21acb$49c8a2a6$a1bbf038$1e40c8f0@invalid.invalid>
<ugck5i$3faav$1@dont-email.me>
<pan$19122$eaff5f26$f64222cd$d70e555c@invalid.invalid>
<ugd37f$3ln97$2@dont-email.me>
<pan$c64d0$8c0ed5b8$62596621$789ec9e7@invalid.invalid>
<86zg0k8u3l.fsf@linuxsc.com>
<pan$b29a$e4923427$117477d2$1f9519d0@invalid.invalid>
<87lebtbkft.fsf@fatphil.org>
Injection-Date: Mon, 23 Oct 2023 17:39:37 -0000 (UTC)
Injection-Info: dont-email.me; posting-host="5c204f9608c1b51964379badb88b6534";
logging-data="3457506"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+mVn8Sy7nL4txsJQjcEd2aSMvUQI+Q3Bw="
User-Agent: slrn/pre1.0.4-9 (Linux)
Cancel-Lock: sha1:cv/La+Nz+t7m+Ctd415lFnadJzQ=
 by: Kaz Kylheku - Mon, 23 Oct 2023 17:39 UTC

On 2023-10-23, Phil Carmody <pc+usenet@asdf.org> wrote:
> Blue-Maned_Hawk <bluemanedhawk@invalid.invalid> writes:
>> Tim Rentsch wrote:
>>
>>> The word obsolete means no longer used or no longer useful. If someone
>>> is still using it then by definition it is not obsolete.
>>
>> That is not my definition. I consider something obsolete when it has been
>> replaced.
>
> If someone is still using it, then it has not been replaced, and thus by
> your definition it's not obsolete.
>
> You are confusing "has been replaced" with "newer alternatives
> exist". They are different concepts.

The problem with a purely use-based definition of obsolescence is that
all sorts of dead obsolete cruft is still in use by someone.

For instance, steam locomotives are still running in places, thus
the steam locomotive isn't obsolete?

Obsolescence is a somewhat broad topic with fuzzy edges.

Let's get one form of obsolescence out of the way: a form of artistic
expression or style is obsolete when all new manifestations of it are
recognized as references to, imitations/parodies of, or homages to that
form's original era, and this aspect of the works interferes with or
occludes consideration of their inherent originality.

I have a sense that this discussion has been about the economic
obsolescence of something practical, like a technology.

Old technologies can be in use, yet obsolete. Someone somewhere is
operating a server on a DEC MicroVAX. Yet that machine is obsolete.

Roughly, a tangible product is obsolete when it is no longer made.

So there are probably people in the world who are becoming new owners of
DEC MicroVAXen. But each time that happens, someone simultaneously stops
being an owner. In other words, trade of DEC MicroVAXen is closed
system in which ecnonomic production isn't taking place. It's a
backwards-looking retro-computing hobby.

Not only are those machines not made, but the ecosystem for making them
isn't there. If you wanted to make an exact replica of that machine, you
would have a hard time sourcing new parts. Same with steam locomotives.
Someone building a replica of a locomotive from 1900 would have to
produce their own parts. Scavenged parts from an existing such
locomotive don't count as new production; that's a rebuild.

Talk was made in this thread about whether to make C code portable to
obsolete systems, which means installations of old machines running old
operating systems.

Economically, it is poorly justified. The users of those systems are
mainly interested in the original software. Some such systems run
in the proverbial corner, serving some role. People in the surrouding
organization have their fingers crossed. Some have their fingers crossed
that the machine will not die today. Others have their fingers crossed
that it does. Neither group wants to put a new C program on it.

(There is some retrocomputing activity whereby new software titles are
written for old machines: such a new games for old eight bit
microcomputers. Those games can run on new machines emulation, so the
games themselves might nto be obsolete.)

There was talk in this thread about using old C dialects: are they
obsolete.

I would say this: that if you're actually using a 30-year-old compiler
binary to build your C90 code, then you're targetting an obsolete
implementation.

If the only way you can use a programming language is via an old
computer system, then it's probably obsolete. Dead programming languages
can be revived much more easily than dead human languages though,
and it's possible to ship a new, working solution in them.

--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazinator@mstdn.ca
NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.

Re: portable way to get highest bit set?

<874jihky56.fsf@nosuchdomain.example.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30069&group=comp.lang.c#30069

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: Keith.S....@gmail.com (Keith Thompson)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Mon, 23 Oct 2023 11:10:45 -0700
Organization: None to speak of
Lines: 20
Message-ID: <874jihky56.fsf@nosuchdomain.example.com>
References: <ug5gvh$1jkar$3@dont-email.me>
<20231011102714.44a870af4dfe68f756974953@g{oogle}mail.com>
<ug6huc$1rvp1$1@dont-email.me> <86h6mxawqq.fsf@linuxsc.com>
<20231012111100.272c96b3209baad26a150e55@g{oogle}mail.com>
<86cyxkb2ka.fsf@linuxsc.com>
<20231012141719.99f5a10ec921db3ee6f7d948@g{oogle}mail.com>
<864jiwaqic.fsf@linuxsc.com> <20231012173021.0000149c@yahoo.com>
<86v8bbanjv.fsf@linuxsc.com> <20231012191641.00007493@yahoo.com>
<865y346qvs.fsf@linuxsc.com> <20231018174110.00003717@yahoo.com>
<86sf675fir.fsf@linuxsc.com> <20231020001455.00006ea4@yahoo.com>
<20231021225010.00001606@yahoo.com> <86ttqi4oae.fsf@linuxsc.com>
<20231023011138.000078ba@yahoo.com> <86jzrd4i1n.fsf@linuxsc.com>
MIME-Version: 1.0
Content-Type: text/plain
Injection-Info: dont-email.me; posting-host="5a5d01c56ec151ef0f06cc7046065444";
logging-data="3472242"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1++rgVCVRClUoBSj/mTJPa0"
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux)
Cancel-Lock: sha1:PWBrotGnXEl2viJVZQe9HYsfx+U=
sha1:RKGO28Vttvz+rpx8agudUwSOu/s=
 by: Keith Thompson - Mon, 23 Oct 2023 18:10 UTC

Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
[...]
> If we wait until you have the benefit of some daylight thinking
> hours I expect you will see how this can be done. (Disclaimer
> and possible spoiler alert: strictly speaking there may be some
> issues on implementations with integer types that have trap
> representations. These days though I don't think any machines
> even have any padding bits, let alone trap representations. Oh,
> I have to take that back - I know of one contemporary machine
> where unsigned types don't use the sign bit, and so have one
> padding bit. In that case though there is enough information
> so the padding bit is known, and potential trap representations
> can be avoided.)

Which contemporary machine is that?

--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

Re: portable way to get highest bit set?

<uh6ti7$3e3n0$1@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30073&group=comp.lang.c#30073

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: nos...@please.ty (jak)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Tue, 24 Oct 2023 00:53:58 +0200
Organization: A noiseless patient Spider
Lines: 117
Message-ID: <uh6ti7$3e3n0$1@dont-email.me>
References: <ug5gvh$1jkar$3@dont-email.me>
<20231011102714.44a870af4dfe68f756974953@g{oogle}mail.com>
<ug6huc$1rvp1$1@dont-email.me> <86h6mxawqq.fsf@linuxsc.com>
<20231012111100.272c96b3209baad26a150e55@g{oogle}mail.com>
<86cyxkb2ka.fsf@linuxsc.com>
<20231012141719.99f5a10ec921db3ee6f7d948@g{oogle}mail.com>
<864jiwaqic.fsf@linuxsc.com> <20231012173021.0000149c@yahoo.com>
<86v8bbanjv.fsf@linuxsc.com> <20231012191641.00007493@yahoo.com>
<865y346qvs.fsf@linuxsc.com> <ugp766$3ppas$1@dont-email.me>
<86wmvj5gkc.fsf@linuxsc.com> <ugqm71$7e0u$1@dont-email.me>
<86y1fu4rfm.fsf@linuxsc.com> <uh43ee$2lgq1$1@dont-email.me>
<86o7gp4ytq.fsf@linuxsc.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Mon, 23 Oct 2023 22:53:59 -0000 (UTC)
Injection-Info: dont-email.me; posting-host="d9fd7f7cdcdb6f0c9276e3bb66f69150";
logging-data="3608288"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+m74J+3/T8KOo9jp6HxMsb"
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101
Firefox/91.0 SeaMonkey/2.53.17.1
Cancel-Lock: sha1:eb2Rp2YK+DMpNyWTQf3jCON/3/Q=
In-Reply-To: <86o7gp4ytq.fsf@linuxsc.com>
 by: jak - Mon, 23 Oct 2023 22:53 UTC

Tim Rentsch ha scritto:
> jak <nospam@please.ty> writes:
>
>> Tim Rentsch ha scritto:
>
> [considering the problems of non-powers-of-two sizes]
>
>> #include <limits.h>
>>
>> typedef unsigned long T;
>>
>> T h_bit(T val)
>> {
>> int tbits = 0, bits = (sizeof(val) * CHAR_BIT) / 2;
>> for(; bits > 0; bits /= 2)
>> if((((T)-1) << bits) & val)
>> {
>> val >>= bits;
>> tbits += bits;
>> }
>> for(; val > 1; val /= 2, tbits++);
>> return val << tbits;
>> }
>>
>> In this way it also works with char_bit == 12 and for any value it
>> performs:
>> 3 Interactions per data 1 byte wide.
>> +1 When the width doubles (e.g. 6 for 8 bytes).
>> +1 if CHAR_BIT == 12.
>> If there is no something that halves these timing, given its
>> simplicity I remain happy.
>
> Two problems: it isn't obvious what the performance costs of
> this scheme are, and clearly it may do more shifts than it
> needs to. The problem is easy to fix, so let's just fix it.
>
> T
> h_bit( T v ){
> T ones = -1;
> unsigned w = ALL_ONES_WIDTH( ones );
> unsigned shift = largest_power_of_two_less_than( w );
> T mask = ones >> w-shift;
> unsigned total_shift = 0;
>
> do {
> if( v > mask ){
> v >>= shift;
> total_shift += shift;
> }
> } while( shift /= 2, mask >>= shift, shift > 0 );
>
> return v << total_shift;
> }
>
> Here ALL_ONES_WIDTH is just a different name for the MASK_WIDTH
> macro I showed before (and is better than multiplying CHAR_BIT
> times sizeof (T), which might not give the right answer):
>
> #define ALL_ONES_WIDTH( m ) ( 0U + (unsigned)+( \
> (m) /((m)%32767 +1) /32767 %32767 *15 \
> + (m) %32767 /((m)%31 +1) /31 %31 *5 \
> + 4 - 12 / ((m)%31 + 3) \
> ))
>
> Yes, it's complicated, but the point of abstraction is it isn't
> necessary to understand how something works when it is abstracted
> away.
>
> All that's left is the largest_power_of_two_less_than() function:
>
> unsigned
> largest_power_of_two_less_than( unsigned n ){
> unsigned s, t = 1;
>
> do s = t, t <<= 1; while( t < n );
>
> return n > 1 ? s : 0;
> }
>
> Easy as falling off a log. Also it isn't hard to write a macro
> that does the same thing, at compile time, for all practical
> values of widths (corresponding to the parameter n). Doing
> that means the initialization of 'shift' is done with a
> compile-time constant.
>

I read, appreciated and I consider your explanation valid, so much so
that I wanted to compare our solutions (main recall function 10000
times). I copied my source file and replaced your solution to mine. I
had a surprise because I expected the opposite:

$ gcc jak.c -o jak
$ gcc tim.c -o tim

$ jak
val = 0x00000000FFFFFFFF
ret = 0x0000000080000000
Time measured: 0.000180 seconds.
$ tim
val = 0x00000000FFFFFFFF
ret = 0x0000000080000000
Time measured: 0.000582 seconds.

$ gcc jak.c -Ofast -o jak
$ gcc tim.c -Ofast -o tim

$ jak
val = 0x00000000FFFFFFFF
ret = 0x0000000080000000
Time measured: 0.000001 seconds.
$ tim
val = 0x00000000FFFFFFFF
ret = 0x0000000080000000
Time measured: 0.000065 seconds.

I don't know how to explain it. Maybe the optimizer manages my version
better.

Re: portable way to get highest bit set?

<86bkco4t89.fsf@linuxsc.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30077&group=comp.lang.c#30077

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: tr.17...@z991.linuxsc.com (Tim Rentsch)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Mon, 23 Oct 2023 20:03:34 -0700
Organization: A noiseless patient Spider
Lines: 59
Message-ID: <86bkco4t89.fsf@linuxsc.com>
References: <ug5gvh$1jkar$3@dont-email.me> <20231011143809.748@kylheku.com> <20231014222046.551@kylheku.com> <86lec48ebs.fsf@linuxsc.com> <20231015084712.400@kylheku.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: dont-email.me; posting-host="99c3b67b33db560fdfb4fb42d317a89b";
logging-data="3825080"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/sSWUlpogq8d5+bjFCRNn3ZR8pU5fwiAI="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:6SjjDJlGLqm93obP6xMGeKfufh8=
sha1:WJSD1hAvievfvXwHV/VWyWuxJQY=
 by: Tim Rentsch - Tue, 24 Oct 2023 03:03 UTC

Kaz Kylheku <864-117-4973@kylheku.com> writes:

> On 2023-10-15, Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>
>> Kaz Kylheku <864-117-4973@kylheku.com> writes:
>>
>>> On 2023-10-11, Kaz Kylheku <864-117-4973@kylheku.com> wrote:
>>>
>>>> E.g. 32 bit code:
>>>>
>>>> uint32_t fill_mask_down(uint32_t x)
>>>> {
>>>> x |= x >> 1; // e.g. 1000...0000 -> 1100...0000
>>>> x |= x >> 2; // e.g. 1100...0000 -> 1111...0000
>>>> x |= x >> 4; // e.g. 11110000... -> 11111111...
>>>> x |= x >> 8;
>>>> x |= x >> 16;
>>>>
>>>> return x;
>>>> }
>>>>
>>>> Thus:
>>>>
>>>> uint32_t isolate_highest_bit(uint32_t x)
>>>> {
>>>> uint32_t m = fill_mask_down(x);
>>>> return m ^ (m >> 1);
>>>> }
>>>
>>> I guess this went over people's heads?
>>
>> Not at all. It's a well-known technique. But it doesn't
>> address the central ask for an approach that works no
>> matter how wide the value type is.
>
> Oh, if I had to make it work with the unsigned long type, like the other
> solutions,

That is a misrepresentation.

> I'd probably just do this:
>
> unsigned long fill_mask_down(unsigned long x)
> {
> x |= x >> 1;
> x |= x >> 2;
> x |= x >> 4;
> x |= x >> 8;
>
> #if UINT_MAX == UINT32_MAX
> x |= x >> 16;
> [...]

The challenge is to find an algorithm that works
without being tied to a specific type. If you
aren't up to the task that's okay with me, but
don't pretend it's something it isn't. It's
always easier to find an answer if one is free
to change the question.

Re: portable way to get highest bit set?

<867cnc4r9j.fsf@linuxsc.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30078&group=comp.lang.c#30078

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: tr.17...@z991.linuxsc.com (Tim Rentsch)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Mon, 23 Oct 2023 20:46:00 -0700
Organization: A noiseless patient Spider
Lines: 86
Message-ID: <867cnc4r9j.fsf@linuxsc.com>
References: <ug5gvh$1jkar$3@dont-email.me> <20231011102714.44a870af4dfe68f756974953@g{oogle}mail.com> <ug6huc$1rvp1$1@dont-email.me> <86h6mxawqq.fsf@linuxsc.com> <20231012111100.272c96b3209baad26a150e55@g{oogle}mail.com> <86cyxkb2ka.fsf@linuxsc.com> <20231012141719.99f5a10ec921db3ee6f7d948@g{oogle}mail.com> <864jiwaqic.fsf@linuxsc.com> <20231012173021.0000149c@yahoo.com> <86v8bbanjv.fsf@linuxsc.com> <20231012191641.00007493@yahoo.com> <865y346qvs.fsf@linuxsc.com> <ugp766$3ppas$1@dont-email.me> <86wmvj5gkc.fsf@linuxsc.com> <ugqm71$7e0u$1@dont-email.me> <86y1fu4rfm.fsf@linuxsc.com> <uh43ee$2lgq1$1@dont-email.me> <86o7gp4ytq.fsf@linuxsc.com> <uh6ti7$3e3n0$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: dont-email.me; posting-host="99c3b67b33db560fdfb4fb42d317a89b";
logging-data="3844315"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX182kT18QdrhQ+XTItSBtv2sw4udyVkR/kY="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:P7UNn+PGkjFEynWg+W+DypAezMY=
sha1:m9U+qUH07z67QfvKtMY8HXO7bbA=
 by: Tim Rentsch - Tue, 24 Oct 2023 03:46 UTC

jak <nospam@please.ty> writes:

> Tim Rentsch ha scritto:

[Tim presented an alternate implementation of jak's algorithm.]

> I read, appreciated and I consider your explanation valid, so much
> so that I wanted to compare our solutions (main recall function
> 10000 times). I copied my source file and replaced your solution to
> mine. I had a surprise because I expected the opposite:
>
> $ gcc jak.c -o jak
> $ gcc tim.c -o tim
>
> $ jak
> val = 0x00000000FFFFFFFF
> ret = 0x0000000080000000
> Time measured: 0.000180 seconds.
> $ tim
> val = 0x00000000FFFFFFFF
> ret = 0x0000000080000000
> Time measured: 0.000582 seconds.
>
> $ gcc jak.c -Ofast -o jak
> $ gcc tim.c -Ofast -o tim
>
> $ jak
> val = 0x00000000FFFFFFFF
> ret = 0x0000000080000000
> Time measured: 0.000001 seconds.
> $ tim
> val = 0x00000000FFFFFFFF
> ret = 0x0000000080000000
> Time measured: 0.000065 seconds.
>
> I don't know how to explain it. Maybe the optimizer manages my
> version better.

I took our two implementations and plugged them into my measuring
setup based on Michael S's testbench.

First pass - mine was a lot worse. That wasn't surprising, since
what I posted calls a runtime function rather than using a scheme
to produce a compile time constant. Incidentally, all of my
tests were done on 128 bit integers (and that only because it was
more convenient for my testing setup than other widths).

Second pass - I plugged in the macro so my version calculated the
intial shift at compile time, making it more an apples-and-apples
comparison. Note by the way that the width involved are already
powers of two, so the sequence of shifts in the two versions will
be identical. Here are results from that run:

my-jak-runit-128
Generating 1000000 test points...done. 60.480 msec.
Throughput time (nsec) mean/med 26.572 / 26.429
Latency time (nsec) mean/med 26.676 / 26.579

jak-runit-128
Generating 1000000 test points...done. 63.289 msec.
Throughput time (nsec) mean/med 23.598 / 23.504
Latency time (nsec) mean/med 24.082 / 24.047

These results show the jak version runs between 10 and 13
percent faster than mine. That was kind of discouraging.

Third pass - I used the same code as in the second pass, but
compiled with clang instead of gcc. Here are results from that
run:

my-jak-runit-128
Generating 1000000 test points...done. 64.892 msec.
Throughput time (nsec) mean/med 8.538 / 8.462
Latency time (nsec) mean/med 11.092 / 11.074

jak-runit-128
Generating 1000000 test points...done. 63.851 msec.
Throughput time (nsec) mean/med 13.648 / 13.563
Latency time (nsec) mean/med 17.995 / 17.983

These results show both versions sped up a lot, but my version
sped up more than jak's, giving an overall result that my
version runs about 60% faster than the jak version.

These kinds of fluctuations were a major part of what motivated
me to stop exploring the different approaches.

Re: portable way to get highest bit set?

<20231024121014.00000bd8@yahoo.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30081&group=comp.lang.c#30081

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!usenet.goja.nl.eu.org!weretis.net!feeder8.news.weretis.net!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: already5...@yahoo.com (Michael S)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Tue, 24 Oct 2023 12:10:14 +0300
Organization: A noiseless patient Spider
Lines: 110
Message-ID: <20231024121014.00000bd8@yahoo.com>
References: <ug5gvh$1jkar$3@dont-email.me>
<20231011143809.748@kylheku.com>
<20231014222046.551@kylheku.com>
<86lec48ebs.fsf@linuxsc.com>
<20231015084712.400@kylheku.com>
<86bkco4t89.fsf@linuxsc.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: dont-email.me; posting-host="977bc0ee08212b7bf0b25159b2b54fa9";
logging-data="3937628"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+bT6hPEZmx0OJmCyiWsK9GtiHPIVWJ/JE="
Cancel-Lock: sha1:5hkJScNcWb8Wqs5jE6DJr8IaDs4=
X-Newsreader: Claws Mail 3.19.1 (GTK+ 2.24.33; x86_64-w64-mingw32)
 by: Michael S - Tue, 24 Oct 2023 09:10 UTC

On Mon, 23 Oct 2023 20:03:34 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

> Kaz Kylheku <864-117-4973@kylheku.com> writes:
>
> > On 2023-10-15, Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
> >
> >> Kaz Kylheku <864-117-4973@kylheku.com> writes:
> >>
> >>> On 2023-10-11, Kaz Kylheku <864-117-4973@kylheku.com> wrote:
> >>>
> >>>> E.g. 32 bit code:
> >>>>
> >>>> uint32_t fill_mask_down(uint32_t x)
> >>>> {
> >>>> x |= x >> 1; // e.g. 1000...0000 -> 1100...0000
> >>>> x |= x >> 2; // e.g. 1100...0000 -> 1111...0000
> >>>> x |= x >> 4; // e.g. 11110000... -> 11111111...
> >>>> x |= x >> 8;
> >>>> x |= x >> 16;
> >>>>
> >>>> return x;
> >>>> }
> >>>>
> >>>> Thus:
> >>>>
> >>>> uint32_t isolate_highest_bit(uint32_t x)
> >>>> {
> >>>> uint32_t m = fill_mask_down(x);
> >>>> return m ^ (m >> 1);
> >>>> }
> >>>
> >>> I guess this went over people's heads?
> >>
> >> Not at all. It's a well-known technique. But it doesn't
> >> address the central ask for an approach that works no
> >> matter how wide the value type is.
> >
> > Oh, if I had to make it work with the unsigned long type, like the
> > other solutions,
>
> That is a misrepresentation.
>
> > I'd probably just do this:
> >
> > unsigned long fill_mask_down(unsigned long x)
> > {
> > x |= x >> 1;
> > x |= x >> 2;
> > x |= x >> 4;
> > x |= x >> 8;
> >
> > #if UINT_MAX == UINT32_MAX
> > x |= x >> 16;
> > [...]
>
> The challenge is to find an algorithm that works
> without being tied to a specific type. If you
> aren't up to the task that's okay with me, but
> don't pretend it's something it isn't. It's
> always easier to find an answer if one is free
> to change the question.

In my own tests I used following form of Kaz's algorithm:

T
highest_bit_set( T u ){
for (int k = 0; ((T)-1 >> ((1 <<k)-1)) > 1; ++k)
u |= u >> (1 << k);
return u ^ (u >> 1);
}

Both gcc -O3 and clang -O2 and -O3 translate it into the same object
code as manually written sequence.
Of course, this code works only for types with number of bits equal to
power of two. For my tests it was o.k. because my test platforms
have no other integer types anyway.

I was not able to generalize this loop for non-power-of-two. For
example, the variant below produces desired code with clang, but gcc12
generates loop instead of straight line.

T
highest_bit_set( T u ){
u |= u >> 1;
for (int k = 0; (((T)-1 >> (1<<k)) >> (1<<k)) != 0; ++k)
u |= u >> (1 << (k+1));
return u ^ (u >> 1);
}

I tried several other variations of this theme. Many were good for
neither compiler, many others only good for clang, one or two only good
for gcc, but none good for both.

Fortunately there is always a magic macro of yours. It works fine
with both compilers. May be, it has theoretical limits, but in practice
it is more than good enough.

T
highest_bit_set( T u ){
const int nbits = MASK_WIDTH((T)-1);
for (int k = 0; (1<<k) < nbits; ++k)
u |= u >> (1<<k);
return u ^ (u >> 1);
}

Re: portable way to get highest bit set?

<86y1fs2ind.fsf@linuxsc.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30086&group=comp.lang.c#30086

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!nntp.comgw.net!paganini.bofh.team!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: tr.17...@z991.linuxsc.com (Tim Rentsch)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Tue, 24 Oct 2023 07:35:02 -0700
Organization: A noiseless patient Spider
Lines: 98
Message-ID: <86y1fs2ind.fsf@linuxsc.com>
References: <ug5gvh$1jkar$3@dont-email.me> <20231011143809.748@kylheku.com> <20231014222046.551@kylheku.com> <86lec48ebs.fsf@linuxsc.com> <20231015084712.400@kylheku.com> <86bkco4t89.fsf@linuxsc.com> <20231024121014.00000bd8@yahoo.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: dont-email.me; posting-host="99c3b67b33db560fdfb4fb42d317a89b";
logging-data="15751"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19u8ygjIIKTsQN119W/BaHqzDaBI2QMd5s="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:46S0hMbXi3QAz7DwfbtMwSh0SEk=
sha1:TCQ+kNBQJF3akpIe46IoC0dwPAs=
 by: Tim Rentsch - Tue, 24 Oct 2023 14:35 UTC

Michael S <already5chosen@yahoo.com> writes:

> On Mon, 23 Oct 2023 20:03:34 -0700
> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>
>> The challenge is to find an algorithm that works
>> without being tied to a specific type. [...]
>
> [an effort to generalize a type-specific function]
>
> T
> highest_bit_set( T u ){
> for (int k = 0; ((T)-1 >> ((1 <<k)-1)) > 1; ++k)
> u |= u >> (1 << k);
> return u ^ (u >> 1);
> }
>
> Both gcc -O3 and clang -O2 and -O3 translate it into the same object
> code as manually written sequence.

Great! That's cool.

> Of course, this code works only for types with number of bits
> equal to power of two. For my tests it was o.k. because my test
> platforms have no other integer types anyway.
>
> I was not able to generalize this loop for non-power-of-two. For
> example, the variant below produces desired code with clang, but
> gcc12 generates loop instead of straight line.
>
> T
> highest_bit_set( T u ){
> u |= u >> 1;
> for (int k = 0; (((T)-1 >> (1<<k)) >> (1<<k)) != 0; ++k)
> u |= u >> (1 << (k+1));
> return u ^ (u >> 1);
> }
>
> I tried several other variations of this theme. Many were good
> for neither compiler, many others only good for clang, one or two
> only good for gcc, but none good for both.

Try this:

T
highest_bit_set( T u ){
T one = 1, all = -one;
unsigned k, s;

u |= u>>1;
for( k = 0; s = 1<<k, all>>s > one<<s; k++ ){
u |= u >> s*2;
}

return u ^ (u >> 1);
}

With -O3 this works for me with both gcc and clang (both at least
several years old).

> Fortunately there is always a magic macro of yours.

Again, not mine. The original author was Hallvard Furuseth
(with my MASK_WIDTH() being a less ambitious version of his
IMAX_BITS()).

> It works
> fine with both compilers. May be, it has theoretical limits,
> but in practice it is more than good enough.
>
> T
> highest_bit_set( T u ){
> const int nbits = MASK_WIDTH((T)-1);
> for (int k = 0; (1<<k) < nbits; ++k)
> u |= u >> (1<<k);
> return u ^ (u >> 1);
> }

The version of MASK_WIDTH I posted tops out at 491504 bits.

If that's not enough, here is the original (my choice of layout,
wrapping, and using 'unsigned long' type, but otherwise the same):

#define IMAX_BITS(m) IMAX_BITS_((m))
#define IMAX_BITS_(m) ( \
m / (m%0x3fffffffUL+1) / 0x3fffffffUL % 0x3fffffffUL * 30 \
+ m%0x3fffffffUL / (m%31+1) / 31 % 31 * 5 \
+ 4 - 12/(m%31+3) \
)

This form is good (or so I understand) up to more than 30 billion
bits. I haven't tested it that high. :)

Original author: Hallvard Breien Furuseth<h.b.furuseth@usit.uio.no>

Reference in
http://www.stackprinter.com/export?question=3957252&service=stackoverflow

Re: portable way to get highest bit set?

<20231024181642.0000314c@yahoo.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30087&group=comp.lang.c#30087

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: already5...@yahoo.com (Michael S)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Tue, 24 Oct 2023 18:16:42 +0300
Organization: A noiseless patient Spider
Lines: 112
Message-ID: <20231024181642.0000314c@yahoo.com>
References: <ug5gvh$1jkar$3@dont-email.me>
<20231011143809.748@kylheku.com>
<20231014222046.551@kylheku.com>
<86lec48ebs.fsf@linuxsc.com>
<20231015084712.400@kylheku.com>
<86bkco4t89.fsf@linuxsc.com>
<20231024121014.00000bd8@yahoo.com>
<86y1fs2ind.fsf@linuxsc.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: dont-email.me; posting-host="977bc0ee08212b7bf0b25159b2b54fa9";
logging-data="4145721"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19JHNDtMpbkIK5xZfERoNnosV7qmvTqVbc="
Cancel-Lock: sha1:Zh1Gk8ms3jMF0crIccqIMCiMZck=
X-Newsreader: Claws Mail 3.19.1 (GTK+ 2.24.33; x86_64-w64-mingw32)
 by: Michael S - Tue, 24 Oct 2023 15:16 UTC

On Tue, 24 Oct 2023 07:35:02 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

> Michael S <already5chosen@yahoo.com> writes:
>
> > On Mon, 23 Oct 2023 20:03:34 -0700
> > Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
> >
> >> The challenge is to find an algorithm that works
> >> without being tied to a specific type. [...]
> >
> > [an effort to generalize a type-specific function]
> >
> > T
> > highest_bit_set( T u ){
> > for (int k = 0; ((T)-1 >> ((1 <<k)-1)) > 1; ++k)
> > u |= u >> (1 << k);
> > return u ^ (u >> 1);
> > }
> >
> > Both gcc -O3 and clang -O2 and -O3 translate it into the same object
> > code as manually written sequence.
>
> Great! That's cool.
>
> > Of course, this code works only for types with number of bits
> > equal to power of two. For my tests it was o.k. because my test
> > platforms have no other integer types anyway.
> >
> > I was not able to generalize this loop for non-power-of-two. For
> > example, the variant below produces desired code with clang, but
> > gcc12 generates loop instead of straight line.
> >
> > T
> > highest_bit_set( T u ){
> > u |= u >> 1;
> > for (int k = 0; (((T)-1 >> (1<<k)) >> (1<<k)) != 0; ++k)
> > u |= u >> (1 << (k+1));
> > return u ^ (u >> 1);
> > }
> >
> > I tried several other variations of this theme. Many were good
> > for neither compiler, many others only good for clang, one or two
> > only good for gcc, but none good for both.
>
> Try this:
>
> T
> highest_bit_set( T u ){
> T one = 1, all = -one;
> unsigned k, s;
>
> u |= u>>1;
> for( k = 0; s = 1<<k, all>>s > one<<s; k++ ){
> u |= u >> s*2;
> }
>
> return u ^ (u >> 1);
> }
>
> With -O3 this works for me with both gcc and clang (both at least
> several years old).
>

Yes, it works with my relatively new compilers too.
I wonder why gcc understands this but not that. Both variants appear
to have equal complexity.

>
> > Fortunately there is always a magic macro of yours.
>
> Again, not mine. The original author was Hallvard Furuseth
> (with my MASK_WIDTH() being a less ambitious version of his
> IMAX_BITS()).
>
> > It works
> > fine with both compilers. May be, it has theoretical limits,
> > but in practice it is more than good enough.
> >
> > T
> > highest_bit_set( T u ){
> > const int nbits = MASK_WIDTH((T)-1);
> > for (int k = 0; (1<<k) < nbits; ++k)
> > u |= u >> (1<<k);
> > return u ^ (u >> 1);
> > }
>
> The version of MASK_WIDTH I posted tops out at 491504 bits.
>
> If that's not enough, here is the original (my choice of layout,
> wrapping, and using 'unsigned long' type, but otherwise the same):
>
> #define IMAX_BITS(m) IMAX_BITS_((m))
> #define IMAX_BITS_(m) ( \
> m / (m%0x3fffffffUL+1) / 0x3fffffffUL % 0x3fffffffUL * 30 \
> + m%0x3fffffffUL / (m%31+1) / 31 % 31 * 5 \
> + 4 - 12/(m%31+3) \
> )
>
> This form is good (or so I understand) up to more than 30 billion
> bits. I haven't tested it that high. :)
>
> Original author: Hallvard Breien Furuseth<h.b.furuseth@usit.uio.no>
>
> Reference in
> http://www.stackprinter.com/export?question=3957252&service=stackoverflow

Thank you. From now on I promise to give a correct attribution.

Re: portable way to get highest bit set?

<20231024093915.234@kylheku.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30088&group=comp.lang.c#30088

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: 864-117-...@kylheku.com (Kaz Kylheku)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Tue, 24 Oct 2023 16:54:33 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 60
Message-ID: <20231024093915.234@kylheku.com>
References: <ug5gvh$1jkar$3@dont-email.me> <20231011143809.748@kylheku.com>
<20231014222046.551@kylheku.com> <86lec48ebs.fsf@linuxsc.com>
<20231015084712.400@kylheku.com> <86bkco4t89.fsf@linuxsc.com>
Injection-Date: Tue, 24 Oct 2023 16:54:33 -0000 (UTC)
Injection-Info: dont-email.me; posting-host="a726e8f2e38540d8fa8b885b814471db";
logging-data="88962"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX181wvgc1U3UkDgiMDR19B3QUhzcRwiPvBM="
User-Agent: slrn/pre1.0.4-9 (Linux)
Cancel-Lock: sha1:iH8q3poifwrRTbNgwWy8IMxT1vM=
 by: Kaz Kylheku - Tue, 24 Oct 2023 16:54 UTC

On 2023-10-24, Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
> Kaz Kylheku <864-117-4973@kylheku.com> writes:
>> Oh, if I had to make it work with the unsigned long type, like the other
>> solutions,
>
> That is a misrepresentation.

I think I based that statement on seeing "typedef unsigned long T"
all over the thread.

>> I'd probably just do this:
>>
>> unsigned long fill_mask_down(unsigned long x)
>> {
>> x |= x >> 1;
>> x |= x >> 2;
>> x |= x >> 4;
>> x |= x >> 8;
>>
>> #if UINT_MAX == UINT32_MAX
>> x |= x >> 16;
>> [...]
>
> The challenge is to find an algorithm that works
> without being tied to a specific type.

The weakest interpretation of that requirement statement is that the
solution must be generic; in the same program, the function is applied
to different types, and is calculated using a specialized variant of the
code customized to hat type.

This does not characterize the solutions I'm seeing in the thread,
which were not challenged on grounds of not conforming to the task.
These ar are organized around a single type called T, which is an alias
for a single, specific type in any given translation of the code.

If the definition of the T typedef is accompanied by a limit macro
such as:

typedef unsigned T;
#define T_MAX UINT_MAX

we can adapt the above solution to T.

> If you
> aren't up to the task that's okay with me, but
> don't pretend it's something it isn't.

I may have mistaken this for something that is supposed to be
practically useful in an actual project.

(If I have to work with a single type T in some project, which is not
defined in my code and which can vary from platform to platform, I can
always come up with a limit macro for it.)

--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazinator@mstdn.ca
NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.

Re: portable way to get highest bit set?

<20231024095439.885@kylheku.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30089&group=comp.lang.c#30089

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!news.niel.me!news.gegeweb.eu!gegeweb.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: 864-117-...@kylheku.com (Kaz Kylheku)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Tue, 24 Oct 2023 17:50:07 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 82
Message-ID: <20231024095439.885@kylheku.com>
References: <ug5gvh$1jkar$3@dont-email.me> <20231011143809.748@kylheku.com>
<20231014222046.551@kylheku.com> <86lec48ebs.fsf@linuxsc.com>
<20231015084712.400@kylheku.com> <86bkco4t89.fsf@linuxsc.com>
<20231024121014.00000bd8@yahoo.com>
Injection-Date: Tue, 24 Oct 2023 17:50:07 -0000 (UTC)
Injection-Info: dont-email.me; posting-host="a726e8f2e38540d8fa8b885b814471db";
logging-data="115930"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18QkKZTXBhJv1ctX8L9jzNkTb1KSKj5wjE="
User-Agent: slrn/pre1.0.4-9 (Linux)
Cancel-Lock: sha1:bKlNuPdAlfZBdpyLbMqjNFX4BMk=
 by: Kaz Kylheku - Tue, 24 Oct 2023 17:50 UTC

On 2023-10-24, Michael S <already5chosen@yahoo.com> wrote:
> In my own tests I used following form of Kaz's algorithm:
>
> T
> highest_bit_set( T u ){
> for (int k = 0; ((T)-1 >> ((1 <<k)-1)) > 1; ++k)
> u |= u >> (1 << k);
> return u ^ (u >> 1);
> }
>
> Both gcc -O3 and clang -O2 and -O3 translate it into the same object
> code as manually written sequence.
> Of course, this code works only for types with number of bits equal to
> power of two. For my tests it was o.k. because my test platforms
> have no other integer types anyway.
>
> I was not able to generalize this loop for non-power-of-two.

For reference, how I would adapt my practical solution to
non-power-of-two would be to accompany the definition of the type T with
a limit macro that gives the maximum value of the smallest
power-of-two-sized type that is no smaller than that type.

(I've not lost track of that the solution still depends on the UINTn_MAX
macros being available, which isn't guaranteed.)

#include <limits.h>
#include <stdint.h>

typedef unsigned long T;
#define T_MAX ULONG_MAX
#define T_BP2_MAX ULONG_MAX /* max of bounding power of two type */

T fill_mask_down(T x)
{
x |= x >> 1;
x |= x >> 2;
#if T_BP2_MAX == UINT8_MAX
x |= x >> 4;
#elif T_BP2_MAX == UINT16_MAX
x |= x >> 4;
x |= x >> 8;
#elif T_BP2_MAX == UINT32_MAX
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
#elif T_BP2_MAX == UINT64_MAX
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x |= x >> 32;
#else
#error port me!
#endif

return x;
}

T isolate_highest_bit(T x)
{
T m = fill_mask_down(x);
return m ^ (m >> 1);
}

Suppose we are working on PIC24 and want T to be the __uint24 type
(or whatever it is called in that toolchain). Then:

typedef define __uint24 T;
#define T_MAX 0xFFFFFFU
#define T_BP2_MAX UINT32_MAX

So essentially, the algorithm pretends that a type between 17 and 32
bits wide is 32 bits wide.

But this is okay because for that size, it never executes a right shift
exceeding 16.

--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazinator@mstdn.ca
NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.

Re: portable way to get highest bit set?

<uh9jdc$88eb$1@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30091&group=comp.lang.c#30091

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: bc...@freeuk.com (Bart)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Wed, 25 Oct 2023 00:19:08 +0100
Organization: A noiseless patient Spider
Lines: 78
Message-ID: <uh9jdc$88eb$1@dont-email.me>
References: <ug5gvh$1jkar$3@dont-email.me>
<20231011102714.44a870af4dfe68f756974953@g{oogle}mail.com>
<ug6huc$1rvp1$1@dont-email.me> <86h6mxawqq.fsf@linuxsc.com>
<20231012111100.272c96b3209baad26a150e55@g{oogle}mail.com>
<86cyxkb2ka.fsf@linuxsc.com>
<20231012141719.99f5a10ec921db3ee6f7d948@g{oogle}mail.com>
<864jiwaqic.fsf@linuxsc.com> <20231012173021.0000149c@yahoo.com>
<86v8bbanjv.fsf@linuxsc.com> <20231012191641.00007493@yahoo.com>
<865y346qvs.fsf@linuxsc.com> <ugp766$3ppas$1@dont-email.me>
<86wmvj5gkc.fsf@linuxsc.com> <ugqm71$7e0u$1@dont-email.me>
<86y1fu4rfm.fsf@linuxsc.com> <uh43ee$2lgq1$1@dont-email.me>
<20231022155123.253@kylheku.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Tue, 24 Oct 2023 23:19:08 -0000 (UTC)
Injection-Info: dont-email.me; posting-host="5500600aecadc06ec2b44f3e7b50acb0";
logging-data="270795"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/vRE8XwqHHILSpslEL7PmldzPlMXDGDNM="
User-Agent: Mozilla Thunderbird
Cancel-Lock: sha1:OZkEjAu1iNz0x926ecgd4KtVbp4=
Content-Language: en-GB
In-Reply-To: <20231022155123.253@kylheku.com>
 by: Bart - Tue, 24 Oct 2023 23:19 UTC

(Your 24-Oct post is not appearing on ES for some reason; I'm responding
to that via a 23-Oct post.)

On 24/10/2023 17:54, Kaz Kylheku wrote:
> On 2023-10-24, Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>> Kaz Kylheku <864-117-4973@kylheku.com> writes:
>>> Oh, if I had to make it work with the unsigned long type, like the
other
>>> solutions,
>>
>> That is a misrepresentation.
>
> I think I based that statement on seeing "typedef unsigned long T"
> all over the thread.
>
>>> I'd probably just do this:
>>>
>>> unsigned long fill_mask_down(unsigned long x)
>>> {
>>> x |= x >> 1;
>>> x |= x >> 2;
>>> x |= x >> 4;
>>> x |= x >> 8;
>>>
>>> #if UINT_MAX == UINT32_MAX
>>> x |= x >> 16;
>>> [...]
>>
>> The challenge is to find an algorithm that works
>> without being tied to a specific type.
>
> The weakest interpretation of that requirement statement is that the
> solution must be generic; in the same program, the function is applied
> to different types, and is calculated using a specialized variant of the
> code customized to hat type.
>
> This does not characterize the solutions I'm seeing in the thread,
> which were not challenged on grounds of not conforming to the task.
> These ar are organized around a single type called T, which is an alias
> for a single, specific type in any given translation of the code.
>
> If the definition of the T typedef is accompanied by a limit macro
> such as:
>
> typedef unsigned T;
> #define T_MAX UINT_MAX
>
> we can adapt the above solution to T.
>
>> If you
>> aren't up to the task that's okay with me, but
>> don't pretend it's something it isn't.
>
> I may have mistaken this for something that is supposed to be
> practically useful in an actual project.

This has long moved on from being anything practical. The original task
was something you'd do in 5 minutes and move on.

A practical solution would be written for u32 or u64 or both.

But the new requirement (which seems to have been invented by Tim)
apparently has to be a single algorithm that works with u128 as well as
u32/u64, and probably any non-power-of-two sizes.

> (If I have to work with a single type T in some project, which is not
> defined in my code and which can vary from platform to platform, I can
> always come up with a limit macro for it.)

I made this point a week ago: if any one program needs this for two or
more different Ts, there will need to be two or more distinct functions
anyway. Exactly how the resulting T-based function would be deployed,
especially when multiple Ts are in the same scope, is not clear.

Re: portable way to get highest bit set?

<86pm132voe.fsf@linuxsc.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30093&group=comp.lang.c#30093

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: tr.17...@z991.linuxsc.com (Tim Rentsch)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Tue, 24 Oct 2023 21:05:53 -0700
Organization: A noiseless patient Spider
Lines: 25
Message-ID: <86pm132voe.fsf@linuxsc.com>
References: <ug5gvh$1jkar$3@dont-email.me> <20231011102714.44a870af4dfe68f756974953@g{oogle}mail.com> <ug6huc$1rvp1$1@dont-email.me> <86h6mxawqq.fsf@linuxsc.com> <20231012111100.272c96b3209baad26a150e55@g{oogle}mail.com> <86cyxkb2ka.fsf@linuxsc.com> <20231012141719.99f5a10ec921db3ee6f7d948@g{oogle}mail.com> <864jiwaqic.fsf@linuxsc.com> <20231012173021.0000149c@yahoo.com> <86v8bbanjv.fsf@linuxsc.com> <20231012191641.00007493@yahoo.com> <865y346qvs.fsf@linuxsc.com> <20231018174110.00003717@yahoo.com> <86sf675fir.fsf@linuxsc.com> <20231020001455.00006ea4@yahoo.com> <20231021225010.00001606@yahoo.com> <86ttqi4oae.fsf@linuxsc.com> <20231023011138.000078ba@yahoo.com> <86jzrd4i1n.fsf@linuxsc.com> <874jihky56.fsf@nosuchdomain.example.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: dont-email.me; posting-host="cf97bd7e9489cbbcf364cc78b48cedaf";
logging-data="549787"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+FziwK44q7feTF2P8cOFbndpTqFhCyobI="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:0REgiPWIHkVRFm169Kyzo2yjOz0=
sha1:5V8++9Y7e6Y1tZeDn2XD+6KoEjw=
 by: Tim Rentsch - Wed, 25 Oct 2023 04:05 UTC

Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
> [...]
>
>> If we wait until you have the benefit of some daylight thinking
>> hours I expect you will see how this can be done. (Disclaimer
>> and possible spoiler alert: strictly speaking there may be some
>> issues on implementations with integer types that have trap
>> representations. These days though I don't think any machines
>> even have any padding bits, let alone trap representations. Oh,
>> I have to take that back - I know of one contemporary machine
>> where unsigned types don't use the sign bit, and so have one
>> padding bit. In that case though there is enough information
>> so the padding bit is known, and potential trap representations
>> can be avoided.)
>
> Which contemporary machine is that?

My understanding is that one of the Unisys machines, which to the
best of my knowledge are still being produced, have unsigned
types that don't use the sign bit as a value bit for unsigned
types (and so for example INT_MAX == UINT_MAX). Even if that
arrangement no longer applies, my belief that it might was
enough that I felt obliged to put in the disclaimer.

Re: portable way to get highest bit set?

<20231025125708.00007ea0@yahoo.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30101&group=comp.lang.c#30101

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!news.swapon.de!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: already5...@yahoo.com (Michael S)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Wed, 25 Oct 2023 12:57:08 +0300
Organization: A noiseless patient Spider
Lines: 21
Message-ID: <20231025125708.00007ea0@yahoo.com>
References: <ug5gvh$1jkar$3@dont-email.me>
<20231011102714.44a870af4dfe68f756974953@g{oogle}mail.com>
<ug6huc$1rvp1$1@dont-email.me>
<86h6mxawqq.fsf@linuxsc.com>
<20231012111100.272c96b3209baad26a150e55@g{oogle}mail.com>
<86cyxkb2ka.fsf@linuxsc.com>
<20231012141719.99f5a10ec921db3ee6f7d948@g{oogle}mail.com>
<864jiwaqic.fsf@linuxsc.com>
<20231012173021.0000149c@yahoo.com>
<86v8bbanjv.fsf@linuxsc.com>
<20231012191641.00007493@yahoo.com>
<865y346qvs.fsf@linuxsc.com>
<ugp766$3ppas$1@dont-email.me>
<86wmvj5gkc.fsf@linuxsc.com>
<ugqm71$7e0u$1@dont-email.me>
<86y1fu4rfm.fsf@linuxsc.com>
<uh43ee$2lgq1$1@dont-email.me>
<20231022155123.253@kylheku.com>
<uh9jdc$88eb$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: dont-email.me; posting-host="a4ee142b619957b129ec11dc1fb3f7f9";
logging-data="656896"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1++A0UzPMK8tHbAYvdxBSeDkn5Ur4VGJ1U="
Cancel-Lock: sha1:zSrqXdygAJPqWR4Jjtp3H2yH3l4=
X-Newsreader: Claws Mail 3.19.1 (GTK+ 2.24.33; x86_64-w64-mingw32)
 by: Michael S - Wed, 25 Oct 2023 09:57 UTC

On Wed, 25 Oct 2023 00:19:08 +0100
Bart <bc@freeuk.com> wrote:

>
> I made this point a week ago: if any one program needs this for two
> or more different Ts, there will need to be two or more distinct
> functions anyway. Exactly how the resulting T-based function would be
> deployed, especially when multiple Ts are in the same scope, is not
> clear.
>

The most obvious answer to that is "Use C preprocessor."
For example, in project A you compile your module with -DT='uint16_t'
and in project B you compile with -DT='unsigned __int128'.
If you want to use both variants in the same project then you apply
token pasting operator of preprocessor to mangle function name,
thus avoiding names clash. The last step is not necessarily trivial,
esp. for type names consisting of more than one token, but off topic
here.

Re: portable way to get highest bit set?

<87ttqexzh5.fsf@bsb.me.uk>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30104&group=comp.lang.c#30104

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: ben.use...@bsb.me.uk (Ben Bacarisse)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Wed, 25 Oct 2023 20:40:22 +0100
Organization: A noiseless patient Spider
Lines: 34
Message-ID: <87ttqexzh5.fsf@bsb.me.uk>
References: <ug5gvh$1jkar$3@dont-email.me>
<20231011102714.44a870af4dfe68f756974953@g{oogle}mail.com>
<ug6huc$1rvp1$1@dont-email.me> <86h6mxawqq.fsf@linuxsc.com>
<20231012111100.272c96b3209baad26a150e55@g{oogle}mail.com>
<86cyxkb2ka.fsf@linuxsc.com>
<20231012141719.99f5a10ec921db3ee6f7d948@g{oogle}mail.com>
<864jiwaqic.fsf@linuxsc.com> <20231012173021.0000149c@yahoo.com>
<86v8bbanjv.fsf@linuxsc.com> <20231012191641.00007493@yahoo.com>
<865y346qvs.fsf@linuxsc.com> <ugp766$3ppas$1@dont-email.me>
<86wmvj5gkc.fsf@linuxsc.com> <ugqm71$7e0u$1@dont-email.me>
<86y1fu4rfm.fsf@linuxsc.com> <uh43ee$2lgq1$1@dont-email.me>
<20231022155123.253@kylheku.com> <uh9jdc$88eb$1@dont-email.me>
<20231025125708.00007ea0@yahoo.com>
MIME-Version: 1.0
Content-Type: text/plain
Injection-Info: dont-email.me; posting-host="6fe5770c5d67651737bf36005d7426d0";
logging-data="1040450"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+nOlzAKTVUHzU71kb0NMoyfeY9eKm+nUU="
User-Agent: Gnus/5.13 (Gnus v5.13)
Cancel-Lock: sha1:VsVyshszxIqQBdEv10T/mIKiZ3c=
sha1:yEqPGFz3DURgkO06s+4AMlPIXAo=
X-BSB-Auth: 1.72e914aaef824d048d5a.20231025204022BST.87ttqexzh5.fsf@bsb.me.uk
 by: Ben Bacarisse - Wed, 25 Oct 2023 19:40 UTC

Michael S <already5chosen@yahoo.com> writes:

> On Wed, 25 Oct 2023 00:19:08 +0100
> Bart <bc@freeuk.com> wrote:
>
>>
>> I made this point a week ago: if any one program needs this for two
>> or more different Ts, there will need to be two or more distinct
>> functions anyway. Exactly how the resulting T-based function would be
>> deployed, especially when multiple Ts are in the same scope, is not
>> clear.
>
> The most obvious answer to that is "Use C preprocessor."
> For example, in project A you compile your module with -DT='uint16_t'
> and in project B you compile with -DT='unsigned __int128'.
> If you want to use both variants in the same project then you apply
> token pasting operator of preprocessor to mangle function name,
> thus avoiding names clash. The last step is not necessarily trivial,
> esp. for type names consisting of more than one token, but off topic
> here.

Why is it off-topic here? It seems right on topic for the group. Do
you mean in this thread? Even so I'd say it's OK since it addresses
something that has caused some confusion*. It's even more on-topic (I'd
say) since C23's proposed unsigned _BitInt(n) have been mentioned.

[*] The idea of a function that will work for any unsigned (but
otherwise arbitrary) integer type has a meaning in other languages that
does not tie up with the meaning used here. Macro fiddling is a way to
approximate the meaning that applies in languages with better type
polymorphism.

--
Ben.

Re: portable way to get highest bit set?

<20231025225905.000044b7@yahoo.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30106&group=comp.lang.c#30106

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: already5...@yahoo.com (Michael S)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Wed, 25 Oct 2023 22:59:05 +0300
Organization: A noiseless patient Spider
Lines: 52
Message-ID: <20231025225905.000044b7@yahoo.com>
References: <ug5gvh$1jkar$3@dont-email.me>
<20231011102714.44a870af4dfe68f756974953@g{oogle}mail.com>
<ug6huc$1rvp1$1@dont-email.me>
<86h6mxawqq.fsf@linuxsc.com>
<20231012111100.272c96b3209baad26a150e55@g{oogle}mail.com>
<86cyxkb2ka.fsf@linuxsc.com>
<20231012141719.99f5a10ec921db3ee6f7d948@g{oogle}mail.com>
<864jiwaqic.fsf@linuxsc.com>
<20231012173021.0000149c@yahoo.com>
<86v8bbanjv.fsf@linuxsc.com>
<20231012191641.00007493@yahoo.com>
<865y346qvs.fsf@linuxsc.com>
<ugp766$3ppas$1@dont-email.me>
<86wmvj5gkc.fsf@linuxsc.com>
<ugqm71$7e0u$1@dont-email.me>
<86y1fu4rfm.fsf@linuxsc.com>
<uh43ee$2lgq1$1@dont-email.me>
<20231022155123.253@kylheku.com>
<uh9jdc$88eb$1@dont-email.me>
<20231025125708.00007ea0@yahoo.com>
<87ttqexzh5.fsf@bsb.me.uk>
MIME-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: dont-email.me; posting-host="a445378963916b62ab2e49cecb6263fb";
logging-data="1042431"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18AYWWuvuk+2BtA3eQ/GiH/HSVbo6a1e2Y="
Cancel-Lock: sha1:YmpFLhKhyc7cPE1WrkDnDjDaZ9I=
X-Newsreader: Claws Mail 4.1.1 (GTK 3.24.34; x86_64-w64-mingw32)
 by: Michael S - Wed, 25 Oct 2023 19:59 UTC

On Wed, 25 Oct 2023 20:40:22 +0100
Ben Bacarisse <ben.usenet@bsb.me.uk> wrote:

> Michael S <already5chosen@yahoo.com> writes:
>
> > On Wed, 25 Oct 2023 00:19:08 +0100
> > Bart <bc@freeuk.com> wrote:
> >
> >>
> >> I made this point a week ago: if any one program needs this for two
> >> or more different Ts, there will need to be two or more distinct
> >> functions anyway. Exactly how the resulting T-based function would
> >> be deployed, especially when multiple Ts are in the same scope, is
> >> not clear.
> >
> > The most obvious answer to that is "Use C preprocessor."
> > For example, in project A you compile your module with
> > -DT='uint16_t' and in project B you compile with -DT='unsigned
> > __int128'. If you want to use both variants in the same project
> > then you apply token pasting operator of preprocessor to mangle
> > function name, thus avoiding names clash. The last step is not
> > necessarily trivial, esp. for type names consisting of more than
> > one token, but off topic here.
>
> Why is it off-topic here? It seems right on topic for the group. Do
> you mean in this thread?

Yes, that what I meant.
This thread is about algorithms or, at least, that what I think it is.

> Even so I'd say it's OK since it addresses
> something that has caused some confusion*. It's even more on-topic
> (I'd say) since C23's proposed unsigned _BitInt(n) have been
> mentioned.
>
> [*] The idea of a function that will work for any unsigned (but
> otherwise arbitrary) integer type has a meaning in other languages
> that does not tie up with the meaning used here. Macro fiddling is a
> way to approximate the meaning that applies in languages with better
> type polymorphism.
>

Hopefully, even if Bart does not remember how to solve it with
concatanation operator ##, now after being reminded about it, with a
little help of search engines he can easily figure it out.
I mean, he can easily figure out how to solve a simple case, where the
type is expressed as a single token. Solving multi-token case is not
trivial and right now I don't know how to do it.

Re: portable way to get highest bit set?

<86lebq2csn.fsf@linuxsc.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30112&group=comp.lang.c#30112

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!rocksolid2!news.neodome.net!news.mixmin.net!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: tr.17...@z991.linuxsc.com (Tim Rentsch)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Wed, 25 Oct 2023 22:06:00 -0700
Organization: A noiseless patient Spider
Lines: 82
Message-ID: <86lebq2csn.fsf@linuxsc.com>
References: <ug5gvh$1jkar$3@dont-email.me> <20231011143809.748@kylheku.com> <20231014222046.551@kylheku.com> <86lec48ebs.fsf@linuxsc.com> <20231015084712.400@kylheku.com> <86bkco4t89.fsf@linuxsc.com> <20231024121014.00000bd8@yahoo.com> <86y1fs2ind.fsf@linuxsc.com> <20231024181642.0000314c@yahoo.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: dont-email.me; posting-host="3aed70167cdc0c0f0f06e8d027845ce8";
logging-data="1450696"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+64NC/bCf7ICjWrxY7/FgJkWD/pissCfg="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:lFy6XSxSBT+p/fVPvBMKlQ770Hg=
sha1:F4tRBxESPxEWpa64iB+xMHMuPgk=
 by: Tim Rentsch - Thu, 26 Oct 2023 05:06 UTC

Michael S <already5chosen@yahoo.com> writes:

> On Tue, 24 Oct 2023 07:35:02 -0700
> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>
>> Michael S <already5chosen@yahoo.com> writes:

[..getting compilers to completely unroll a loop..]

>>> I was not able to generalize this loop for non-power-of-two.
>>> For example, the variant below produces desired code with
>>> clang, but gcc12 generates loop instead of straight line.
>>>
>>> T
>>> highest_bit_set( T u ){
>>> u |= u >> 1;
>>> for (int k = 0; (((T)-1 >> (1<<k)) >> (1<<k)) != 0; ++k)
>>> u |= u >> (1 << (k+1));
>>> return u ^ (u >> 1);
>>> }
>>>
>>> I tried several other variations of this theme. Many were
>>> good for neither compiler, many others only good for clang,
>>> one or two only good for gcc, but none good for both.
>>
>> Try this:
>>
>> T
>> highest_bit_set( T u ){
>> T one = 1, all = -one;
>> unsigned k, s;
>>
>> u |= u>>1;
>> for( k = 0; s = 1<<k, all>>s > one<<s; k++ ){
>> u |= u >> s*2;
>> }
>>
>> return u ^ (u >> 1);
>> }
>>
>> With -O3 this works for me with both gcc and clang (both at least
>> several years old).
>
> Yes, it works with my relatively new compilers too. I wonder
> why gcc understands this but not that. Both variants appear to
> have equal complexity.

I played around with this a bit. It looks like gcc is following
some heuristic for when a control expression is too complicated,
and the one you used was over the line - the "complexity" of one
variable shift (rather than a constant shift) followed by another
is more than gcc wants to deal with.

Here is my latest version:

T
highest_bit_set( T u ){
for( long s = 1; (T){-1} >>s/2 > (T){1} <<s/2; s <<= 1 ){
u |= u>>s;
}
return u ^ u>>1;
}

I am pleased by the simple form of this function. Also I think
you deserve kudos for the idea of two half-shifts, which works
great.

Incidentally, for people who are focused on absolute correctness,
there is an almost insignificant limitation in the above function
definition. What is the limitation and how can it be addressed?
No hints now but I am willing to give a hint if asked.

>>> Fortunately there is always a magic macro of yours.
>>
>> Again, not mine. The original author was Hallvard Furuseth
>> (with my MASK_WIDTH() being a less ambitious version of his
>> IMAX_BITS()). [...]
>
> Thank you. From now on I promise to give a correct attribution.

I didn't mean to take you to task. I felt it necessary to give
the attribution to observe my own sense of intellectual honesty.

Re: portable way to get highest bit set?

<86a5rhzo8y.fsf@linuxsc.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=30262&group=comp.lang.c#30262

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: tr.17...@z991.linuxsc.com (Tim Rentsch)
Newsgroups: comp.lang.c
Subject: Re: portable way to get highest bit set?
Date: Mon, 13 Nov 2023 07:06:37 -0800
Organization: A noiseless patient Spider
Lines: 189
Message-ID: <86a5rhzo8y.fsf@linuxsc.com>
References: <ug5gvh$1jkar$3@dont-email.me> <20231011102714.44a870af4dfe68f756974953@g{oogle}mail.com> <ug6huc$1rvp1$1@dont-email.me> <86h6mxawqq.fsf@linuxsc.com> <20231012111100.272c96b3209baad26a150e55@g{oogle}mail.com> <86cyxkb2ka.fsf@linuxsc.com> <20231012141719.99f5a10ec921db3ee6f7d948@g{oogle}mail.com> <864jiwaqic.fsf@linuxsc.com> <20231012173021.0000149c@yahoo.com> <86v8bbanjv.fsf@linuxsc.com> <20231013021504.12623444fc7d7fdaab87f1e0@gmail.moc> <86mswm9mwk.fsf@linuxsc.com> <20231014015035.a51cbb621de8eea5ac6a8651@gmail.moc> <20231017183345.26e2afd8641d5c63f8e8e630@gmail.moc> <86o7gv5bk1.fsf@linuxsc.com> <20231019122318.424cc40a22971a045ef11be5@gmail.moc>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: dont-email.me; posting-host="3143d63c853d96637c76865c2342b4ed";
logging-data="744437"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+x4/C/fQ92TLJiJqXiw0+Alf39S6kW5PY="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:oyDh89XbjT/A1whtuQ4K0Uk4Qq8=
sha1:Zy8j8MOey93z0aYavAlTmF2AEsA=
 by: Tim Rentsch - Mon, 13 Nov 2023 15:06 UTC

Anton Shepelev <anton.txt@gmail.moc> writes:

> Tim Rentsch to Anton Shepelev:
> [earlier version removed]
>
>> I would like to take any code posted and incorporate it
>> into my little test bench here so I can test it and see
>> how it does, but having to go through this code and change
>> all the 'unsigned long's and so forth makes that a big
>> pain in the ass.
>
> OK:
>
> T
> high_bit_mask( T n )
> { const T M = (T)1 << (CHAR_BIT * sizeof( T ) - 1);
> T mask = 0;
> int l = -1,
> r = CHAR_BIT * sizeof( T );
>
> do
> { const int m = (l + r)/2;
> T C = M >> m;
>
> if( n >= C ) { r = m; mask = C; }
> else { l = m; }
> } while( r - l > 1 );
>
> return mask;
> }
>
>> The following binary search code is simpler and runs faster.
>>
>> T
>> hbs_binary( T u ){
>> const T one = 1, v = u>>1;
>> unsigned least = 0, limit = MASK_WIDTH( -one );
>>
>> do {
>> const unsigned k = least+limit >> 1;
>> const T bit = one << k;
>>
>> /**/ if( bit <= v ) least = k+1;
>> else if( bit > u ) limit = k;
>> else return bit;
>>
>> } while( limit > 0 );
>>
>> return 0;
>> }
>
> I disagree about the higher simplicity of your code,

I have responses to your comments below, followed by some more
general remarks about your rendition.

> because it
>
> 1. has two return statements,

Having two return statements makes the code easier to understand,
not harder. During the course of the loop if the answer is found
it is returned immediately. It's easy to see from the code that
the right value is being returned; just immediately returning it
makes it easier to reason about what else is going on.

General comment: a dogmatic aversion to having multiple returns
is wrongheaded, especially in pure functions like this one.

> 2. employs the /clever trick/ of comparing the mask to
> different values in different branches.

It isn't particularly clever, and it certainly isn't a trick.
It's easy to see that, if

u>>1 < bit && bit <= u

then bit is the value we are looking for, so we're done. Outside
of that range the value is either too high or too low, and the
boundary markers are adjusted accordingly.

> 3. uses a three-way `if'.

There are three branches because the interval subdivides naturally
into three parts. The problem here is unlike a general binary
search in that we know there is exactly one solution, and it will
be an exact match to one of the generated values. Searching for a
value in an array is different because, one, we aren't sure in
general that the value we're looking for will be there, and two,
the array might contain duplicate values. Neither of those apply
here, so the three-way choice is natural. In a sense we are
deciding what to do depending on whether the generated bit value
is less than, greater than, or equal to, the right value. By
contrast the two-way branch is either greater than or {less than
or maybe equal} (or maybe the other way around; it isn't easy to
tell). The three-way test is a more natural fit, and easier to
reason about for determining correctness.

> 4. uses conditions that are not mutually exclusive.

Given an argument value 'u' and a generated test value 'bit',
exactly one of

bit <= u<<1

u<<1 < bit && bit <= u

u < bit

is true. These conditions correspond directly to the three
branches of the if-else chain, and they are mutually exclusive.
So either your statement is wrong or I don't know what you
mean.

> 5. uses `least' and `limit' instead of intuitive `left'
> and `right' or `min' and `max'. My version makes a
> point of giving its left and right indices the
> intuitive meaning that they have in the standard
> positional notation.

Pshaw. The comparison operators in C are less than and greater
than, not left-of and right-of. Calling the end markers left and
right means having to mentally translate from a left/right
coordinate system to the less-than/greater-then numeric coordinate
system that C uses. Another problem with left/right is that they
seem to be symmetric. Generally reasoning about binary search is
easier if a half-open interval is used (which indeed is what my
code does). The name 'limit' is chosen to indicate which boundary
marker corresponds to the half-open end, and 'least' for the
closed end (i.e., the 'least' value can be possible, whereas the
'limit' value never is).

I would never use either 'left' and 'right' or 'max' and 'min' for
names of the boundary markers in a binary search, because they are
either confusingly or misleadingly evocative. Also I think of
'left' as "bigger", because digits more leftward represent larger
values. For me your 'left' and 'right' are backwards.

> My version, however, is still not a plain-vanilla binary search.

It's a different problem, not like a typical binary search.

For me "simpler" usually means "easier to convince myself that it
works." There are several things about the code you posted that
cause it to take more mental effort for me to understand:

name choices that make it harder to see how the code works

confusingly shifting a top bit down rather than a low bit
up; shifting a low bit up is easier because then the
generated value (what I call bit) goes in the same direction
as the quantity used to produce it

choice of 'int' for the boundary markers, including one
initialized to a negative number. Thinking of the boundary
markers as holding shift values on '1' is natural, and it's
easy to see that the initial values are right: the least
shift is zero, and the width of the argument type is one
more than the largest shift allowed. Shifting a high-order
bit means I have to think harder about the calculation to
produce the high-order bit, and more mental effort is
needed to translate between the shift values and the
generated bit value, because numerically they go in opposite
directions, making the relationship more complicated (and
also different for different width types). Seeing an 'int'
used as a shift amount, with one of the boundary markers
initialized with a negative value, makes me nervous, because
I need to think carefully to be sure there is never a shift
with a negative shift amount. Using an unsigned type for
the shift amounts gets rid of that problem.

Probably my biggest complaint is that to see how the code is
working I need to keep track of the state changes to 'mask' to see
that it has the right value. This property could be a consequence
of avoiding multiple returns: if there is a rule against having
more than one return, that can cause one or more of (a) the code
needing to be altered to avoid doing an early return, (b) having
to use some kind of intra-function jump (goto or break), or (c)
needing a variable to hold the return value, so it can be returned
by the one 'return' statement. The code you posted has such a
variable, and that results in more mental effort needed to see
whether the function works. Needing that extra variable is a huge
cost in terms of reasoning about the code, and that by itself is
enough for me see my code as simpler.

Pages:12345678
server_pubkey.txt

rocksolid light 0.9.8
clearnet tor