Home > OS >  Wrong ouptut of a c function returning a double called from python
Wrong ouptut of a c function returning a double called from python

Time:05-29

I want to speed up a python code my calling a c function:

I have a the function in vanilla python sum_and_multiply.py:

def sam_py(lim_sup):
  total = 0
  for i in range(0,lim_sup): # xrange is slower according 
    for j in range(1, lim_sup):            #to my test but more memory-friendly.
      total  = (i / j)
  return total

then I have the equivalent function in C sum_and_multiply_c.c:

#include <stdio.h>


double sam_c(int lim_sup){
  int i;
  int j;
  double total;
  total = 0;
  double div;
  for (i=0; i<lim_sup; i  ){
    for (j=1; j<lim_sup; j  ){

      div = (double) i / j;
//      printf("div: %.2f\n", div);
      total  = div;
 //     printf("total: %.2f\n", total);
    }
  }
  printf("total: %.2f\n", total);
  return total;
}

a file script.py which calls the 2 functions

from sum_and_multiply import sam_py
import time

lim_sup = 6000

start = time.time()
print(sam_py(lim_sup))
end = time.time()
time_elapsed01 = end - start
print("time elapsed: %.4fs" % time_elapsed01)

from ctypes import *
my_c_fun = CDLL("sum_and_multiply_c.so")
start = time.time()
print(my_c_fun.sam_c(lim_sup))
end = time.time()
time_elapsed02 = end - start
print("time elapsed: %.4fs" % time_elapsed02)
print("Speedup coefficient: %.2fx" % (time_elapsed01/time_elapsed02))

and finally a shell script bashscript.zsh which compile the C code and then call script.py

cc -fPIC -shared -o sum_and_multiply_c.so sum_and_multiply_c.c
python script.py

Here is the output:

166951817.45311993
time elapsed: 2.3095s
total: 166951817.45
20
time elapsed: 0.3016s
Speedup coefficient: 7.66x

Here is my question although the c function calculate correctly the result (as output 166951817.45 via printf) its output when passed to python is 20 which wrong. How could I have 166951817.45 instead?

Edit the problem persists after changing the last part of the script.py as follows:

from ctypes import *
my_c_fun = CDLL("sum_and_multiply_c.so")
my_c_fun.restype = c_double
my_c_fun.argtypes = [ c_int ]
start = time.time()
print(my_c_fun.sam_c(lim_sup))
end = time.time()
time_elapsed02 = end - start
print("time elapsed: %.4fs" % time_elapsed02)
print("Speedup coefficient: %.2fx" % (time_elapsed01/time_elapsed02))

CodePudding user response:

You're assuming Python can "see" your function returns a double. But it can't. C doesn't "encode" the return type in anything, so whoever calls a function from a library needs to know its return type, or risk misinterpreting it.

You should have read the documentation of CDLL before using it! If you say this is for the sake of exercise, then that exercise needs to include reading the documentation (that's what good programmers do, no excuses).

class ctypes.CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False)

Instances of this class represent loaded shared libraries. Functions in these libraries use the standard C calling convention, and are assumed to return int.

(emphasis mine.)

https://docs.python.org/2.7/library/ctypes.html#return-types is your friend (and the top of the page will tell you that Python2 is dead and you shouldn't use it, even if you insist on it. I'm sure you have a better reason than the Python developers themselves!).

my_c_fun = CDLL("sum_and_multiply_c.so")
sam_c = my_c_fun.sam_c
sam_c.restype = c_double
sam_c.argtypes = [ c_int ]
value = sam_c(6000)
print(value)

is the way to go.

  • Related