হাস্কেলের (^) এর আজব আচরণ


12

কেন GHCi নীচে ভুল উত্তর দেয়?

GHCi

λ> ((-20.24373193905347)^12)^2 - ((-20.24373193905347)^24)
4.503599627370496e15

Python3

>>> ((-20.24373193905347)**12)**2 - ((-20.24373193905347)**24)
0.0

আপডেট করুন আমি নীচে হাস্কেলের ('s) ফাংশনটি প্রয়োগ করব implement

powerXY :: Double -> Int -> Double
powerXY x 0 = 1
powerXY x y
    | y < 0 = powerXY (1/x) (-y)
    | otherwise = 
        let z = powerXY x (y `div` 2)
        in  if odd y then z*z*x else z*z

main = do 
    let x = -20.24373193905347
    print $ powerXY (powerXY x 12) 2 - powerXY x 24 -- 0
    print $ ((x^12)^2) - (x ^ 24) -- 4.503599627370496e15

যদিও আমার সংস্করণটি @ উইলেমভ্যানঅনসেমের নীচে প্রদত্ত কোনওটির চেয়ে বেশি সঠিক বলে মনে হচ্ছে না, তবুও এটি আশ্চর্যরূপে কমপক্ষে এই বিশেষ ক্ষেত্রে সঠিক উত্তর দেয়।

পাইথনও একই রকম।

def pw(x, y):
    if y < 0:
        return pw(1/x, -y)
    if y == 0:
        return 1
    z = pw(x, y//2)
    if y % 2 == 1:
        return z*z*x
    else:
        return z*z

# prints 0.0
print(pw(pw(-20.24373193905347, 12), 2) - pw(-20.24373193905347, 24))

এটি ম্যান্টিসার একটি ত্রুটি। a^24আনুমানিক হয় 2.2437e31, এবং এইভাবে এটি তৈরি করে এমন একটি গোলাকার ত্রুটি রয়েছে।
উইলেম ভ্যান অনসেম

আমি বুঝতে পারছি না। জিএইচসিতে কেন রাউন্ডিং ত্রুটি রয়েছে?
এলোমেলো বউ

এর সাথে জিসিসি-র কোনও সম্পর্ক নেই, ভাসমান পয়েন্ট ইউনিটটি কীভাবে ভাসমান পরিচালনা করে তা কেবল এটি।
উইলেম ভ্যান অনসেম

1
এটি সংখ্যার মধ্যে 2.243746917640863e31 - 2.2437469176408626e31একটি ছোট গোলাকৃতি ত্রুটি রয়েছে যা প্রশস্ত হয়। দেখে মনে হচ্ছে একটি বাতিল হওয়া ইস্যু।
চি

2
সম্ভবত অজগর ক্ষয়ক্ষতির জন্য একটি পৃথক অ্যালগরিদম ব্যবহার করে, যা এই ক্ষেত্রে আরও সুনির্দিষ্ট? সাধারণভাবে, আপনি যে ভাষা ব্যবহার করেন তা নির্বিশেষে ভাসমান পয়েন্ট অপারেশনগুলি কিছু গোলাকার ত্রুটি প্রদর্শন করে। তবুও, দুটি অ্যালগরিদমের মধ্যে পার্থক্য বোঝা আকর্ষণীয় হতে পারে।
চি

উত্তর:


14

সংক্ষিপ্ত উত্তর : (^) :: (Num a, Integral b) => a -> b -> aএবং এর মধ্যে পার্থক্য রয়েছে (**) :: Floating a => a -> a -> a

(^)ফাংশন শুধুমাত্র অবিচ্ছেদ্য বহিঃপ্রকাশ কাজ করে। এটি সাধারণত একটি পুনরাবৃত্ত অ্যালগরিদম ব্যবহার করবে যা প্রতিবার শক্তিটি দুটি দ্বারা বিভাজ্য কিনা তা পরীক্ষা করে দেখবে এবং শক্তিকে দুটি দ্বারা বিভক্ত করে (এবং যদি বিভাজকটি ফলাফলটির সাথে গুণিত হয় x)। এর অর্থ 12এটির জন্য এটি মোট ছয়টি গুণকে সম্পাদন করবে । গুণটির যদি নির্দিষ্ট গোলাকরণ বন্ধ ত্রুটি থাকে, তবে ত্রুটিটি "বিস্ফোরিত" হতে পারে। আমরা সোর্স কোডটিতে দেখতে পাচ্ছি , (^)ফাংশনটি এইভাবে প্রয়োগ করা হয়েছে :

(^) :: (Num a, Integral b) => a -> b -> a
x0 ^ y0 | y0 < 0    = errorWithoutStackTrace "Negative exponent"
        | y0 == 0   = 1
        | otherwise = f x0 y0
    where -- f : x0 ^ y0 = x ^ y
          f x y | even y    = f (x * x) (y `quot` 2)
                | y == 1    = x
                | otherwise = g (x * x) (y `quot` 2) x         -- See Note [Half of y - 1]
          -- g : x0 ^ y0 = (x ^ y) * z
          g x y z | even y = g (x * x) (y `quot` 2) z
                  | y == 1 = x * z
                  | otherwise = g (x * x) (y `quot` 2) (x * z) -- See Note [Half of y - 1]

(**)ফাংশন জন্য অন্তত হয় Floats এবং Doubleফ্লোটিং পয়েন্ট ইউনিট কাজ করার বাস্তবায়িত s। প্রকৃতপক্ষে, আমরা যদি এর বাস্তবায়নটি একবার (**)দেখে নিই তবে আমরা দেখতে পাই:

instance Floating Float where
    -- …
    (**) x y = powerFloat x y
    -- …

এটি ফাংশনটিতে পুনঃনির্দেশ powerFloat# :: Float# -> Float# -> Float#করে, যা সাধারণত সংকলক দ্বারা সংশ্লিষ্ট এফপিইউ অপারেশনের সাথে যুক্ত হবে।

যদি আমরা এর (**)পরিবর্তে ব্যবহার করি তবে আমরা একটি 64-বিট ভাসমান পয়েন্ট ইউনিটের জন্য শূন্যটিও পাই:

Prelude> (a**12)**2 - a**24
0.0

উদাহরণস্বরূপ আমরা পাইথনে পুনরাবৃত্ত অ্যালগরিদমটি প্রয়োগ করতে পারি:

def pw(x0, y0):
    if y0 < 0:
        raise Error()
    if y0 == 0:
        return 1
    return f(x0, y0)


def f(x, y):
    if (y % 2 == 0):
        return f(x*x, y//2)
    if y == 1:
        return x
    return g(x*x, y // 2, x)


def g(x, y, z):
    if (y % 2 == 0):
        return g(x*x, y//2, z)
    if y == 1:
        return x*z
    return g(x*x, y//2, x*z)

তারপরে যদি আমরা একই অপারেশন করি তবে আমি স্থানীয়ভাবে পেলাম:

>>> pw(pw(-20.24373193905347, 12), 2) - pw(-20.24373193905347, 24)
4503599627370496.0

আমরা (^)জিএইচসিআই-তে যা পাই তার সমান মান ।


1
পাইথনে প্রয়োগ করার সময় (^) এর পুনরাবৃত্ত অ্যালগরিদম এই বৃত্তাকার ত্রুটি দেয় না। (*) কি হাস্কেল এবং পাইথনে আলাদা?
এলোমেলো বোন

@ র্যান্ডমডুড: যতদূর আমি জানি, pow(..)পাইথনের ফাংশনটিতে কেবল "ইনট / লং" এর জন্য একটি নির্দিষ্ট অ্যালগরিদম রয়েছে , ভাসমানদের জন্য নয়। ভাসমানদের জন্য, এটি এফপিইউর শক্তিতে "ফ্যালব্যাক" করবে।
উইলেম ভ্যান অনসেম

আমার অর্থ যখন আমি পাইথনে (*) ব্যবহার করে পাওয়ার ফাংশনটি বাস্তবায়িত করি ঠিক তেমনিভাবে হাস্কেলের প্রয়োগ (^) প্রয়োগ করে। আমি pow()ফাংশন ব্যবহার করছি না ।
এলোমেলো বন্ধু

2
@ র্যান্ডমডুড: আমি পাইথনে অ্যালগরিদম বাস্তবায়ন করেছি এবং জিএইচসি-র মতো একই মান অর্জন করেছি।
উইলেম ভ্যান অনসেম

1
হাস্কেল এবং পাইথনের আমার সংস্করণ (^) এর সাথে আমার প্রশ্ন আপডেট করেছে। ভাবনা দয়া করে?
এলোমেলো বন্ধু
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.