সর্বাধিক সুনির্দিষ্ট ফলাফল পেতে কোন আদেশে ফ্লোট যুক্ত করা উচিত?


105

এটি আমার সাম্প্রতিক সাক্ষাত্কারে আমাকে জিজ্ঞাসা করা হয়েছিল এবং আমি জানতে চাই (আমি সংখ্যার বিশ্লেষণের তত্ত্বটি আসলে মনে করি না, তাই দয়া করে আমাকে সহায়তা করুন :)

আমাদের যদি কিছু ফাংশন থাকে যা ভাসমান-পয়েন্ট সংখ্যাগুলি জমে:

std::accumulate(v.begin(), v.end(), 0.0);

vএকটি হল std::vector<float>উদাহরণস্বরূপ,।

  • এই সংখ্যাগুলি সঞ্চারের আগে এগুলি বাছাই করা ভাল?

  • কোন আদেশ সবচেয়ে সুনির্দিষ্ট উত্তর দিতে হবে?

আমি সন্দেহ করি যে আরোহী ক্রম অনুসারে সংখ্যাগুলি বাছাই করা আসলে সংখ্যাসূচক ত্রুটি কমিয়ে দেবে , তবে দুর্ভাগ্যক্রমে আমি নিজেকে এটি প্রমাণ করতে পারি না।

পিএস আমি বুঝতে পারি এটির সত্যিকারের প্রোগ্রামিংয়ের সাথে সম্ভবত কিছু করার নেই, কেবল কৌতূহলী হওয়া।


17
রিয়েল-ওয়ার্ল্ড প্রোগ্রামিংয়ের সাথে এটির আসলে কিছুই রয়েছে। যাইহোক, অনেক অ্যাপ্লিকেশন যতক্ষণ না এটি 'বেশ কাছাকাছি' যতক্ষণ না গণনার নিখুঁত সেরা নির্ভুলতা সম্পর্কে সত্যই যত্ন করে না। ইঞ্জিনিয়ারিং অ্যাপ্লিকেশন? খুবই গুরুত্বপূর্ণ. চিকিত্সা অ্যাপ্লিকেশন? খুবই গুরুত্বপূর্ণ. বড় আকারের পরিসংখ্যান? কিছুটা কম নির্ভুলতা গ্রহণযোগ্য।
জাইচিন

18
আপনি যতক্ষণ না জেনে থাকেন এবং কোনও পৃষ্ঠায় ইঙ্গিত করতে না পারলে দয়া করে উত্তর দিবেন না যাতে আপনার যুক্তি বিশদটি ব্যাখ্যা করে। আমরা ডন এর চারপাশে উড়তে ভাসমান পয়েন্ট সংখ্যাগুলি সম্পর্কে ইতিমধ্যে অনেক বাজে কথা রয়েছে; এটি এতে যুক্ত করতে চাই না। আপনি যদি ভাবেন আপনি জানেন। বন্ধ করুন। কারণ যদি আপনি কেবল ভাবেন যে আপনি জানেন তবে আপনি সম্ভবত ভুল।
মার্টিন ইয়র্ক

4
@ জ্যাচিন "ইঞ্জিনিয়ারিং অ্যাপ্লিকেশন? অত্যন্ত গুরুত্বপূর্ণ। চিকিত্সা অ্যাপ্লিকেশন? অত্যন্ত গুরুত্বপূর্ণ।" ??? আমার মনে হয় আপনি যদি তোমরা সত্যবাদী :) জানত বিস্মিত হবে
BЈовић

3
@ জায়েচিন নিখুঁত ত্রুটি অপ্রাসঙ্গিক। যা গুরুত্বপূর্ণ তা হ'ল আপেক্ষিক ত্রুটি। যদি কোনও রেডিয়ানের কয়েক শততম হয় 0.001%, তবে কে যত্ন করে?
BЈовић

3
আমি সত্যিই এই পড়ার পরামর্শ দিচ্ছি: "প্রতিটি কম্পিউটার বিজ্ঞানী ভাসমান পয়েন্ট সম্পর্কে যা জানতে হবে" perso.ens-lyon.fr/jean-michel.muller/goldberg.pdf
মোহাম্মদ আলাগান

উত্তর:


108

আপনার প্রবৃত্তিটি মূলত সঠিক, আরোহী ক্রম বাছাই (প্রস্থের) সাধারণত কিছুটা উন্নতি করে। কেসটি বিবেচনা করুন যেখানে আমরা একক নির্ভুলতা (32 বিট) ভাসমান যুক্ত করছি এবং এখানে 1 / বিলিয়ন মান 1 / (1 বিলিয়ন) এর সমান এবং 1 টির সমান মান রয়েছে যদি 1 প্রথম আসে, তবে যোগফল আসবে 1 এ, যেহেতু 1 + (1/1 বিলিয়ন) নির্ভুলতার ক্ষতি হওয়ার কারণে 1 হয় is প্রতিটি সংযোজন মোট মোটে কোন প্রভাব নেই।

যদি ছোট মানগুলি প্রথমে আসে তবে সেগুলি কমপক্ষে কিছু পরিমাণে যোগ হবে, যদিও তার পরেও আমার মধ্যে তাদের মধ্যে 2 ^ 30 রয়েছে, যদিও 2 ^ 25 বা তার পরে আমি এমন পরিস্থিতিতে ফিরে এসেছি যেখানে প্রত্যেকে পৃথকভাবে মোটের উপর প্রভাব ফেলছে না আর কোন। সুতরাং আমি এখনও আরও কৌশল প্রয়োজন।

এটি একটি চূড়ান্ত ক্ষেত্রে, তবে সাধারণভাবে ভিন্ন ভিন্ন মাত্রার দুটি মান যুক্ত করার চেয়ে একই আকারের দুটি মান যুক্ত করা আরও সঠিক, কারণ আপনি যেভাবে ছোট মানটিতে নির্ভুলতার কম বিটগুলি "বাতিল" করেন। সংখ্যার বাছাই করে, আপনি একই আকারের মানগুলিকে একত্রে গোষ্ঠীভুক্ত করেন এবং এগুলি আরোহী ক্রমে যুক্ত করে আপনি ছোট মানগুলিকে বৃহত্তর সংখ্যার মাত্রায় একত্রে পৌঁছানোর "সুযোগ" দেন।

তবুও, যদি নেতিবাচক সংখ্যাগুলি জড়িত থাকে তবে এই পদ্ধতিকে "ছাপিয়ে যাওয়া" সহজ। যোগফল তিনটি মান বিবেচনা করুন {1, -1, 1 billionth}। গাণিতিকভাবে সঠিক যোগফল 1 billionth, তবে আমার প্রথম সংযোজনটিতে যদি ছোট মানটি জড়িত থাকে তবে আমার চূড়ান্ত যোগফল 0 হবে possible সম্ভাব্য 6 টি আদেশের মধ্যে কেবল 2 "সঠিক" - {1, -1, 1 billionth}এবং {-1, 1, 1 billionth}। সমস্ত 6 টি অর্ডার ফলাফল দেয় যা ইনপুট (0.0000001% আউট) এর বৃহত্তম-মানের মানের স্কেলগুলিতে নির্ভুল, তবে তাদের 4 টির জন্য ফলাফলটি সত্য সমাধানের স্কেল (100% আউট) এর ক্ষেত্রে সঠিক নয়। আপনি যে বিশেষ সমস্যাটি সমাধান করছেন সেটি আপনাকে জানিয়ে দেবে যে পূর্বেরটি যথেষ্ট ভাল কিনা।

প্রকৃতপক্ষে, আপনি এগুলি সাজানোর ক্রমে যুক্ত করার চেয়ে আরও অনেক কৌশল খেলতে পারেন। আপনার যদি খুব ছোট মান, প্রচুর পরিমাণে মিডলিং মান এবং একটি ছোট সংখ্যক বড় মান থাকে তবে প্রথমে সমস্ত ছোট ছোটগুলি যোগ করার পরে সঠিকভাবে পৃথক করে মোটামুটি মোটগুলি যোগ করুন, এই দুটি মোট যোগ করুন একসাথে তারপর বড় বেশী যোগ করুন। ভাসমান-পয়েন্ট সংযোজনের সবচেয়ে সঠিক সংমিশ্রণটি মোটেও তুচ্ছ নয়, তবে সত্যিই খারাপ ক্ষেত্রে আপনি বিভিন্ন মাত্রায় মোট রান চালিয়ে যেতে পারেন, প্রতিটি নতুন মান মোটের সাথে যোগ করতে পারেন যা তার দৈর্ঘ্যের সাথে সবচেয়ে ভাল মেলে, এবং যখন একটি চলমান মোট তার প্রস্থের জন্য খুব বড় হতে শুরু করে, পরবর্তী মোটটিতে এটি যুক্ত করুন এবং একটি নতুন শুরু করুন। যৌক্তিক চরম দিকে নিয়ে যাওয়া, এই প্রক্রিয়াটি একটি স্বেচ্ছাসেবী-নির্ভুলতার ধরণের সমষ্টি সম্পাদনের সমতুল্য (সুতরাং আপনি ' d কর)। তবে প্রস্থের আরোহণ বা অবতরণ ক্রমে যুক্ত করার সরল পছন্দ অনুসারে আরোহণ আরও ভাল বাজি।

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


8
ব্যাখ্যার জন্য +1। এটি কিছুটা পাল্টে স্বজ্ঞাত যেহেতু সংযোজনটি সাধারণত সংখ্যাগতভাবে স্থিতিশীল হয় (বিয়োগ এবং বিভাগের বিপরীতে)।
কনরাড রুডলফ

2
@ কনরাড, এটি সংখ্যার দিক থেকে স্থিতিশীল হতে পারে তবে এটি অপারেশনগুলির বিভিন্ন মাত্রা দেওয়া সুনির্দিষ্ট নয় :)
এমএসএন

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

8
আপনি যদি এই সাধারণ স্কিমটি ধরে রেখে চলেছেন, আমি সর্বদা সর্বনিম্ন প্রস্থের সাথে দুটি সংখ্যা যুক্ত করব এবং সেটটিতে যোগফলটি আবার যুক্ত করব। (ঠিক আছে, সম্ভবত এখানে মার্জ সাজানোর কাজটি সবচেয়ে ভাল কাজ করবে the আপনি পূর্বে যোগফলগুলি যুক্ত অ্যারের অংশটি আংশিক অঙ্কের জন্য কার্যকারী অঞ্চল হিসাবে ব্যবহার করতে পারেন))
নীল

2
@ কেভিন পানকো: সহজ সংস্করণটি হ'ল একক নির্ভুলতা ভাসমানটির 24 বাইনারি অঙ্ক রয়েছে যার মধ্যে সবচেয়ে বড় সংখ্যার বৃহত্তম সেট বিট। সুতরাং আপনি যদি দুটি সংখ্যাকে যোগ করেন যা 2 ^ 24 এর বেশি মাত্রার সাথে পৃথক হয় তবে আপনি ছোট মানটির মোট ক্ষতি হবেন, এবং যদি এটি একটি ছোট ডিগ্রি দ্বারা প্রস্থে পৃথক হয় তবে আপনি ছোটটির যথার্থতার বিটগুলির সাথে সম্পর্কিত সংখ্যা হারাবেন সংখ্যা।
স্টিভ জেসোপ

88

এই ধরণের জমে থাকা অপারেশনের জন্য ডিজাইন করা একটি অ্যালগরিদমও রয়েছে, যার নাম কাহান সামোমেশন , আপনার সম্ভবত সচেতন হওয়া উচিত।

উইকিপিডিয়া অনুসারে,

Kahan সঙ্কলন অ্যালগরিদম (নামেও পরিচিত ক্ষতিপূরণ সমষ্টি ) উল্লেখযোগ্যভাবে, মোট সসীম স্পষ্টতা ফ্লোটিং পয়েন্ট সংখ্যার একটি ক্রম যোগ করে প্রাপ্ত মধ্যে সংখ্যাসূচক ত্রুটি হ্রাস সুস্পষ্ট পদ্ধতির তুলনায়। এটি পৃথক চলমান ক্ষতিপূরণ (ছোট ত্রুটিগুলি জমা করার জন্য একটি ভেরিয়েবল) রাখার মাধ্যমে করা হয়।

সিউডোকোডে, অ্যালগরিদমটি হ'ল:

function kahanSum(input)
 var sum = input[1]
 var c = 0.0          //A running compensation for lost low-order bits.
 for i = 2 to input.length
  y = input[i] - c    //So far, so good: c is zero.
  t = sum + y         //Alas, sum is big, y small, so low-order digits of y are lost.
  c = (t - sum) - y   //(t - sum) recovers the high-order part of y; subtracting y recovers -(low part of y)
  sum = t             //Algebraically, c should always be zero. Beware eagerly optimising compilers!
 next i               //Next time around, the lost low part will be added to y in a fresh attempt.
return sum

3
এই থ্রেডটিতে +1 সুন্দর সংযোজন। যে বিবৃতিগুলি "উত্সাহীভাবে সর্বোত্তমভাবে প্রস্তুত করে" যে কোনও সংকলক নিষিদ্ধ করা উচিত।
ক্রিস এ।

1
দুটি যোগফলের ভেরিয়েবল sumএবং cবিবিধ মাত্রার ব্যবহার করে নির্ভুলতা প্রায় দ্বিগুণ করার একটি সহজ পদ্ধতি । এটি তুচ্ছভাবে এন ভেরিয়েবলগুলিতে প্রসারিত হতে পারে।
MSalters

2
@ChrisA। ভাল আপনি এটি গণনা করে এমন সমস্ত সংকলকগুলিতে স্পষ্টতই এটি নিয়ন্ত্রণ করতে পারেন (যেমন -ffast-mathজিসিসির মাধ্যমে )।
কনরাড রুডল্ফ

6
@ কনরাড রুডলফ এটি উল্লেখ করার জন্য ধন্যবাদ যে এটি একটি সম্ভাব্য অপ্টিমাইজেশন -ffast-math। আমি এই আলোচনা এবং এই লিঙ্কটি থেকে যা শিখেছি তা হ'ল আপনি যদি সংখ্যাগত নির্ভুলতার বিষয়ে যত্নশীল হন -ffast-mathতবে সম্ভবত আপনার ব্যবহার এড়ানো উচিত তবে এমন অনেক অ্যাপ্লিকেশন যেখানে আপনি সিপিইউ-বন্ড হতে পারেন তবে সঠিক সংখ্যাসূচক গুণাগুলির যত্ন নেবেন না, (উদাহরণস্বরূপ গেম প্রোগ্রামিং) ), -ffast-mathব্যবহারযোগ্য যুক্তিযুক্ত। সুতরাং, আমি আমার দৃ strongly়ভাবে শব্দযুক্ত "নিষিদ্ধ" মন্তব্যটির প্রশংসা করতে চাই।
ক্রিস এ।

এর জন্য ডাবল নির্ভুলতা ভেরিয়েবলগুলি ব্যবহার sum, c, t, yকরা সহায়তা করবে। আপনি sum -= cআগে যোগ করা প্রয়োজন return sum
জি। কোহেন

34

স্টিভ জেসোপের সরবরাহ করা উত্তরে আমি চরম উদাহরণটি চেষ্টা করেছিলাম।

#include <iostream>
#include <iomanip>
#include <cmath>

int main()
{
    long billion = 1000000000;
    double big = 1.0;
    double small = 1e-9;
    double expected = 2.0;

    double sum = big;
    for (long i = 0; i < billion; ++i)
        sum += small;
    std::cout << std::scientific << std::setprecision(1) << big << " + " << billion << " * " << small << " = " <<
        std::fixed << std::setprecision(15) << sum <<
        "    (difference = " << std::fabs(expected - sum) << ")" << std::endl;

    sum = 0;
    for (long i = 0; i < billion; ++i)
        sum += small;
    sum += big;
    std::cout  << std::scientific << std::setprecision(1) << billion << " * " << small << " + " << big << " = " <<
        std::fixed << std::setprecision(15) << sum <<
        "    (difference = " << std::fabs(expected - sum) << ")" << std::endl;

    return 0;
}

আমি নিম্নলিখিত ফলাফল পেয়েছি:

1.0e+00 + 1000000000 * 1.0e-09 = 2.000000082740371    (difference = 0.000000082740371)
1000000000 * 1.0e-09 + 1.0e+00 = 1.999999992539933    (difference = 0.000000007460067)

প্রথম লাইনে ত্রুটি দ্বিতীয়টিতে দশগুণ বেশি।

আমি যদি উপরের কোডটিতে doubleএসগুলিতে পরিবর্তন করি তবে floatআমি পাই:

1.0e+00 + 1000000000 * 1.0e-09 = 1.000000000000000    (difference = 1.000000000000000)
1000000000 * 1.0e-09 + 1.0e+00 = 1.031250000000000    (difference = 0.968750000000000)

দুটিই উত্তরও 2.0 এর কাছাকাছি নয় (তবে দ্বিতীয়টি কিছুটা কাছাকাছি)।

doubleড্যানিয়েল প্রাইডেন বর্ণিত কাহান সংক্ষেপণ ( গুলি) ব্যবহার করে :

#include <iostream>
#include <iomanip>
#include <cmath>

int main()
{
    long billion = 1000000000;
    double big = 1.0;
    double small = 1e-9;
    double expected = 2.0;

    double sum = big;
    double c = 0.0;
    for (long i = 0; i < billion; ++i) {
        double y = small - c;
        double t = sum + y;
        c = (t - sum) - y;
        sum = t;
    }

    std::cout << "Kahan sum  = " << std::fixed << std::setprecision(15) << sum <<
        "    (difference = " << std::fabs(expected - sum) << ")" << std::endl;

    return 0;
}

আমি ঠিক 2.0 পেয়েছি:

Kahan sum  = 2.000000000000000    (difference = 0.000000000000000)

এমনকি যদি আমি উপরের কোডটিতে doubleএসগুলিকে পরিবর্তন করেও float, আমি পাই:

Kahan sum  = 2.000000000000000    (difference = 0.000000000000000)

মনে হ'ল কাহান সেই পথ!


আমার "বড়" মান 1e9 নয়, 1 এর সমান। আপনার দ্বিতীয় উত্তর, ক্রমবর্ধমান আকারের ক্রমে যুক্ত করা হয়েছে, গাণিতিকভাবে সঠিক (1 বিলিয়ন, আরও এক বিলিয়ন বিলিয়ন, 1 বিলিয়ন এবং 1), যদিও ভাগ্যক্রমে পদ্ধতির কোনও সাধারণ সাবলীলতা :-) নোট যে doubleখারাপ ভোগ করে না , এক বিলিয়ন billionths একসঙ্গে যোগ যেহেতু এটি, 52 উল্লেখযোগ্য বিট আছে যেহেতু আইইইই মধ্যে স্পষ্টতা হারানোর floatশুধুমাত্র 24 এবং would।
স্টিভ জেসপ

@ স্টিভ, আমার ত্রুটি, ক্ষমা। আপনি যা ইচ্ছা করেছিলেন আমি উদাহরণ কোডটি আপডেট করেছি।
অ্যান্ড্রু স্টেইন

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

14

অ্যালগরিদমগুলির একটি শ্রেণি রয়েছে যা এই সঠিক সমস্যাটি সমাধান করে, ডেটা বাছাই বা অন্যথায় পুনরায় অর্ডার করার প্রয়োজন ছাড়াই

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

এখানে একটি সাম্প্রতিক কাগজের বিমূর্ততা:

ভাসমান-পয়েন্ট সংখ্যাগুলির একটি স্রোতের সঠিক সংক্ষিপ্তসার জন্য আমরা একটি উপন্যাস, অনলাইন অ্যালগরিদম উপস্থাপন করি। "অনলাইন" এর মাধ্যমে আমরা বোঝাতে চাইছি যে অ্যালগরিদমকে একবারে কেবল একটি ইনপুট দেখতে হবে এবং কেবল ধ্রুবক মেমরির প্রয়োজনে এ জাতীয় ইনপুটগুলির একটি নির্বিচার দৈর্ঘ্য ইনপুট স্ট্রিম নিতে পারে। "যথাযথ" দ্বারা আমরা বোঝাতে চাইছি যে আমাদের অ্যালগোরিদমের অভ্যন্তরীণ অ্যারের যোগফল সমস্ত ইনপুটগুলির যোগফলের সমান, এবং প্রত্যাবর্তিত ফলাফলটি সঠিকভাবে গোলাকার যোগফল। নির্ভুলতার প্রমাণ সমস্ত ইনপুটগুলির জন্য বৈধ (ননরমালাইজড সংখ্যার সাথে তবে মডুলো ইন্টারমিডিয়েট ওভারফ্লো সহ) এবং সমান্ডের সংখ্যা বা যোগফলের শর্ত সংখ্যার থেকে পৃথক। অ্যালগোরিদম asympototically প্রতি যোগ প্রতি মাত্র 5 টি FLOPs প্রয়োজন, এবং নির্দেশ স্তরের সমান্তরালতা সুস্পষ্ট তুলনায় প্রায় 2--3 গুণ ধীর গতিতে চলে, যখন স্যামেন্ডের সংখ্যা 10,000 এর বেশি হয় তখন দ্রুত-তবে-বোবা "সাধারণ পুনরাবৃত্তির সমষ্টি" লুপ। সুতরাং, আমাদের জ্ঞানের কাছে, এটি জানা অ্যালগরিদমের মধ্যে দ্রুত, সবচেয়ে নির্ভুল এবং সর্বাধিক মেমরির দক্ষ। প্রকৃতপক্ষে, এটি একটি হার্ড অ্যালগোরিদম বা হার্ডওয়ার উন্নতি ছাড়া উল্লেখযোগ্যভাবে কম FLOPs প্রয়োজন এমন একটির কীভাবে উপস্থিত থাকতে পারে তা দেখা মুশকিল। বিপুল সংখ্যক তদন্তের জন্য একটি আবেদন সরবরাহ করা হয়েছে।

উত্স: অ্যালগরিদম 908: ভাসমান-পয়েন্ট স্ট্রিমগুলির অনলাইনে ঠিক সমষ্টি


1
@ বিপরীত: এখনও চারপাশে ইট এবং মর্টার লাইব্রেরি আছে। বিকল্পভাবে, পিডিএফ অনলাইন কেনার জন্য $ 5- $ 15 খরচ হয় (আপনি এসিএম সদস্য কিনা তার উপর নির্ভর করে)। শেষ অবধি, ডিপডাইভ 24 ঘন্টা $ 2.99 এর জন্য কাগজ leণ
এনপিই

2

আরোহী ক্রম অনুসারে প্রথমে সংখ্যা বাছাইয়ের স্টিভের জবাবকে কেন্দ্র করে আমি আরও দুটি ধারণা পেশ করবো:

  1. উপরে দুটি সংখ্যার ঘনিষ্ঠতার পার্থক্যের বিষয়ে সিদ্ধান্ত নিন যা আপনি সিদ্ধান্ত নিতে পারেন যে আপনি খুব বেশি নির্ভুলতা হারাবেন।

  2. তারপরে পরবর্তী সংখ্যার জন্য সঞ্চয়ের পরিমাণটি খুব বড় না হওয়া অবধি ক্রম সংখ্যাটি যুক্ত করুন, তারপরে অস্থায়ী সারিতে সংযোজকটি রাখুন এবং পরবর্তী সংখ্যার সাহায্যে সংযোজক শুরু করুন। আপনি আসল তালিকাটি শেষ না করা অবধি চালিয়ে যান।

আপনি অস্থায়ী সারিতে (এটি বাছাই করে) এবং ঘোরের মধ্যে সম্ভবত আরও বড় পার্থক্য দিয়ে প্রক্রিয়াটি পুনরাবৃত্তি করেন।

আমি মনে করি আপনি যদি সার্বক্ষণিক এক্সপোজারগুলি গণনা করতে থাকেন তবে এটি বেশ ধীর হবে।

আমি একটি প্রোগ্রামের সাথে দ্রুত যেতে হয়েছিলাম এবং ফলাফলটি ছিল 1.99903


2

আমি মনে করি আপনি সংখ্যার সঞ্চারের আগে বাছাই করার চেয়ে আরও ভাল করতে পারেন, কারণ সঞ্চয়ের প্রক্রিয়া চলাকালীন, সঞ্চালক আরও বড় হয়ে ওঠে। আপনার যদি একই পরিমাণের বৃহত পরিমাণ থাকে তবে আপনি দ্রুত নির্ভুলতা হারাতে শুরু করবেন। পরিবর্তে আমি যা প্রস্তাব করব তা এখানে:

while the list has multiple elements
    remove the two smallest elements from the list
    add them and put the result back in
the single element in the list is the result

অবশ্যই এই অ্যালগরিদম কোনও তালিকার পরিবর্তে অগ্রাধিকারের সারিতে সবচেয়ে কার্যকর হবে। সি ++ কোড:

template <typename Queue>
void reduce(Queue& queue)
{
    typedef typename Queue::value_type vt;
    while (queue.size() > 1)
    {
        vt x = queue.top();
        queue.pop();
        vt y = queue.top();
        queue.pop();
        queue.push(x + y);
    }
}

ড্রাইভার:

#include <iterator>
#include <queue>

template <typename Iterator>
typename std::iterator_traits<Iterator>::value_type
reduce(Iterator begin, Iterator end)
{
    typedef typename std::iterator_traits<Iterator>::value_type vt;
    std::priority_queue<vt> positive_queue;
    positive_queue.push(0);
    std::priority_queue<vt> negative_queue;
    negative_queue.push(0);
    for (; begin != end; ++begin)
    {
        vt x = *begin;
        if (x < 0)
        {
            negative_queue.push(x);
        }
        else
        {
            positive_queue.push(-x);
        }
    }
    reduce(positive_queue);
    reduce(negative_queue);
    return negative_queue.top() - positive_queue.top();
}

সারিতে সংখ্যা নেতিবাচক কারণ হয় topউৎপাদনের বৃহত্তম সংখ্যা, কিন্তু আমরা চাই ক্ষুদ্রতম । আমি কাতারে আরও টেম্পলেট আর্গুমেন্ট সরবরাহ করতে পারতাম, তবে এই পদ্ধতিটি সহজ বলে মনে হচ্ছে।


2

এটি আপনার প্রশ্নের পুরোপুরি উত্তর দেয় না, তবে একটি চালাক কাজটি হ'ল দু'বার যোগফল চালানো, একবার রাউন্ডিং মোড "রাউন্ড আপ" এবং একবার "রাউন্ড ডাউন" দিয়ে। দুটি উত্তরের সাথে তুলনা করুন এবং আপনি কীভাবে / আপনার ফলাফলগুলি কীভাবে সঠিক / তা জানেন এবং যদি আপনার তাই চালক সংক্ষেপণ কৌশল ব্যবহার করার প্রয়োজন হয় তবে। দুর্ভাগ্যক্রমে, বেশিরভাগ ভাষাগুলি ভাসমান পয়েন্টের রাউন্ডিং মোডটিকে যতটা সহজ হওয়া উচিত ঠিক ততটা পরিবর্তন করে না কারণ লোকেরা জানেন না যে এটি দৈনন্দিন গণনার ক্ষেত্রে আসলে কার্যকর।

ইন্টারভাল পাটিগণিতের দিকে একবার নজর দিন যেখানে আপনি যেমন যান তেমন উচ্চতর এবং সর্বনিম্ন মান রেখে all এটি কিছু আকর্ষণীয় ফলাফল এবং আশাবাদী বাড়ে।


0

নির্ভুলতার উন্নতি করার সবচেয়ে সহজ বাছাই হ'ল আরোহী পরম মান অনুসারে বাছাই। এটি ক্ষুদ্রতর परिमाणের মানগুলিকে সংক্ষিপ্ত বা ক্ষতিগ্রস্থ হওয়ার সাথে আরও বড় আকারের মানগুলির সাথে কথোপকথনের আগে বাতিল করার সুযোগ দেয়।

এটি বলেছে, একাধিক অ-ওভারল্যাপিং আংশিক অঙ্কগুলি ট্র্যাক করে আপনি আরও ভাল করতে পারেন। কৌশলটি বর্ণনা করার জন্য এবং একটি যথাযথতার প্রমাণ উপস্থাপন করার জন্য একটি কাগজ এখানে রয়েছে: www-2.cs.cmu.edu/afs/cs/project/quake/public/papers/robust-arithmetic.ps

সেই অ্যালগরিদম এবং সঠিক ভাসমান বিন্দু সংক্ষেপণের অন্যান্য পন্থাগুলি সাধারণ পাইথনে এখানে প্রয়োগ করা হয়: http://code.activestate.com/recips/393090/ এর মধ্যে কমপক্ষে দু'জনকে তুচ্ছভাবে সি ++ তে রূপান্তর করা যায়।


0

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

/* clear array */
void clearsum(float asum[256])
{
size_t i;
    for(i = 0; i < 256; i++)
        asum[i] = 0.f;
}

/* add a number into array */
void addtosum(float f, float asum[256])
{
size_t i;
    while(1){
        /* i = exponent of f */
        i = ((size_t)((*(unsigned int *)&f)>>23))&0xff;
        if(i == 0xff){          /* max exponent, could be overflow */
            asum[i] += f;
            return;
        }
        if(asum[i] == 0.f){     /* if empty slot store f */
            asum[i] = f;
            return;
        }
        f += asum[i];           /* else add slot to f, clear slot */
        asum[i] = 0.f;          /* and continue until empty slot */
    }
}

/* return sum from array */
float returnsum(float asum[256])
{
float sum = 0.f;
size_t i;
    for(i = 0; i < 256; i++)
        sum += asum[i];
    return sum;
}

ডাবল স্পষ্টতা উদাহরণ:

/* clear array */
void clearsum(double asum[2048])
{
size_t i;
    for(i = 0; i < 2048; i++)
        asum[i] = 0.;
}

/* add a number into array */
void addtosum(double d, double asum[2048])
{
size_t i;
    while(1){
        /* i = exponent of d */
        i = ((size_t)((*(unsigned long long *)&d)>>52))&0x7ff;
        if(i == 0x7ff){         /* max exponent, could be overflow */
            asum[i] += d;
            return;
        }
        if(asum[i] == 0.){      /* if empty slot store d */
            asum[i] = d;
            return;
        }
        d += asum[i];           /* else add slot to d, clear slot */
        asum[i] = 0.;           /* and continue until empty slot */
    }
}

/* return sum from array */
double returnsum(double asum[2048])
{
double sum = 0.;
size_t i;
    for(i = 0; i < 2048; i++)
        sum += asum[i];
    return sum;
}

এটি কিছুটা ম্যালকমের 1971 এর পদ্ধতির মতো বা আরও বেশি, এর রূপটি ডেমেল এবং হিদা ("অ্যালগোরিদম 3") দ্বারা প্রকাশকারীকে ব্যবহার করে sounds সেখানে আরও একটি অ্যালগরিদম আছে যা আপনার মতো বহন-ভিত্তিক লুপ করে, তবে আমি এই মুহুর্তে এটি খুঁজে পাচ্ছি না।
ZachB

@ জ্যাচবি - ধারণাটি লিঙ্কযুক্ত তালিকার জন্য ডাউন আপ মার্জ সাজ্টের সমান , যা একটি ছোট অ্যারেও ব্যবহার করে, যেখানে অ্যারে [i] পয়েন্ট 2 ^ i নোডের সাথে তালিকাবদ্ধ করে। আমি জানি না এটি কত পিছনে যায়। আমার ক্ষেত্রে এটি 1970 এর দশকে স্ব-আবিষ্কার ছিল।
rcgldr

-1

আপনার ভাসমানগুলি ডাবল নির্ভুলতায় যুক্ত করা উচিত। এটি আপনাকে অন্য যে কোনও প্রযুক্তির তুলনায় আরও অতিরিক্ত নির্ভুলতা দেবে। কিছুটা আরও স্পষ্টতা এবং উল্লেখযোগ্যভাবে আরও গতির জন্য আপনি চারটি যোগফল তৈরি করতে পারেন এবং এগুলি শেষে যুক্ত করতে পারেন।

আপনি যদি ডাবল স্পষ্টতা সংখ্যা যুক্ত করে থাকেন তবে যোগফলের জন্য লম্বা দ্বিগুণ ব্যবহার করুন - তবে এটি কেবলমাত্র বাস্তবায়নে ইতিবাচক প্রভাব ফেলবে যেখানে লম্বা ডাবলটির প্রকৃতপক্ষে দ্বিগুণের চেয়ে বেশি নির্ভুলতা থাকে (সাধারণত x86, পাওয়ার সংযোগকারী সেটিংসের উপর নির্ভর করে পাওয়ারপিসি)।


1
"এটি আপনাকে অন্য যে কোনও প্রযুক্তির চেয়ে আরও বেশি নির্ভুলতা দিতে পারে" আপনি কী বুঝতে পেরেছেন যে উত্তরটি আগের এক দেরির উত্তরের এক বছরেরও বেশি সময় পরে আসে যা সঠিক সংক্ষেপণটি কীভাবে ব্যবহার করতে হবে তা বর্ণনা করে?
পাস্কেল কুয়াক

"দীর্ঘ ডাবল" প্রকারটি ভয়ঙ্কর এবং আপনার এটি ব্যবহার করা উচিত নয়।
জেফ

-1

বাছাইয়ের বিষয়ে, আমার কাছে মনে হয় আপনি যদি বাতিল প্রত্যাশা করেন তবে সংখ্যাগুলি ক্রমবর্ধমান ক্রমের সাথে যুক্ত করা উচিত , আরোহী নয়। এই ক্ষেত্রে:

((-1 + 1) + 1e-20) 1e-20 দেবে

কিন্তু

((1e-20 + 1) - 1) 0 দেবে

প্রথম সমীকরণে যে দুটি বৃহত সংখ্যক বাতিল হয়ে গেছে, অন্যদিকে 1e-20 পদটি 1-এ যুক্ত হওয়ার পরে হারিয়ে যায়, কারণ এটি ধরে রাখার যথেষ্ট যথার্থতা নেই।

এছাড়াও, সংখ্যার সংখ্যার যোগফলের জন্য জুটিওয়ালা সংমিশ্রণটি বেশ শালীন।

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