Date: Tue, 7 Jan 2020 21:19:48 +0000

On Tue, 7 Jan 2020 at 06:46, Владимир Прокофьев via Std-Proposals <

std-proposals_at_[hidden]> wrote:

> I have found a mistake in the C++ Standard,

> https://en.cppreference.com/w/cpp/language/operator_arithmetic#Conversion :

> in the rule:

>

> *Otherwise, if the unsigned operand's conversion rank is greater or equal

> to the conversion rank of the signed operand, the signed operand is

> converted to the unsigned operand's type.*

>

> The NEGATIVE signed value CANNOT be converted to unsigned for any types.

> But opposite conversion from unsigned to signed is valid with appropriate

> rank.

>

Surely this depends on the value of the operands. For example, the

expression "0x80000000U/2" comes out just fine. Would that still be the

case if signed -- not unsigned -- was chosen on the rank tie-breaker?

> To prove, please see wrong results here https://rextester.com/CKKDX46498

>

(Minor point: do your row and column headings have the wrong signedness?)

> Note, that the error is observed for VS, CLang and GCC C++ compilers.

>

> As you can see the error is observer in *division* operation to *unsigned*

> *32* and *64* bits.

> The *division* operation to *SIGNED* types is VALID (see *first* table in

> the example).

> Also *multiplication* of signed and unsigned values is VALID.

>

You mean multiplication is mathematically correct *with* the 'fix', right?

I think you can make the same claim with most of the binary operators.

Division is perhaps among the more surprising operators in this respect but

I believe this design choice is fairly consistent. For example "-1<1U"

evaluates to false.

> The example above shows that the C++ compiler shows *unreliable* behavior

> which leads to produce wrong values as a result of division.

>

> The correct rule *shall* be:

>

> *Otherwise, unsigned operand is converted to signed type of same or higher

> conversion rank of unsigned operand's type and then the operand with lesser

> conversion rank is converted to the operand with the greater conversion

> rank*

>

I agree that the choice that was made was unfortunate in the post-16-bit

era. But remember that when `int` was 16-bit, the alternative would have

meant that "40000<30000" was true. Also pretty surprising.

Ultimately, there's no way you can guarantee the correct result with

mixed-signedness operands. So the rule we really need to enforce (in

tooling) is "ES.100: Don't mix signed and unsigned arithmetic

<https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es100-dont-mix-signed-and-unsigned-arithmetic>

".

John

> С уважением.

>

> Владимир.

> --

> Std-Proposals mailing list

> Std-Proposals_at_[hidden]

> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

>

std-proposals_at_[hidden]> wrote:

> I have found a mistake in the C++ Standard,

> https://en.cppreference.com/w/cpp/language/operator_arithmetic#Conversion :

> in the rule:

>

> *Otherwise, if the unsigned operand's conversion rank is greater or equal

> to the conversion rank of the signed operand, the signed operand is

> converted to the unsigned operand's type.*

>

> The NEGATIVE signed value CANNOT be converted to unsigned for any types.

> But opposite conversion from unsigned to signed is valid with appropriate

> rank.

>

Surely this depends on the value of the operands. For example, the

expression "0x80000000U/2" comes out just fine. Would that still be the

case if signed -- not unsigned -- was chosen on the rank tie-breaker?

> To prove, please see wrong results here https://rextester.com/CKKDX46498

>

(Minor point: do your row and column headings have the wrong signedness?)

> Note, that the error is observed for VS, CLang and GCC C++ compilers.

>

> As you can see the error is observer in *division* operation to *unsigned*

> *32* and *64* bits.

> The *division* operation to *SIGNED* types is VALID (see *first* table in

> the example).

> Also *multiplication* of signed and unsigned values is VALID.

>

You mean multiplication is mathematically correct *with* the 'fix', right?

I think you can make the same claim with most of the binary operators.

Division is perhaps among the more surprising operators in this respect but

I believe this design choice is fairly consistent. For example "-1<1U"

evaluates to false.

> The example above shows that the C++ compiler shows *unreliable* behavior

> which leads to produce wrong values as a result of division.

>

> The correct rule *shall* be:

>

> *Otherwise, unsigned operand is converted to signed type of same or higher

> conversion rank of unsigned operand's type and then the operand with lesser

> conversion rank is converted to the operand with the greater conversion

> rank*

>

I agree that the choice that was made was unfortunate in the post-16-bit

era. But remember that when `int` was 16-bit, the alternative would have

meant that "40000<30000" was true. Also pretty surprising.

Ultimately, there's no way you can guarantee the correct result with

mixed-signedness operands. So the rule we really need to enforce (in

tooling) is "ES.100: Don't mix signed and unsigned arithmetic

<https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es100-dont-mix-signed-and-unsigned-arithmetic>

".

John

> С уважением.

>

> Владимир.

> --

> Std-Proposals mailing list

> Std-Proposals_at_[hidden]

> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

>

Received on 2020-01-07 15:22:31