为了创建任意精度的浮点数/替换 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]