Сравнение float, int в ctypes

Приветствую!

Ковыряюсь с библиотекой ctypes. Хочу добиться в питоновом скрипте такого же поведения, как в С.
Например, имеется С-шный код

    int a = 117440517;
    float b = 117440520.0;
    if (a == b)
        printf("equal");
    else
        printf("non equal");

В С эти значения при сравнении будут неотличимы друг от друга (Выводится “equal”).
Если такое же попытаться провернуть с типами из ctypes, то результат будет другой (“non equal”)

    a=ctypes.c_int(117440517)
    b=ctypes.c_float(117440520.0)

    if(a==b):
    	print("equal")
    else:
        print("non equal")

Как заставить Python сравнивать типы ctypes так же, как в С? Ну кроме помещения функции сравнения в dll и вызова этой функции из скрипта.

А цель какая? Откуда числа?

В Си же вроде тоже так сравнивать не рекомендуется.

Это пример, кажется с Вики, про неявное приведение типов и возможные проблемы при этом.

Не рекомендуется, но используется.

Сам вопрос обусловлен необходимостью работы с legacy-прогой на CUDA, которая работает с float и как раз эти неявные приведения активно практикует (да, она ужасна:) ). Потеря точности от сравнения невелика, но хотелось бы, чтобы питоновский скрипт выдавал те же результаты, что и С-шный код.

Так она пусть практикует, а “снаружи” в своем коде можно нормально делать )

Вообще такие сравнения и в Си же вроде зависят от компилятора и т.д., так что точно так же вряд ли получится.

В любом случае наверно придется написать какую-нибудь функцию cmp_numbers для сравнения по любым правилам отличным от ==, так что можно там сразу и написать правильно.

Такое решение не пойдёт? https://rextester.com/UJTE28384

def isEqual(a, b):
    return abs(a - b) < 0.0001

a = 0.3
b = 0.1 + 0.2

print(a) # 0.3
print(b) # 0.30000000000000004

if isEqual(a, b):
    print("Равны")
else:
    print("Неравны")

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

А питон эти ctypes вообще не пойми как сравнивает…

>>> import ctypes
>>> a=ctypes.c_int(117440517)
>>> b=ctypes.c_float(117440520.0)
>>> a
c_long(117440517)
>>> b
c_float(117440520.0)
>>> a == b
False
>>> ctypes.c_float(a.value)
c_float(117440520.0)
>>> ctypes.c_float(a.value) == b
False
>>> ctypes.c_float(a.value).value == b.value
True
1 лайк

без .value видимо просто ссылки сравниваются, как у всех объектов по умолчанию.

>>> b = ctypes.c_float(117440520.0)
>>> b2 = ctypes.c_float(117440520.0)
>>> b.value == b2.value
True

Всё же можно было надеяться на более разумное переопределение.

Но, если честно, не могу понять, зачем использовать ctypes внутри питона
@Kernel, может, обрисуете задачу подробнее? Что откуда берётся и куда?

Сейчас так и организовано. Из питона дергается функция в dll, которая сравнивает с сишным кастом int к float. Хотелось бы сделать все в питоновкском коде.

Нет, т.к. здесь не учитывается особенности каста сишного int к float. Например, для приведенного примера разница будет 3 и получится не тот результат, что в С.

Во, похоже на то, что надо. Спасибо!

Есть прога для CUDA, которая работает с float значениями. В источник данных для проги данные пишутся как int (другой прогой).
Хотелось бы в питоне получить такое же поведение, чтобы проводить некоторые вычисления с поведение, и только потом запихивать это в CUDA-прогу.

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

так оно не сработает как вы хотели для == float.

даже если кастануть.

>>> b = ctypes.c_float(117440520.0)
>>> a = ctypes.c_int(117440517)
>>> b = ctypes.c_float(117440520.0)
>>> a.value == b.value
False
>>> a.value == int(b.value)
False
>>> float(a.value) == b.value
False
>>> float(a.value)
117440517.0

Так к c_float же можно кастануть. И тогда будет то, что надо

>>> ctypes.c_float(a.value)
c_float(117440520.0)