質問

Doubleの代わりに任意の精度の浮動小数点/ドロップを作成するために、 MPFR FFIを使用していますが、私の努力にもかかわらず、最も単純なコードは機能しません。コンパイル、実行はされますが、しばらく動作するふりをした後、モックでクラッシュします。コードの単純なCバージョンは、数字「1」を喜んで出力します。 〜(小数点以下640位)合計10,000回。 Haskellバージョンは、同じことをするように求められたとき、「1.0000 ... 0000」の289枚の出力だけでデータを静かに破損(?)します。 385枚の印刷後、アサーションの失敗と爆弾が発生します。これが「うまくいくはず」だからデバッグの進め方に困っています。

http://hpaste.org/10923 でコードを熟読し、 http://www.updike.org/mpfr-broken.tar.gz

FreeBSD 6のGHC 6.83とMac OS XのGHC 6.8.2を使用しています。libsとヘッダーファイルの正しいパス(Makefileの変更)でインストールされたMPFR(2.3.2でテスト済み)が必要です。 GMPのものと一緒に)これを正常にコンパイルします。

質問

  • Cバージョンは機能するのに、Haskellバージョンは機能しなくなるのはなぜですか? FFIに近づくと、他に何が欠けていますか? StablePtrsを試したところ、まったく同じ結果が得られました。

  • コードをコンパイルして実行することで、これがMac / BSDのみの問題であるかどうかを他の誰かが確認できますか? (Cコードは動作しますか?Haskellコードは動作しませんか?)LinuxとWindowsの誰でもコンパイル/実行を試みて、同じ結果が得られるかどうかを確認できますか?

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

Haskellコード:(Main.hs ---は機能しません)

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]  
役に立ちましたか?

解決

問題も見られます、

$ 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

また、出力が1.0000 ... 000から1.0000 ... [garbage]に変化するのを見ます。

見てみましょう、次は機能します:

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

これは、実行中に何らかの形で破壊される one の部分に問題を絞り込みます。ただし、 ghc -C および ghc -S の出力を確認しても、ヒントは得られません。

うーん、 ./ noworks + RTS -H1G も機能し、 [のさまざまな値に対して ./ noworks + RTS -k [n] k も機能しますn] 、さまざまな方法で障害を示します。

確固たるリードはありませんが、2つの可能性が思い浮かびます。

  • GHCランタイムが使用するGMPと、奇妙な相互作用を持つMPFR
  • GHCランタイム内で呼び出されるC関数のスタック領域は制限されており、MPFRはうまく処理されません

言われていることは、 HMPFR

他のヒント

Judah JacobsenはHaskell-cafeメーリングリストでこれに回答しました:

これは GHCの既知の問題です。GHCの使用方法が原因です。内部的にGMP(整数を維持するため)。

明らかに、ヒープ内のCデータは、GMPまたはGMPに依存するCライブラリ(使用したいMPFRなど)にアクセスするためにFFIを使用するコードを基本的にすべてのケースでGHCによってそのまま残されます)。いくつかの回避策(痛みを伴う)がありますが、「正しい」方法は、GHCをハッキングする(ハード)か、またはSimonsにGHCのGMPへの依存を削除する(ハード)ことです。

エール&#353; Bizjak、 HMPFR のメンテナーがhaskell-cafeに投稿して公開GHCが手足の割り当てを制御しないようにする方法(したがって、GCして手足を壊すのではなく、手足をそのままにしておく):

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

私にとって、これはGHCにGMPの代替を書く努力に参加するよりもはるかに簡単です。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top