【问题标题】:Haskell FFI / C MPFR library wrapper woesHaskell FFI / C MPFR 库包装问题
【发布时间】:2010-09-15 10:25:05
【问题描述】:

为了创建一个任意精度的浮点数/替换 Double,我尝试使用 FFI 包装 MPFR,但尽管我付出了所有努力,但最简单的代码位不起作用。它编译,它运行,但在假装工作一段时间后它会模拟地崩溃。一个简单的 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。请注意,您需要为库和头文件(以及来自 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]  

【问题讨论】:

    标签: c haskell floating-point ffi mpfr


    【解决方案1】:

    HMPFR 的维护者 Aleš Bizjak 发布到 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 替代品要容易得多,如果我真的想使用任何依赖 GMP 的库,这将是唯一的选择。

    【讨论】:

    • HMPFR 似乎有一个突出的问题,当我展示它们时,我仍然遇到内存损坏。
    • @Edward: 真不幸……我有一段时间没有回来做这个项目了
    • 看起来 MPFR(和 GMP,也是)使用全局状态。这是问题的原因吗?
    【解决方案2】:

    我也看到了问题,在一个

    $ 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...[垃圾]。

    让我们看看,以下确实有效:

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

    这将问题缩小到one 的某些部分在运行时以某种方式被破坏。不过,查看ghc -Cghc -S 的输出并没有给我任何提示。

    嗯,./noworks +RTS -H1G 也有效,./noworks +RTS -k[n]k,对于不同的 [n] 值,以不同的方式演示失败。

    我没有可靠的线索,但我想到了两种可能性:

    • GHC 运行时使用的 GMP 和 MPFR 有一些奇怪的交互
    • 在 GHC 运行时调用的 C 函数的堆栈空间有限,并且 MPFR 处理不好

    话虽如此...您是否有理由滚动自己的绑定而不是使用HMPFR

    【讨论】:

    • 哦,你已经明白了。很高兴知道我在正确的轨道上......
    • HMPFR 于 9 月底上传,我在 7 月开始了自己的绑定。感谢您帮助调查。
    【解决方案3】:

    Judah Jacobsen 在 Haskell-cafe 邮件列表中回答了这个问题:

    这是a known issue with GHC,因为 GHC 在内部使用 GMP 的方式(以维护整数)。

    显然,堆中的 C 数据基本上在所有情况下都被 GHC 单独留下除了使用 FFI 访问 GMP 的代码或任何依赖 GMP 的 C 库(比如我想使用的 MPFR )。有一些解决方法(痛苦),但“正确”的方法是破解 GHC(困难)或让 Simons 消除 GHC 对 GMP 的依赖(更困难)。

    【讨论】:

      猜你喜欢
      • 2012-04-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-02
      相关资源
      最近更新 更多