реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Преобразование UINT64 к REAL64
Grizzzly
сообщение Feb 28 2014, 18:44
Сообщение #1


Знающий
****

Группа: Свой
Сообщений: 565
Регистрация: 22-02-13
Пользователь №: 75 748



В наследство досталось много кода, написанного уволившимся программистом. Ищу ошибки, разбираюсь. Специфика программы в том, что код был изначально написан под TMS с фиксированной точкой, затем был перенесем на ARM7, где часть операций стала производиться с вещественными числами. Есть множество приведений типов.
Нашел баг.
Код
UINT64 p1, p2;
...
REAL64 Power = (REAL64)(p1-p2);

Когда разность получалась отрицательной, результат был неверный.
Корректно ли делать приведение типов так?
Код
Power = (REAL64)p1-(REAL64)p2;

Или нужно сначала разность привести к SINT64, а затем уже к REAL64?

Сообщение отредактировал Grizzzly - Feb 28 2014, 18:45
Go to the top of the page
 
+Quote Post
smalcom
сообщение Mar 1 2014, 07:35
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 292
Регистрация: 26-06-07
Пользователь №: 28 718



>> Power = (REAL64)p1-(REAL64)p2;
так верно
Go to the top of the page
 
+Quote Post
DpInRock
сообщение Mar 1 2014, 07:50
Сообщение #3


Гуру
******

Группа: Участник
Сообщений: 2 254
Регистрация: 4-05-07
Из: Moscow
Пользователь №: 27 515



Изначально неверно использовать UINT для арифметических операций со знаком. Экономия одного бита при 64 разрядах вряд ли оправдана.


--------------------
On the road again (Canned Heat)
Go to the top of the page
 
+Quote Post
Grizzzly
сообщение Mar 1 2014, 11:08
Сообщение #4


Знающий
****

Группа: Свой
Сообщений: 565
Регистрация: 22-02-13
Пользователь №: 75 748



Цитата(smalcom @ Mar 1 2014, 11:35) *
>> Power = (REAL64)p1-(REAL64)p2;
так верно

Спасибо!
У меня выходило, что этот вариант не всегда прокатывал.
В программе p1, p2 могут принимать значения в диапазоне от 50000 до нескольких десятков миллионов. Тут такое приведение типов срабатывало.
При тестировании взял такие значения: p1 = 800000000000000000, p2 = 800000000000000001. Тогда работает вариант
Код
UINT64 t = p[0]-p[1];
Power = (REAL64)((SINT64)t);
, а в первом случае ошибка.
Теперь понял, что так получалось из-за того, что в примере было больше 16 значащих десятичных цифр.

Цитата(DpInRock @ Mar 1 2014, 11:50) *
Изначально неверно использовать UINT для арифметических операций со знаком. Экономия одного бита при 64 разрядах вряд ли оправдана.

Согласен. Что досталось, с тем и пришлось работать...
Go to the top of the page
 
+Quote Post
maksimp
сообщение Mar 1 2014, 17:23
Сообщение #5


Местный
***

Группа: Участник
Сообщений: 313
Регистрация: 2-07-11
Пользователь №: 66 023



Цитата(Grizzzly @ Mar 1 2014, 14:08) *
При тестировании взял такие значения: p1 = 800000000000000000, p2 = 800000000000000001. Тогда работает вариант

Чтобы не терять точность в подобных случаях можно например так:
Код
Power = (p1>=p2) ? ((REAL64)(p1-p2)) : (-(REAL64)(p2-p1));

Фактически нужно 65-битную промежуточную переменную, и результат (p1>=p2) как раз хранит дополнительный бит.
Go to the top of the page
 
+Quote Post
Grizzzly
сообщение Mar 2 2014, 05:53
Сообщение #6


Знающий
****

Группа: Свой
Сообщений: 565
Регистрация: 22-02-13
Пользователь №: 75 748



Цитата(maksimp @ Mar 1 2014, 21:23) *
Фактически нужно 65-битную промежуточную переменную, и результат (p1>=p2) как раз хранит дополнительный бит.

Спасибо.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 03:31
Рейтинг@Mail.ru


Страница сгенерированна за 0.01392 секунд с 7
ELECTRONIX ©2004-2016