【问题标题】:Bit representation for floats?浮点数的位表示?
【发布时间】:2016-02-19 10:27:13
【问题描述】:

我知道如何使用 % 2 和 / 2 将浮点数转换为二进制表示,但是有没有捷径或更简洁的方法呢?我在做什么甚至被认为是按位表示浮点数吗?因为我应该在两个浮点数之间使用按位比较,但我不确定这是否意味着使用按位运算。

例如,要获得一个数字的二进制表示,我会将 10 % 2 之类的数字的结果存储到一个数组中,直到该数字在 while 循环内达到 0,如果要向后打印该数组,它将表示二进制数。

array[] = num % 2;
num = num / 2; 

我所做的是对两个浮点数使用上面的方法,将它们加载到各自的数组中,然后通过它们的数组比较它们。

我也在它们的数组中以 IEEE 浮点格式设置它们。

编辑:我必须通过按位比较和运算来比较两个浮点类型的数字,以查看一个数字是否大于、小于或是否与以有偏指数表示法表示的浮点数相等。具体是它测试一个浮点数 number1 是否小于、等于或大于另一个浮点数 number2,方法是简单地使用从左到右的按位比较来按位比较它们的浮点表示,一旦第一个就停止遇到不同的位。

【问题讨论】:

  • 计算机上常用的浮点格式是IEEE floating point format。在两个这样的数字之间进行逐位比较根本没有意义。
  • 不太确定是否可以通过%2/2 获得float 的二进制表示。
  • 如果您想查看浮点数的二进制表示,您不能只使用/ 2% 2,因为它们只会为您提供有关数字的数字解释的信息,而不是它的按位表示。要查看它的表示,您可以将其放入具有相同大小的整数类型的union(这取决于机器)或相同大小的char 数组(也取决于机器,但您可以使用sizeof 获取它),存储到 float 成员,然后访问其他成员以查看存储的内容。还要注意大端与小端表示。
  • 不清楚您要问的是两个完全不同的事情中的哪一个。你想要浮点数的内部按位表示吗?或者你想要二进制的数字?这些根本不一样,因为浮点数的内部按位表示是浮点数。例如,2 和 16 以相同的尾数和大于 4 的指数存储。除以二只是移动一个二进制点。它不会移出位。
  • 您只希望在 C 中对两个 float 类型的变量进行按位比较是否正确?因为您的想法不正确,如果您澄清这是您的目标,我们可以帮助您。

标签: c


【解决方案1】:

不,不会。将浮点数除以 2 将得到一半的数字,如下所示:

#include <stdio.h>
int main(void)
{
    float x = 5.0f;
    float y = x / 2;
    printf("%f\n", y);
}

结果:

2.50000

看到了吗?和比特无关。

浮点数的二进制表示由尾数、指数和符号位组成,这意味着与普通整数不同,您提到的技巧在这里不适用。您可以通过阅读an article on Wikipedia on IEEE floating points.了解更多信息

为确保两个浮点数具有完全相同的位配置,您可以使用 memcmp 比较它们的内容,它会逐字节比较事物,而无需额外的强制转换/算术/其他:

#include <stdio.h>
int main(void)
{
    float x = 5.0f;
    float y = 4.99999999999999f; //gets rounded up to 5.0f
    float z = 4.9f;
    printf("%d\n", memcmp(&x, &y, sizeof(float)) == 0);
    printf("%d\n", memcmp(&x, &z, sizeof(float)) == 0);
}

...将分别打印 1 和 0。您还可以通过这种方式检查各个位(例如,通过对 *(char*)&amp;x 进行操作。

【讨论】:

  • memcmp() 接受 const void *,绝对没有必要强制转换为 char *。最好使用sizeof x,即对象的大小而不是类型。
  • 更准确地说,将浮点数除以 2 只会将其指数减一。
  • 请原谅我的 C++ :) 已修复。关于sizeof x - 使用哪个操作数(sizeof xsizeof y)并不明显,所以我保持原样。
  • 现在我怎么知道一个是否大于另一个?我看到这可以给我条件,看看它们是否相等。
【解决方案2】:

照你说的做不会给你浮点表示的位。而是使用 union 在浮点和整数表示之间进行转换,并像往常一样打印位:

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

typedef union {
    uint32_t i;
    float f;
} float_conv_t;

void
int_to_bin_print(uint32_t number)
{
    char binaryNumber[33];
    int i;
    for (i = 31; i >= 0; --i)
    {
        binaryNumber[i] = (number & 1) ? '1' : '0';
        number >>= 1;
    }
    binaryNumber[32] = '\0';
    fprintf(stdout, "Number %s\n", binaryNumber);
}

int main(void) {
    float_conv_t f;
    f.f = 10.34;
    int_to_bin_print(f.i);
    f.f = -10.34;
    int_to_bin_print(f.i);
    f.f = 0.1;
    int_to_bin_print(f.i);
    f.f = 0.2;
    int_to_bin_print(f.i);
    return 0;
}

输出:

号码01000001001001010111000010100100

号码 11000001001001010111000010100100

号码00111101110011001100110011001101


我的目标是通过比较两个浮点数 按位浮点表示。

然后你可以使用memcmp比较原始内存:

float f1 = 0.1;
float f2 = 0.2;
if (memcmp(&f1, &f2, sizeof(float)) == 0)
    // equal

概要 #包括

   int memcmp(const void *s1, const void *s2, size_t n);

描述 memcmp() 函数比较内存区域 s1 和 s2 的前 n 个字节(每个字节都解释为无符号字符)。

返回值 如果找到 s1 的前 n 个字节,则 memcmp() 函数返回一个小于、等于或大于零的整数, 分别为 小于、匹配或大于 s2 的前 n 个字节。

【讨论】:

  • 但这实际上是从左到右比较位吗?对不起,当谈到比特时,我只是迷路了。我的意思是我猜是在内存中以 IEEE 格式存储的 0.1?然后 memcmp 会一点一点地比较两个浮点数?如果它们碰巧不相等,你怎么知道哪个更大?
  • 是的,memcmp 逐字节比较,然后逐位转换,如果不同的字节在第一个 argumnet 中具有更高的值,则 memcmp 返回 > 0,否则返回
  • 啊,我没有仔细阅读说明,比较需要有偏差的指数符号。
  • 对于您首先提供的代码,我将如何在不使用标准输出的情况下打印出这些位?我可以将其加载到数组中并打印出来吗?还是不行?
【解决方案3】:

这会逐位比较两个 IEEE 32 位 floats,返回 -1、0 或 1,并指示它们不同的位。它们可以作为符号和大小的数字进行比较。下面的函数float_comp首先将它们逐位比较为uint32_t,如果它们的符号位(第31位)不同,则否定比较。

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

static int float_comp(float f1, float f2, int *bit)
{
    const uint32_t *a, *b;
    int comp = 0;

    a = (const uint32_t *)(const void *)&f1;
    b = (const uint32_t *)(const void *)&f2;
    for (*bit = 31; *bit >= 0; (*bit)--) {
        if ((*a & (UINT32_C(1) << *bit))
             && !(*b & (UINT32_C(1) << *bit))) {
            comp = 1;
            break;
        }
        if (!(*a & (UINT32_C(1) << *bit))
             && (*b & (UINT32_C(1) << *bit))) {
            comp = -1;
            break;
        }
    }
    if (*bit == 31)
        comp = -comp;   /* sign and magnitude conversion */
    return comp;
}

int main(int argc, char **argv)
{
    float f1, f2;
    int comp, bit;

    if (argc != 3) {
        fprintf(stderr, "usage: %s: float1 float2\n", argv[0]);
        return 2;
    }
    f1 = strtof(argv[1], NULL);
    f2 = strtof(argv[2], NULL);
    comp = float_comp(f1, f2, &bit);
    if (comp == 0)
        printf("%.8g = %.8g\n", f1, f2);
    else if (comp < 0)
        printf("%.8g < %.8g (differ at bit %d)\n", f1, f2, bit);
    else
        printf("%.8g > %.8g (differ at bit %d)\n", f1, f2, bit);
    return 0;
}

【讨论】:

    猜你喜欢
    • 2011-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-10
    • 2016-05-17
    • 2020-09-03
    • 2023-04-11
    • 2012-10-27
    相关资源
    最近更新 更多