2010-10-21 8 views
18

से 32 बिट फ्लोट का निर्माण करना मैं अपने 4 समग्र बाइट्स में से 32 बिट फ्लोट बनाने की कोशिश कर रहा हूं। क्या निम्न विधि के मुकाबले ऐसा करने के लिए कोई बेहतर (या अधिक पोर्टेबल) तरीका है?अपने 4 समग्र बाइट्स [सी ++]

#include <iostream> 

typedef unsigned char uchar; 

float bytesToFloat(uchar b0, uchar b1, uchar b2, uchar b3) 
{ 
    float output; 

    *((uchar*)(&output) + 3) = b0; 
    *((uchar*)(&output) + 2) = b1; 
    *((uchar*)(&output) + 1) = b2; 
    *((uchar*)(&output) + 0) = b3; 

    return output; 
} 

int main() 
{ 
    std::cout << bytesToFloat(0x3e, 0xaa, 0xaa, 0xab) << std::endl; // 1.0/3.0 
    std::cout << bytesToFloat(0x7f, 0x7f, 0xff, 0xff) << std::endl; // 3.4028234 × 10^38 (max single precision) 

    return 0; 
} 
+3

यह मानते हुए कि यह स्टैक ओवरफ़्लो पर मेरा पहला प्रश्न था, मैं विभिन्न प्रतिक्रियाओं से रोमांचित हूं। मैं उनके इनपुट के लिए सभी को धन्यवाद देता हूं। – Madgeek

उत्तर

26

आप इस्तेमाल कर सकते हैं एक memcpy (Result)

float f; 
uchar b[] = {b3, b2, b1, b0}; 
memcpy(&f, &b, sizeof(f)); 
return f; 

या एक संघ * (Result)

union { 
    float f; 
    uchar b[4]; 
} u; 
u.b[3] = b0; 
u.b[2] = b1; 
u.b[1] = b2; 
u.b[0] = b3; 
return u.f; 

लेकिन यह अपने कोड से अधिक नहीं पोर्टेबल है, के बाद से कोई गारंटी है कि मंच छोटा-एंडियन है या float आईईईई बाइनरी 32 या यहां तक ​​कि sizeof(float) == 4 का उपयोग कर रहा है।

(नोट *: @James द्वारा समझाया रूप में, यह तकनीकी रूप से मानक में अनुमति नहीं है (सी ++ § [class.union]/1) यूनियन सदस्य u.f तक पहुँचने के लिए।)

+3

'आकार (फ्लोट)' समस्या को हल करने के लिए आप 'बी' सदस्य को 'उचर बी [आकार (फ्लोट)] के रूप में घोषित कर सकते हैं; '। –

+0

@ मेटेटो: ठीक है, लेकिन फिर इनपुट को भी संशोधित करने की आवश्यकता है। – kennytm

12

आप std::copy उपयोग कर सकते हैं:

float bytesToFloat(uchar b0, uchar b1, uchar b2, uchar b3) 
{ 
    uchar byte_array[] = { b3, b2, b1, b0 }; 
    float result; 
    std::copy(reinterpret_cast<const char*>(&byte_array[0]), 
       reinterpret_cast<const char*>(&byte_array[4]), 
       reinterpret_cast<char*>(&result)); 
    return result; 
} 

यह यूनियन हैक से बचाता है, जिसे तकनीकी रूप से भाषा द्वारा अनुमति नहीं दी जाती है। यह भी बचा जाता है आमतौर पर reinterpret_cast<float*>(byte_array) इस्तेमाल किया है, जो सख्त अलियासिंग नियम (ताकि इस समाधान में reinterpret_cast रों सख्त अलियासिंग नियमों का उल्लंघन नहीं करते यह, char की एक सरणी के रूप में किसी भी वस्तु पुनर्व्याख्या की अनुमति नहीं है) का उल्लंघन है।

यह अभी भी चौड़ाई में float जा रहा है चार बाइट्स पर निर्भर करता है और अपने कार्यान्वयन के चल बिन्दु प्रारूप में एक मान्य चल बिन्दु संख्या जा रहा है अपने चार बाइट्स पर निर्भर करता है, लेकिन आप या तो उन मान्यताओं बनाने के लिए है या आप के लिए विशेष हैंडलिंग कोड लिखने के लिए है रूपांतरण करो

+0

यह अभी भी पोर्टेबल नहीं है, है ना? मैं सिर्फ उत्सुक हूँ ... – JoshD

+0

@ जोश डी: नहीं; यह अभी भी 'sizeof (float) == 4' पर निर्भर करता है और अंतहीनता को ध्यान में नहीं लेता है। यह सिर्फ 'reinterpret_cast (some_uchar_array) 'और यूनियन हैक से बचाता है। –

+0

मैं काफी हद तक निश्चित हूं कि reteterpret_cast (byte_array) 'को अनुमति दी जानी चाहिए यदि बाइट_एरे (1) ठीक से संरेखित है और (2) वास्तव में एक फ्लोट है। मुझे ऐसा लगता है क्योंकि अन्यथा 'फ्लोट' को 'फ्लोट' को 'फ्लैट'' करना असंभव होगा (चूंकि 'memcpy' बाइट सरणी में लिखता है), और फिर भी 'फ्लोट' archetypical POD प्रकार है। – MSalters

3

आप एक पोर्टेबल तरीका ऐसा करना चाहते हैं, तो आप प्रणाली के endianess पता लगाने के लिए कोड का एक सा लिखने के लिए होगा।

float bytesToFloatA(uchar b0, uchar b1, uchar b2, uchar b3) 
{ 
    float output; 

    *((uchar*)(&output) + 3) = b0; 
    *((uchar*)(&output) + 2) = b1; 
    *((uchar*)(&output) + 1) = b2; 
    *((uchar*)(&output) + 0) = b3; 

    return output; 
} 


float bytesToFloatB(uchar b0, uchar b1, uchar b2, uchar b3) 
{ 
    float output; 

    *((uchar*)(&output) + 3) = b3; 
    *((uchar*)(&output) + 2) = b2; 
    *((uchar*)(&output) + 1) = b1; 
    *((uchar*)(&output) + 0) = b0; 

    return output; 
} 

float (*correctFunction)(uchar b0, uchar b1, uchar b2, uchar b3) = bytesToFloatA; 

if ((*correctFunction)(0x3e, 0xaa, 0xaa, 0xab) != 1.f/3.f) // horrifying, I know 
{ 
    correctFunction = bytesToFloatB; 
} 
+1

यह किसी भी एंडियन में बराबर नहीं होगा क्योंकि '1./3.'' डबल 'है, न कि' फ्लोट '। आपको '1.0f/3' जैसे कुछ का उपयोग करना चाहिए। – kennytm

4

, यह पोर्टेबल करने के लिए कोई तरीका नहीं है, क्योंकि विभिन्न प्लेटफार्मों का उपयोग कर सकते हैं:

  • अलग बाइट आदेश (बड़ा endian बनाम छोटे endian) चल बिन्दु मूल्यों के लिए
  • अलग अभ्यावेदन (http://en.wikipedia.org/wiki/IEEE_754-1985 देखना उदाहरण के लिए)
  • फ़्लोटिंग पॉइंट मानों के लिए विभिन्न आकार

मुझे यह भी आश्चर्य है कि आप इन 4 बाइट्स कहां से प्राप्त करते हैं?

तो मुझे लगता है कि आप उन्हें किसी अन्य प्रणाली से मिलता है, और आप गारंटी ले सकते हैं कि दोनों सिस्टम ठीक उसी विधि का उपयोग स्मृति में फ्लोटिंग प्वाइंट मान संग्रहीत करने के लिए, आप संघ चाल का उपयोग कर सकते हैं। अन्यथा, आपका कोड लगभग पोर्टेबल होने की गारंटी है।

13

निम्नलिखित कार्य पैक/खोल एक एकल परिशुद्धता चल नेटवर्क बाइट क्रम में एक बफर से/बिंदु मूल्य का प्रतिनिधित्व बाइट्स। केवल पैक विधि को खाते में अंतहीनता लेने की आवश्यकता होती है क्योंकि अनपैक विधि स्पष्ट रूप से उचित बाइट्स को स्थानांतरित करने के लिए अलग-अलग बाइट्स से 32-बिट मान बनाता है और फिर उन्हें एक साथ जोड़ता है। ये फ़ंक्शन केवल सी/सी ++ कार्यान्वयन के लिए मान्य हैं जो 32-बिट्स में एक फ्लोट स्टोर करते हैं।यह IEEE 754-1985 फ़्लोटिंग पॉइंट कार्यान्वयन के लिए सच है।

// unpack method for retrieving data in network byte, 
// big endian, order (MSB first) 
// increments index i by the number of bytes unpacked 
// usage: 
// int i = 0; 
// float x = unpackFloat(&buffer[i], &i); 
// float y = unpackFloat(&buffer[i], &i); 
// float z = unpackFloat(&buffer[i], &i); 
float unpackFloat(const void *buf, int *i) { 
    const unsigned char *b = (const unsigned char *)buf; 
    uint32_t temp = 0; 
    *i += 4; 
    temp = ((b[0] << 24) | 
      (b[1] << 16) | 
      (b[2] << 8) | 
      b[3]); 
    return *((float *) temp); 
} 

// pack method for storing data in network, 
// big endian, byte order (MSB first) 
// returns number of bytes packed 
// usage: 
// float x, y, z; 
// int i = 0; 
// i += packFloat(&buffer[i], x); 
// i += packFloat(&buffer[i], y); 
// i += packFloat(&buffer[i], z); 
int packFloat(void *buf, float x) { 
    unsigned char *b = (unsigned char *)buf; 
    unsigned char *p = (unsigned char *) &x; 
#if defined (_M_IX86) || (defined (CPU_FAMILY) && (CPU_FAMILY == I80X86)) 
    b[0] = p[3]; 
    b[1] = p[2]; 
    b[2] = p[1]; 
    b[3] = p[0]; 
#else 
    b[0] = p[0]; 
    b[1] = p[1]; 
    b[2] = p[2]; 
    b[3] = p[3]; 
#endif 
    return 4; 
} 
+0

मुझे लगता है कि कोड लाइन में कोई गलती है: वापसी * ​​((फ्लोट *) अस्थायी); यह होना चाहिए: वापसी * ​​((फ्लोट *) &temp); –