Борьба с проблемой переполнения C - как это сделать? - PullRequest
0 голосов
/ 08 июля 2019

У меня проблема с проверкой переполнения.

У меня есть коэффициент, который я должен использовать для умножения значения.Мой компилятор / программное обеспечение может использовать только целочисленные вычисления.

Я использую компилятор, который имеет __int32 (соответственно без знака __int32) как самый большой тип для использования, он содержит 4 байта.Я могу использовать только целочисленную математику.Так, например, коэффициент равен 0,8. Я записываю это значение в виде дроби 8/10 и использую ее для вычисления (вычисляю дробь таким образом, чтобы знаменатель всегда составлял 10)

Поскольку коэффициент меньше 1 initillay IЯ подумал, что нет необходимости в проверке переполнения.

 [I]
 But calculating
   __int32 a;
   a = (a * (__int32)8 ) / (__int32)10;  // [1]
Will lead to an overflow, if a * (__int32)8 is bigger as __INT32_MAX (2^31-1 = 2147483647)

 So I have to reverse the things:
 a = (a / (__int32)10 ) * (__int32)8 // [2]

 But in this variant there I might loose precision:
 Assume a is small, eg. 25:
 [2] a = (25/10) * 8 = 2,5 * 8 -> integer math will calculate 2*8 = 16

 If I had calculated:
 [1] a = 25*8/10 I would have got the precise result 20


 [II]
 For factors > 1 I use following check:

 unsigned __int16 b;

 /* overflow check ( factor = 1.5 -> 15/10) */
 if ( (unsigned __int32)b  >= ( ((unsigned __int32)__UNSIGNED_INT16_MAX * (unsigned __int32)10)/15) )
 {
    b = __UNSIGNED_INT16_MAX;
 }
 else
 {
    b = (unsigned __int16)(((unsigned __int32)b * 15)/ 10);
 }

Проблема, с которой я сталкиваюсь, заключается в том, что коэффициенты, которые я умножаю на a или b в приведенном выше примере, могут измениться: от менее 1 до более 1 (или наоборот)), например, это может быть 1,25 (-> 125/10) или 25 (-> 250/10). Я не хочу менять логику SW каждый раз, когда это происходит, я только хочу изменить значения коэффициента.

Так есть ли какое-либо решение для такой проверки переполнения?Он должен работать с факторами> 1, факторами <1 и с различными типами переменных (__int8, __int16, __int32, без знака __int8, без знака __int16, без знака __int32) и сохранять точность результата как можно выше (-> усечение десятичного разрядавыпуск)

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

Спасибо за любую подсказку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...