켈 FFI/C MPFR 라이브러리 래퍼로 불황
-
05-07-2019 - |
문제
을 만들기 위해서는 임의의 정밀 부동 소수점/drop 에서 교체 위해 더블,해요 포장 MPFR 를 사용하 FFI 그러나에도 불구하고 내 모든 노력을 가장 간단한 비트의 코드 작동하지 않습니다.그것은 컴파일하고,그것을 실행하지만,그것은 충돌을 조롱한 후에 일하는 척한다.간단한 C 버전의 코드를 행복하게 인쇄 숫자"1"(640 소수 자릿수)의 총 10,000 번입니다.일 버전을 물었을 때,같은,조용히 부패한(?) 데이터 후 289 인쇄 밖의"1.0000...0000"후 385 인쇄 아웃,그것을 일으키는 주장 실패와 합니다.나는 손실에 대한 진행하는 방법에 디버깅 이 때문에 그것은"작업해야 합".
코드할 수 있습 숙독 http://hpaste.org/10923 에서 다운로드 http://www.updike.org/mpfr-broken.tar.gz
내가 사용하여 지 6.83on FreeBSD6GHC6.8.2Mac OS X.참고해야 합 MPFR(스 테스트 2.3.2)이 설치되어 있으로 올바른 경로(변경 Makefile)한 라이브러리 및 헤더 파일(사람들과 함께서 GMP)을 성공적으로 컴파일한다.
질문
왜 C 버전하지만,일켈 버전 플레이크까?무엇이 다른 나는 누락에 접근할 때 FFI?나 StablePtrs 고 했다 정확한 결과입니다.
할 수 있는 다른 사람을 확인하는 경우 이은 맥/BSD 만 문제가하여 컴파일하고 실행할 수 있는 내 코드는?(않 C 코드는"작품"일하는가?지 않는 메인 코드는"noworks"일하는가?) 할 수 있는 사람이 리눅스에서 윈도우 시도를 사용하여 컴파일을 실행하고 당신 동일한 결과를 얻을 수?
C 코드:(작동합니다.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);
}
}
켈 코드:(습니다.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...[쓰레기].
보자는 다음 작업:
main = do
setPrecisionDecimal 640
mapM_ (const $ c_set_signed_int (fromInteger 1) >>= c_show) [1..10000]
는 좁혀 문제가 부분의 one
는 어떻게든 사방에서 있습니다.보고서 출력 ghc -C
고 ghc -S
, 하지만,포함하여 모든니다.
Hmm, ./noworks +RTS -H1G
또한,고 ./noworks +RTS -k[n]k
, 을 위해,다양한 값의 [n]
, 입증 장애에서 다른 방법이 있습니다.
난 솔리드 리드,하지만 두 가지는 가능성을 뛰어 내 마:
- GMP 는 모 runtime 사용 MPFR 을 갖는 몇 가지 이상한 상호 작용
- 스택을 위한 공간은 C 함수 호출에 들어 런타임이 제한,그리고 MPFR 지 않을 다루는 아
는 말하고...는 이유 있는 당신의 자신의 바인딩 보다는 오히려 사용 HMPFR?
다른 팁
유다 Jacobsen 응답이에켈-카페 메일링 리스트:
이 알려진 문제 GHC 때문에의 방법으로 데이타 모델을 사용하 GMP 내부적으로(을 유지해 정수).
분명히 C 데이터 힙에 혼자서에 의해 들어에 기본적으로 모든 경우 를 제외하고 를 사용하는 코드 FFI 액세스 GMP 또는 C 라이브러리에 의존하는 GMP(같은 MPFR 고 싶었다는 것을 포함)를 사용합니다.방법을 사용하여 해결할 수 있습니다(고)하지만"오른쪽"이 방법은 것 중 하나에 해킹 GHC(하드)또는 시몬을 제거한 데이타 모델의 의존에 GMP(힘).
Aleš Bizjak,유지 관리자의 HMPFR 게시켈-카페 및 보여준을 유지하는 방법 들에서 제어할당의 사지(따라서 그들을 떠나,혼자는 대신 GCing 그들과 그들 건드리지):
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;
}
나를 위해,이것은 많은 보다 쉽게 결합하는 노력을 작성을 위한 보충 GMP 에서 구현하는 것이 유일한 대안이 될 경우 내가 정말 원하는 사용하는 라이브러리에 따라 달라집 GMP.