简体   繁体   English

Ubuntu 64位上的单精度浮点数表示不正确

[英]Incorrect single precision floating point representation on ubuntu 64 bit

I have the following data. 我有以下数据。

float u[4] = {0x3f951d32, 0x3f207887, 0x3d99c3a0, 0x3eb405d2};
ScaleFunction(u);

void ScaleFunction(float *u_ptr)
{
  for(int i = 0; i < 4; i++)
  {
    printf("u[%d] = %f\n", u_ptr[i]);
  }
  // And a lot more
}

The application containing the snippet above is executed on a 64 bit machine running ubuntu 16.10. 包含上述代码段的应用程序在运行ubuntu 16.10的64位计算机上执行。

Much to my chagrin, the floating point numbers are incorrectly interpreted as: 1066736960.000000, 1059092608.000000, 1033487232.000000 and 1051985344.000000. 令我烦恼的是,浮点数被错误地解释为:1066736960.000000,1059092608.000000,1033487232.000000和1051985344.000000。

The numbers when printed in hexadecimal confirm that the caller passes the correct values to callee. 当数字以十六进制打印时,确认呼叫者将正确的值传递给被呼叫者。

What am I doing wrong here? 我在这里做错了什么?

I even tried the following with no joy. 我什至没有高兴地尝试了以下方法。

uint32_t u[4] = {0x3f951d32, 0x3f207887, 0x3d99c3a0, 0x3eb405d2};
ScaleFunction(u);

void ScaleFunction(uint32_t *u_ptr)
{
  float ut[4];
  for(int i = 0; i < 4; i++)
  {
    ut[i] = (float) u_ptr[i];
    printf("ut[%d] = %f\n", ut[i]);
  }
  // And a lot more
}

I expect to interpret the hexadecimals in the callee as: 1.1649, 0.6268, 0.075, 0.5516 我希望将被调用方中的十六进制解释为:1.1649、0.6268、0.075、0.5516

The problem is, that you initialize your array with large integer values, not the hex representation of the floats. 问题是,您使用大整数值而不是浮点数的十六进制表示来初始化数组。 With your hex constants starting with values around 0x3f it's pretty clear that these are floating point data with values around 1.0. 十六进制常数以0x3f左右的值开头,因此很明显,它们是1.0左右的浮点数据。

As far as I know there is no direct way to initialize a float array with hex constants (if there is one, community, please tell me!). 据我所知,没有直接方法用十六进制常量初始化浮点数组(如果有的话,请告诉我!)。

So you have to define your data-array as int and convert it to float as you use it. 因此,您必须将数据数组定义为int,并在使用时将其转换为float。 IMPORTANT: Directly casting the pointer from int to float will break the aliasing rule of C and may result in code that looks correct but misbehaves. 重要说明:将指针直接从int转换为float将破坏C的别名规则,并可能导致看起来正确但行为不当的代码。

Converting between the two data-types via memcpy is safe though and the compiler is usually smart enough to spot this and optimize it out. 通过memcpy在两种数据类型之间进行转换是安全的,并且编译器通常足够聪明以发现并优化它。

So this solution here does what you want: 因此,此解决方案可以满足您的需求:

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

uint32_t u[4] = {0x3f951d32, 0x3f207887, 0x3d99c3a0, 0x3eb405d2};

void ScaleFunction(uint32_t *u_ptr)
{
  for(int i = 0; i < 4; i++)
  {
      float temp;
      memcpy (&temp, &u[i], sizeof (float));
      printf("u[%d] = %f\n", i, temp);
  }
  // And a lot more
}


void main (int argc, char **args)
{
  ScaleFunction (u);
}

You code cannot work as you think: you are assigning integers to your float. 您的代码无法按照您的想法工作:您正在为浮点数分配整数。 You are not assigning the HEX values as float. 您未将十六进制值分配为浮点数。

Best thing you can do is to have a init array and copy it to your float array 最好的办法是拥有一个初始化数组并将其复制到您的float数组中

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>

uint32_t init[] = {0x3f951d32u, 0x3f207887u, 0x3d99c3a0u, 0x3eb405d2u};

void ScaleFunction(float *u_ptr, size_t size)
{
  for(size_t i = 0; i < size; i++)
  {
    printf("u[%zu] = %f\n", i, u_ptr[i]);
  }
  // And a lot more
}

int main (void)
{
    assert ( sizeof(float) == sizeof(uint32_t) );

    float u[sizeof(init)/sizeof(init[0])];

    memcpy(u, init, sizeof(init));

    ScaleFunction(u, sizeof(init)/sizeof(init[0]));
}

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

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