سؤال

من أجل إنشاء نقطة عائمة/إسقاط دقة تعسفية بدلاً من 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، ولكن إصدار هاسكل يتقشر؟ما الذي أفتقده أيضًا عند التواصل مع المؤسسة المالية الأجنبية؟لقد قمت بتجريب StablePtrs وحصلت على نفس النتائج بالضبط.

  • هل يمكن لشخص آخر التحقق مما إذا كانت هذه مشكلة Mac/BSD فقط عن طريق تجميع الكود الخاص بي وتشغيله؟(هل يعمل رمز C؟هل يعمل رمز Haskell "noworks"؟) هل يمكن لأي شخص على Linux وWindows محاولة التجميع/التشغيل ومعرفة ما إذا كنت ستحصل على نفس النتائج؟

كود ج:(يعمل.ج)

#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);
    }  
}  

كود هاسكل:(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]  
هل كانت مفيدة؟

المحلول

أرى المشكلة أيضا، على

$ 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, ومع ذلك، لا يعطيني أي تلميحات.

همم، ./noworks +RTS -H1G يعمل أيضا، و ./noworks +RTS -k[n]k, ، لقيم متفاوتة [n], ، إظهار الفشل بطرق مختلفة.

ليس لدي أي خيوط قوية، ولكن هناك احتمالان يتبادران إلى ذهني:

  • GMP، الذي يستخدمه وقت تشغيل GHC، و MPFR له بعض التفاعل الغريب
  • مساحة المكدس لوظائف C التي يتم استدعاؤها خلال وقت تشغيل GHC محدودة، ولا يتعامل MPFR بشكل جيد

ما قيل...هل هناك سبب وراء قيامك بتدوير الروابط الخاصة بك بدلاً من استخدامها همبفر?

نصائح أخرى

أجاب يهوذا جاكوبسن على هذا في القائمة البريدية لمقهى هاسكل:

هذا هو مشكلة معروفة مع GHC بسبب الطريقة التي تستخدم بها GHC ممارسات التصنيع الجيدة داخليًا (للحفاظ على الأعداد الصحيحة).

من الواضح أن بيانات C الموجودة في الكومة يتم تركها بمفردها بواسطة GHC في جميع الحالات بشكل أساسي يستثني الكود الذي يستخدم FFI للوصول إلى GMP أو أي مكتبة C تعتمد على GMP (مثل MPFR الذي أردت استخدامه).هناك بعض الحلول (مؤلمة) ولكن الطريقة "الصحيحة" ستكون إما اختراق GHC (صعب) أو جعل Simons يزيل اعتماد GHC على GMP (أصعب).

أليس بزجاك، مشرف همبفر تم النشر في haskell-cafe وأوضح كيفية منع GHC من التحكم في تخصيص الأطراف (وبالتالي تركها بمفردها، بدلاً من ربطها وضربها):

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 في GHC، والذي سيكون البديل الوحيد إذا كنت أرغب حقًا في استخدام أي مكتبة تعتمد على GMP.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top