0.1x से 0 को 10x तक धीमा करने में प्रदर्शन क्यों बदल जाता है?


1527

यह बिट कोड क्यों है,

const float x[16] = {  1.1,   1.2,   1.3,     1.4,   1.5,   1.6,   1.7,   1.8,
                       1.9,   2.0,   2.1,     2.2,   2.3,   2.4,   2.5,   2.6};
const float z[16] = {1.123, 1.234, 1.345, 156.467, 1.578, 1.689, 1.790, 1.812,
                     1.923, 2.034, 2.145,   2.256, 2.367, 2.478, 2.589, 2.690};
float y[16];
for (int i = 0; i < 16; i++)
{
    y[i] = x[i];
}

for (int j = 0; j < 9000000; j++)
{
    for (int i = 0; i < 16; i++)
    {
        y[i] *= x[i];
        y[i] /= z[i];
        y[i] = y[i] + 0.1f; // <--
        y[i] = y[i] - 0.1f; // <--
    }
}

निम्न बिट की तुलना में 10 गुना अधिक तेजी से चलाएं (समान को छोड़कर जहां उल्लेख किया गया है)?

const float x[16] = {  1.1,   1.2,   1.3,     1.4,   1.5,   1.6,   1.7,   1.8,
                       1.9,   2.0,   2.1,     2.2,   2.3,   2.4,   2.5,   2.6};
const float z[16] = {1.123, 1.234, 1.345, 156.467, 1.578, 1.689, 1.790, 1.812,
                     1.923, 2.034, 2.145,   2.256, 2.367, 2.478, 2.589, 2.690};
float y[16];
for (int i = 0; i < 16; i++)
{
    y[i] = x[i];
}

for (int j = 0; j < 9000000; j++)
{
    for (int i = 0; i < 16; i++)
    {
        y[i] *= x[i];
        y[i] /= z[i];
        y[i] = y[i] + 0; // <--
        y[i] = y[i] - 0; // <--
    }
}

जब Visual Studio 2010 SP1 के साथ संकलन। अनुकूलन के स्तर का था -02साथ sse2सक्षम होना चाहिए। मैंने अन्य संकलक के साथ परीक्षण नहीं किया है।


10
आपने अंतर कैसे मापा? और जब आपने संकलित किया तो आपने किन विकल्पों का उपयोग किया?
जेम्स कान्ज

158
संकलक इस मामले में सिर्फ +/- 0 को क्यों नहीं छोड़ रहा है?
माइकल डोरगन

127
@ Zyx2000 कंपाइलर उस बेवकूफ के पास कहीं भी नहीं है। LINQPad में एक तुच्छ उदाहरण को नष्ट करने से पता चलता है कि यह एक ही कोड को बाहर निकालता है चाहे आप उपयोग करें 0, 0fऔर 0d, यहां तक (int)0कि एक संदर्भ में जहां doubleइसकी आवश्यकता है।
मिलीमोसे

14
अनुकूलन स्तर क्या है?
ओट्टो अल्मडिंगर

जवाबों:


1615

डिनराइज़्ड फ़्लोटिंग-पॉइंट की दुनिया में आपका स्वागत है ! वे प्रदर्शन पर कहर बरपा सकते हैं !!!

फ्लोटिंग पॉइंट प्रतिनिधित्व से शून्य के करीब कुछ अतिरिक्त मान प्राप्त करने के लिए असामान्य (या सबनॉर्मल) नंबर एक हैक की तरह होते हैं। सामान्यीकृत फ्लोटिंग-पॉइंट की तुलना में डिनराइज्ड फ्लोटिंग-पॉइंट पर ऑपरेशन दसियों बार धीमा हो सकता है । ऐसा इसलिए है क्योंकि कई प्रोसेसर सीधे उन्हें संभाल नहीं सकते हैं और उन्हें ट्रैप और माइक्रोकोड का उपयोग करके हल करना चाहिए।

यदि आप 10,000 पुनरावृत्तियों के बाद संख्याओं का प्रिंट आउट करते हैं, तो आप देखेंगे कि उन्होंने अलग-अलग मानों में कनवर्ट किया है 0या नहीं, इसके आधार पर 0.1उपयोग किया जाता है।

यहाँ परीक्षण कोड x64 पर संकलित किया गया है:

int main() {

    double start = omp_get_wtime();

    const float x[16]={1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0,2.1,2.2,2.3,2.4,2.5,2.6};
    const float z[16]={1.123,1.234,1.345,156.467,1.578,1.689,1.790,1.812,1.923,2.034,2.145,2.256,2.367,2.478,2.589,2.690};
    float y[16];
    for(int i=0;i<16;i++)
    {
        y[i]=x[i];
    }
    for(int j=0;j<9000000;j++)
    {
        for(int i=0;i<16;i++)
        {
            y[i]*=x[i];
            y[i]/=z[i];
#ifdef FLOATING
            y[i]=y[i]+0.1f;
            y[i]=y[i]-0.1f;
#else
            y[i]=y[i]+0;
            y[i]=y[i]-0;
#endif

            if (j > 10000)
                cout << y[i] << "  ";
        }
        if (j > 10000)
            cout << endl;
    }

    double end = omp_get_wtime();
    cout << end - start << endl;

    system("pause");
    return 0;
}

आउटपुट:

#define FLOATING
1.78814e-007  1.3411e-007  1.04308e-007  0  7.45058e-008  6.70552e-008  6.70552e-008  5.58794e-007  3.05474e-007  2.16067e-007  1.71363e-007  1.49012e-007  1.2666e-007  1.11759e-007  1.04308e-007  1.04308e-007
1.78814e-007  1.3411e-007  1.04308e-007  0  7.45058e-008  6.70552e-008  6.70552e-008  5.58794e-007  3.05474e-007  2.16067e-007  1.71363e-007  1.49012e-007  1.2666e-007  1.11759e-007  1.04308e-007  1.04308e-007

//#define FLOATING
6.30584e-044  3.92364e-044  3.08286e-044  0  1.82169e-044  1.54143e-044  2.10195e-044  2.46842e-029  7.56701e-044  4.06377e-044  3.92364e-044  3.22299e-044  3.08286e-044  2.66247e-044  2.66247e-044  2.24208e-044
6.30584e-044  3.92364e-044  3.08286e-044  0  1.82169e-044  1.54143e-044  2.10195e-044  2.45208e-029  7.56701e-044  4.06377e-044  3.92364e-044  3.22299e-044  3.08286e-044  2.66247e-044  2.66247e-044  2.24208e-044

ध्यान दें कि दूसरे रन में संख्या शून्य के बहुत करीब है।

सामान्यीकृत संख्याएं आमतौर पर दुर्लभ होती हैं और इस प्रकार अधिकांश प्रोसेसर उन्हें कुशलता से संभालने की कोशिश नहीं करते हैं।


यह प्रदर्शित करने के लिए कि यह हर किसी के लिए असमान संख्याओं के साथ है, अगर हम इसे कोड की शुरुआत में जोड़कर शून्य को फ्लश करते हैं:

_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);

तब वाला संस्करण 0अब 10x धीमा नहीं है और वास्तव में तेज हो जाता है। (इसके लिए यह आवश्यक है कि कोड को एसएसई सक्षम के साथ संकलित किया जाए।)

इसका मतलब यह है कि इन अजीब कम सटीक लगभग-शून्य मानों का उपयोग करने के बजाय, हम इसके बजाय केवल गोल करते हैं।

समय: कोर i7 920 @ 3.5 GHz:

//  Don't flush denormals to zero.
0.1f: 0.564067
0   : 26.7669

//  Flush denormals to zero.
0.1f: 0.587117
0   : 0.341406

अंत में, इसका वास्तव में कोई लेना-देना नहीं है कि यह पूर्णांक है या फ्लोटिंग-पॉइंट है। 0या 0.1fपरिवर्तित / दोनों छोरों का एक रजिस्टर के बाहर में संग्रहित है। ताकि प्रदर्शन पर कोई प्रभाव न पड़े।


100
मुझे अभी भी यह थोड़ा अजीब लग रहा है कि "+ 0" डिफ़ॉल्ट रूप से कंपाइलर द्वारा पूरी तरह से अनुकूलित नहीं है। क्या ऐसा होता, अगर उसने "+ 0.0f" रखा होता?
s73v3r

51
@ s73v3r यह एक बहुत अच्छा सवाल है। अब जब मैं विधानसभा को देखता हूं, तो + 0.0fबाहर अनुकूलित भी नहीं किया जाता है। अगर मुझे अनुमान लगाना होता, तो ऐसा हो सकता है कि + 0.0fसाइड-इफेक्ट होता अगर y[i]सिग्नलिंग NaNया कुछ और होता ... मैं गलत हो सकता था।
रहस्यमयी

14
डबल्स अभी भी कई मामलों में एक ही समस्या में चलेगा, बस एक अलग संख्यात्मक परिमाण में। ऑडियो अनुप्रयोगों के लिए फ्लश-टू-जीरो ठीक है (और अन्य जहां आप 1e-38 को यहां और वहां खोने का जोखिम उठा सकते हैं), लेकिन मेरा मानना ​​है कि x87 पर लागू नहीं होता है। एफटीजेड के बिना, ऑडियो अनुप्रयोगों के लिए सामान्य निर्धारण बहुत कम आयाम (श्रव्य नहीं) डीसी या वर्ग तरंग संकेत इंजेक्ट करने के लिए है, जो कि विकृतीकरण से दूर संख्याओं को चिढ़ाता है।
रसेल बोरोगोव

16
@Isaac क्योंकि जब y [i] 0.1 की तुलना में काफी छोटा होता है, तो इससे सटीकता का नुकसान होता है क्योंकि संख्या में सबसे महत्वपूर्ण अंक अधिक हो जाता है।
दान

167
@ s73v3r: + 0.f को ऑप्टिमाइज़ नहीं किया जा सकता क्योंकि फ्लोटिंग-पॉइंट का ऋणात्मक 0 है, और + 0.f को -.0f जोड़ने का परिणाम + 0.f है। इसलिए 0.f जोड़ना एक पहचान कार्य नहीं है और इसे अनुकूलित नहीं किया जा सकता है।
एरिक पोस्टपिसिल

415

gccजनरेट असेंबली में किसी अंतर का उपयोग करना और लागू करना केवल इस अंतर को उत्पन्न करता है:

73c68,69
<   movss   LCPI1_0(%rip), %xmm1
---
>   movabsq $0, %rcx
>   cvtsi2ssq   %rcx, %xmm1
81d76
<   subss   %xmm1, %xmm0

cvtsi2ssqएक 10 बार किया जा रहा है धीमी वास्तव में।

जाहिरा तौर पर, floatसंस्करण मेमोरी से लोड किए गए एक एक्सएमएम रजिस्टर का उपयोग करता है , जबकि intसंस्करण को निर्देश का उपयोग intकरने के लिए वास्तविक मूल्य 0 में परिवर्तित होता है , बहुत समय लगता है। पासिंगfloatcvtsi2ssq-O3 करने के लिए जीसीसी मदद नहीं करता है। (gcc संस्करण ४.२.१)

(इसका उपयोग doubleकरने के बजाय floatकोई फर्क नहीं पड़ता, सिवाय इसके कि यह cvtsi2ssqएक में बदल जाता हैcvtsi2sdq ।)

अपडेट करें

कुछ अतिरिक्त परीक्षण बताते हैं कि यह जरूरी नहीं कि cvtsi2ssqनिर्देश हो। एक बार समाप्त हो जाने ( इसके बजाय int ai=0;float a=ai;और उपयोग करके ), गति अंतर बना रहता है। तो @ मिस्टीकल सही है, अलंकृत फ़्लोट्स अंतर बनाते हैं। इसे और के बीच मानों के परीक्षण द्वारा देखा जा सकता है । उपरोक्त कोड में मोड़ लगभग उसी समय होता है, जब लूप अचानक 10 गुना लंबा हो जाता है।a000.1f0.00000000000000000000000000000001

अद्यतन << 1

इस दिलचस्प घटना का एक छोटा सा दृश्य:

  • कॉलम 1: एक फ्लोट, जिसे प्रत्येक पुनरावृत्ति के लिए 2 से विभाजित किया गया है
  • कॉलम 2: इस फ्लोट का द्विआधारी प्रतिनिधित्व
  • कॉलम 3: इस फ्लोट को 1e7 बार लेने का समय

आप स्पष्ट रूप से घातांक (अंतिम 9 बिट्स) को इसके न्यूनतम मूल्य में बदल सकते हैं, जब मूल्य-निर्धारण में सेट होता है। उस बिंदु पर, साधारण जोड़ 20 गुना धीमा हो जाता है।

0.000000000000000000000000000000000100000004670110: 10111100001101110010000011100000 45 ms
0.000000000000000000000000000000000050000002335055: 10111100001101110010000101100000 43 ms
0.000000000000000000000000000000000025000001167528: 10111100001101110010000001100000 43 ms
0.000000000000000000000000000000000012500000583764: 10111100001101110010000110100000 42 ms
0.000000000000000000000000000000000006250000291882: 10111100001101110010000010100000 48 ms
0.000000000000000000000000000000000003125000145941: 10111100001101110010000100100000 43 ms
0.000000000000000000000000000000000001562500072970: 10111100001101110010000000100000 42 ms
0.000000000000000000000000000000000000781250036485: 10111100001101110010000111000000 42 ms
0.000000000000000000000000000000000000390625018243: 10111100001101110010000011000000 42 ms
0.000000000000000000000000000000000000195312509121: 10111100001101110010000101000000 43 ms
0.000000000000000000000000000000000000097656254561: 10111100001101110010000001000000 42 ms
0.000000000000000000000000000000000000048828127280: 10111100001101110010000110000000 44 ms
0.000000000000000000000000000000000000024414063640: 10111100001101110010000010000000 42 ms
0.000000000000000000000000000000000000012207031820: 10111100001101110010000100000000 42 ms
0.000000000000000000000000000000000000006103515209: 01111000011011100100001000000000 789 ms
0.000000000000000000000000000000000000003051757605: 11110000110111001000010000000000 788 ms
0.000000000000000000000000000000000000001525879503: 00010001101110010000100000000000 788 ms
0.000000000000000000000000000000000000000762939751: 00100011011100100001000000000000 795 ms
0.000000000000000000000000000000000000000381469876: 01000110111001000010000000000000 896 ms
0.000000000000000000000000000000000000000190734938: 10001101110010000100000000000000 813 ms
0.000000000000000000000000000000000000000095366768: 00011011100100001000000000000000 798 ms
0.000000000000000000000000000000000000000047683384: 00110111001000010000000000000000 791 ms
0.000000000000000000000000000000000000000023841692: 01101110010000100000000000000000 802 ms
0.000000000000000000000000000000000000000011920846: 11011100100001000000000000000000 809 ms
0.000000000000000000000000000000000000000005961124: 01111001000010000000000000000000 795 ms
0.000000000000000000000000000000000000000002980562: 11110010000100000000000000000000 835 ms
0.000000000000000000000000000000000000000001490982: 00010100001000000000000000000000 864 ms
0.000000000000000000000000000000000000000000745491: 00101000010000000000000000000000 915 ms
0.000000000000000000000000000000000000000000372745: 01010000100000000000000000000000 918 ms
0.000000000000000000000000000000000000000000186373: 10100001000000000000000000000000 881 ms
0.000000000000000000000000000000000000000000092486: 01000010000000000000000000000000 857 ms
0.000000000000000000000000000000000000000000046243: 10000100000000000000000000000000 861 ms
0.000000000000000000000000000000000000000000022421: 00001000000000000000000000000000 855 ms
0.000000000000000000000000000000000000000000011210: 00010000000000000000000000000000 887 ms
0.000000000000000000000000000000000000000000005605: 00100000000000000000000000000000 799 ms
0.000000000000000000000000000000000000000000002803: 01000000000000000000000000000000 828 ms
0.000000000000000000000000000000000000000000001401: 10000000000000000000000000000000 815 ms
0.000000000000000000000000000000000000000000000000: 00000000000000000000000000000000 42 ms
0.000000000000000000000000000000000000000000000000: 00000000000000000000000000000000 42 ms
0.000000000000000000000000000000000000000000000000: 00000000000000000000000000000000 44 ms

एआरएम के बारे में एक समान चर्चा स्टैक ओवरफ्लो प्रश्न में पाई जा सकती है उद्देश्य-सी में असामान्य चल बिन्दु?


27
-Oयह तय नहीं है, लेकिन -ffast-mathकरता है। (मैं हर समय उपयोग करता हूं, IMO के कोने मामले जहां यह सटीक परेशानी का कारण बनता है, ठीक से डिज़ाइन किए गए प्रोग्राम में वैसे भी चालू नहीं होना चाहिए।)
10:22

Gcc-4.6 के साथ किसी भी सकारात्मक अनुकूलन स्तर पर कोई रूपांतरण नहीं है।
जेद

@leftaroundabout: एफसीजेड -ffast-math(फ्लश टू जीआर) और डीएजेड (डीएलएड शून्य) को एमएक्ससीएसआर में सेट करने वाले कुछ अतिरिक्त स्टार्टअप कोड लिंक के साथ एक निष्पादन योग्य (लाइब्रेरी नहीं) संकलन करना , इसलिए सीपीयू को कभी-कभी डॉर्मोर्मल के लिए धीमी गति से पिनकोड लेने की आवश्यकता नहीं होती है।
पीटर कॉर्डेस

34

इसके कारण यह अस्थायी फ्लोटिंग पॉइंट का उपयोग है। इसे और प्रदर्शन जुर्माना दोनों से कैसे छुटकारा पाया जाए? अमान्य संख्याओं को मारने के तरीकों के लिए इंटरनेट को कुरेदने के बाद, ऐसा लगता है कि ऐसा करने का कोई "सबसे अच्छा" तरीका नहीं है। मैंने इन तीन तरीकों को पाया है जो विभिन्न वातावरणों में सबसे अच्छा काम कर सकते हैं:

  • कुछ जीसीसी वातावरण में काम नहीं कर सकते हैं:

    // Requires #include <fenv.h>
    fesetenv(FE_DFL_DISABLE_SSE_DENORMS_ENV);
  • कुछ विज़ुअल स्टूडियो वातावरण में काम नहीं कर सकते हैं: 1

    // Requires #include <xmmintrin.h>
    _mm_setcsr( _mm_getcsr() | (1<<15) | (1<<6) );
    // Does both FTZ and DAZ bits. You can also use just hex value 0x8040 to do both.
    // You might also want to use the underflow mask (1<<11)
  • GCC और Visual Studio दोनों में काम करने की अपील करता है:

    // Requires #include <xmmintrin.h>
    // Requires #include <pmmintrin.h>
    _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
    _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
  • इंटेल कंपाइलर के पास आधुनिक इंटेल सीपीयू पर डिफ़ॉल्ट रूप से डिमोर्मल को अक्षम करने के विकल्प हैं। अधिक जानकारी यहाँ

  • संकलक स्विच। -ffast-math, -msseया -mfpmath=sseविकृतीकरण को निष्क्रिय कर देगा और कुछ अन्य चीजों को तेज कर देगा, लेकिन दुर्भाग्य से कई अन्य सन्निकटन भी करते हैं जो आपके कोड को तोड़ सकते हैं। ध्यान से परीक्षण! विज़ुअल स्टूडियो कंपाइलर के लिए फास्ट-गणित के बराबर है, /fp:fastलेकिन मैं यह पुष्टि करने में सक्षम नहीं हूं कि क्या यह भी डिमोर्मल को निष्क्रिय करता है। 1


1
यह एक अलग लेकिन संबंधित प्रश्न के लिए एक सभ्य उत्तर की तरह लगता है (मैं संख्यात्मक परिणामों को असामान्य परिणामों के उत्पादन से कैसे रोक सकता हूं?) हालांकि यह इस सवाल का जवाब नहीं देता है।
बेन वोइग्ट

जब यह लॉन्च होता है तो Windows X64 अचानक अंडरफ़्लो की एक सेटिंग से गुजरता है। exe, जबकि Windows 32-बिट और लिनक्स नहीं करता है। Linux पर, gcc -ffast-math को अचानक अंडरफ़्लो सेट करना चाहिए (लेकिन मुझे लगता है कि विंडोज़ पर नहीं)। इंटेल कंपाइलर्स को मुख्य () में इनिशियलाइज़ करना माना जाता है ताकि ये OS डिफरेंशियल पास न हों, लेकिन मुझे काट लिया गया है, और इसे प्रोग्राम में स्पष्ट रूप से सेट करने की आवश्यकता है। सैंडी ब्रिज के साथ शुरू होने वाले इंटेल सीपीयू को कुशलता से जोड़ने / घटाना (लेकिन विभाजित / गुणा नहीं) में उत्पन्न होने वाले सबनॉर्मल को संभालने के लिए माना जाता है, इसलिए क्रमिक अंडरफ्लो का उपयोग करने के लिए एक मामला है।
टाइम 18

1
Microsoft / fp: fast (डिफ़ॉल्ट नहीं) gcc -ffast-math या ICL (डिफ़ॉल्ट) / fp में निहित आक्रामक चीजों में से कोई भी काम नहीं करता है: तेज। यह ICL / fp: स्रोत की तरह है। इसलिए आपको इन संकलकों की तुलना करने की इच्छा होने पर स्पष्ट रूप से / fp: (और, कुछ मामलों में, अंडरफ्लो मोड में) सेट करना होगा।
टिम 18

18

Gcc में आप इसके साथ FTZ और DAZ को सक्षम कर सकते हैं:

#include <xmmintrin.h>

#define FTZ 1
#define DAZ 1   

void enableFtzDaz()
{
    int mxcsr = _mm_getcsr ();

    if (FTZ) {
            mxcsr |= (1<<15) | (1<<11);
    }

    if (DAZ) {
            mxcsr |= (1<<6);
    }

    _mm_setcsr (mxcsr);
}

gcc स्विचेस का भी उपयोग करें: -msse -mfpmath = sse

(कार्ल हेथरिंगटन को संबंधित क्रेडिट [1])

[१] http://carlh.net/plugins/denormals.php


यह भी देखें fesetround()से fenv.h(गोलाई का अधिक पोर्टेबल रास्ता (C99 के लिए परिभाषित) किसी अन्य के लिए, linux.die.net/man/3/fesetround ) (लेकिन यह सभी एफपी संचालन सिर्फ subnormals नहीं प्रभावित करती है, )
जर्मन गार्सिया

क्या आप सुनिश्चित हैं कि आपको FTZ के लिए 1 << 15 और 1 << 11 की आवश्यकता है? मैंने केवल 1 << 15 को कहीं और उद्धृत किया है ...
अंजीर

@fig: 1 << 11 अंडरफ्लो मास्क के लिए है। यहाँ अधिक जानकारी: softpixel.com/~cwright/programming/simd/sse.php
जर्मन गार्सिया

@ GemGarcia यह OPs प्रश्न का उत्तर नहीं देता है; सवाल यह था कि "यह बिट कोड क्यों होता है, की तुलना में 10 गुना तेज चलता है ..." - आपको या तो यह जवाब देने का प्रयास करना चाहिए कि इस समाधान को प्रदान करने से पहले या टिप्पणी में इसे प्रदान करें।

9

डैन नीली की टिप्पणी को एक उत्तर में विस्तारित किया जाना चाहिए:

यह शून्य स्थिरांक नहीं है जो 0.0fकि अपभ्रंश है या धीमा होने का कारण बनता है, यह मान है जो लूप के प्रत्येक पुनरावृत्ति के दृष्टिकोण में आता है। जैसे ही वे करीब आते हैं और शून्य के करीब आते हैं, उन्हें प्रतिनिधित्व करने के लिए अधिक सटीकता की आवश्यकता होती है और वे अपभ्रंश हो जाते हैं। ये y[i]मूल्य हैं। (वे शून्य तक पहुंचते हैं क्योंकि x[i]/z[i]सभी के लिए 1.0 से कम हैi ।)

कोड के धीमे और तेज़ संस्करणों के बीच महत्वपूर्ण अंतर कथन है y[i] = y[i] + 0.1f;। जैसे ही इस पंक्ति को लूप के प्रत्येक पुनरावृत्ति को निष्पादित किया जाता है, फ़्लोट में अतिरिक्त परिशुद्धता खो जाती है, और उस सटीकता का प्रतिनिधित्व करने के लिए आवश्यक अपभ्रंश की आवश्यकता नहीं होती है। बाद में, फ्लोटिंग पॉइंट ऑपरेशंस y[i]तेजी से बने रहते हैं क्योंकि वे अपभ्रंश नहीं होते हैं।

जब आप जोड़ते हैं तो अतिरिक्त परिशुद्धता क्यों खो जाती है 0.1f? क्योंकि फ्लोटिंग पॉइंट नंबरों में केवल इतने महत्वपूर्ण अंक होते हैं। मान लें कि आपके पास तीन महत्वपूर्ण अंकों के लिए पर्याप्त भंडारण है 0.00001 = 1e-5, और 0.00001 + 0.1 = 0.1, कम से कम इस उदाहरण के लिए फ्लोट प्रारूप है, क्योंकि इसमें कम से कम महत्वपूर्ण बिट को स्टोर करने के लिए जगह नहीं है 0.10001

संक्षेप में, y[i]=y[i]+0.1f; y[i]=y[i]-0.1f;ऐसा नहीं है कि आप सोच सकते हैं कि यह है।

मिस्टिकल ने यह भी कहा : तैरने की सामग्री मायने रखती है, न कि केवल विधानसभा कोड।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.