Смело добавляйте, вычитайте делите неподписанные символы

Скажем, у каждого есть 8 неподписанных символов x1,x2,...x8 и мы хотим рассчитать:

abs((x1 + x2 + x3 + x4) - (x5 + x6 + x7 + x8)) / 4

Каков наилучший способ обеспечить наиболее точные результаты, не допуская больших переполнений или ошибок переполнения?

Я использую это в шаблонном классе, поэтому я не могу просто конвертировать неподписанные значения в подписанные.

0

Решение

operator + работает только для int и больше. Таким образом, когда вы используете его с объектами типа char (который меньше, чем int) эти значения автоматически преобразуются в int до того, как произойдет операция.

таким образом

abs((x1 + x2 + x3 + x4) - (x5 + x6 + x7 + x8)) / 4

Преобразуется компилятором в:

abs((static_cast<int>(x1) + static_cast<int>(x2) + static_cast<int>(x3) + static_cast<int>(x4)) -
(static_cast<int>(x5) + static_cast<int>(x6) + static_cast<int>(x7) + static_cast<int>(x8))) / 4

Поэтому, если вы не добавляете много символов, вы вряд ли переполнитесь.

Существует проблема с присвоением результата обратно unsigned char, Если результат выражения отрицателен, то у вас будет преобразование, которое делает значение положительным (но четко определенным).

7

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

Похоже, вы хотите, чтобы метафункция сообщала вам, какой промежуточный тип данных использовать в ваших вычислениях.

    template <class T>
struct arithmetic_type
{
typedef std::int64_t type;
};

template <>
struct arithmetic_type<float>
{
typedef double type;
};

template <>
struct arithmetic_type<double>
{
typedef double type;
};

template <>
struct arithmetic_type<std::uint64_t>
{
typedef std::uint64_t type;
};

typedef typename arithmetic_type<T>::type ar_type;
abs(((ar_type)x1 + x2 + x3 + x4) - ((ar_type)x5 + x6 + x7 + x8)) / 4;

Конечно, вы можете настроить специализацию и добавлять / удалять в соответствии с вашими потребностями, но это должно дать вам правильное представление.

1

Как и с любыми данными фиксированного размера, лучший подход — привести их к типу, достаточно большому, чтобы соответствовать сценарию наихудшего случая. В этом случае приведение их к int будет достаточно хорошим — он будет соответствовать диапазону любых возможных значений и позволит обрабатывать потенциальные потери.

Обратите внимание, что вы должны быть осторожны с вычитанием — результат будет зависеть от семантики, которую вы хотите прикрепить к нему: либо вы предполагаете, что оно никогда не будет недооценено (и любое отрицательное значение является ошибкой, либо должно быть равно 0), либо отрицательным Значение имеет значение, и вы хотите извлечь из него абсолютное значение.

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