将C++双精度转换为DEC双精度

Convert C++ double to DEC double

本文关键字:双精度 DEC 转换 C++      更新时间:2023-10-16

我希望能够获得用户给定的双精度并以DEC 64 dpfp格式写出(http://www.wsmr.army.mil/RCCsite/Documents/106%20Previous%20Versions/106-07/addlexO.pdf)。如果无法正确排列,有人有DEC类型的转换函数的经验或编写过吗?

这看起来很直接,让我试一下。注意,我没有任何方法来测试它的正确性。

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;
}
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

我发现将libvaxdata C库集成到我的C++解决方案中是最好的方法。在我的用例中,所需要的只是一些字节翻转,然而例程的工作是完美的。

在处理与IEEE/DEC类型的转换时,我建议使用libvaxdata库。

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