Проблемы с Uint64

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

CRobin
постоялец
Сообщения: 145
Зарегистрирован: 26.01.2016 11:15:39

Проблемы с Uint64

Сообщение CRobin »

Здравствуйте. Надавно стал замечать, что в ранее работавшем коде стали появляться логические ошибки. После дебага оказалось что ошибка возникает в результат выполнения арифметических операций с двумя переменными типа Uint64. Например 110840 - 110842 = 18446744073709551614. Как я понимаю вычитание беззнаковых интерпретирует результат вычитание как такое же беззнаковое число. Но ранее этого небыло. Что я мог сломать и откуда взялась такая странная логика? Lazarus 1.4.4 оптимизация O3
Аватара пользователя
Лекс Айрин
долгожитель
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград
Контактная информация:

Сообщение Лекс Айрин »

А если отключить оптимизацию?

Добавлено спустя 4 минуты 56 секунд:
Вообще, результат законен. При вычитании большего из меньшего и должно получиться такое громадное число, если не используется информация о переполнении регистра. Есть подозрение, что излишне ретивый оптимизатор эту проверку убирает, считая, что за этим должен следить программист.
Аватара пользователя
Дож
энтузиаст
Сообщения: 900
Зарегистрирован: 12.10.2008 16:14:47

Сообщение Дож »

Например 110840 - 110842 = 18446744073709551614.

А что, по-вашему, должно являться результатом вычитания этих чисел в UInt64?
CRobin
постоялец
Сообщения: 145
Зарегистрирован: 26.01.2016 11:15:39

Сообщение CRobin »

Дож писал(а):А что, по-вашему, должно являться результатом вычитания этих чисел в UInt64?

должно получится -2 и ранее получалось
Аватара пользователя
Лекс Айрин
долгожитель
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград
Контактная информация:

Сообщение Лекс Айрин »

CRobin, вообще-то, это было из-за того, что переменные неявно превращались в знаковые, а потом, если надо, обратно.
CRobin
постоялец
Сообщения: 145
Зарегистрирован: 26.01.2016 11:15:39

Сообщение CRobin »

Лекс Айрин писал(а):CRobin, вообще-то, это было из-за того, что переменные неявно превращались в знаковые, а потом, если надо, обратно.

Я ничего не менял в коде. Могу только вспомнить восстановление LPI и LPS файлов после падения диска, может быть там были объявлены какие то опции компилятора?
Аватара пользователя
Лекс Айрин
долгожитель
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград
Контактная информация:

Сообщение Лекс Айрин »

CRobin, ты нет. А вот компилятор (оптимизатор) вполне.
по ссылке пример для языка С++, но, на самом деле, проблема может возникнуть для любого языка.
https://habrahabr.ru/post/307702/

Ах, да... именно во избежание подобных бяк и не люблю использовать беззнаковые типы, хотя иногда и можно было бы.
Аватара пользователя
Дож
энтузиаст
Сообщения: 900
Зарегистрирован: 12.10.2008 16:14:47

Сообщение Дож »

CRobin писал(а):
Дож писал(а):А что, по-вашему, должно являться результатом вычитания этих чисел в UInt64?

должно получится -2 и ранее получалось

UInt64 расшифровывается как Unsigned (беззнаковый) Integer на 64 бита. Как и полагается беззнаковому типу, он не может хранить отрицательные числа

Код: Выделить всё

begin
  Writeln('UInt64 of -2 = ', UInt64(-2));
end.

Код: Выделить всё

UInt64 of -2 = 18446744073709551614


Т.е. сейчас указанная вами проблема про вычитание не является ошибкой, а если ранее вы наблюдали -2 в UInt64, то это было что-то странное.
Аватара пользователя
Лекс Айрин
долгожитель
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград
Контактная информация:

Сообщение Лекс Айрин »

Дож писал(а): то это было что-то странное.


всего лишь приведение типа, ничего странного. Не думаю, что он присваивал результат в беззнаковую переменную. Другое дело, что этоо детали реализации, которые не всегда явно прописаны.
Аватара пользователя
Дож
энтузиаст
Сообщения: 900
Зарегистрирован: 12.10.2008 16:14:47

Сообщение Дож »

Лекс Айрин и где это приведение типов? Я что-то не вижу никакого кода.
CRobin
постоялец
Сообщения: 145
Зарегистрирован: 26.01.2016 11:15:39

Сообщение CRobin »

Дож писал(а):сейчас указанная вами проблема про вычитание не является ошибкой, а если ранее вы наблюдали -2 в UInt64, то это было что-то странное.


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

Код: Выделить всё

if a - b > c then 
изза этого возникала ошибка самого алгоритма. Решил проблему явным указанием типа

Код: Выделить всё

if int64(a - b) > c then 
. Вообще говоря, меня пугает не то что надо приводить тип, а непредсказукемость алгоритма, поскольку ранее поведение этих проверок было другое.
Аватара пользователя
Лекс Айрин
долгожитель
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград
Контактная информация:

Сообщение Лекс Айрин »

Дож, в паскале много неявного приведения, которое в код добавляет компилятор.

CRobin, всякое бывает. Иногда и не знаешь где аукнется.
alexey38
долгожитель
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Сообщение alexey38 »

Вообще-то операция "if a - b > c then" с беззнаковыми типами, если "b" больше "a" является грубой логической ошибкой программиста, а не компилятора. Раньше, когда по молодости делал такие же ошибки в Borland Pascal или Delphi, то при выполнении программа вылетала с ошибкой типа, по-моему, "Run time Error 201 ...".

Когда начал работать в области промышленной автоматизации, то за такие косяки могли уволить с работы или лишить премии на полгода вперед. А если кто-то пытался оправдаться, говоря, что при отключенных проверках диапазонов программа работает правильно, то увольняли сразу и без дальнейших разговоров.
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

alexey38
Давайие сразу сажать за такое))
Обычная ошибка, не лучше не хуже других.

Мерилом в подобных случаях у разрабов является делфи. Раньше было както посвоему, теперь стало как в делфи.
Сейчас (в транке fpc) например такой код работает поразному в делфи\фпц

Код: Выделить всё

program Project1;

{$APPTYPE CONSOLE}

var
  a,b:longword;
begin
  a:=1;b:=2;
  if (a-b)>0 then
   Writeln('Passed');
  readln;
end.

Напишет ктонить багрепорт и CRobin еще раз удивится))
>>Вообще говоря, меня пугает не то что надо приводить тип, а непредсказукемость алгоритма
Алгоритм тут совершенно непричем,
alexey38
долгожитель
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Сообщение alexey38 »

zub писал(а):alexey38Давайие сразу сажать за такое)). Обычная ошибка, не лучше не хуже других.
...
>>Вообще говоря, меня пугает не то что надо приводить тип, а непредсказукемость алгоритма
Алгоритм тут совершенно непричем,


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

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

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

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