দ্বিগুণ থেকে 32-বিট ইন্টি করে বর্ণিত একটি দ্রুত পদ্ধতি method


169

লুয়ার উত্স কোডটি পড়ার সময় , আমি লক্ষ করেছি যে লুয়া একটি 32- বিটকে macroগোল doubleকরতে একটি ব্যবহার করে int। আমি এটি বের করেছি macroএবং এটি দেখতে এরকম দেখাচ্ছে:

union i_cast {double d; int i[2]};
#define double2int(i, d, t)  \
    {volatile union i_cast u; u.d = (d) + 6755399441055744.0; \
    (i) = (t)u.i[ENDIANLOC];}

এখানে বিস্তৃত ইন্ডিয়ানের জন্য , অ্যান্ডিয়ানেসের জন্য , আন্ডিয়াননেসENDIANLOC হিসাবে সংজ্ঞায়িত করা হয়েছে । লুয়া সাবধানতার সাথে আধ্যাত্মিকতা পরিচালনা করে। পূর্ণসংখ্যা টাইপের জন্য দাঁড়ায়, যেমন বা ।01tintunsigned int

আমি কিছুটা গবেষণা করেছি এবং এর একটি সহজ ফর্ম্যাট রয়েছে macroযা একই চিন্তাভাবনাটি ব্যবহার করে:

#define double2int(i, d) \
    {double t = ((d) + 6755399441055744.0); i = *((int *)(&t));}

অথবা একটি সি ++ - শৈলীতে:

inline int double2int(double d)
{
    d += 6755399441055744.0;
    return reinterpret_cast<int&>(d);
}

এই কৌশলটি আইইইই 754 ব্যবহার করে যে কোনও মেশিনে কাজ করতে পারে (যার অর্থ আজ প্রতিটি মেশিন বেশ)। এটি ইতিবাচক এবং নেতিবাচক উভয় সংখ্যার জন্যই কাজ করে এবং গোলটি ব্যাঙ্কারের নিয়ম অনুসরণ করে । (এটি আশ্চর্যজনক নয়, যেহেতু এটি আইইইই 754 অনুসরণ করে))

আমি এটি পরীক্ষা করার জন্য একটি ছোট প্রোগ্রাম লিখেছি:

int main()
{
    double d = -12345678.9;
    int i;
    double2int(i, d)
    printf("%d\n", i);
    return 0;
}

এবং এটি ফলাফল হিসাবে -12345679, আশানুরূপ হিসাবে।

এই কৌশলটি কীভাবে macroকাজ করে তা আমি বিশদে যেতে চাই । যাদু নম্বরটি 6755399441055744.0আসলে 2^51 + 2^52, বা 1.5 * 2^52, এবং 1.5বাইনারি হিসাবে উপস্থাপন করা যেতে পারে 1.1। এই যাদু নম্বরটিতে যখন কোনও 32-বিট পূর্ণসংখ্যার যোগ করা হয়, ভাল, আমি এখান থেকে হারিয়েছি। এই কৌশলটি কীভাবে কাজ করে?

পিএস: এটি লুয়া সোর্স কোড, লিমিটসহ'ল

আপডেট :

  1. @ মিস্টিটিয়াল পয়েন্ট হিসাবে, এই পদ্ধতিটি নিজেকে 32-বিটের মধ্যে সীমাবদ্ধ করে না , সংখ্যাটি 2 ^ 52 এর সীমাতে থাকা পর্যন্ত এটি intএকটি 64- বিটেও প্রসারিত হতে পারে int। ( macroকিছুটা পরিবর্তন দরকার))
  2. কিছু উপকরণ বলে যে এই পদ্ধতিটি ডিরেক্ট 3 ডি তে ব্যবহার করা যাবে না ।
  3. X86 এর জন্য মাইক্রোসফ্ট এসেম্বলারের সাথে কাজ করার সময়, আরও একটি দ্রুত macroলিখিত আছে assembly(এটি লুয়া উত্স থেকেও নেওয়া হয়):

    #define double2int(i,n)  __asm {__asm fld n   __asm fistp i}
  4. একক নির্ভুলতার জন্য একই ধরণের ম্যাজিক নম্বর রয়েছে: 1.5 * 2 ^23


3
"দ্রুত" কিসের তুলনায়?
কোরি নেলসন

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

2
ডান - আমি দেখতে পাচ্ছি এটির চেয়ে বেশি দ্রুত হচ্ছে ftoi। আপনি যদি এসএসইতে কথা বলছেন তবে কেন কেবল একক নির্দেশনা ব্যবহার করবেন না CVTTSD2SI?
কোরি নেলসন

3
@tmyklebu যে ব্যবহারের অনেকগুলি ঘটনা double -> int64প্রকৃতপক্ষে 2^52সীমার মধ্যে রয়েছে। ভাসমান-পয়েন্ট এফএফটি ব্যবহার করে পূর্ণসংখ্যার কনভোলিউশনগুলি সম্পাদন করার সময় এগুলি সাধারণত সাধারণ।
রহস্যময়

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

উত্তর:


161

একজন doubleভালো প্রতিনিধিত্ব করা হয়:

ডাবল প্রতিনিধিত্ব

এবং এটি দুটি 32-বিট পূর্ণসংখ্যার হিসাবে দেখা যেতে পারে; এখন, intআপনার কোডের সমস্ত সংস্করণে নেওয়া (এটি একটি 32-বিট হিসাবে মনে করুন int) চিত্রের ডানদিকে এক, তাই আপনি শেষ পর্যন্ত যা করছেন তা হ'ল ম্যান্টিসার সর্বনিম্ন 32 বিট নিচ্ছেন।


এখন, যাদু সংখ্যায়; যেমনটি আপনি সঠিকভাবে বলেছেন, 6755399441055744 হ'ল 2 ^ 51 + 2 ^ 52; এই জাতীয় সংখ্যা যুক্ত করে double2 ^ 52 এবং 2 ^ 53 এর মধ্যে "মিষ্টি পরিসীমা" যেতে বাধ্য করে, যা এখানে উইকিপিডিয়া দ্বারা ব্যাখ্যা করা হয়েছে , একটি আকর্ষণীয় সম্পত্তি রয়েছে:

2 52 = 4,503,599,627,370,496 এবং 2 53 = 9,007,199,254,740,992 এর মধ্যে প্রতিনিধিত্বযোগ্য সংখ্যা হুবহু পূর্ণসংখ্যা

এটি ম্যান্টিসা 52 বিট প্রশস্ত যে সত্য থেকে অনুসরণ করে।

2 51 + 2 52 যোগ করার বিষয়ে অন্যান্য আকর্ষণীয় সত্যটি হ'ল এটি ম্যান্টিসাকে কেবলমাত্র দুটি সর্বোচ্চ বিটগুলিতে প্রভাবিত করে - যা যাইহোক বাতিল করা হয়, কারণ আমরা এটির সর্বনিম্ন 32 বিট নিচ্ছি।


সর্বশেষ কিন্তু কমপক্ষে: সাইন।

আইইইই 754 ভাসমান বিন্দু একটি মাত্রা এবং সাইন প্রতিনিধিত্ব ব্যবহার করে, যখন "সাধারণ" মেশিনগুলিতে পূর্ণসংখ্যা 2 এর পরিপূরক গাণিতিক ব্যবহার করে; এখানে কিভাবে এটি পরিচালনা করা হয়?

আমরা কেবল ইতিবাচক পূর্ণসংখ্যার কথা বলেছি; এখন ধরা যাক আমরা একটি 32-বিট দ্বারা উপস্থাপনযোগ্য পরিসরে একটি নেতিবাচক সংখ্যা নিয়ে কাজ করছি int, (-2 ^ 31 + 1) এর চেয়ে কম (পরম মান); এটা কল -a। এই জাতীয় সংখ্যাটি যাদু সংখ্যার যোগ করে স্পষ্টতই ইতিবাচক করা হয়, এবং ফলাফলটির মান 2 52 +2 51 + (- এ) হয়।

এখন, আমরা যদি 2 এর পরিপূরক উপস্থাপনায় মান্টিসাকে ব্যাখ্যা করি তবে আমরা কী পেতে পারি? এটি অবশ্যই 2 এর পরিপূরক সমষ্টি (2 52 +2 51 ) এবং (-এ) এর ফলাফল হতে হবে। আবার প্রথম শব্দটি কেবল উপরের দুটি বিটকে প্রভাবিত করে, বিট 0 ~ 50 এ যা থাকে তা 2-এর পরিপূরক উপস্থাপনা (-এ) (আবার, উপরের দুটি বিট বিয়োগ)।

যেহেতু একটি 2 এর পরিপূরক সংখ্যাটিকে একটি ছোট প্রস্থে হ্রাস করা হয়েছে কেবল বামদিকে অতিরিক্ত বিটগুলি কেটে ফেললে নীচের 32 বিটগুলি আমাদের 32-বিটের সঠিকভাবে (-a) দেয়, 2 এর পরিপূরক গাণিতিক হয়।


"" "2 ^ 51 + 2 ^ 52 যোগ করার বিষয়ে অন্যান্য আকর্ষণীয় ঘটনাটি হ'ল এটি মান্টিসাকে কেবলমাত্র দুটি সর্বোচ্চ বিটগুলিতে প্রভাবিত করে - যা যেভাবেই বাতিল করা হয়, যেহেতু আমরা কেবল তার সর্বনিম্ন 32 বিট নিচ্ছি" "" এটি কী? এটিকে যুক্ত করে সমস্ত মন্টিসে স্থানান্তরিত হতে পারে!
YvesgereY

@ জন: অবশ্যই, এগুলি যুক্ত করার পুরো বিষয়টি হ'ল মানটিকে সেই সীমার মধ্যে থাকতে বাধ্য করা যা ফলস্বরূপ মূল মানটির ক্ষেত্রে মান্টিসা (অন্যান্য জিনিসের মধ্যে) স্থানান্তরিত করতে পারে। আমি এখানে যা বলছিলাম তা হ'ল একবার আপনি যদি এই ব্যাপ্তিতে উপস্থিত হন তবে কেবলমাত্র 53 টি বিট সংখ্যার চেয়ে পৃথক বিটগুলি বিট ৫১ এবং ৫২ হয়, যা যাইহোক বাতিল করা হয়।
মাত্তেও ইটালিয়া

2
যারা আপনাকে রূপান্তর করতে চান তাদের int64_tজন্য ম্যান্টিসা বামদিকে এবং তারপরে ডান 13 বিটের মাধ্যমে সরিয়ে এটি করতে পারেন। এটি 'ম্যাজিক' নম্বর থেকে কাফের এবং দুটি বিট সাফ করবে, তবে চিহ্নটি পুরো 64-বিট স্বাক্ষরিত পূর্ণসংখ্যায় রেখে এবং প্রচার করবে। union { double d; int64_t l; } magic; magic.d = input + 6755399441055744.0; magic.l <<= 13; magic.l >>= 13;
ওয়াজাইচ মিগদা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.