Pregunta

Para crear un punto flotante / gota de precisión arbitraria en reemplazo de Double, estoy tratando de envolver MPFR usando la FFI pero a pesar de todos mis esfuerzos, el código más simple no funciona. Se compila, se ejecuta, pero se bloquea de forma burlona después de pretender trabajar durante un tiempo. Una simple versión C del código imprime felizmente el número " 1 " a (640 decimales) un total de 10,000 veces. Cuando se le pide a la versión de Haskell que haga lo mismo, corrompe silenciosamente (?) Los datos después de solo 289 impresiones de " 1.0000 ... 0000 " y después de 385 copias impresas, causa un fallo de afirmación y bombas. No sé cómo proceder a la depuración de esto, ya que " debería funcionar " ;.

El código se puede leer en http://hpaste.org/10923 y descargarlo en http://www.updike.org/mpfr-broken.tar.gz

Estoy usando GHC 6.83 en FreeBSD 6 y GHC 6.8.2 en Mac OS X. Tenga en cuenta que necesitará MPFR (probado con 2.3.2) instalado con las rutas correctas (cambiar el Makefile) para las librerías y los archivos de encabezado ( junto con los de GMP) para compilar esto con éxito.

Preguntas

  • ¿Por qué funciona la versión C, pero la versión de Haskell falla? ¿Qué más me falta al acercarme a la FFI? Probé StablePtrs y obtuve los mismos resultados.

  • ¿Puede alguien más verificar si se trata de un problema único de Mac / BSD al compilar y ejecutar mi código? (¿El código C " funciona " funciona? ¿Funciona el código Haskell " noworks "?) ¿Puede alguien en Linux y Windows intentar compilar / ejecutar y ver si obtiene los mismos resultados?

Código C: (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);
    }  
}  

Código Haskell: (Main.hs --- no funciona)

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 k n = do  
   print n  
   c_show k  

main = do  
   setPrecisionDecimal 640  
   one <- c_set_signed_int (fromInteger 1)  
   mapM_ (showNums one) [1..10000]  
¿Fue útil?

Solución

También veo el problema, en un

$ 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

También veo que la salida cambia de 1.0000 ... 000 a 1.0000 ... [basura].

Veamos, lo siguiente funciona:

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

que reduce el problema a partes de one que se obstruyen de alguna manera durante el tiempo de ejecución. Sin embargo, mirar la salida de ghc -C y ghc -S , no me da ninguna pista.

Hmm, ./noworks + RTS -H1G también funciona, y ./noworks + RTS -k [n] k , para valores variables de [ n] , demuestra fallas de diferentes maneras.

No tengo pistas sólidas, pero hay dos posibilidades que saltan a mi mente:

  • GMP, que utiliza el tiempo de ejecución de GHC, y MPFR teniendo alguna interacción extraña
  • el espacio de la pila para las funciones C llamadas dentro del tiempo de ejecución de GHC es limitado, y MPFR no funciona bien

Dicho esto ... ¿hay alguna razón por la que esté creando sus propios enlaces en lugar de usar HMPFR ?

Otros consejos

Judah Jacobsen respondió esto en la lista de correo de Haskell-cafe:

Esto es un problema conocido con GHC debido a la forma en que GHC utiliza GMP internamente (para mantener enteros).

Aparentemente, los datos de C en el montón se quedan solos por GHC en básicamente todos los casos excepto que usa el FFI para acceder a GMP o a cualquier biblioteca de C que dependa de GMP (como el MPFR que quería usar) ). Hay algunas soluciones (dolorosas) pero la " derecha " La forma sería hackear GHC (difícilmente) o hacer que los Simons eliminen la dependencia de GHC en GMP (más difícil).

Aleš Bizjak, mantenedor de HMPFR publicado en haskell -cafe y mostró cómo evitar que GHC controle la asignación de las extremidades (y, por lo tanto, dejarlas solas, en lugar de pegarlas y golpearlas):

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;  
}

Para mí, esto es mucho más fácil que unir el esfuerzo por escribir un reemplazo para GMP en GHC, que sería la única alternativa si realmente quisiera usar cualquier biblioteca que dependa de GMP.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top