How do I force usage of long doubles with Cython?

2019-05-10 09:38发布

问题:

I apologize in advance for my poor knowledge of C: I use Python to code and have written a few modules with Cython using the standard C functions to effect a great increase in speed. However, I need a range higher than 1e308 (yes, you read it right), which is what I currently get by using the type double complex and the functions cexp and cabs.

I tried to use the functions cexpl and cabsl, and declared my variables to be of type long double complex, but I still encounter overflows after 1e308. This probably means that my compiler converts long doubles to doubles, is that right? But according to Wikipedia,

With the GNU C Compiler, long double is 80-bit extended precision on x86 processors regardless of the physical storage used for the type (which can be either 96 or 128 bits)..[4]

I am using a 64-bit system with arch Linux (and Python 2.7.8 if it matters).

How do I write a Cython module that forces the use of long doubles? I need such big numbers for some scientific computation I am doing.

Edit: Compiling with the flag -m128bit-long-double gives the same result. As indicated here,

In the x86-64 compiler, -m128bit-long-double is the default choice as its ABI specifies that long double is to be aligned on 16 byte boundary.

So this seems to make no difference.

I also ran this following program to check the range on my system:

#include <stdio.h>
#include <float.h>

int main()
{
   printf("Storage size for float : %d \n", sizeof(float));
   printf("Minimum float positive value: %E\n", FLT_MIN );
   printf("Maximum float positive value: %E\n", FLT_MAX );
   printf("Precision value: %d\n", FLT_DIG );

   printf("Storage size for double : %d \n", sizeof(double));
   printf("Minimum double positive value: %E\n", DBL_MIN );
   printf("Maximum double positive value: %E\n", DBL_MAX );
   printf("Precision value: %d\n", DBL_DIG );

   printf("Storage size for long double : %d \n", sizeof(long double));
   printf("Minimum long double positive value: %Le\n", LDBL_MIN );
   printf("Maximum long double positive value: %Le\n", LDBL_MAX );
   printf("Precision value: %d\n", LDBL_DIG );

   return 0;
}

and got the following output:

Storage size for float : 4 
Minimum float positive value: 1.175494E-38
Maximum float positive value: 3.402823E+38
Precision value: 6
Storage size for double : 8 
Minimum double positive value: 2.225074E-308
Maximum double positive value: 1.797693E+308
Precision value: 15
Storage size for long double : 16 
Minimum long double positive value: 3.362103e-4932
Maximum long double positive value: 1.189731e+4932
Precision value: 18

So I guess the problem lies in my code, is that right? Are there any explicit identifiers I need to add other than declaring variables to ensure that my program actually uses long doubles?

回答1:

As was seen in the edit to the question, my system and compiler was behaving as expected by printing the correct range for long double, the relevant variable here being LDBL_MAX = 1.189731e+4932

Also, the module written with Cython was correctly giving an output of type long double. However, since this type is not natively supported in Python (see this question), the value that was returned was greater than the maximum size of double ,1.797693E+308 on my system and hence being equated to +inf + 0j. So this was not related to gcc at all, but to Python interpreting long doubles in an incorrect way.

I can hopefully get around this by working with another C module that can accept long double input types and process it further, the expected results from this sub-part is not expected to be outside the range of a double (or for that matter, even a float).

Another option might be to use libraries with Python that can support high precision and high range numbers, possibly GMPY.