Haskell FFI / C MPFR Library Cover

To create arbitrary floating point / replace precision for Double, I try to wrap MPFR using FFI, but despite all my efforts, the simplest part of the code does not work. It compiles, it works, but it scoffs at us, pretending to need some work. A simple version of C code happily prints the number β€œ1” (640 decimal places) for a total of 10,000 times. The Haskell version, when asked to do the same, silently decomposes (?) The data after 289 printouts of "1.0000 ... 0000" and after 385 printouts, this causes an assertion and bomb error. I do not understand how to do this, since it "should work."

The code can be viewed at http://hpaste.org/10923 and downloaded at http://www.updike.org/mpfr-broken.tar.gz

I use GHC 6.83 on FreeBSD 6 and GHC 6.8.2 on Mac OS X. Note that you will need MPFR (verified from 2.3.2) installed with the correct paths (changing the Makefile) for libs and headers (along with that of GMP) to successfully compile this.

Questions

  • Why does version C work, but version of Haskell has leaked? What else am I missing when approaching FFI? I tried StablePtrs and had the same results.

  • Can anyone else check if this is a Mac / BSD only issue by compiling and running my code? (Does the β€œC” code work? Does the Haskell code β€œrun”?) Can someone from Linux and Windows try to compile / run and see if you get the same results?

C code: (works.c)

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <gmp.h> #include <mpfr.h> #include "mpfr_ffi.c" int main() { int i; mpfr_ptr one; mpf_set_default_prec_decimal(640); one = mpf_set_signed_int(1); for (i = 0; i < 10000; i++) { printf("%d\n", i); mpf_show(one); } } 

Haskell Code: (Main.hs --- not working)

 module Main where import Foreign.Ptr ( Ptr, FunPtr ) import Foreign.C.Types ( CInt, CLong, CULong, CDouble ) import Foreign.StablePtr ( StablePtr ) data MPFR = MPFR foreign import ccall "mpf_set_default_prec_decimal" c_set_default_prec_decimal :: CInt -> IO () setPrecisionDecimal :: Integer -> IO () setPrecisionDecimal decimal_digits = do c_set_default_prec_decimal (fromInteger decimal_digits) foreign import ccall "mpf_show" c_show :: Ptr MPFR -> IO () foreign import ccall "mpf_set_signed_int" c_set_signed_int :: CLong -> IO (Ptr MPFR) showNums kn = do print n c_show k main = do setPrecisionDecimal 640 one <- c_set_signed_int (fromInteger 1) mapM_ (showNums one) [1..10000] 
+4
source share
3 answers

I also see the problem on

 $ uname -a Linux burnup 2.6.26-gentoo-r1 #1 SMP PREEMPT Tue Sep 9 00:05:54 EDT 2008 i686 Intel(R) Pentium(R) 4 CPU 2.80GHz GenuineIntel GNU/Linux $ gcc --version gcc (GCC) 4.2.4 (Gentoo 4.2.4 p1.0) $ ghc --version The Glorious Glasgow Haskell Compilation System, version 6.8.3 

I also see that the output changes from 1.0000 ... 000 to 1.0000 ... [garbage].

Let's see the following work:

 main = do setPrecisionDecimal 640 mapM_ (const $ c_set_signed_int (fromInteger 1) >>= c_show) [1..10000] 

which narrows the problem down until one parts are knocked down at runtime. However, looking at the results of ghc -C and ghc -S does not give me any hints.

Hmm, ./noworks +RTS -H1G also works, and ./noworks +RTS -k[n]k , for different values ​​of [n] , shows failures in different ways.

I have no solid leads, but there are two possibilities that come to my mind:

  • GMP, which uses the GHC runtime, and MPFR, which has some kind of weird interaction
  • the stack space for C functions called in the GHC runtime is limited and MPFR does not work well

As the saying goes ... is there a reason why you collapse your own bindings rather than using HMPFR ?

+3
source

Judah Jacobsen replied to this on the Haskell-cafe mailing list:

This is a known issue with the GHC due to the way the GHC uses GMP internally (to support integers).

Apparently, the C data on the heap is left separate by the GHC in most cases except for the code that uses FFI to access GMP or any C library that relies on GMP (like the MPFR I wanted to use). There are some workarounds (painful), but the β€œright” way is to either crack the GHC (hard) or get Simons to remove the GHC's GMP dependency (harder).

+4
source

Alyos Bizzhak, accompanying the HMPFR , sent to a haskell-cafe and showed how to keep the GHC from controlling the distribution of limbs (and therefore leaving them alone, instead of grouping them and knocking them down):

 mpfr_ptr mpf_new_mpfr() { mpfr_ptr result = malloc(sizeof(__mpfr_struct)); if (result == NULL) return NULL; /// these three lines: mp_limb_t * limb = malloc(mpfr_custom_get_size(mpfr_get_default_prec())); mpfr_custom_init(limb, mpfr_get_default_prec()); mpfr_custom_init_set(result, MPFR_NAN_KIND, 0, mpfr_get_default_prec(), limb); return result; } 

For me, this is much easier than joining an attempt to write a GMP replacement in the GHC, which would be the only alternative if I really wanted to use any library that depends on GMP.

+1
source

Source: https://habr.com/ru/post/1277492/


All Articles