Domanda

Per creare una virgola mobile / precisione arbitraria di precisione in sostituzione di Double, sto provando a racchiudere MPFR usando l'FFI ma nonostante tutti i miei sforzi il bit di codice più semplice non funziona. Si compila, funziona, ma si blocca in modo beffardo dopo aver fatto finta di lavorare per un po '. Una semplice versione C del codice stampa felicemente il numero "1". a (640 decimali) per un totale di 10.000 volte. La versione di Haskell, quando gli viene chiesto di fare lo stesso, corrompe silenziosamente (?) I dati dopo solo 289 stampe di "1.0000 ... 0000". e dopo 385 stampe, provoca un'asserzione fallita e bombe. Sono in perdita per come procedere nel debug di questo dato che "dovrebbe funzionare".

Il codice può essere consultato su http://hpaste.org/10923 e scaricato su http://www.updike.org/mpfr-broken.tar.gz

Sto usando GHC 6.83 su FreeBSD 6 e GHC 6.8.2 su Mac OS X. Nota che avrai bisogno di MPFR (testato con 2.3.2) installato con i percorsi corretti (cambia il Makefile) per libs e file header ( insieme a quelli di GMP) per compilare con successo questo.

Domande

  • Perché la versione C funziona, ma la versione Haskell si sfalda? Cos'altro mi manca quando mi avvicino all'FFI? Ho provato StablePtrs e ho avuto gli stessi esatti risultati.

  • Qualcun altro può verificare se questo è un problema Mac / BSD solo compilando ed eseguendo il mio codice? (Il codice C "funziona" funziona? Il codice Haskell "funziona ora"? Qualcuno su Linux e Windows può tentare di compilare / eseguire e vedere se si ottengono gli stessi risultati?

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

Codice Haskell: (Main.hs --- non funziona)

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]  
È stato utile?

Soluzione

Vedo anche il problema, su 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

Vedo anche che l'output cambia da 1.0000 ... 000 a 1.0000 ... [immondizia].

Vediamo, il seguente funziona:

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

che restringe il problema a parti di one che sono in qualche modo ostruite durante il runtime. Guardare l'output di ghc -C e ghc -S , tuttavia, non mi dà alcun suggerimento.

Hmm, ./noworks + RTS -H1G funziona anche e ./noworks + RTS -k [n] k , per valori variabili di [ n] , dimostra i guasti in diversi modi.

Non ho solidi contatti, ma ci sono due possibilità che mi vengono in mente:

  • GMP, che utilizza il runtime GHC, e MPFR con strane interazioni
  • lo spazio di stack per le funzioni C chiamate all'interno del runtime GHC è limitato e MPFR non funziona bene

Detto questo ... c'è una ragione per cui stai facendo rotolare i tuoi attacchi piuttosto che usare HMPFR ?

Altri suggerimenti

Judah Jacobsen ha risposto alla mailing list di Haskell-cafe:

Questo è un problema noto con GHC a causa del modo in cui GHC utilizza GMP internamente (per mantenere numeri interi).

Apparentemente i dati C nell'heap sono lasciati soli da GHC in sostanza in tutti i casi tranne che utilizza l'FFI per accedere a GMP o qualsiasi libreria C che si basa su GMP (come MPFR che volevo usare ). Ci sono alcune soluzioni alternative (dolorose) ma il "giusto" il modo sarebbe hackerare GHC (difficile) o convincere i Simons a rimuovere la dipendenza di GHC da GMP (più difficile).

Aleš Bizjak, manutentore di HMPFR pubblicato su haskell -cafe e ha mostrato come impedire a GHC di controllare l'allocazione degli arti (e quindi lasciarli soli, invece di GCing e bloccarli):

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

Per me, questo è molto più semplice che unirmi allo sforzo di scrivere un sostituto di GMP in GHC, che sarebbe l'unica alternativa se volessi davvero usare qualsiasi libreria che dipende da GMP.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top