简体   繁体   English

将C中的浮点数转换为IEEE标准

[英]Converting a floating point number in C to IEEE standard

I am trying to write a code in C that generates a random integer , performs simple calculation and then I am trying to print the values of the file in IEEE standard. 我试图用C编写一个生成随机整数的代码,执行简单的计算,然后尝试以IEEE标准打印文件的值。 But I am unable to do so , Please help. 但是我无法这样做,请帮助。

I am unable to print it in Hexadecimal/Binary which is very important. 我无法以十六进制/二进制格式打印,这非常重要。 If I type cast the values in fprintf , I am getting this Error expected expression before double . 如果我在fprintf键入fprintf值, expected expression before double收到此Error expected expression before double

int main (int argc, char *argv) {

     int limit = 20 ; double a[limit], b[limit];                //Inputs
     double result[limit]    ; int i , k ;            //Outputs
     printf("limit = %d", limit ); double q;


     for (i= 0 ; i< limit;i++)
         {
         a[i]= rand();
         b[i]= rand();
         printf ("A= %x B = %x\n",a[i],b[i]);

         }

     char op;

      printf("Enter the operand used : add,subtract,multiply,divide\n"); 
     scanf ("%c", &op); switch (op) {

     case '+': {
             for (k= 0 ; k< limit ; k++)
                 {

                 result [k]= a[k] + b[k];
            printf ("result= %f\n",result[k]);

                 }
             }
         break;

     case '*': {
             for (k= 0 ; k< limit ; k++)
                 {

                 result [k]= a[k] * b[k];

                 }
             }
         break;

     case '/': {
             for (k= 0 ; k< limit ; k++)
                 {

                 result [k]= a[k] / b[k];

                 }
             }
         break;

     case '-': {
             for (k= 0 ; k< limit ; k++)
                 {

                 result [k]= a[k] - b[k];

     }
             }
         break; }


     FILE *file; file = fopen("tb.txt","w"); for(k=0;k<limit;k++) {  
     fprintf (file,"%x\n
     %x\n%x\n\n",double(a[k]),double(b[k]),double(result[k]) );

     }


     fclose(file); /*done!*/
 }

If your C compiler supports IEEE-754 floating point format directly (because the CPU supports it) or fully emulates it, you may be able to print doubles simply as bytes. 如果您的C编译器直接支持IEEE-754浮点格式(因为CPU支持它)或完全模拟它,则您可能可以将doubles形式打印为字节。 And that is the case for the x86/64 platform. x86 / 64平台就是这种情况。

Here's an example: 这是一个例子:

#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <float.h>

void PrintDoubleAsCBytes(double d, FILE* f)
{
  unsigned char a[sizeof(d)];
  unsigned i;
  memcpy(a, &d, sizeof(d));
  for (i = 0; i < sizeof(a); i++)
    fprintf(f, "%0*X ", (CHAR_BIT + 3) / 4, a[i]);
}

int main(void)
{
  PrintDoubleAsCBytes(0.0, stdout); puts("");
  PrintDoubleAsCBytes(0.5, stdout); puts("");
  PrintDoubleAsCBytes(1.0, stdout); puts("");
  PrintDoubleAsCBytes(2.0, stdout); puts("");
  PrintDoubleAsCBytes(-2.0, stdout); puts("");
  PrintDoubleAsCBytes(DBL_MIN, stdout); puts("");
  PrintDoubleAsCBytes(DBL_MAX, stdout); puts("");
  PrintDoubleAsCBytes(INFINITY, stdout); puts("");
#ifdef NAN
  PrintDoubleAsCBytes(NAN, stdout); puts("");
#endif
  return 0;
}

Output ( ideone ): 输出( ideone ):

00 00 00 00 00 00 00 00 
00 00 00 00 00 00 E0 3F 
00 00 00 00 00 00 F0 3F 
00 00 00 00 00 00 00 40 
00 00 00 00 00 00 00 C0 
00 00 00 00 00 00 10 00 
FF FF FF FF FF FF EF 7F 
00 00 00 00 00 00 F0 7F 
00 00 00 00 00 00 F8 7F 

If IEEE-754 isn't supported directly, the problem becomes more complex. 如果不直接支持IEEE-754,问题将变得更加复杂。 However, it can still be solved. 但是,仍然可以解决。

Here are a few related questions and answers that can help: 以下是一些可以帮助您的相关问题和解答:

And, of course, all the IEEE-754 related info can be found in Wikipedia . 并且,当然,所有与IEEE-754相关的信息都可以在Wikipedia中找到。

Try this in your fprint part: 在您的fprint部分尝试以下操作:

fprintf (file,"%x\\n%x\\n%x\\n\\n",*((int*)(&a[k])),*((int*)(&b[k])),*((int*)(&result[k])));

That would translate the double as an integer so it's printed in IEEE standard. 那会将double转换为整数,因此按IEEE标准打印。

But if you're running your program on a 32-bit machine on which int is 32-bit and double is 64-bit, I suppose you should use: 但是,如果您是在int是32位而double是64位的32位计算机上运行程序,那么我想您应该使用:

fprintf (file,"%x%x\\n%x%x\\n%x%x\\n\\n",*((int*)(&a[k])),*((int*)(&a[k])+1),*((int*)(&b[k])),*((int*)(&b[k])+1),*((int*)(&result[k])),*((int*)(&result[k])+1));

In C, there are two ways to get at the bytes in a float value: a pointer cast, or a union. 在C语言中,有两种方法可以获取浮点值中的字节:指针强制转换或联合。 I recommend a union. 我推荐一个工会。

I just tested this code with GCC and it worked: 我刚刚在GCC中测试了此代码,它的工作原理是:

#include <stdio.h>
typedef unsigned char BYTE;

int
main()
{
    float f = 3.14f;
    int i = sizeof(float) - 1;
    BYTE *p = (BYTE *)(&f);
    p[i] = p[i] | 0x80;  // set the sign bit
    printf("%f\n", f);  // prints -3.140000
}

We are taking the address of the variable f , then assigning it to a pointer to BYTE (unsigned char). 我们获取变量f的地址,然后将其分配给指向BYTE(无符号char)的指针。 We use a cast to force the pointer. 我们使用强制转换来强制指针。

If you try to compile code with optimizations enabled and you do the pointer cast shown above, you might run into the compiler complaining about "type-punned pointer" issues. 如果尝试在启用了优化的情况下编译代码,并且执行了上面显示的指针转换,则可能会遇到编译器抱怨“类型标记指针”问题。 I'm not exactly sure when you can do this and when you can't. 我不确定什么时候可以做到,什么时候不能做到。 But you can always use the other way to get at the bits: put the float into a union with an array of bytes. 但是,您始终可以使用另一种方法来获取位:将浮点数与字节数组组合成一个并集。

#include <stdio.h>

typedef unsigned char BYTE;

typedef union
{
    float f;
    BYTE b[sizeof(float)];
} UFLOAT;

int
main()
{
    UFLOAT u;
    int const i = sizeof(float) - 1;

    u.f = 3.14f;
    u.b[i] = u.b[i] | 0x80;  // set the sign bit
    printf("%f\n", u.f);  // prints -3.140000
}

What definitely will not work is to try to cast the float value directly to an unsigned integer or something like that. 什么是绝对不会的工作是试图直接投浮点值到一个无符号整数或类似的东西。 C doesn't know you just want to override the type, so C tries to convert the value, causing rounding. C不知道您只是想覆盖该类型,因此C尝试转换该值,从而导致舍入。

float f = 3.14;
unsigned int i = (unsigned int)f;

if (i == 3)
    printf("yes\n"); // will print "yes"

PS Discussion of "type-punned" pointers here: PS在这里讨论“类型打孔”指针:

Dereferencing type-punned pointer will break strict-aliasing rules 取消引用类型化指针会破坏严格的别名规则

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM