如何使用 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 int1。最好将浮点值视为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 课程中为复习而做的教科书问题。我需要使用我提供的内容和 作为资源来完成此操作。给定的真的无法改变。你能再看看吗? @user14452102 我不使用任何库。

以上是关于如何使用 C 中的常量格式化将浮点数转换为指数的主要内容,如果未能解决你的问题,请参考以下文章

将浮点数转换为字符串

如何在没有指数表示法的情况下将浮点数作为字符串获取?

将浮点数的数据框转换为熊猫中的整数?

java - 如何将浮点数转换为 BigDecimal? [复制]

如何将浮点数转换为长度为 4 的字节数组(char* 数组)?

C将浮点数转换为int