2014-10-10 121 views
0

我希望能夠讓用戶給出double並以DEC 64 dpfp格式(http://www.wsmr.army.mil/RCCsite/Documents/106%20Previous%20Versions/106-07/appendixO.pdf)寫出。無法正確排列這些信息,任何人都有經驗或已經爲DEC類型編寫了轉換函數?將C++ double轉換爲DEC double

+0

刷新我的記憶,是DEC的大端還是小端? – 2014-10-10 15:42:39

+0

Little-endian我相信 – favre45 2014-10-10 19:07:24

+1

2分鐘後,我創建了自己的答案我發現這個:http://pubs.usgs.gov/of/2005/1424/of2005-1424_v1.2.pdf – 2014-10-10 21:01:36

回答

0

這看起來很直截了當,讓我試試吧。請注意,我沒有任何方法來測試它是否正確。

std::vector<unsigned char> ToDEC64Float(double d) 
{ 
    uint64_t dec_bits = 0ULL; 
    if (d != 0.0) 
    { 
     assert(sizeof(double) == sizeof(uint64_t)); 
     uint64_t bits = *reinterpret_cast<uint64_t*>(&d); 
     uint64_t fraction = bits & 0x000fffffffffffffULL; 
     int exp = (int)((bits >> 52) & 0x7ff) - 1023; 
     bool sign = (bool)(bits & 0x8000000000000000ULL); 
     // convert the individual values for the new format 
     fraction <<= 3; 
     exp += 1 + 128; 
     if (exp > 255) 
      throw std::overflow_error("overflow"); 
     if (exp < 0 || (exp == 0 && fraction != 0)) 
      throw std::underflow_error("underflow"); 
     dec_bits = (uint64_t)sign << 63 | (uint64_t)exp << 55 | fraction; 
    } 
    std::vector<unsigned char> result; 
    for (int i = 0; i < 64; i+=8) 
     result.push_back((unsigned char)((dec_bits >> i) & 0xff)); 
    return result; 
} 
+0

用一些測試數據試驗過你的方法 – favre45 2014-10-14 16:41:54

+0

當採用DEC值時,使用上面貼出的代碼進行輸出,轉換爲雙倍並再次轉換回來。我意識到發生了一些損失,它不是一對一,但認爲它應該至少有點接近 – favre45 2014-10-14 16:52:53

+0

@ favre45該方法的問題是,該錯誤可能是在轉換*到*或轉換*從*。更糟糕的是,如果你們在兩方面都有錯誤,那麼互相補償就會導致你相信這是錯的。唯一真正的測試是將結果與正確格式的已知數字進行比較。 – 2014-10-14 17:52:01

0
double static const DECBytesToDouble(uint64_t value) 
{ 
    //DEC Byte Conversion Constants 
    static const float MANTISSA_CONSTANT = 0.5; 
    static const int32_t EXPONENT_BIAS = 128; 
    uint8_t * byte_array = (uint8_t*)&value; 
    uint8_t first = byte_array[0]; 
    uint8_t second = byte_array[1]; 
    uint8_t third = byte_array[2]; 
    uint8_t fourth = byte_array[3]; 
    uint8_t fifth = byte_array[4]; 
    uint8_t sixth = byte_array[5]; 
    uint8_t seventh = byte_array[6]; 
    uint8_t eighth = byte_array[7]; 
    // |second |first|fourth|third|sixth|fifth|eighth|seventh| 
    // |s|exponent|mantissa         | 
    bool sign = second & 0x80; 
    std::cout<<"(DECBytesToDouble) Sign: "<<sign<<std::endl; 
    int32_t exponent = ((second & 0x7F) << 1) + ((first >> 7) & 0x1); 
    std::cout<<"(DECBytesToDouble) Exponent: "<<exponent<<std::endl; 
    int64_t mantissa = ((int64_t)(first & 0x7F) << 48) + ((int64_t)fourth << 40) 
    + ((int64_t)third << 32) + ((int64_t)sixth << 24) + ((int64_t)fifth << 16) 
    + ((int64_t)eighth << 8) + (int64_t)  seventh; 
    std::cout<<"(DECBytesToDouble) Fraction: "<<mantissa<<std::endl; 
    double fraction = MANTISSA_CONSTANT; 
    for (int32_t i=0; i<55; i++) 
    { 
    fraction += ((mantissa >> i) & 0x1) * pow(2,i-56); 
    }//for 
    return pow(-1,sign)*fraction*pow(2,exponent-EXPONENT_BIAS); 
}//DECBytesToDouble 


uint64_t static const DoubleToDECBytes(double value) 
{ 
    static const int32_t EXPONENT_BIAS = 128; 
    uint64_t dec_bits = 0ULL; 
    if (value != 0.0) 
    { 
    uint64_t bits = *reinterpret_cast<uint64_t*>(&value); 
    uint64_t fraction = bits & 0x000fffffffffffffULL; 
    int exp = (int)((bits >> 52) & 0x7ff) - 1023; 
    bool sign = false; 
    if(value < 0) 
    { 
     sign = true; 
    }//if 
    std::cout<<"(DoubleToDECBytes) Sign: "<<sign<<std::endl; 
    // convert the individual values for the new format 
    fraction <<= 3; 
    exp += EXPONENT_BIAS + 1; 
    std::cout<<"(DoubleToDECBytes) Exponent: "<<exp<<std::endl; 
    std::cout<<"(DoubleToDECBytes) Fraction: "<<fraction<<std::endl; 
    if (exp > 255) 
     throw std::overflow_error("overflow"); 
    if (exp < 0 || (exp == 0 && fraction != 0)) 
     throw std::underflow_error("underflow"); 
    dec_bits = (uint64_t)(sign << 63) | (uint64_t)(exp << 55) | fraction; 
    //|second |first|fourth|third|sixth|fifth|eighth|seventh| 
    uint8_t * byte_array = (uint8_t*)&dec_bits; 
    uint8_t first = byte_array[0]; 
    uint8_t second = byte_array[1]; 
    uint8_t third = byte_array[2]; 
    uint8_t fourth = byte_array[3]; 
    uint8_t fifth = byte_array[4]; 
    uint8_t sixth = byte_array[5]; 
    uint8_t seventh = byte_array[6]; 
    uint8_t eighth = byte_array[7]; 
    byte_array[7] = second; 
    byte_array[6] = first; 
    byte_array[5] = fourth; 
    byte_array[4] = third; 
    byte_array[3] = sixth; 
    byte_array[2] = fifth; 
    byte_array[1] = eighth; 
    byte_array[0] = seventh; 
    std::cout<<"(DoubleToDECBytes) Guess ="<<dec_bits<<std::endl; 

    }//if 
    /*std::vector<unsigned char> result; 
    for (int i = 0; i < 64; i+=8) 
    { 
    result.push_back((unsigned char)((dec_bits >> i) & 0xff)); 
    }//for 
    uint64_t final_result = 0; 
    memcpy(&final_result, &result[0], sizeof(uint64_t)); 
    std::cout<<"Final result: "<<final_result<<std::endl;*/ 
    return dec_bits; 
}//DoubleToDECBytes 

Output: 
input uint64_t value: 9707381994276473045 
(DECBytesToDouble) Sign: 0 
(DECBytesToDouble) Exponent: 145 
(DECBytesToDouble) Fraction: 24184718387676855 
output double value: 109527.7465 
(DoubleToDECBytes) Sign: 0 
(DoubleToDECBytes) Exponent: 145 
(DoubleToDECBytes) Fraction: 24184718387676848 
(DoubleToDECBytes) Guess =9705411669439479893 
Converted double, uint64_t: 9705411669439479893 
uint64_t difference: 1970324836993152 
(DECBytesToDouble) Sign: 0 
(DECBytesToDouble) Exponent: 0 
(DECBytesToDouble) Fraction: 24184718387676848 
output double value: 0.0000 
+0

@MarkRansom以上是我目前所在的位置,無法完全轉換來回轉換 – favre45 2014-10-14 17:01:21

0

我才發現,libvaxdata C庫集成到我的C++的解決辦法是最好的一段路要走。在我的用例情況下,所需的只是一些字節翻轉,然而這些例程完美無缺地工作。

我在處理與IEEE/DEC類型的轉換時建議使用libvaxdata庫。

http://pubs.usgs.gov/of/2005/1424/