ubuntu 64 位上的单精度浮点表示不正确
Incorrect single precision floating point representation on ubuntu 64 bit
我有以下数据。
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
}
包含上述代码片段的应用程序在 64 位机器上执行 运行 ubuntu 16.10.
令我懊恼的是,浮点数被错误地解释为:1066736960.000000、1059092608.000000、1033487232.000000 和 1051985344.000000。
以十六进制打印的数字确认调用方将正确的值传递给被调用方。
我做错了什么?
我什至尝试了以下方法,但并不高兴。
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
}
我希望将被调用方中的十六进制解释为:
1.1649、0.6268、0.075、0.5516
问题是,您使用大整数值而不是浮点数的十六进制表示来初始化数组。您的十六进制常量以 0x3f 左右的值开头,很明显这些是值在 1.0 左右的浮点数据。
据我所知,没有直接的方法可以用十六进制常量初始化浮点数组(如果有的话,社区,请告诉我!)。
因此您必须将数据数组定义为 int 并在使用时将其转换为 float。 重要提示: 直接将指针从 int 转换为 float 将打破 C 的别名规则,并可能导致代码看起来正确但行为异常。
尽管通过 memcpy 在两种数据类型之间进行转换是安全的,而且编译器通常足够聪明,可以发现并优化它。
所以这里的解决方案可以满足您的需求:
#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);
}
您的代码不能像您想象的那样工作:您正在为浮点数分配整数。您没有将 HEX 值分配为浮点数。
你能做的最好的事情就是拥有一个初始化数组并将其复制到你的 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]));
}
我有以下数据。
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
}
包含上述代码片段的应用程序在 64 位机器上执行 运行 ubuntu 16.10.
令我懊恼的是,浮点数被错误地解释为:1066736960.000000、1059092608.000000、1033487232.000000 和 1051985344.000000。
以十六进制打印的数字确认调用方将正确的值传递给被调用方。
我做错了什么?
我什至尝试了以下方法,但并不高兴。
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
}
我希望将被调用方中的十六进制解释为: 1.1649、0.6268、0.075、0.5516
问题是,您使用大整数值而不是浮点数的十六进制表示来初始化数组。您的十六进制常量以 0x3f 左右的值开头,很明显这些是值在 1.0 左右的浮点数据。
据我所知,没有直接的方法可以用十六进制常量初始化浮点数组(如果有的话,社区,请告诉我!)。
因此您必须将数据数组定义为 int 并在使用时将其转换为 float。 重要提示: 直接将指针从 int 转换为 float 将打破 C 的别名规则,并可能导致代码看起来正确但行为异常。
尽管通过 memcpy 在两种数据类型之间进行转换是安全的,而且编译器通常足够聪明,可以发现并优化它。
所以这里的解决方案可以满足您的需求:
#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);
}
您的代码不能像您想象的那样工作:您正在为浮点数分配整数。您没有将 HEX 值分配为浮点数。
你能做的最好的事情就是拥有一个初始化数组并将其复制到你的 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]));
}