Целочисленное переполнение UDL (пользовательский литерал) для __int128 @ мин. Отрицательное значение

Для ясности и простоты я сокращу следующие числа следующим образом:

  • −170,141,183,460,469,231,731,687,303,715,884,105,728 как -170…728
  • 170,141,183,460,469,231,731,687,303,715,884,105,727 как 170…727

Эти числа представляют минимальное и максимальное значения 128-разрядного целого числа со знаком (__int128 в gcc).

Я реализовал пользовательские литералы (необработанные литералы) для этого типа данных, поскольку gcc не предлагает способ определения констант этого типа: _u128 за unsigned __int128 а также _i128 за __int128,

Символ минус не является частью UDL, но унарный оператор минус применяется к результату UDL.

Так что для -ddddd_i128 (где d является цифрой) UDL вычисляет подписанный __int128 с положительным значением ddddd и тогда компилятор применит к нему унарный оператор минус. Все идет нормально.

Проблема с -170…128_i128 (которое должно быть действительным значением для __int128):
UDL вычисляет подписанный __int128 положительное число 170…128 который находится за пределами диапазона __int128, что приводит к неопределенному поведению (целочисленное переполнение со знаком).

Любое решение для представления этой числовой константы с UDL?


Мои UDL объявлены (просто не constexpr, чокнутый версия на данный момент) (они необработанные литералы):

unsigned __int128 operator"" _u128(char const *str);
__int128 operator"" _i128(char const *str);

Некоторые использования:

  1000000000000000000000000000000000_i128
-1000000000000000000000000000000000_i128
-170141183460469231731687303715884105728_i128 // <-- this has UB
170141183460469231731687303715884105727_u128
340282366920938463463374607431768211455_u128

Я знаю, что есть способы определения постоянной -170…728 с различными способами, такими как битовые сдвиги, математические операции, но я хочу иметь возможность создавать его согласованным образом, например, Я не хочу этой ситуации: вы можете создать любую константу, используя этот UDL, кроме -170…728_i128, для которого вы должны использовать дополнительные трюки.

7

Решение

По сути, это та же проблема, что и у разработчиков <limits.h>: INT_MIN не может быть определено (в типичной 32-битной системе) как -2147483648, Это может быть (и обычно) определяется как (-2147483647 - 1) вместо. Вам придется сделать что-то подобное. Может не быть никакого способа представить наиболее отрицательное число одним оператором отрицания и литералом, но это нормально: в этом просто нет необходимости.

6

Другие решения


По вопросам рекламы [email protected]