Просмотр полной версии : Переполнение DINT
Добрый день!
Написал некий фильтр в котором суммируются данные в переменной DINT итд, при маленькой глубине фильтра (8-16 значений) все работает, но стоит увеличить его глубину и DINT начинает переполняться, сумма положительных значений превращается в отрицательную. Как можно побороть это? Какие есть форматы целого со знаком (типа DINT64 или что то в этом роде)? DWORD не подходит так как значения могут приходить и отрицательные. В REAL тоже не все так гладко, так как к большой сумме прибавляются малые значения и накапливается ошибка (нужно допиливать напильником).
Заранее благодарен :)
Для результата(суммы) используйте UDINT
для входных значений - INT или DINT
27032
Для результата(суммы) используйте UDINT
для входных значений - INT или DINT
UDINT тот же DWORD сумма должна быть со знаком так как иногда могут приходить и отрицательные значения. INT для входящих тоже не вариант так как значения могут быть больше 32767. Нужен более вместительный формат целого со знаком чем от -2147483648 до 2147483647.
lara197a
14.10.2016, 12:40
так можно предварительно выделить знак.
При работе с DWORD учитывайте самый старший бит как знак.
Сергей0308
14.10.2016, 12:45
Добрый день!
Написал некий фильтр в котором суммируются данные в переменной DINT итд, при маленькой глубине фильтра (8-16 значений) все работает, но стоит увеличить его глубину и DINT начинает переполняться, сумма положительных значений превращается в отрицательную. Как можно побороть это? Какие есть форматы целого со знаком (типа DINT64 или что то в этом роде)? DWORD не подходит так как значения могут приходить и отрицательные. В REAL тоже не все так гладко, так как к большой сумме прибавляются малые значения и накапливается ошибка (нужно допиливать напильником).
Заранее благодарен :)
Математику никак нельзя применить?
(а+б)/с = а/с + б/с
UDINT тот же DWORD сумма должна быть со знаком так как иногда могут приходить и отрицательные значения. INT для входящих тоже не вариант так как значения могут быть больше 32767. Нужен более вместительный формат целого со знаком чем от -2147483648 до 2147483647.
Ну тогда только если разделить суммирование положительных и отрицательных чисел по двум переменным UDINT, а в конце из положительной суммы вычитать отрицательную.
Математику никак нельзя применить?
(а+б)/с = а/с + б/с
Ващето гениально :D
попробую, но боюсь не всегда может прокатить при a < c например. где с - глубина фильтра.
Ну тогда только если разделить суммирование положительных и отрицательных чисел по двум переменным 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;
petera, ок, попробую, спасибо )
ок, попробую, спасибо )
Возможно придется немного модифицировать код
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.
чето какой то ерундой занимаетесь, у нас что уже преобразования DINT_TO_REAL и/или обратно перестали работать?
чето какой то ерундой занимаетесь, у нас что уже преобразования DINT_TO_REAL и/или обратно перестали работать?
Не хочет ТС REAL использовать
Пост #1
В REAL тоже не все так гладко, так как к большой сумме прибавляются малые значения и накапливается ошибка (нужно допиливать напильником).
ну наверное на самом деле что изменилось в этом мире, раз целочисленные начали в реале ошибку привносить
ну наверное на самом деле что изменилось в этом мире, раз целочисленные начали в реале ошибку привносить
Так REAL ведь не точные числа
Например при сложении
4 000 000 + 0.005
получим результат 4 000 000
ЗЫ.
Даже
40 000 + 0.005
получим результат 40 000
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;
поэтому думаю с разделением сумм тоже траблы получацо =(
Написал некий фильтр в котором суммируются данные в переменной DINT итд, при маленькой глубине фильтра (8-16 значений) все работает,
INT для входящих тоже не вариант так как значения могут быть больше 32767
2147483647 / 16 = 134 217 727
130 миллионов, что такое измеряете? неужели аналоговый сигнал разрешением в 27 бит получаете? или что то напутали всётаки?
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 ???
dwX: DWORD
dnY: DINT
m_dnSXY DINT
Вопрос снят. без циклов внутри фильтра все же не обойтись. ту дело еще и в dwX. это миллисекунды. изменяюцо от нуля в плюс с шагом где то около 20. так что долго этот фильтр все равно без переполнения не проработал бы. решение найдено. всем респект )
Powered by vBulletin® Version 4.2.3 Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot