On Tue, 7 Jan 2020 at 06:46, Владимир Прокофьев via Std-Proposals <std-proposals@lists.isocpp.org> 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".

John

С уважением.

Владимир.

--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals