为了创建一个任意精度的浮点数/Double的替代品,我尝试使用FFI包装MPFR,但是尽管我付出了所有努力,最简单的代码也无法正常工作。它可以编译,可以运行,但是在假装工作一段时间后,它会嘲笑地崩溃。一个简单的C版本的代码高兴地将数字“1”打印出来(640位小数)共计10,000次。当要求Haskell版本执行相同操作时,它在仅289次打印“1.0000...0000”后静默地破坏(?)数据,并在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。请注意,您需要安装正确路径的MPFR(已测试使用2.3.2),包括来自GMP的库和头文件(以及修改Makefile),以成功编译此代码。
Haskell代码:(Main.hs --- 不起作用)
代码可在http://hpaste.org/10923上查看,并可在http://www.updike.org/mpfr-broken.tar.gz上下载。
我正在使用FreeBSD 6上的GHC 6.83和Mac OS X上的GHC 6.8.2。请注意,您需要安装正确路径的MPFR(已测试使用2.3.2),包括来自GMP的库和头文件(以及修改Makefile),以成功编译此代码。
问题
为什么C版本可以工作,但Haskell版本会出现问题?在处理FFI时还需要注意什么?我尝试使用StablePtrs并得到了完全相同的结果。
是否有其他人可以通过编译和运行我的代码验证这是一个仅限于Mac/BSD的问题?(C代码“works.c”是否有效?Haskell代码“noworks”是否有效?)任何在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]