2010-01-06 21 views
5

किसी को भी तुरंत अवर के लिए एक आईईईई 754 double कन्वर्ट करने के लिए कोड का काम के टुकड़े है बिना फ्लोट करने के लिए (resp। बेहतर) float, बदलने या एफपीयू की वर्तमान राउंडिंग बारे में कुछ भी यह सोचते हैं बिना मोड?डबल परिवर्तित एफपीयू राउंडिंग मोड पर निर्भर

नोट: यह बाधा शायद एफपीयू का उपयोग न करने का तात्पर्य है। मुझे उम्मीद है कि इन परिस्थितियों में इसे करने का सबसे आसान तरीका 64-बिट लंबे समय तक डबल के बिट्स को पढ़ना और उसके साथ काम करना है।

आप सादगी के लिए अपनी पसंद के endianness मान सकते हैं, और है कि प्रश्न में डबल नीचे संघ के d क्षेत्र के माध्यम से उपलब्ध है:

union double_bits 
{ 
    long i; 
    double d; 
}; 

मैं इसे अपने आप करने की कोशिश करेंगे, लेकिन मैं कुछ कर रहा हूँ मैं denormalized या नकारात्मक संख्या के लिए हार्ड-टू-नोटिस बग पेश करेगा।

+0

glibc सिस्टम पर आप एक हेडर फाइल ieee754.h है, जो चल बिन्दु प्रकार और एक bitfield संरचना के लिए यूनियनों को परिभाषित करता है लगता है, तो आप अपूर्णांश और प्रतिपादक आसान, खेद के साथ काम कर सकते हैं लेकिन मैं आपको असली नहीं दे सकता कोड। – quinmars

उत्तर

3

मैं निम्नलिखित काम करता है लगता है, लेकिन मैं पहले मेरी मान्यताओं की जानकारी मौजूद होगी :

  • फ्लोटिंग प्वाइंट नंबर,
  • अपने कार्यान्वयन पर आईईईई-754 प्रारूप में जमा हो जाती है
  • कोई ओवरफ़्लो,
  • आपके पास nextafterf() उपलब्ध है (यह C99 में निर्दिष्ट है)।

इसके अलावा, सबसे अधिक संभावना है, यह विधि बहुत ही कुशल नहीं है।

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 

int main(int argc, char *argv[]) 
{ 
    /* Change to non-zero for superior, otherwise inferior */ 
    int superior = 0; 

    /* double value to convert */ 
    double d = 0.1; 

    float f; 
    double tmp = d; 

    if (argc > 1) 
     d = strtod(argv[1], NULL); 

    /* First, get an approximation of the double value */ 
    f = d; 

    /* Now, convert that back to double */ 
    tmp = f; 

    /* Print the numbers. %a is C99 */ 
    printf("Double: %.20f (%a)\n", d, d); 
    printf("Float: %.20f (%a)\n", f, f); 
    printf("tmp: %.20f (%a)\n", tmp, tmp); 

    if (superior) { 
     /* If we wanted superior, and got a smaller value, 
      get the next value */ 
     if (tmp < d) 
      f = nextafterf(f, INFINITY); 
    } else { 
     if (tmp > d) 
      f = nextafterf(f, -INFINITY); 
    } 
    printf("converted: %.20f (%a)\n", f, f); 

    return 0; 
} 

मेरी मशीन पर, यह प्रिंट:

Double: 0.10000000000000000555 (0x1.999999999999ap-4) 
Float: 0.10000000149011611938 (0x1.99999ap-4) 
tmp: 0.10000000149011611938 (0x1.99999ap-4) 
converted: 0.09999999403953552246 (0x1.999998p-4) 

विचार यह है कि मैं एक float मूल्य — करने के लिए double मूल्य परिवर्तित कर रहा हूँ इस से कम या उसके आधार पर डबल मूल्य से अधिक हो सकता है गोलाकार मोड। जब double पर वापस परिवर्तित किया गया, तो हम जांच सकते हैं कि यह मूल मान से छोटा या बड़ा है या नहीं। फिर, यदि float का मान सही दिशा में नहीं है, तो हम मूल संख्या की दिशा में परिवर्तित संख्या से अगले float नंबर देखें।

+0

इस कोड के लिए बहुत बहुत धन्यवाद। मैं धीरे-धीरे आश्वस्त हो रहा था कि यह कम से कम त्रुटि-प्रवण समाधान था। 'Nextafterf' को इंगित करने के लिए भी धन्यवाद, यह 'फ्लोट' की बिट्स को कम/घटाने से काफी बेहतर है जैसे कि यह 'int' था। 'F + 1' के बराबर' f + 1' के जोखिम को कम करने के लिए, क्या मैं इसके बजाय 'nextafterf (f, INFINITY)' लिख सकता हूं? –

+0

मैंने बस मैन पेज, सी मानक ड्राफ्ट पढ़ा, और इसे आज़माया, और ऐसा लगता है कि 'इन्फिनिटी' को काम करना चाहिए। –

+0

ठीक है, मैंने अपनी पोस्ट संपादित की है। टिप्पणी के लिए धन्यवाद। –

3

अधिक सही से सिर्फ अपूर्णांश फिर से गठबंधन और यह काम करने के लिए प्रतिपादक बिट के चेक इस बाहर:

http://www.mathworks.com/matlabcentral/fileexchange/23173

संबंध

+0

धन्यवाद। 'Doubles2halfp' फ़ंक्शन जितना जटिल था उतना जटिल है, लेकिन कम से कम पहले से ही आधा स्थिरांक है, इसलिए यह एक अच्छा प्रारंभिक बिंदु है। –

+0

मैं संदर्भ के रूप में दिए गए कोड का उपयोग करता हूं और एक सरल दृष्टिकोण को फिर से लिखता हूं, >> द्वारा अनुशंसित और >> और फिर बहुत छोटी और बहुत बड़ी संख्याओं की जांच करता है। Http://babbage.cs.qc.edu/IEEE-754/Decimal से एक नज़र में शिफ्ट गणना और बिट-स्थिति लें।एचटीएमएल – stacker

2

मैंने इसे यहां करने के लिए कोड पोस्ट किया: https://stackoverflow.com/q/19644895/364818 और आपकी सुविधा के लिए इसे नीचे कॉपी किया।

// d is IEEE double, but double is not natively supported. 
    static float ConvertDoubleToFloat(void* d) 
    { 
     unsigned long long x; 
     float f; // assumed to be IEEE float 
     unsigned long long sign ; 
     unsigned long long exponent; 
     unsigned long long mantissa; 

     memcpy(&x,d,8); 

     // IEEE binary64 format (unsupported) 
     sign  = (x >> 63) & 1; // 1 
     exponent = ((x >> 52) & 0x7FF); // 11 
     mantissa = (x >> 0) & 0x000FFFFFFFFFFFFFULL; // 52 
     exponent -= 1023; 

     // IEEE binary32 format (supported) 
     exponent += 127; // rebase 
     exponent &= 0xFF; 
     mantissa >>= (52-23); // left justify 

     x = mantissa | (exponent << 23) | (sign << 31); 
     memcpy(&f,&x,4); 

     return f; 
    } 
+0

धन्यवाद। रेखा 'एक्सपोनेंट और = 0xFF;' का अर्थ है कि जब यह '± FLT_MAX' या' ± inf' को वापस करने के लिए उचित होगा, तो एक अजीब एक्सपोनेंट के साथ एक 'फ्लोट' इसके बदले वापस कर दिया जाएगा (और असामान्य परिणाम भी बंद हैं)। –

संबंधित मुद्दे