Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #83667 > unrolled thread
| Started by | "Graeme C." <graec58@gmail.com> |
|---|---|
| First post | 2022-04-22 04:41 -0700 |
| Last post | 2022-06-04 07:57 -0700 |
| Articles | 11 on this page of 31 — 14 participants |
Back to article view | Back to comp.lang.c++
This code is effective for modest-sized numbers, but can you tell what it does? "Graeme C." <graec58@gmail.com> - 2022-04-22 04:41 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Christian Gollwitzer <auriocus@gmx.de> - 2022-04-22 17:19 +0200
Re: This code is effective for modest-sized numbers, but can you tell what it does? "Alf P. Steinbach" <alf.p.steinbach@gmail.com> - 2022-04-22 17:42 +0200
Re: This code is effective for modest-sized numbers, but can you tell what it does? red floyd <no.spam.here@its.invalid> - 2022-04-22 09:16 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Frederick Gotham <cauldwell.thomas@gmail.com> - 2022-04-22 09:22 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? "Graeme C." <graec58@gmail.com> - 2022-04-22 10:24 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Christian Gollwitzer <auriocus@gmx.de> - 2022-04-22 20:33 +0200
Re: This code is effective for modest-sized numbers, but can you tell what it does? "Graeme C." <graec58@gmail.com> - 2022-04-22 17:57 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-04-22 19:18 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? "Graeme C." <graec58@gmail.com> - 2022-04-22 19:40 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-04-22 20:00 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? "Graeme C." <graec58@gmail.com> - 2022-04-23 04:21 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Juha Nieminen <nospam@thanks.invalid> - 2022-04-25 05:48 +0000
Re: This code is effective for modest-sized numbers, but can you tell what it does? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-04-25 05:27 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Öö Tiib <ootiib@hot.ee> - 2022-04-25 05:40 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Vir Campestris <vir.campestris@invalid.invalid> - 2022-04-25 16:48 +0100
Re: This code is effective for modest-sized numbers, but can you tell what it does? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2022-04-30 03:51 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-04-30 08:28 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-04-30 10:30 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Manfred <noname@add.invalid> - 2022-04-30 19:20 +0200
Re: This code is effective for modest-sized numbers, but can you tell what it does? Manfred <noname@add.invalid> - 2022-04-30 23:20 +0200
Re: This code is effective for modest-sized numbers, but can you tell what it does? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-04-30 10:40 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Manfred <noname@add.invalid> - 2022-04-30 19:12 +0200
Re: This code is effective for modest-sized numbers, but can you tell what it does? Juha Nieminen <nospam@thanks.invalid> - 2022-04-26 05:20 +0000
Re: This code is effective for modest-sized numbers, but can you tell what it does? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-04-29 16:12 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Paavo Helde <eesnimi@osa.pri.ee> - 2022-04-25 15:44 +0300
Re: This code is effective for modest-sized numbers, but can you tell what it does? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-05-10 07:18 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? scott@slp53.sl.home (Scott Lurndal) - 2022-05-10 14:34 +0000
Re: This code is effective for modest-sized numbers, but can you tell what it does? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-05-24 05:43 -0700
Re: This code is effective for modest-sized numbers, but can you tell what it does? Paavo Helde <eesnimi@osa.pri.ee> - 2022-05-10 20:34 +0300
Re: This code is effective for modest-sized numbers, but can you tell what it does? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-06-04 07:57 -0700
Page 2 of 2 — ← Prev page 1 [2]
| From | Manfred <noname@add.invalid> |
|---|---|
| Date | 2022-04-30 23:20 +0200 |
| Message-ID | <t4k970$rb4$1@gioia.aioe.org> |
| In reply to | #83903 |
On 4/30/2022 7:40 PM, Andrey Tarasevich wrote:
> On 4/30/2022 10:20 AM, Manfred wrote:
>>
>> However, what you really should do is:
>>
>> using MyVector = std::vector<int>;
>>
>> ...
>>
>> for (MyVector::reverse_iterator it = v.rbegin(); v.rend() != it; ++it)
>> {
>> ...
>> }
>>
>
> Well... yes and no. Reverse iterators are intended to encapsulate the
> "offset by 1" idiom. In indexing terms it is equivalent to
>
> for (std::size_t i = v.size(); i > 0; --i)
> {
> // Remember to work with v[i - 1] instead of v[i]
> }
>
I wouldn't assume this. If I had to implement a reverse iterator I might
have to do something like that, for example because the standard gives
guarantees about "one past the end" pointers, but not about "one before
the beginning".
But an implementation is more free than I would be. A standard library
implementor could use, for example, some "one before the beginning"
guarantee given by the implementation, that would lead to a different
pattern.
> When wrapped into iterators it is superficially elegant, yet comes at a
> price. In more performance-conscious situations it might prove to be too
> expensive.
Hmm. Instead, I think that using a standard library feature would be
recommended for performance reasons too.
In such contexts a better idea would be to learn and use the
> alternative reverse iteration idioms, which are not that complicated.
>
[toc] | [prev] | [next] | [standalone]
| From | Andrey Tarasevich <andreytarasevich@hotmail.com> |
|---|---|
| Date | 2022-04-30 10:40 -0700 |
| Message-ID | <t4jsaj$f0p$1@dont-email.me> |
| In reply to | #83903 |
On 4/30/2022 10:20 AM, Manfred wrote:
>
> However, what you really should do is:
>
> using MyVector = std::vector<int>;
>
> ...
>
> for (MyVector::reverse_iterator it = v.rbegin(); v.rend() != it; ++it)
> {
> ...
> }
>
Well... yes and no. Reverse iterators are intended to encapsulate the
"offset by 1" idiom. In indexing terms it is equivalent to
for (std::size_t i = v.size(); i > 0; --i)
{
// Remember to work with v[i - 1] instead of v[i]
}
When wrapped into iterators it is superficially elegant, yet comes at a
price. In more performance-conscious situations it might prove to be too
expensive. In such contexts a better idea would be to learn and use the
alternative reverse iteration idioms, which are not that complicated.
--
Best regards,
Andrey Tarasevich
[toc] | [prev] | [next] | [standalone]
| From | Manfred <noname@add.invalid> |
|---|---|
| Date | 2022-04-30 19:12 +0200 |
| Message-ID | <t4jqm3$n8j$1@gioia.aioe.org> |
| In reply to | #83898 |
On 4/30/2022 5:28 PM, Andrey Tarasevich wrote:
> On 4/30/2022 3:51 AM, Malcolm McLean wrote:
>> On Monday, 25 April 2022 at 16:48:28 UTC+1, Vir Campestris wrote:
>>> On 25/04/2022 13:40, Öö Tiib wrote:
>>>> The issue as I read it was about chance that int is 32 bits, the
>>>> vf[gen-1] has 2,200,000,000 elements and so the ++ will be
>>>> applied to INT_MAX that is undefined behavior.
>>> Some of us remember when int was only 16 bits...
>>>
>>> There's actually no guarantee that int and size_t are the same size,
>>> never mind the signed problem.
>>>
>>> for (int i = 0;
>>> is however traditional. I suspect at least in part because int is
>>> easiest to type.
>>>
>> If you need to interate in reverse
>>
>> for (int i = (int) v.size()-1; i >= 0; i--)
>>
>> you can't substitute a size_t.
>> You can do
>>
>> size_t i = v.size();
>> while(i--)
>> so there's a workaround.
>
> If one needs to iterate in reverse one uses
>
> for (std::size_t i = v.size(); i > 0; )
> {
> --i;
> ...
> }
>
> or
>
> for (std::size_t i = v.size(); i-- > 0; )
> {
> ...
> }
>
> or even plain
>
> for (std::size_t i = v.size(); i != -1; --i)
> {
> ...
> }
>
> These are not "workarounds". These are idioms.
>
Change the last one to:
for (std::size_t i = v.size(); i != 0; --i)
{
...
}
[toc] | [prev] | [next] | [standalone]
| From | Juha Nieminen <nospam@thanks.invalid> |
|---|---|
| Date | 2022-04-26 05:20 +0000 |
| Message-ID | <t47vee$10e7$1@gioia.aioe.org> |
| In reply to | #83721 |
Öö Tiib <ootiib@hot.ee> wrote:
> On Monday, 25 April 2022 at 15:27:42 UTC+3, Tim Rentsch wrote:
>> Juha Nieminen <nos...@thanks.invalid> writes:
>>
>> > Graeme C. <gra...@gmail.com> wrote:
>>
>> [...]
>> >> for (int i=0; i<vf[gen-1].size(); i++) { // from previous gen
>> >
>> > std::vector::size() returns a value of type std::size_t. You
>> > shouldn't be using an int with it.
>> I don't want to start a holy war, but in this particular case
>> there is no problem comparing a signed type to a size_t (which is
>> an unsigned type). More generally, whenever a value of a signed
>> type has a non-negative value, as is obviously true in this
>> construct, then there is never a problem comparing a value of a
>> signed type to a value of an unsigned type.
>>
>> Some people prefer using an unsigned type for indexing variables
>> like 'i' above, and that a reasonable style choice here IMO. But
>> there is nothing logically wrong with giving 'i' a signed type
>> here instead.
>
> The issue as I read it was about chance that int is 32 bits, the
> vf[gen-1] has 2,200,000,000 elements and so the ++ will be
> applied to INT_MAX that is undefined behavior.
Yeah, it's not that much about the signedness, but about the size.
After all, the program accepts a 'long long' value as input, so
ostensibly the vector might have more than INT_MAX and even more
than UINT_MAX elements (might not be the case with this particular
program, I haven't checked, but in general it could be).
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2022-04-29 16:12 -0700 |
| Message-ID | <868rrn5vrz.fsf@linuxsc.com> |
| In reply to | #83763 |
Juha Nieminen <nospam@thanks.invalid> writes:
> <<D6 F6 [05b6]>> Tiib <ootiib@hot.ee> wrote:
>
>> On Monday, 25 April 2022 at 15:27:42 UTC+3, Tim Rentsch wrote:
>>
>>> Juha Nieminen <nos...@thanks.invalid> writes:
>>>
>>>> Graeme C. <gra...@gmail.com> wrote:
>>>
>>> [...]
>>>
>>>>> for (int i=0; i<vf[gen-1].size(); i++) { // from previous gen
>>>>
>>>> std::vector::size() returns a value of type std::size_t. You
>>>> shouldn't be using an int with it.
>>>
>>> I don't want to start a holy war, but in this particular case
>>> there is no problem comparing a signed type to a size_t (which is
>>> an unsigned type). More generally, whenever a value of a signed
>>> type has a non-negative value, as is obviously true in this
>>> construct, then there is never a problem comparing a value of a
>>> signed type to a value of an unsigned type.
>>>
>>> Some people prefer using an unsigned type for indexing variables
>>> like 'i' above, and that a reasonable style choice here IMO. But
>>> there is nothing logically wrong with giving 'i' a signed type
>>> here instead.
>>
>> The issue as I read it was about chance that int is 32 bits, the
>> vf[gen-1] has 2,200,000,000 elements and so the ++ will be
>> applied to INT_MAX that is undefined behavior.
>
> Yeah, it's not that much about the signedness, but about the size.
> After all, the program accepts a 'long long' value as input, so
> ostensibly the vector might have more than INT_MAX and even more
> than UINT_MAX elements (might not be the case with this particular
> program, I haven't checked, but in general it could be).
Does this mean that if the loop variable 'i' had been given type
'long long' then you would have no complaints?
[toc] | [prev] | [next] | [standalone]
| From | Paavo Helde <eesnimi@osa.pri.ee> |
|---|---|
| Date | 2022-04-25 15:44 +0300 |
| Message-ID | <t4652k$296$1@dont-email.me> |
| In reply to | #83720 |
25.04.2022 15:27 Tim Rentsch kirjutas:
> Juha Nieminen <nospam@thanks.invalid> writes:
>
>> Graeme C. <graec58@gmail.com> wrote:
>
> [...]
>
>>> for (int i=0; i<vf[gen-1].size(); i++) { // from previous gen
>>
>> std::vector::size() returns a value of type std::size_t. You
>> shouldn't be using an int with it.
>
> I don't want to start a holy war, but in this particular case
> there is no problem comparing a signed type to a size_t (which is
> an unsigned type).
I don't really care if such code uses signed or unsigned types. However,
there is a problem when comparing signed and unsigned types, namely the
gcc compiler issues warnings for them with -Wall, and sometimes these
warnings are actually useful.
So, in order to not lose these useful warnings in the avalanche of
non-useful ones, one should use matching types in such simple code, it
does not cost anything.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2022-05-10 07:18 -0700 |
| Message-ID | <86mtfp4gjw.fsf@linuxsc.com> |
| In reply to | #83722 |
Paavo Helde <eesnimi@osa.pri.ee> writes:
> 25.04.2022 15:27 Tim Rentsch kirjutas:
>
>> Juha Nieminen <nospam@thanks.invalid> writes:
>>
>>> Graeme C. <graec58@gmail.com> wrote:
>>
>> [...]
>>
>>>> for (int i=0; i<vf[gen-1].size(); i++) { // from previous gen
>>>
>>> std::vector::size() returns a value of type std::size_t. You
>>> shouldn't be using an int with it.
>>
>> I don't want to start a holy war, but in this particular case
>> there is no problem comparing a signed type to a size_t (which is
>> an unsigned type).
>
> I don't really care if such code uses signed or unsigned types.
> However, there is a problem when comparing signed and unsigned
> types, namely the gcc compiler issues warnings for them with -Wall,
> and sometimes these warnings are actually useful.
IME these warnings from gcc give false positives too often to
be used on every single compile. Of course it can be useful
to turn them on now and then, to make sure nothing is askew,
but trying to avoid them even in all the false positive cases
is IMO more trouble than it is worth.
> So, in order to not lose these useful warnings in the avalanche of
> non-useful ones, one should use matching types in such simple code,
> it does not cost anything.
That seems plainly false. Any change that incurs some programming
effort and disturbs what code is written obviously costs something.
A claim could be made that the cost is worth the benefit, but
clearly the cost is greater than zero.
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2022-05-10 14:34 +0000 |
| Message-ID | <KJueK.11561$IQK.4031@fx02.iad> |
| In reply to | #84022 |
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>Paavo Helde <eesnimi@osa.pri.ee> writes:
>
>> 25.04.2022 15:27 Tim Rentsch kirjutas:
>>
>>> Juha Nieminen <nospam@thanks.invalid> writes:
>>>
>>>> Graeme C. <graec58@gmail.com> wrote:
>>>
>>> [...]
>>>
>>>>> for (int i=0; i<vf[gen-1].size(); i++) { // from previous gen
>>>>
>>>> std::vector::size() returns a value of type std::size_t. You
>>>> shouldn't be using an int with it.
>>>
>>> I don't want to start a holy war, but in this particular case
>>> there is no problem comparing a signed type to a size_t (which is
>>> an unsigned type).
>>
>> I don't really care if such code uses signed or unsigned types.
>> However, there is a problem when comparing signed and unsigned
>> types, namely the gcc compiler issues warnings for them with -Wall,
>> and sometimes these warnings are actually useful.
>
>IME these warnings from gcc give false positives too often to
>be used on every single compile. Of course it can be useful
>to turn them on now and then, to make sure nothing is askew,
>but trying to avoid them even in all the false positive cases
>is IMO more trouble than it is worth.
I beg to differ. We include -Wall and -Werror on all compiles
(well over 2 million lines of C/C++).
It is far too common for C programmers to use 'int' when
the domain of the value doesn't include negative numbers.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2022-05-24 05:43 -0700 |
| Message-ID | <86leur14p7.fsf@linuxsc.com> |
| In reply to | #84024 |
scott@slp53.sl.home (Scott Lurndal) writes:
> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>
>> Paavo Helde <eesnimi@osa.pri.ee> writes:
>>
>>> 25.04.2022 15:27 Tim Rentsch kirjutas:
>>>
>>>> Juha Nieminen <nospam@thanks.invalid> writes:
>>>>
>>>>> Graeme C. <graec58@gmail.com> wrote:
>>>>
>>>> [...]
>>>>
>>>>>> for (int i=0; i<vf[gen-1].size(); i++) { // from previous gen
>>>>>
>>>>> std::vector::size() returns a value of type std::size_t. You
>>>>> shouldn't be using an int with it.
>>>>
>>>> I don't want to start a holy war, but in this particular case
>>>> there is no problem comparing a signed type to a size_t (which is
>>>> an unsigned type).
>>>
>>> I don't really care if such code uses signed or unsigned types.
>>> However, there is a problem when comparing signed and unsigned
>>> types, namely the gcc compiler issues warnings for them with -Wall,
>>> and sometimes these warnings are actually useful.
>>
>> IME these warnings from gcc give false positives too often to
>> be used on every single compile. Of course it can be useful
>> to turn them on now and then, to make sure nothing is askew,
>> but trying to avoid them even in all the false positive cases
>> is IMO more trouble than it is worth.
>
> I beg to differ. We include -Wall and -Werror on all compiles
> (well over 2 million lines of C/C++).
This sounds like you are offering an implicit argument that
because your group does it all the time it follows that it's
a good idea. I don't find such an argument convincing in any
way.
> It is far too common for C programmers to use 'int' when
> the domain of the value doesn't include negative numbers.
Such cases would still be caught if the signed/unsigned warnings
were turned on only before every code review rather than on every
single compile.
[toc] | [prev] | [next] | [standalone]
| From | Paavo Helde <eesnimi@osa.pri.ee> |
|---|---|
| Date | 2022-05-10 20:34 +0300 |
| Message-ID | <t5e7no$bfv$1@dont-email.me> |
| In reply to | #84022 |
10.05.2022 17:18 Tim Rentsch kirjutas: > Paavo Helde <eesnimi@osa.pri.ee> writes: >> So, in order to not lose these useful warnings in the avalanche of >> non-useful ones, one should use matching types in such simple code, >> it does not cost anything. > > That seems plainly false. Any change that incurs some programming > effort and disturbs what code is written obviously costs something. > A claim could be made that the cost is worth the benefit, but > clearly the cost is greater than zero. One can argue that it's using of mismatching types in a comparison which means non-zero programming effort. If the types used in a comparison are of different types and especially of different signedness, the programmer needs to know the promotion rules which might depend on the operand sizes, which in turn might depend on the platform/implementation. The programmer needs to think through what happens when the signed operand becomes negative. Is it possible and what happens then? Even more to the point, when a maintenance programmer comes around and sees the code, they have to think it through again, every time. Why are incompatible types used in comparison? Was it an oversight and is it possible it might cause problems? I will see that as a significant programming effort. YMMV.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2022-06-04 07:57 -0700 |
| Message-ID | <864k101npb.fsf@linuxsc.com> |
| In reply to | #84029 |
Paavo Helde <eesnimi@osa.pri.ee> writes:
> 10.05.2022 17:18 Tim Rentsch kirjutas:
>
>> Paavo Helde <eesnimi@osa.pri.ee> writes:
>>
>>> So, in order to not lose these useful warnings in the avalanche of
>>> non-useful ones, one should use matching types in such simple code,
>>> it does not cost anything.
>>
>> That seems plainly false. Any change that incurs some programming
>> effort and disturbs what code is written obviously costs something.
>> A claim could be made that the cost is worth the benefit, but
>> clearly the cost is greater than zero.
>
> One can argue that it's using of mismatching types in a comparison
> which means non-zero programming effort.
That contrast is different than what I was talking about, but let
me respond to your comments here.
> If the types used in a comparison are of different types and
> especially of different signedness, the programmer needs to know the
> promotion rules which might depend on the operand sizes, which in
> turn might depend on the platform/implementation.
This is an overstatement. Comparing two signed types, or two
unsigned types, is always safe, regardless of the widths of the
types involved. It's only when one type is signed and the other
type is unsigned, and the unsigned type is "larger" than int, that
there is even just possibly a problem; for example, comparing a
signed type against an unsigned char, or unsigned short, or
unsigned bit-field whose width is less than the width of unsigned
int, will never give a result different than what the unconverted
values would indicate.
> The programmer needs to think through what happens when the signed
> operand becomes negative. Is it possible and what happens then?
These questions do need to be considered but that doesn't mean
they are difficult necessarily. If we see a code fragment like
int a[] = { ... };
for( Index i = 0; i < sizeof a / sizeof a[0]; i++ ){ ... }
it's immediately obvious that the value in 'i' is non-negative, no
matter whether the type Index is signed or unsigned. Almost no
mental effort is needed.
> Even more to the point, when a maintenance programmer comes around
> and sees the code, they have to think it through again, every time.
> Why are incompatible types used in comparison? Was it an oversight
> and is it possible it might cause problems?
This observation doesn't change the argument. Any factors needing
consideration for the original developer still need consideration
for maintenance work. The same kind of response applies.
> I will see that as a significant programming effort. YMMV.
No one is saying that there is no programming effort involved.
Whether the effort is _significant_ in each case is a different
question. Furthermore, the comments you make are looking at only
one side of the equation. It isn't always practicable to choose
the two types involved so that they must be the same; for example,
one type could be dictated by the type of a third party function
interface, and the other type could be dictated by language
semantics (subtracting one pointer from another gives a signed
type, but sizeof gives an unsigned type). Even when it is feasible
to give the two types the same signedness, doing that may entail
other tradeoffs that have their own costs. For example, if a
parameter 'n' has an unsigned type, we know that it has a
non-negative value. Changing the type of 'n' to be a signed type
would mean either more code in the function to accommodate a
possible negative value of 'n', or more mental effort during
development or maintenance to consider whether such code is needed,
etc (and quite possibly both). A proposed rule that comparands
should /always/ have the same signedness tacitly assumes that this
factor always outweighs all other factors. That assumption simply
isn't right: sometimes it does, but sometimes it doesn't.
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | comp.lang.c++
csiph-web