Вход

Просмотр полной версии : Переполнение DINT



lazy
14.10.2016, 12:06
Добрый день!

Написал некий фильтр в котором суммируются данные в переменной DINT итд, при маленькой глубине фильтра (8-16 значений) все работает, но стоит увеличить его глубину и DINT начинает переполняться, сумма положительных значений превращается в отрицательную. Как можно побороть это? Какие есть форматы целого со знаком (типа DINT64 или что то в этом роде)? DWORD не подходит так как значения могут приходить и отрицательные. В REAL тоже не все так гладко, так как к большой сумме прибавляются малые значения и накапливается ошибка (нужно допиливать напильником).

Заранее благодарен :)

petera
14.10.2016, 12:21
Для результата(суммы) используйте UDINT
для входных значений - INT или DINT
27032

lazy
14.10.2016, 12:37
Для результата(суммы) используйте UDINT
для входных значений - INT или DINT

UDINT тот же DWORD сумма должна быть со знаком так как иногда могут приходить и отрицательные значения. INT для входящих тоже не вариант так как значения могут быть больше 32767. Нужен более вместительный формат целого со знаком чем от -2147483648 до 2147483647.

lara197a
14.10.2016, 12:40
так можно предварительно выделить знак.
При работе с DWORD учитывайте самый старший бит как знак.

RA.
14.10.2016, 12:45
LINT используйте

Сергей0308
14.10.2016, 12:45
Добрый день!

Написал некий фильтр в котором суммируются данные в переменной DINT итд, при маленькой глубине фильтра (8-16 значений) все работает, но стоит увеличить его глубину и DINT начинает переполняться, сумма положительных значений превращается в отрицательную. Как можно побороть это? Какие есть форматы целого со знаком (типа DINT64 или что то в этом роде)? DWORD не подходит так как значения могут приходить и отрицательные. В REAL тоже не все так гладко, так как к большой сумме прибавляются малые значения и накапливается ошибка (нужно допиливать напильником).

Заранее благодарен :)

Математику никак нельзя применить?
(а+б)/с = а/с + б/с

petera
14.10.2016, 12:49
UDINT тот же DWORD сумма должна быть со знаком так как иногда могут приходить и отрицательные значения. INT для входящих тоже не вариант так как значения могут быть больше 32767. Нужен более вместительный формат целого со знаком чем от -2147483648 до 2147483647.

Ну тогда только если разделить суммирование положительных и отрицательных чисел по двум переменным UDINT, а в конце из положительной суммы вычитать отрицательную.

lazy
14.10.2016, 12:55
Математику никак нельзя применить?
(а+б)/с = а/с + б/с

Ващето гениально :D
попробую, но боюсь не всегда может прокатить при a < c например. где с - глубина фильтра.

petera
14.10.2016, 12:57
Ну тогда только если разделить суммирование положительных и отрицательных чисел по двум переменным UDINT, а в конце из положительной суммы вычитать отрицательную.

VAR
SumPlus: UDINT;
SumMinus: UDINT;
Curr: DINT;
Sum: DINT;
END_VAR

IF Curr >=0 THEN
SumPlus:=SumPlus + Curr;
ELSE
SumMinus:=SumMinus - Curr;
END_IF
Sum:=SumPlus - SumMinus;

lazy
14.10.2016, 12:57
petera, ок, попробую, спасибо )

petera
14.10.2016, 13:17
ок, попробую, спасибо )

Возможно придется немного модифицировать код

VAR
SumPlus: UDINT;
SumMinus: UDINT;
Curr: DINT;
Sum: UDINT;
Sign: BOOL;
END_VAR

IF Curr >=0 THEN
SumPlus:=SumPlus + Curr;
ELSE
SumMinus:=SumMinus - Curr;
END_IF

Sum:=ABS(SumPlus - SumMinus);
Sign:= SumMinus > SumPlus;
Здесь для итоговой суммы (Sum) используется UDINT (от 0 до 4294967295) и ввел переменную Sign для знака Sum.
Т.е. фактически диапазон вычислений Sum от - 4294967295 до 4294967295.
В конце вычислений (после деления), умножить результат на "-1", если Sign был BOOL.

capzap
14.10.2016, 13:21
чето какой то ерундой занимаетесь, у нас что уже преобразования DINT_TO_REAL и/или обратно перестали работать?

petera
14.10.2016, 13:26
чето какой то ерундой занимаетесь, у нас что уже преобразования DINT_TO_REAL и/или обратно перестали работать?
Не хочет ТС REAL использовать
Пост #1

В REAL тоже не все так гладко, так как к большой сумме прибавляются малые значения и накапливается ошибка (нужно допиливать напильником).

capzap
14.10.2016, 14:47
ну наверное на самом деле что изменилось в этом мире, раз целочисленные начали в реале ошибку привносить

petera
14.10.2016, 15:06
ну наверное на самом деле что изменилось в этом мире, раз целочисленные начали в реале ошибку привносить

Так REAL ведь не точные числа
Например при сложении
4 000 000 + 0.005
получим результат 4 000 000

ЗЫ.
Даже
40 000 + 0.005
получим результат 40 000

lazy
14.10.2016, 17:00
petera, пока не пробовал, только в фильтре циклов нет для скорости. есть буфер приходящих значений. новое прлюсуецо а старое отнимаецо. как то так:

m_yNew: BYTE := 0;
m_yOld: BYTE;
m_aData: ARRAY [0..255] OF F_DATA;

m_aData[m_yNew].dwX := i_dwX;
m_aData[m_yNew].dnY := i_dnY;

m_yOld := m_yNew - m_yLen; (* m_yLen - глубина *)
m_dnSXY := m_dnSXY + i_dwX * i_dnY - m_aData[m_yOld].dwX * m_aData[m_yOld].dnY;
m_yNew := m_yNew + 1;

поэтому думаю с разделением сумм тоже траблы получацо =(

BETEP
14.10.2016, 17:27
Написал некий фильтр в котором суммируются данные в переменной DINT итд, при маленькой глубине фильтра (8-16 значений) все работает,


INT для входящих тоже не вариант так как значения могут быть больше 32767
2147483647 / 16 = 134 217 727

130 миллионов, что такое измеряете? неужели аналоговый сигнал разрешением в 27 бит получаете? или что то напутали всётаки?

petera
14.10.2016, 19:30
petera, пока не пробовал, только в фильтре циклов нет для скорости. есть буфер приходящих значений. новое прлюсуецо а старое отнимаецо. как то так:

m_yNew: BYTE := 0;
m_yOld: BYTE;
m_aData: ARRAY [0..255] OF F_DATA;

m_aData[m_yNew].dwX := i_dwX;
m_aData[m_yNew].dnY := i_dnY;

m_yOld := m_yNew - m_yLen; (* m_yLen - глубина *)
m_dnSXY := m_dnSXY + i_dwX * i_dnY - m_aData[m_yOld].dwX * m_aData[m_yOld].dnY;
m_yNew := m_yNew + 1;

поэтому думаю с разделением сумм тоже траблы получацо =(

В структуре F_DATA
dwX: DINT ???
dnY: DINT ???

И m_dnSXY тоже DINT ???

lazy
14.10.2016, 21:24
dwX: DWORD
dnY: DINT
m_dnSXY DINT

lazy
14.10.2016, 21:53
Вопрос снят. без циклов внутри фильтра все же не обойтись. ту дело еще и в dwX. это миллисекунды. изменяюцо от нуля в плюс с шагом где то около 20. так что долго этот фильтр все равно без переполнения не проработал бы. решение найдено. всем респект )