যোগফলের অর্ডার পরিবর্তন করা কেন আলাদা ফলাফল দেয়?


294

যোগফলের অর্ডার পরিবর্তন করা কেন আলাদা ফলাফল দেয়?

23.53 + 5.88 + 17.64 = 47.05

23.53 + 17.64 + 5.88 = 47.050000000000004

উভয় জাভা এবং জাভাস্ক্রিপ্ট একই ফলাফল দেয়।

আমি বুঝতে পারি যে, ভাসমান পয়েন্ট সংখ্যাগুলি বাইনারি হিসাবে উপস্থাপন করার কারণে কিছু যুক্তিযুক্ত সংখ্যা ( যেমন 1/3 - 0.333333 ... ) যথাযথভাবে উপস্থাপন করা যায় না।

কেন কেবল উপাদানগুলির ক্রম পরিবর্তন করে ফলাফলকে প্রভাবিত করে?


28
আসল সংখ্যার যোগফল হ'ল সংঘবদ্ধ এবং ভ্রমণকারী। ভাসমান-পয়েন্টগুলি আসল সংখ্যা নয়। বাস্তবে আপনি কেবল প্রমাণ করেছেন যে তাদের ক্রিয়াকলাপগুলি পরিবহণমূলক নয়। এগুলি দেখানো খুব সহজ যে তারা খুব সাহসীও নয় (উদাঃ (2.0^53 + 1) - 1 == 2.0^53 - 1 != 2^53 == 2^53 + (1 - 1))। সুতরাং, হ্যাঁ: অঙ্কগুলি এবং অন্যান্য ক্রিয়াকলাপের ক্রমটি বেছে নেওয়ার ক্ষেত্রে সতর্ক থাকুন। কিছু ভাষা "উচ্চ-নির্ভুলতা" যোগফলগুলি (উদাহরণস্বরূপ পাইথনের math.fsum) সঞ্চালনের জন্য অন্তর্নির্মিত সরবরাহ করে , তাই আপনি নিষ্পাপ যোগ অ্যালগোরিদমের পরিবর্তে এই ফাংশনগুলি ব্যবহার করার বিষয়ে বিবেচনা করতে পারেন।
বাকুরিউ

1
@RBerteig এটি গাণিতিক অভিব্যক্তির জন্য ভাষার ক্রিয়াকলাপের ক্রমটি পরীক্ষা করে নির্ধারিত হতে পারে এবং যদি না তাদের স্মৃতিতে ভাসমান পয়েন্ট সংখ্যার প্রতিনিধিত্ব আলাদা না হয়, তবে যদি তাদের অপারেটর অগ্রাধিকারের নিয়মগুলি একই হয় তবে ফলাফলগুলি একই হবে। নোটের আরেকটি বিষয়: আমি অবাক হয়েছি যে ব্যাংকগুলি অ্যাপ্লিকেশন বিকাশকারী ডেভসগুলি এটি খুঁজে পেতে কতক্ষণ সময় নিয়েছিল? সেই অতিরিক্ত 0000000000004 সেন্ট সত্যিই যুক্ত!
ক্রিস সাইরেফাইস

3
@ ক্রিসক্রাইফাইস: আপনার যদি 0.00000004 সেন্ট থাকে তবে আপনি এটি ভুল করছেন। আর্থিক গণনার জন্য আপনার কখনই বাইনারি ভাসমান বিন্দু ব্যবহার করা উচিত নয়
ড্যানিয়েল প্রাইডেন

2
@ ড্যানিয়েলপ্রাইডেন আহা হায়, এটি একটি রসিকতা ছিল ... কেবল এই ধারণাটি ছড়িয়ে দিয়েছিলেন যে লোকেরা যাঁকে এই ধরণের সমস্যার সমাধান করতে হবে তাদের সবচেয়ে গুরুত্বপূর্ণ একটি চাকরি ছিল যা আপনি জানেন, জনগণের আর্থিক অবস্থান ধরে রেখেছিল এবং এই সমস্ত কিছু । আমি খুব ব্যঙ্গাত্মক হয়ে
উঠছিলাম

উত্তর:


276

হতে পারে এই প্রশ্নটি মূ ?়, তবে কেবলমাত্র উপাদানগুলির ক্রম পরিবর্তন করে ফলাফলকে প্রভাবিত করে কেন?

এটি তাদের প্রস্থের উপর ভিত্তি করে মানগুলিকে গোল করার পয়েন্টগুলিকে পরিবর্তন করবে। আমরা যে ধরণের জিনিসটি দেখছি তার উদাহরণ হিসাবে , চলুন যে ভান করা যায় বাইনারি ফ্লোটিং পয়েন্টের পরিবর্তে আমরা একটি দশমিক ভাসমান পয়েন্ট টাইপ ব্যবহার করেছিলাম 4 টি উল্লেখযোগ্য অঙ্ক সহ যেখানে প্রতিটি সংযোজন "অসীম" নির্ভুলতায় সম্পাদিত হয় এবং তারপরে গোল করা হয় নিকটতম প্রতিনিধিত্বযোগ্য সংখ্যা। এখানে দুটি যোগফল রয়েছে:

1/3 + 2/3 + 2/3 = (0.3333 + 0.6667) + 0.6667
                = 1.000 + 0.6667 (no rounding needed!)
                = 1.667 (where 1.6667 is rounded to 1.667)

2/3 + 2/3 + 1/3 = (0.6667 + 0.6667) + 0.3333
                = 1.333 + 0.3333 (where 1.3334 is rounded to 1.333)
                = 1.666 (where 1.6663 is rounded to 1.666)

এটির সমস্যা হওয়ার জন্য আমাদের অ-পূর্ণসংখ্যারও প্রয়োজন নেই:

10000 + 1 - 10000 = (10000 + 1) - 10000
                  = 10000 - 10000 (where 10001 is rounded to 10000)
                  = 0

10000 - 10000 + 1 = (10000 - 10000) + 1
                  = 0 + 1
                  = 1

এটি সম্ভবত আরও স্পষ্টভাবে প্রমাণ করে যে গুরুত্বপূর্ণ অংশটি হ'ল আমাদের কাছে সীমিত সংখ্যক উল্লেখযোগ্য সংখ্যা রয়েছে - দশমিক জায়গার সীমিত সংখ্যার নয় । যদি আমরা সর্বদা দশমিক স্থান একই সংখ্যায় রাখতে পারি, তবে কমপক্ষে সংযোজন এবং বিয়োগফলের সাথে আমরা ভাল থাকব (এত দিন মানগুলি উপচে পড়েনি)। সমস্যাটি হ'ল আপনি যখন বড় সংখ্যায় পৌঁছে যান, ছোট তথ্য হারিয়ে যায় - 10001 এই ক্ষেত্রে গোল হয়ে 10000 হয়ে যায়। ( এরিক লিপার্ট তার উত্তরে যে সমস্যার উল্লেখ করেছেন এটি এটি উদাহরণ ।)

এটি লক্ষ করা গুরুত্বপূর্ণ যে ডান হাতের প্রথম লাইনের মানগুলি সমস্ত ক্ষেত্রে একই রকম - তবে এটি আপনার পক্ষে দশমিক সংখ্যা (২৩.৫৩, ৫.৮৮, ১ 17.44) হুবহু প্রদর্শিত হবে না তা বোঝা গুরুত্বপূর্ণ double মান that's উপরের সমস্যাগুলির কারণে কেবল একটি সমস্যা।


10
May extend this later - out of time right now!@Jon জন্য সাগ্রহে অপেক্ষা
Prateek

3
যখন আমি বলি যে আমি পরে কোনও জবাব ফিরে পাব তখন সম্প্রদায়টি আমার প্রতি কিছুটা কম দয়া করে <আমি মজা করছি এবং কোন ঝাঁকুনি নয়> দেখানোর জন্য এখানে কিছু ধরণের হালকা হৃদয়ের ইমোটিকন প্রবেশ করুন ... ... এটি পরে ফিরে আসবে।
গ্রেডি প্লেয়ার

2
@ জোংজেংলি: যদিও এটি বোঝার পক্ষে এটি অবশ্যই গুরুত্বপূর্ণ তবে এই ক্ষেত্রে এটি মূল কারণ নয়। আপনি মান যা দিয়ে একটি অনুরূপ উদাহরণ লিখতে পারে হয় ঠিক বাইনারি প্রতিনিধিত্ব, এবং একই প্রভাব দেখুন। এখানে সমস্যাটি একই সাথে বড় আকারের তথ্য এবং ছোট আকারের তথ্য বজায় রাখছে।
জন স্কিটি

1
@ বুকসী: 10000 তে গোল হয়েছে - কারণ আমরা এমন একটি ডেটাটাইপ নিয়ে কাজ করছি যা কেবলমাত্র 4 টি উল্লেখযোগ্য অঙ্ক সঞ্চয় করতে পারে। (সুতরাং x.xxx * 10 ^ n)
জন স্কিটি

3
@ প্রবীণরা: না, এটি একটি উপচে পড়ার কারণ নয় - এবং আপনি ভুল সংখ্যা ব্যবহার করছেন। এটি 10001 এর সাথে গোল করা হচ্ছে 10000 নয়, এটি 1001 এর সাথে গোল করা হয়েছে। এটি আরও পরিষ্কার করার জন্য, 54321কে গোল করা হবে 54320 - কারণ এতে কেবল চারটি উল্লেখযোগ্য সংখ্যা রয়েছে। "চারটি উল্লেখযোগ্য অঙ্ক" এবং "সর্বোচ্চ 9999 এর মান" এর মধ্যে একটি বড় পার্থক্য রয়েছে। আমি আগেই বলেছি, আপনি মূলত x.xxx * 10 ^ n প্রতিনিধিত্ব করছেন যেখানে 10000, x.xxx হবে 1.000, এবং এন 4 হবে This এটি ঠিক এর মতো doubleএবং floatযেখানে খুব বড় সংখ্যক জন্য পরপর প্রতিনিধিত্বযোগ্য সংখ্যার জন্য 1 এরও বেশি আলাদা।
জন স্কিটি

52

বাইনারি কী হচ্ছে তা এখানে। যেমনটি আমরা জানি, কিছু ভাসমান-পয়েন্টের মানগুলি বাইনারিতে হুবহু উপস্থাপন করা যায় না, এমনকি যদি সেগুলি দশমিক ক্ষেত্রেও ঠিক উপস্থাপন করা যায়। এই 3 টি সংখ্যা সেই বাস্তবতার উদাহরণ মাত্র।

এই প্রোগ্রামটির সাথে আমি প্রতিটি সংখ্যার হেক্সাডেসিমাল উপস্থাপনা এবং প্রতিটি সংযোজনের ফলাফল আউটপুট করি।

public class Main{
   public static void main(String args[]) {
      double x = 23.53;   // Inexact representation
      double y = 5.88;    // Inexact representation
      double z = 17.64;   // Inexact representation
      double s = 47.05;   // What math tells us the sum should be; still inexact

      printValueAndInHex(x);
      printValueAndInHex(y);
      printValueAndInHex(z);
      printValueAndInHex(s);

      System.out.println("--------");

      double t1 = x + y;
      printValueAndInHex(t1);
      t1 = t1 + z;
      printValueAndInHex(t1);

      System.out.println("--------");

      double t2 = x + z;
      printValueAndInHex(t2);
      t2 = t2 + y;
      printValueAndInHex(t2);
   }

   private static void printValueAndInHex(double d)
   {
      System.out.println(Long.toHexString(Double.doubleToLongBits(d)) + ": " + d);
   }
}

দ্য printValueAndInHexপদ্ধতি মাত্র একটি হেক্স-প্রিন্টার সাহায্যকারী নেই।

আউটপুট নিম্নরূপ:

403787ae147ae148: 23.53
4017851eb851eb85: 5.88
4031a3d70a3d70a4: 17.64
4047866666666666: 47.05
--------
403d68f5c28f5c29: 29.41
4047866666666666: 47.05
--------
404495c28f5c28f6: 41.17
4047866666666667: 47.050000000000004

প্রথম 4 সংখ্যা x, y, z, এবং sএর হেক্সাডেসিমেল উপস্থাপনা। আইইইইই ভাসমান পয়েন্ট উপস্থাপনায়, বিট 2-12 বাইনারি এক্সপোনেন্টকে প্রতিনিধিত্ব করে , যা সংখ্যার স্কেল। (প্রথম বিটটি হ'ল সাইন বিট এবং ম্যান্টিসার বাকী বিট )) উপস্থাপকটি হ'ল আসলে বাইনারি সংখ্যা বিয়োগ 1023।

প্রথম 4 টি সংখ্যার জন্য এক্সটেন্ডারগুলি বের করা হয়:

    sign|exponent
403 => 0|100 0000 0011| => 1027 - 1023 = 4
401 => 0|100 0000 0001| => 1025 - 1023 = 2
403 => 0|100 0000 0011| => 1027 - 1023 = 4
404 => 0|100 0000 0100| => 1028 - 1023 = 5

সংযোজনের প্রথম সেট

দ্বিতীয় সংখ্যাটি ( y) ছোট আকারের। এই দুটি সংখ্যা পেতে যোগ করার সময় x + y, দ্বিতীয় সংখ্যা ( 01) এর শেষ 2 বিটগুলি সীমার বাইরে চলে যায় এবং গণনাটির মধ্যে থাকে না।

দ্বিতীয় সংযোজন যোগ করে x + yএবং zএকই স্কেলের দুটি সংখ্যা যুক্ত করে।

সংযোজন দ্বিতীয় সেট

এখানে, x + zপ্রথম ঘটে। এগুলি একই স্কেলের, তবে তারা এমন একটি সংখ্যা দেয় যা স্কেলের চেয়ে বেশি:

404 => 0|100 0000 0100| => 1028 - 1023 = 5

দ্বিতীয় সংযোজন যোগ করে x + zএবং y, এবং এখন 3 টি বিটগুলি yসংখ্যা ( 101) যুক্ত করতে বাদ দেওয়া হয় । এখানে অবশ্যই উপরে একটি বৃত্তাকার হতে হবে, কারণ ফলাফলটি পরবর্তী ভাসমান পয়েন্ট নম্বর আপ: 4047866666666666বনাম সংযোজনের প্রথম সেটটির জন্য4047866666666667 দ্বিতীয় সেটের জন্য জন্য। মোট প্রিন্টআউটে প্রদর্শিত ত্রুটিটি যথেষ্ট তাৎপর্যপূর্ণ।

উপসংহারে, আইইইই সংখ্যাতে গাণিতিক ক্রিয়াকলাপ সম্পাদন করার সময় সতর্কতা অবলম্বন করুন। কিছু উপস্থাপনা নিখুঁত হয় এবং স্কেলগুলি পৃথক হয়ে গেলে সেগুলি আরও নিখুঁত হয়। আপনি যদি পারেন তবে অনুরূপ স্কেলের সংখ্যাগুলি বিয়োগ করুন।


স্কেলগুলি পৃথক হওয়া গুরুত্বপূর্ণ অংশ। বাইনারি ইনপুট হিসাবে প্রতিনিধিত্ব করা হচ্ছে যে সঠিক মান আপনি লিখতে পারেন (দশমিকভাবে) এবং এখনও একই সমস্যা আছে।
জন স্কিটি

@ আরজেটম্যান একজন প্রোগ্রামার হিসাবে আমি আপনার উত্তরটি =)আপনার হেক্স-প্রিন্টার সহায়কটির জন্য আরও ভাল পছন্দ করি ... এটি সত্যই পরিষ্কার!
ADTC

44

জনের উত্তর অবশ্যই সঠিক। আপনার ক্ষেত্রে ত্রুটিটি ত্রুটিটির চেয়ে বড় নয় যে কোনও সহজ ভাসমান পয়েন্ট অপারেশন করে আপনি ত্রুটি সংগ্রহ করবেন। আপনি এমন একটি দৃশ্য পেয়েছেন যেখানে এক ক্ষেত্রে আপনি শূন্য ত্রুটি পান এবং অন্য ক্ষেত্রে আপনি একটি ক্ষুদ্র ত্রুটি পান; এটি আসলে তেমন আকর্ষণীয় একটি দৃশ্য নয়। একটি ভাল প্রশ্ন হ'ল: এমন কোনও দৃশ্য আছে যেখানে গণনার ক্রম পরিবর্তন করা একটি ক্ষুদ্র ত্রুটি থেকে একটি (অপেক্ষাকৃত) প্রবল ত্রুটিতে চলে যায়?উত্তরটি দ্ব্যর্থহীনভাবে হ্যাঁ।

উদাহরণস্বরূপ বিবেচনা করুন:

x1 = (a - b) + (c - d) + (e - f) + (g - h);

বনাম

x2 = (a + c + e + g) - (b + d + f + h);

বনাম

x3 = a - b + c - d + e - f + g - h;

স্পষ্টতই গণিতের ক্ষেত্রে তারা একই হবে। একটি, বি, সি, ডি, ই, এফ, জি, এইচ এর জন্য x1 এবং x2 এবং x3 এর মানগুলি একটি বৃহত পরিমাণে পৃথক হওয়ার জন্য মানগুলি খুঁজে বার করার জন্য এটি মজাদার। আপনি যদি এটি করতে পারেন কিনা দেখুন!


আপনি কিভাবে একটি বৃহত পরিমাণ নির্ধারণ করবেন? আমরা কি 1000 তম অর্ডারে কথা বলছি? 100ths? 1 এর ???
ক্রুঙ্কার

3
@ ক্রাঙ্কার: সঠিক গাণিতিক ফলাফল এবং এক্স 1 এবং এক্স 2 মানগুলি গণনা করুন। সত্য এবং গণিত ফলাফল ই 1 এবং ই 2 এর মধ্যে সঠিক গাণিতিক পার্থক্যটি কল করুন। ত্রুটির আকার সম্পর্কে চিন্তা করার এখন বেশ কয়েকটি উপায় রয়েছে। প্রথমটি হ'ল: আপনি এমন কোনও দৃশ্যের সন্ধান করতে পারেন যেখানে | ই 1 / ই 2 | বা | ই 2 / ই 1 | বড় হয়? পছন্দ করুন, আপনি কি দশ বারের ত্রুটিটিকে অন্যটির ত্রুটি করতে পারেন? তবে আরও আকর্ষণীয় হ'ল যদি আপনি কোনওটির ত্রুটিটিকে সঠিক উত্তরের আকারের একটি উল্লেখযোগ্য ভগ্নাংশ তৈরি করতে পারেন।
এরিক লিপার্ট

1
আমি বুঝতে পেরেছি যে তিনি রানটাইম সম্পর্কে কথা বলছেন, তবে আমি অবাক হই: অভিব্যক্তিটি যদি একটি সংকলন-সময় (বলুন, কনস্টেক্সপ্র) হয়ে থাকে তবে সংযোজকগুলি ত্রুটিটি হ্রাস করতে যথেষ্ট স্মার্ট হয়?
কেভিন হু

@ কেভিনহসু সাধারণ নং, সংকলকটি তেমন স্মার্ট নয়। অবশ্যই সংকলকটি যদি এটি পছন্দ করে তবে সঠিক গাণিতিকভাবে অপারেশন করতে বেছে নিতে পারে, তবে এটি সাধারণত তা করে না।
এরিক লিপার্ট

8
@ ফ্রোজেনকোই: হ্যাঁ, ত্রুটিটি খুব সহজেই অসীম হতে পারে। উদাহরণস্বরূপ, সি # বিবেচনা করুন: double d = double.MaxValue; Console.WriteLine(d + d - d - d); Console.WriteLine(d - d + d - d);- আউটপুটটি ইনফিনিটি হয় 0 0
জন স্কিটি

10

এটি আসলে জাভা এবং জাভাস্ক্রিপ্টের চেয়ে অনেক বেশি কভার করে এবং সম্ভবত ফ্লোট বা ডাবল ব্যবহার করে যে কোনও প্রোগ্রামিং ভাষার উপর প্রভাব ফেলবে affect

স্মৃতিতে, ভাসমান পয়েন্টগুলি আইইইই 754 এর লাইন ধরে একটি বিশেষ ফর্ম্যাট ব্যবহার করে (কনভার্টারটি আমার চেয়ে আরও ভাল ব্যাখ্যা সরবরাহ করে)।

যাইহোক, এখানে ভাসমান রূপান্তরকারী।

http://www.h-schmidt.net/FloatConverter/

ক্রিয়াকলাপের ক্রম সম্পর্কিত বিষয়টি হ'ল অপারেশনের "সূক্ষ্মতা"।

আপনার প্রথম লাইনটি প্রথম দুটি মান থেকে 29.41 উপার্জন করে, যা আমাদেরকে ঘাঁটি হিসাবে 2 ^ 4 দেয়।

আপনার দ্বিতীয় লাইনটি 41.17 দেয় যা আমাদেরকে 2 onent 5 ব্যয়কারী হিসাবে দেয়।

আমরা ব্যয় বাড়িয়ে একটি উল্লেখযোগ্য চিত্র হারাচ্ছি, যার ফলে ফলাফলটি পরিবর্তিত হওয়ার সম্ভাবনা রয়েছে।

৪১.১ the এর জন্য ডানদিকে এবং ডানদিকে সর্বশেষ বিটটি টিক দেওয়ার চেষ্টা করুন এবং আপনি দেখতে পাচ্ছেন যে ক্ষুদ্রের 1/2 ^ 23 হিসাবে "তুচ্ছ" হিসাবে কিছু এই ভাসমান পয়েন্ট পার্থক্যের জন্য যথেষ্ট হবে।

সম্পাদনা: আপনারা যারা উল্লেখযোগ্য পরিসংখ্যান মনে রাখেন তাদের ক্ষেত্রে এটি এই বিভাগের অধীনে চলে আসবে। 1 এর উল্লেখযোগ্য চিত্র সহ 10 ^ 4 + 4999 হতে চলেছে 10 ^ 4। এই ক্ষেত্রে, উল্লেখযোগ্য চিত্রটি অনেক ছোট, তবে আমরা এর সাথে সংযুক্ত .00000000004 সহ ফলাফল দেখতে পাচ্ছি।


9

আইআইইই 754 ফর্ম্যাট ব্যবহার করে ভাসমান পয়েন্ট সংখ্যাগুলি প্রতিনিধিত্ব করা হয়, যা ম্যান্টিসার জন্য একটি নির্দিষ্ট আকারের বিট সরবরাহ করে (তাৎপর্য)। দুর্ভাগ্যক্রমে এটি আপনাকে খেলতে নির্দিষ্ট সংখ্যক 'ভগ্নাংশ বিল্ডিং ব্লকস' দেয় এবং নির্দিষ্ট কিছু ভগ্নাংশের মানটি যথাযথভাবে উপস্থাপন করা যায় না।

আপনার ক্ষেত্রে যা ঘটছে তা হ'ল দ্বিতীয় ক্ষেত্রে, সংযোজনগুলি মূল্যায়ন করার আদেশের কারণে সংযোজনটি সম্ভবত কিছু সূক্ষ্ম ইস্যুতে চলছে। আমি মানগুলি গণনা করি নি, তবে এটি উদাহরণস্বরূপ হতে পারে যে 23.53 + 17.64 যথাযথভাবে উপস্থাপন করা যায় না, যখন 23.53 + 5.88 পারে।

দুর্ভাগ্যক্রমে এটি একটি পরিচিত সমস্যা যা আপনাকে কেবল মোকাবেলা করতে হবে।


6

আমি বিশ্বাস করি এটি বিবর্তনের আদেশের সাথে সম্পর্কযুক্ত। যদিও অঙ্কটি গণিত বিশ্বে স্বাভাবিকভাবে সমান হয়, বাইনারি জগতে A + B + C = D এর পরিবর্তে এটি হয়

A + B = E
E + C = D(1)

সুতরাং যে দ্বিতীয় পদক্ষেপ আছে যেখানে ভাসমান পয়েন্ট নম্বর বন্ধ পেতে পারেন।

আপনি যখন আদেশ পরিবর্তন করেন,

A + C = F
F + B = D(2)

4
আমি মনে করি এই উত্তরটি আসল কারণটিকে এড়িয়ে চলে। "সেই দ্বিতীয় পদক্ষেপটি যেখানে ভাসমান পয়েন্ট সংখ্যাগুলি নামতে পারে"। স্পষ্টতই, এটি সত্য, তবে আমরা কী ব্যাখ্যা করতে চাই তা কেন
জং
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.