Question

Pour créer un point / virgule flottante de précision arbitraire en remplacement de Double, j'essaie d'encapsuler MPFR < Mais, malgré tous mes efforts, le plus simple des codes ne fonctionne pas. Il compile, il fonctionne, mais il se bloque moqueusement après avoir prétendu travailler pendant un certain temps. Une version C simple du code imprime avec bonheur le numéro "1". à (640 décimales) un total de 10 000 fois. Lorsqu'on lui a demandé de faire de même, la version Haskell corrompt (?) Les données après seulement 289 impressions de "1.0000 ... 0000" et après 385 impressions, cela provoque un échec de l'assertion et des bombes. Je ne sais pas comment procéder pour le débogage car cela "devrait fonctionner".

Le code peut être consulté à partir de http://hpaste.org/10923 et téléchargé à http://www.updike.org/mpfr-broken.tar.gz

J'utilise GHC 6.83 sous FreeBSD 6 et GHC 6.8.2 sous Mac OS X. Notez que vous aurez besoin de MPFR (testé avec la version 2.3.2) installé avec les chemins corrects (modifiez le fichier Makefile) pour les fichiers de bibliothèque et d'en-tête ( ainsi que ceux de GMP) pour compiler avec succès.

Questions

  • Pourquoi la version C fonctionne-t-elle alors que la version de Haskell s'effrite? Que manque-t-il à l'approche de la FFI? J'ai essayé StablePtrs et j'ai eu exactement les mêmes résultats.

  • Est-ce que quelqu'un d'autre peut vérifier s'il s'agit d'un problème uniquement Mac / BSD en compilant et en exécutant mon code? (Le code C fonctionne-t-il? Le code Haskell fonctionne-t-il?) Est-ce que n'importe qui sur Linux et Windows peut essayer de compiler / exécuter et voir si vous obtenez les mêmes résultats?

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

Code Haskell: (Main.hs --- ne fonctionne pas)

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]  
Était-ce utile?

La solution

Je vois aussi le problème, sur 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

Je vois également que la sortie passe de 1,0000 ... 000 à 1,0000 ... [garbage].

Voyons, ce qui suit fonctionne:

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

qui limite le problème aux parties de one qui sont en quelque sorte écrasées pendant l'exécution. Regarder la sortie de ghc -C et de ghc -S ne me donne cependant aucune indication.

Hmm, ./ noworks + RTS -H1G fonctionne également, et ./ noworks + RTS -k [n] k , pour modifier les valeurs de [ n] , démontrez les échecs de différentes manières.

Je n'ai pas de piste solide, mais il y a deux possibilités qui me viennent à l'esprit:

  • GMP, utilisé par le runtime GHC, et MPFR ayant une interaction étrange
  • l'espace de pile pour les fonctions C appelées dans le runtime GHC est limité et MPFR ne traite pas correctement

Cela étant dit ... existe-t-il une raison pour que vous utilisiez vos propres liaisons plutôt que d'utiliser HMPFR ?

Autres conseils

Judah Jacobsen a répondu à cette question sur la liste de diffusion Haskell-cafe:

Il s'agit de problème connu avec GHC en raison de la manière dont il est utilisé par GHC GMP en interne (pour maintenir les nombres entiers).

Apparemment, GHC a laissé les données C du segment de mémoire dans presque tous les cas, sauf le code qui utilise le FFI pour accéder à GMP ou à toute bibliothèque C reposant sur GMP (comme MPFR que je souhaitais utiliser). ). Il y a quelques solutions de contournement (douloureuses) mais le "droit" moyen serait de pirater GHC (difficile) ou de demander aux Simons de supprimer la dépendance de GHC vis-à-vis des BPF (plus difficile).

Aleš Bizjak, responsable de la HMPFR envoyé sur haskell -cafe et a montré comment empêcher GHC de contrôler l’allocation des membres (et donc de les laisser seuls, au lieu de les gêner et de les encombrer):

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

Pour moi, c'est beaucoup plus facile que de joindre les efforts pour écrire un remplacement de GMP dans GHC, ce qui serait la seule alternative si je voulais vraiment utiliser une bibliothèque dépendant de GMP.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top