如何使用 C 中的常量格式化将浮点数转换为指数
Posted
技术标签:
【中文标题】如何使用 C 中的常量格式化将浮点数转换为指数【英文标题】:How to Format Turn Floating Point into Exponent Using Constants in C 【发布时间】:2020-10-14 22:08:25 【问题描述】:所以我得到了
const int mask = 0x7F800000
const int shift = 23
const int bias = 127
int exp (float number)
unsigned int u = *(unsigned int*)&number;
int field = 0;
老实说,我只是对如何正确格式化以获得我想要的东西感到困惑。本质上,客户端输入一个浮点数,然后 u 是与浮点数具有相同位模式的无符号整数。
我知道我需要首先屏蔽除数字中的指数变量之外的所有内容。所以我认为它是
field = (u & mask)
这大概应该掩盖位模式,除了我们想要的部分 - 指数。
然后第二步是将它移动 23,所以它不会被所有的零包围......这就是我感到困惑的地方。
field = (u & mask) >> shift ???
看,我有点迷路了。也许这是对的。不管怎样,我们都向右移动了 23 个。
那么最后是考虑偏差。您想返回实际指数,而不是位。这样做的公式是指数位=(exp位模式)-偏差......所以我试试这个
field = ((u & mask) >> shift) - bias;
return(field);
而我就是无法得到正确的答案。首先,请在我的格式上放轻松。我是 C 新手,这是一个初学者项目。我知道这并不好。但是,有人可以帮助我理解格式以使这些步骤起作用吗?或者帮助我缺少什么?我只是在寻求逻辑方面的帮助。
【问题讨论】:
屏蔽、移位和减法是正确的,即使 C 标准没有定义别名,许多 C 实现也会容忍别名,尽管有更好的方法。因此,可能还有其他原因导致“我无法得到正确的答案”。编辑您的问题以显示minimal reproducible example,包括完整的程序、示例输入、观察到的输出和所需的输出。仅仅说“我就是无法得到正确的答案”并不是一个充分的问题描述。显示程序产生的错误答案和正确答案的具体案例。 我会尝试一下。这是一个更大问题的一部分,所以问题可能是其他问题还没有完成。如果我提供的内容是正确的,我会继续看看测试是否满意。如果没有,我会回到这里。但是测试很简单......比如 6 == 6, 12 == 12。我是新手,所以我很困惑,所以我很抱歉 【参考方案1】:注意字节顺序问题 - 对于类似 IEEE-754 的布局,我们可以有以下内容:
A A+1 A+2 A+3 Big-endian addressing
+--------+--------+--------+--------+
|seeeeeee|efffffff|ffffffff|ffffffff|
+--------+--------+--------+--------+
A+3 A+2 A+1 A Little-endian addressing
所以在 x86 这样的 little-endian 系统上,您的值将被格式化为
+--------+--------+-------+--------+
|ffffffff|ffffffff|effffff|seeeeeee|
+--------+--------+-------+--------+
其中第一个字节将是有效数的最低 8 位,然后是有效数的中间 8 位,然后是最低指数位,然后是有效数的高 7 位,然后是符号位,其次是指数的高7位。
此外,不能保证float
值的位模式将适合unsigned int
1。最好将浮点值视为unsigned char
的数组:
union f32
float f;
unsigned char c[sizeof f];
;
您可以将您的值分配给f
成员:
union f32 myval = .f = 1.234;
然后通过c
成员检查它:
printf( "sign bit is %d\n", (f32.c[3] & 0x80) >> 7 );
unsigned int
只需要在至少[0..65535]
范围内存储值,这意味着它可以小至 16 位宽;在 2000 年之后构建的几乎所有系统上,它都是 32 位宽,但这不是您可以指望普遍正确的东西。
【讨论】:
“几乎所有 2000 年之后构建的系统都将是 32 位宽,” --> 如今,每年有 10-100 万的嵌入式处理器使用 16 位int/unsigned
。
我不想问,但是请您再看看提供的格式和库吗?我相信这确实是一个更简单的问题。我最想格式化给定的最后返回实际指数。它基本上是(1)给定字段的掩码,(2)用于格式化的移位,(3)使用公式 exp bits = exp bit pattern - 1 得出指数。
@chux-ReinstateMonica:点。我不做嵌入式工作,所以我从没想过。
@user14452102:我必须写一些代码来确定。如果您将浮点数分解为 unsigned char
的数组,如我上面的示例所示,则指数位不连续,您必须使用 2 个单独的掩码。 但是,如果你将值保存到uint32_t
(不是unsigned int
!),那么是的,你需要做的就是屏蔽0x7f800000
,shift右 23 位,然后减去 127。至少在我的系统上。我不能保证这会一直在任何地方都有效。
@chux - 8bit 是的。【参考方案2】:
三种方法:
-
最安全
int exp (float number)
unsigned int u;
memcpy(&u, &numberm sizeof(u));
-
在 C 中安全
int exp (float number)
union
unsigned int u;
float f;
fu = .f = number;
那么你可以使用fu.u
-
不安全(指针插入)
int exp (float number)
unsigned int *u = (void *)&number;
具有无符号值u
你可以例如:
#define SIGN (1U << 31)
#define EXP (0xff << 23)
unsigned sign = !!(u & SIGN)
unsigned exp = (u & EXP) >> 23;
unsigned mant = u & ~(SIGN | EXP);
【讨论】:
我很感激。但是,这是我在初学者 C 课程中为复习而做的教科书问题。我需要使用我提供的内容和以上是关于如何使用 C 中的常量格式化将浮点数转换为指数的主要内容,如果未能解决你的问题,请参考以下文章
java - 如何将浮点数转换为 BigDecimal? [复制]