2
I am creating a program in Python - using the library ctypes
- to read and write values in memory, and I want to be accurate in the size of the data to be read and written.
In this case, if the floating point value has a size of 4 bytes, its type should be float
. If it has 8 bytes, it must be a double
. For this, I am using the following code:
def get_type(value, size):
return ctypes.c_float(value) if size <= 4 else ctypes.c_double(value)
The problem is that the ctypes.c_float
, unlike ctypes.c_double
, is always getting a value x.yz
and turning into x.ab
. In other words, it generates a different value after the point. See the examples below:
ctypes.c_float(590621.2148).value # 590621.1875
ctypes.c_float(324456.234).value # 324456.21875
ctypes.c_float(987.1).value # 987.0999755859375
ctypes.c_float(456.234) # 456.2340087890625
I know that the float
is less precise than the guy double
, but the problem is happening from the first decimal! Something curious that I noticed is that the smaller the number to the left of the dot, the smaller the error in the decimal numbers. See below:
ctypes.c_float(590621.2148).value # 590621.1875 -> Todos os decimais errados
ctypes.c_float(90621.2148).value # 90621.2109375 -> Os 2 primeiros decimais corretos
ctypes.c_float(621.2148).value # 621.2147827148438 -> Os 3 primeiros decimais corretos
For this reason, I entertained the idea that the problem was occurring due to the lack of space float
to bear the value. But obviously, it’s impossible for that to be the reason, since this guy can carry numbers as high as 10 to the 38 - as far as I can remember.
My question is: what is this problem happening and what should I do to fix it? Remembering again that I don’t want to use the c_double
for any floating point value that appears, only to "fix" the problem. I want to put each value in its correct type, by aesthetics and not to occupy unnecessary space.
Take a look in this table.
ctypes.c_float
andctypes.c_double
allocate the same amount of memory. And herectypes.c_float
andctypes.c_double
implement types internally C float and double which respectively use 4bytes and 8bytes.– Augusto Vasques
@Augustovasques I looked at the table. Where did you see that both allocate the same amount of memory? It just says that both can be used for
float
in Python (since in Python, the only floating point type isfloat
). If you use the functionsizeof
, will see that they have different sizes (4 bytes and 8 bytes). As for the second part, yes I know that, and that’s what I just said... What does all this have to do with the question after all?– JeanExtreme002
See https://ideone.com/EPhw5x, what has to do with the question you are using a lower precision type with the same memory consumption.
– Augusto Vasques
@Augustovasques Yes, this is the size of its raw value in Python. But what about the size of the buffer created for it with CTYPE? See here: https://docs.python.org/3/library/ctypes.html#ctypes.sizeof
– JeanExtreme002
So from these 24 bytes to
ctypes.c_float
4 are allocated to float in , 4 become empty and in the other 8 bytes are allocated to double. There is no computational advantage whatsoever.– Augusto Vasques
@Augustovasques I have the impression that you are getting confused about something. These 24 bytes are not from
C_FLOAT
, they are of valuefloat
python itself. The attributevalue
returns a valuefloat
. Also, I need to pass the value to a CTYPE for me to use the functions ofwinapi
.– JeanExtreme002
Who is getting confused is you "this buffer" stays within 24 bytes of type float.
– Augusto Vasques
@Augustovasques I see now what you mean (although I have no idea how a primitive type of Python has been modified this way). Still, I’d like to know the problem with
c_float
, and bonus, why size is the same in practice, although the documentation says otherwise.– JeanExtreme002
This ctype representation is useful when you want to serialize/deserialize binary data or export data or data pointer to a lib. To write directly into memory would be better to use the module structs
– Augusto Vasques