双精度到十六进制字符串 & 十六进制字符串转为双精度

发布于 2024-07-13 04:11:44 字数 444 浏览 4 评论 0原文

我想做的是将双精度数转换为十六进制字符串,然后再转换回双精度数。

以下代码将双精度字符串转换为十六进制字符串。

char * double2HexString(double a)
{
   char *buf = new char[17]; // double is 8-byte long, so we have 2*8 + terminating \0
   char *d2c;
   d2c = (char *) &a;
   char *n = buf;
   int i;
   for(i = 0; i < 8; i++)
   {
      sprintf(n, "%02X", *d2c++);
      n += 2;
   } 
   *(n) = '\0';
}

这似乎可行,但是,我不确定如何将结果字符串转换回双精度。 请指教 :)

What I'm trying to do is to convert a double to hex string and then back to double.

The following code does conversion double-to-hex string.

char * double2HexString(double a)
{
   char *buf = new char[17]; // double is 8-byte long, so we have 2*8 + terminating \0
   char *d2c;
   d2c = (char *) &a;
   char *n = buf;
   int i;
   for(i = 0; i < 8; i++)
   {
      sprintf(n, "%02X", *d2c++);
      n += 2;
   } 
   *(n) = '\0';
}

This seems work, however, I'm not sure how to convert the resulting string back to double.
Please advise :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

柠檬 2024-07-20 04:11:44

我很惊讶地发现没有人提出标准解决方案,即 ISO C99 标准中的 %a 格式说明符。

#include <iostream>
#include <string>
#include <stdio.h>

std::string double2hexastr(double d) {

  char buffer[25] = { 0 };

  ::snprintf(buffer, 25, "%A", d); // TODO Check for errors

  return buffer;
}

double hexastr2double(const std::string& s) {

  double d = 0.0;

  ::sscanf(s.c_str(), "%lA", &d); // TODO Check for errors

  return d;
}


int main() {

  std::cout << "0.1 in hexadecimal: " << double2hexastr(0.1) << std::endl;

  std::cout << "Reading back 0X1.999999999999AP-4, it is ";

  std::cout << hexastr2double("0X1.999999999999AP-4") << std::endl;

}

I am surprised to see nobody has come up with the standard solution, which is the %a format specifier in the ISO C99 Standard.

#include <iostream>
#include <string>
#include <stdio.h>

std::string double2hexastr(double d) {

  char buffer[25] = { 0 };

  ::snprintf(buffer, 25, "%A", d); // TODO Check for errors

  return buffer;
}

double hexastr2double(const std::string& s) {

  double d = 0.0;

  ::sscanf(s.c_str(), "%lA", &d); // TODO Check for errors

  return d;
}


int main() {

  std::cout << "0.1 in hexadecimal: " << double2hexastr(0.1) << std::endl;

  std::cout << "Reading back 0X1.999999999999AP-4, it is ";

  std::cout << hexastr2double("0X1.999999999999AP-4") << std::endl;

}
温馨耳语 2024-07-20 04:11:44
char *doubleToRawString(double x) {
    // Assumes sizeof(long long) == 8.

    char *buffer = new char[32];
    sprintf(buffer, "%llx", *(unsigned long long *)&x);  // Evil!
    return buffer;
}

double rawStringToDouble(const char *s) {
    // Assumes sizeof(long long) == 8.

    double ret;
    sscanf(s, "%llx", (unsigned long long *)&ret);  // Evil!
    return ret;
}
char *doubleToRawString(double x) {
    // Assumes sizeof(long long) == 8.

    char *buffer = new char[32];
    sprintf(buffer, "%llx", *(unsigned long long *)&x);  // Evil!
    return buffer;
}

double rawStringToDouble(const char *s) {
    // Assumes sizeof(long long) == 8.

    double ret;
    sscanf(s, "%llx", (unsigned long long *)&ret);  // Evil!
    return ret;
}
感性不性感 2024-07-20 04:11:44
char *doubleToRawString(double x) {
    const size_t bytesInDouble = 8;

    union {
        double value;
        unsigned char bytes[bytesInDouble];
    } u;

    u.value = x;

    char *buffer = new char[bytesInDouble * 2 + 1];
    unsigned char *input = u.bytes;
    char *output = buffer;

    for(int i = 0; i < bytesInDouble; ++i) {
        sprintf(output, "%02hhX", *input);

        ++input;
        output += 2;
    }

    return buffer;
}

double rawStringToDouble(const char *input) {
    const size_t bytesInDouble = 8;

    union {
        double value;
        unsigned char bytes[bytesInDouble];
    } u;

    unsigned char *output = u.bytes;

    for(int i = 0; i < bytesInDouble; ++i) {
        sscanf(input, "%02hhX", output);

        input += 2;
        ++output;
    }

    return u.value;
}

这使用非标准 hh 修饰符。 如果您不想使用它,请使用:

unsigned int tmp = *input;
sprintf(output, "%02X", tmp);

unsigned int tmp;
sscanf(input, "%02X", &tmp);
*output = tmp;
char *doubleToRawString(double x) {
    const size_t bytesInDouble = 8;

    union {
        double value;
        unsigned char bytes[bytesInDouble];
    } u;

    u.value = x;

    char *buffer = new char[bytesInDouble * 2 + 1];
    unsigned char *input = u.bytes;
    char *output = buffer;

    for(int i = 0; i < bytesInDouble; ++i) {
        sprintf(output, "%02hhX", *input);

        ++input;
        output += 2;
    }

    return buffer;
}

double rawStringToDouble(const char *input) {
    const size_t bytesInDouble = 8;

    union {
        double value;
        unsigned char bytes[bytesInDouble];
    } u;

    unsigned char *output = u.bytes;

    for(int i = 0; i < bytesInDouble; ++i) {
        sscanf(input, "%02hhX", output);

        input += 2;
        ++output;
    }

    return u.value;
}

This uses the non-standard hh modifier. If you don't want to use that, use:

unsigned int tmp = *input;
sprintf(output, "%02X", tmp);

unsigned int tmp;
sscanf(input, "%02X", &tmp);
*output = tmp;
沫离伤花 2024-07-20 04:11:44

对于 MFC,将 double 转换为 CString :)

CString MFCClass::DoubleToCString(double d, int beforKomma)
{
    char a[17]="0123456789ABCDEF";
    CString str = _T("");
    double dInt=0,dPunkt=0;
    bool is_otr=0;
    if (d<0) {is_otr=1; d=-d;}
    dPunkt = modf(d, &dInt);
    //целая часть
    long ld = (long)dInt;
    long mask = 0xf;
    int it;
    while(ld>0)
    {
        it = ld&mask;
        ld = ld>>4;
        str.Insert(0,a[it]);
    };
    // дробная часть
    //если целая часть 0:
    if (str.GetLength()==0) str += _T("0");
    str += _T(".");
    for (int i=0; i<beforKomma; i++)
    {
        dPunkt*=16;
        dPunkt = modf(dPunkt, &dInt);
        str += a[(int)dInt];
    }

    if (is_otr) str.Insert(0,_T("-"));
    return (str);
}

-345.86783907228863 -> "-159.DE2" (beforKomma=3)

For MFC, convert double to CString :)

CString MFCClass::DoubleToCString(double d, int beforKomma)
{
    char a[17]="0123456789ABCDEF";
    CString str = _T("");
    double dInt=0,dPunkt=0;
    bool is_otr=0;
    if (d<0) {is_otr=1; d=-d;}
    dPunkt = modf(d, &dInt);
    //целая часть
    long ld = (long)dInt;
    long mask = 0xf;
    int it;
    while(ld>0)
    {
        it = ld&mask;
        ld = ld>>4;
        str.Insert(0,a[it]);
    };
    // дробная часть
    //если целая часть 0:
    if (str.GetLength()==0) str += _T("0");
    str += _T(".");
    for (int i=0; i<beforKomma; i++)
    {
        dPunkt*=16;
        dPunkt = modf(dPunkt, &dInt);
        str += a[(int)dInt];
    }

    if (is_otr) str.Insert(0,_T("-"));
    return (str);
}

-345.86783907228863 -> "-159.DE2" (beforKomma=3)

半寸时光 2024-07-20 04:11:44

老实说,使用 sprintf 很慢,但您可以使用 sscanf 恢复它,做几乎完全相同的事情。

好吧,实际上,您必须将每两个字符复制到缓冲区字符串中,才能单独解码每个字符。 我的第一次尝试,下面是不正确的:

double hexString2Double(char *buf)
{
  char *buf2 = new char[3];
  double a;
  char* c2d;
  c2d = (char *) &a;
  int i;

  buf2[2] = '\0'

  for(i = 0; i < 16; i++)
  {
    buf2[0] = *buf++;
    buf2[1] = *buf++;
    sscanf(buf2, "%X", c2d++);
  }

  return a;
}

你看,%X 被解码为 int,而不是字节。 它甚至可能有效,具体取决于低端/高端问题,但它基本上已经损坏了。 因此,让我们尝试解决这个问题:

double hexString2Double(char *buf)
{
  char *buf2 = new char[3];
  double a;
  char* c2d;
  c2d = (char *) &a;
  int i;
  int decoder;

  buf2[2] = '\0'

  for(i = 0; i < 16; i++)
  {
    buf2[0] = *buf++;
    buf2[1] = *buf++;
    sscanf(buf2, "%X", &decoder);
    c2d++ = (char) decoder;
  }

  return a;
}

除非出现语法错误等,我认为这应该可行。

Using sprintf is slow, to be honest, but you can revert it with sscanf, doing almost exactly the same thing.

Well, actually, you'd have to copy each two characters to a buffer string, to decode each individually. My first try, below is incorrect:

double hexString2Double(char *buf)
{
  char *buf2 = new char[3];
  double a;
  char* c2d;
  c2d = (char *) &a;
  int i;

  buf2[2] = '\0'

  for(i = 0; i < 16; i++)
  {
    buf2[0] = *buf++;
    buf2[1] = *buf++;
    sscanf(buf2, "%X", c2d++);
  }

  return a;
}

You see, %X is decoded as an int, not as a byte. It might even work, depending on low-ending/high-endian issues, but it's basically broken. So, let's try to get around that:

double hexString2Double(char *buf)
{
  char *buf2 = new char[3];
  double a;
  char* c2d;
  c2d = (char *) &a;
  int i;
  int decoder;

  buf2[2] = '\0'

  for(i = 0; i < 16; i++)
  {
    buf2[0] = *buf++;
    buf2[1] = *buf++;
    sscanf(buf2, "%X", &decoder);
    c2d++ = (char) decoder;
  }

  return a;
}

Barring syntax errors and such, I think this should work.

唱一曲作罢 2024-07-20 04:11:44

应该执行几乎相同的程序

void hex2double(const char* buf, double& a)
{
   char tmpbuf[3]={0};
   char *d2c;
   unsigned int tmp;
   d2c = (char *) &a;
   char *n = buf;
   int i;
   for(i = 0; i < 8; i++)
   {
      tmpbuf[0]=*buf++;
      tmpbuf[1]=*buf++;
      sscanf(tmpbuf, "%X", &tmp);
      *d2c++=tmp;
   }
}

Quick & 。 肮脏的。

但请注意,这是在玩火。 首先,您的十六进制字符串只能在具有相同双精度格式和相同字节序的机器上使用。 其次,转换函数缺乏严格的别名规则。

Almost the same procedure should do

void hex2double(const char* buf, double& a)
{
   char tmpbuf[3]={0};
   char *d2c;
   unsigned int tmp;
   d2c = (char *) &a;
   char *n = buf;
   int i;
   for(i = 0; i < 8; i++)
   {
      tmpbuf[0]=*buf++;
      tmpbuf[1]=*buf++;
      sscanf(tmpbuf, "%X", &tmp);
      *d2c++=tmp;
   }
}

Quick & dirty.

Note, however, that this is playing with fire. First, your hex strings are only usable on machines with the same double format, and the same endianness. Second, the conversion functions are short on strict aliasing rule.

霊感 2024-07-20 04:11:44
#include <stdio.h>
main() {
  union double_ull_t {
    double d;
    unsigned long long u;
  } x;
  scanf("%lf",&x.d);
  printf("%016llX %lf\n",x.u,x.d);
  scanf("%016llX",&x.u);
  printf("%016llX %lf\n",x.u,x.d);
}

也许不是最有效的解决方案,但最容易编码。

#include <stdio.h>
main() {
  union double_ull_t {
    double d;
    unsigned long long u;
  } x;
  scanf("%lf",&x.d);
  printf("%016llX %lf\n",x.u,x.d);
  scanf("%016llX",&x.u);
  printf("%016llX %lf\n",x.u,x.d);
}

Maybe not the most efficient solution, but the easiest to code.

洒一地阳光 2024-07-20 04:11:44

你想使用联合并避免这个坏习惯:

char *d2c;

d2c = (char *) &a;

仅仅打印它还不错,当你尝试修改 d2c 然后使用 a is 时,你就会遇到麻烦。 (对于共享相同(理论上)内存的任何两个变量或指针(或数组)也是如此。

union
{
    double f;
    unsigned long ul;
} myun;

myun.f = a;
printf("0x%lX",myun.ul);

to go the other way (scanf is also a very dangerous function that should be avoided).

myun.ul=strtoul(string,NULL,16);
a=myun.f;

You want to use a union and avoid this bad habit:

char *d2c;

d2c = (char *) &a;

For just printing its not bad, its when you try to modify d2c and then use a is when you get into trouble. (same is true for any two variables or pointers (or arrays) sharing the same (theoretical) memory.

union
{
    double f;
    unsigned long ul;
} myun;

myun.f = a;
printf("0x%lX",myun.ul);

to go the other way (scanf is also a very dangerous function that should be avoided).

myun.ul=strtoul(string,NULL,16);
a=myun.f;
尘世孤行 2024-07-20 04:11:44

我正在使用下面的函数将双精度转换为十六进制。

char * double2HexString(double a) 
{ 
   char *buf = new char[17]; // double is 8-byte long, so we have 2*8 + terminating \0 
   char *d2c; 
   d2c = (char *) &a; 
   char *n = buf; 
   int i; 
   for(i = 0; i < 8; i++) 
   { 
      sprintf(n, "%02X", *d2c++); 
      n += 2; 
   }  
   *(n) = '\0'; 
}  

通过1.0 & 16.0 到这个函数,观察到的返回值是 000000000000FF37 & 分别为 0000000000003040。 我认为我们应该得到 1 & 10.

I am using the below function, to convert double to hexadecimal.

char * double2HexString(double a) 
{ 
   char *buf = new char[17]; // double is 8-byte long, so we have 2*8 + terminating \0 
   char *d2c; 
   d2c = (char *) &a; 
   char *n = buf; 
   int i; 
   for(i = 0; i < 8; i++) 
   { 
      sprintf(n, "%02X", *d2c++); 
      n += 2; 
   }  
   *(n) = '\0'; 
}  

passing 1.0 & 16.0 to this function, the return values observed are 000000000000FF37 & 0000000000003040 respectively. I think we should get 1 & 10.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文