From: kj on



I have a C library function hg that returns a long double, so when
I import it using C types I specify this return type like this:

MYLIB.hg.restype = ctypes.c_longdouble

But certain non-zero values returned by hg appear as zero Python-side.
If I modify hg so that it prints out its value right before returning
it, I get stuff like the following:

>>> 0 == MYLIB.hg(100, 200, 100, 6000)
from hg: 2.96517e-161
False
>>> 0 == MYLIB.hg(200, 200, 200, 6000)
from hg: 5.28791e-380
True

So, although the value returned by hg in the second invocation
above is 5.28791e-380, Python sees it as 0.

What am I doing wrong?

TIA!

~K
From: Thomas Jollans on
On 07/14/2010 03:24 PM, kj wrote:
>
>
>
> I have a C library function hg that returns a long double, so when
> I import it using C types I specify this return type like this:
>
> MYLIB.hg.restype = ctypes.c_longdouble
>
> But certain non-zero values returned by hg appear as zero Python-side.
> If I modify hg so that it prints out its value right before returning
> it, I get stuff like the following:
>
>>>> 0 == MYLIB.hg(100, 200, 100, 6000)
> from hg: 2.96517e-161
> False
>>>> 0 == MYLIB.hg(200, 200, 200, 6000)
> from hg: 5.28791e-380
> True
>
> So, although the value returned by hg in the second invocation
> above is 5.28791e-380, Python sees it as 0.
>
> What am I doing wrong?

Nothing.

http://docs.python.org/library/ctypes.html#fundamental-data-types

c_longdouble maps to float

http://docs.python.org/library/stdtypes.html#numeric-types-int-float-long-complex

"floating point numbers are implemented using double in C"

ergo, the extra precision a long double gives you versus a normal double
is lost if you use Python (or, at least, ctypes)

If you really want to keep the precision, you need a new/different type.
ctypes won't help you. Cython and NumPy may or may not be useful here.

- Thomas
From: kj on
In <mailman.733.1279124991.1673.python-list(a)python.org> Thomas Jollans <thomas(a)jollans.com> writes:

>http://docs.python.org/library/ctypes.html#fundamental-data-types

>c_longdouble maps to float

Thanks for pointing this out!
~K
(Does it make *any difference at all* to use c_longdouble instead
of c_double? If not, I wonder what's the point of having c_longdouble
at all.)
From: Thomas Jollans on
On 07/15/2010 06:41 PM, kj wrote:
> In <mailman.733.1279124991.1673.python-list(a)python.org> Thomas Jollans <thomas(a)jollans.com> writes:
>
>> http://docs.python.org/library/ctypes.html#fundamental-data-types
>
>> c_longdouble maps to float
>
> Thanks for pointing this out!
> ~K
> (Does it make *any difference at all* to use c_longdouble instead
> of c_double? If not, I wonder what's the point of having c_longdouble
> at all.)

they're still different types (in C).

on my machine, a double is 64 bits wide, while a long double is 128 bits
wide. This means that a function that expects a long double argument
will expect 16 bytes, but ctypes will only pass 8 bytes if you tell it
to pass double. The same applies to return values.

From: kj on
In <mailman.778.1279213534.1673.python-list(a)python.org> Thomas Jollans <thomas(a)jollans.com> writes:

>On 07/15/2010 06:41 PM, kj wrote:
>> In <mailman.733.1279124991.1673.python-list(a)python.org> Thomas Jollans <thomas(a)jollans.com> writes:
>>
>>> http://docs.python.org/library/ctypes.html#fundamental-data-types
>>
>>> c_longdouble maps to float
>>
>> Thanks for pointing this out!
>> ~K
>> (Does it make *any difference at all* to use c_longdouble instead
>> of c_double? If not, I wonder what's the point of having c_longdouble
>> at all.)

>they're still different types (in C).

i understand that doubles and long doubles are different in C.

>on my machine, a double is 64 bits wide, while a long double is 129 bits
>wide. This means that a function that expects a long double argument
>will expect 16 bytes, but ctypes will only pass 8 bytes if you tell it
>to pass double. The same applies to return values.

This is extremely confusing. From my naive reading of the
documentation, I would have expected that the following two blocks
would produce identical results (expl is one of the standard C math
library exponential functions, with signature "long double expl(long
double)"):

MATH.expl.argtypes = [c_longdouble]
MATH.expl.restype = c_longdouble
print MATH.expl(0)

MATH.expl.argtypes = [c_double]
MATH.expl.restype = c_double
print MATH.expl(0)

....but no, they don't: the first one prints out the correct result,
1.0, while the second one prints out 0.0, of all things. (In fact,
with the second (mis)configuration, the value returned by MATH.expl
is always equal to its argument, go figure.)

I find these results perplexing because, based on the docs, I
expected that they *both* would be analogous to doing the following
in C:

printf("%f\n", (double) expl((double) 0.0)); /* prints out 1.000000 */

i.e., in *both* cases, expl would get passed a double (which gets
automatically cast into a long double), and in both cases its
returned value would be cast into a double. Clearly, this is not
what's happening, but I can't figure out the correct interpreation
of what's going on based on the documentation...
 |  Next  |  Last
Pages: 1 2
Prev: Identify the Color of an Image
Next: list.insert