Pergunta

A fim de criar uma precisão arbitrária ponto flutuante / gota no substituto para o dobro, eu estou tentando envolver MPFR utilizando a FFI, mas apesar de todos os meus esforços a pouco mais simples de código não funciona. Ele compila, ele é executado, mas ele trava ironicamente depois fingindo trabalho por um tempo. Uma versão simples C do código felizmente imprime o número "1" para (640 casas decimais) um total de 10.000 vezes. A versão Haskell, quando solicitado a fazer o mesmo, corrompe silenciosamente (?) Os dados depois de apenas 289 impressões de "1,0000 ... 0000" e após 385 impressões de, faz com que uma falha de declaração e bombas. Eu estou em uma perda de como proceder na depuração, visto que isso "deve funcionar".

O código pode ser examinada em http://hpaste.org/10923 e baixado em http://www.updike.org/mpfr-broken.tar.gz

Eu estou usando GHC 6,83 no FreeBSD 6 e GHC 6.8.2 no Mac OS X. Nota você precisará MPFR (testado com 2.3.2) instalado com os caminhos corretos (mudar o Makefile) para libs e arquivos de cabeçalho ( juntamente com os de GMP) para com êxito compilar este.

Perguntas

  • Por que o C trabalho versão, mas a versão Haskell floco fora? O que mais estou em falta quando se aproxima o FFI? Tentei StablePtrs e teve exatamente o mesmo resultado.

  • Can alguém verificar se este é um única Mac / BSD problema, compilar e executar o meu código? (Será que o código C "funciona" o trabalho? Será que o código Haskell trabalho "noworks"?) Can qualquer um em Linux e Windows tentativa de compilar / run e veja se você obter os mesmos 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 --- não trabalho)

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]  
Foi útil?

Solução

Eu vejo o problema também, em um

$ 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

Também vejo a saída mudando de 1,0000 ... 000-1,0000 ... [lixo].

Vamos ver, o seguinte não funciona:

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

que se reduz o problema de peças de one sendo de algum modo derrotado durante a execução. Olhando para a saída do ghc -C e ghc -S, porém, não está me dando alguma dica.

Hmm, ./noworks +RTS -H1G também funciona, e ./noworks +RTS -k[n]k, para diferentes valores de [n], demonstram falhas de maneiras diferentes.

Eu não tenho pistas sólidas, mas há duas possibilidades que salto para a minha mente:

  • GMP, que os usos de tempo de execução GHC, e MPFR ter alguma interação estranho
  • espaço de pilha para funções C chamados dentro do runtime GHC é limitado, e MPFR não lidar bem

Dito isto ... há uma razão que você está rolando suas próprias ligações ao invés de uso HMPFR ?

Outras dicas

Judah Jacobsen respondeu a esta na lista Haskell-café de discussão:

Esta é um conhecido problema com GHC por causa dos usos GHC maneira GMP internamente (para manter inteiros).

Aparentemente dados C no heap é deixado sozinho por GHC em basicamente todos os casos , exceto código que usa o FFI para acesso GMP ou qualquer biblioteca C que depende de GMP (como MPFR que eu queria usar ). Há algumas soluções alternativas (dolorosa), mas o jeito "certo" seria quer cortar GHC (duro) ou obter os Simons para remover a dependência do GHC sobre BPF (mais difícil).

Aleš Bizjak, mantenedor do HMPFR enviada para Haskell -Cafe e mostrou como manter GHC de controlar a alocação dos membros (e, portanto, deixá-los sozinhos, em vez de GCing eles e sobrepor-los):

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 mim, isso é muito mais fácil do que juntar o esforço para escrever um substituto para GMP em GHC, o que seria a única alternativa se eu realmente queria usar qualquer biblioteca que depende de GMP.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top