Чтобы создать произвольную точность с плавающей запятой / заменой для Double, я пытаюсь обернуть MPFR , используя FFI, но, несмотря на все мои усилия, самый простой бит кода не работает. Он компилируется, запускается, но насмешливо вылетает после того, как некоторое время притворяется, что работает. Простая C-версия кода с радостью печатает число от «1» до (640 десятичных знаков) в общей сложности 10000 раз. Версия на Haskell, когда ее просят сделать то же самое, молча повреждает (?) Данные только после 289 распечаток «1.0000 ... 0000» и после 385 распечаток, это вызывает ошибку подтверждения и бомбы. Я в недоумении, как приступить к отладке этого, так как это «должно работать».
Код можно просмотреть на http://hpaste.org/10923 и загрузить на http://www.updike.org/mpfr-broken.tar.gz
Я использую GHC 6.83 во FreeBSD 6 и GHC 6.8.2 в Mac OS X. Обратите внимание, что вам понадобится MPFR (протестированный с 2.3.2) с правильными путями (измените Makefile) для библиотек и заголовочных файлов ( вместе с таковыми из GMP), чтобы успешно скомпилировать это.
Вопросы
Почему работает версия C, но версия на Haskell не работает? Что еще мне не хватает при приближении к FFI? Я попробовал StablePtrs и получил точно такие же результаты.
Может ли кто-нибудь еще проверить, является ли это проблемой только для Mac / BSD, скомпилировав и выполнив мой код? (Работает ли код на 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]