Get random bit off the end of a float

时间:2016-07-11 23:07:02

标签: c bit-manipulation

I have a float in my program that changes after each iteration, namely G[0]. I want to use the last bit of the mantissa as a "random" bit that I will use to pick which path to take in my computation. However, the calculation I'm using now always prints out 0, while it should be roughly 50/50; what's my error? The function signature defines float* G.

unsigned rand_bit = *((unsigned *)&G[0])>>31;
printf("%i", rand_bit);

2 个答案:

答案 0 :(得分:1)

虽然你的实际问题已经解决了但我想建议使用union代替它,它有点清洁,但我不知道什么是更快(如果你使用GPU我认为我可以安全地假设你想要它快速)。字节序也是一个问题;我无法在GPU方面找到太多关于GPU的信息,所以这里有一些你可能想要使用的行。

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

int last_bit(float f)
{
  // Endianness testing should be done at compile-time, such that a simple macro
  // would suffice. Your compiler/libc might already offer one for that
#ifdef USE_TYPE_PUNNING
  // So called "type punning" is frowned upon by some
  uint32_t ui = 0x76543210;
  unsigned char *c = (unsigned char *) &ui;
#else
  union {
    uint32_t ui;
    uint8_t uc[4];
  } end = {0x76543210};
  // only to save some code branching, end.uc can be used directly, of course
  unsigned char *c = (unsigned char *) end.uc;
#endif
  int rand_bit;

  union {
    float fl;
    uint32_t ui;
  } w;

  w.fl = f;
#ifdef DEBUG
  printf("%x\n", w.ui);
#endif
  // Little endian
  if (*c == 0x10) {
    rand_bit = w.ui & 0x1;
  }
  // Big endian
  else if (*c == 0x76) {
    rand_bit = w.ui & 0x1;
  }
  // Too old/new
  else {
    fprintf(stderr, "unknown endianness\n");
    return -1;
  }
  return rand_bit;
}


int main(int argc, char **argv)
{
  float f;

  // all checks omitted!
  if (argc >= 2) {
    f = atof(argv[1]);
  } else {
    // 0x40e00000 even
    //f = 7;
    // 0x3f8ccccd odd
    f = 1.1;
  }
  printf("last bit of mantissa = %d\n", last_bit(f));
  exit(EXIT_SUCCESS);
}

答案 1 :(得分:1)

首先,*((unsigned *)&G[0])会导致undefined behaviour违反严格别名规则。在标准C中,除少数特殊情况外,不允许使用不同类型访问一种类型的内存。

您可以通过在编译器中禁用严格别名,或使用unionmemcpy来解决此问题。

(此外,您的代码依赖unsignedfloat的大小相同,但一般情况下并非如此。

但假设您确实解决了这些问题,那么您的代码正在测试最重要的一点。在IEEE 32-bit floating point format中,该位是符号位。因此,正数会显示0,负数会显示1

将尾数重新解释为整数后,尾数的最后一位将是最低有效位。

更正的代码可能如下所示:

unsigned u;
assert( sizeof u == sizeof *G );
memcpy(&u, G, sizeof u);
printf("%u", u & 1);

NB。我会犹豫是否假设这个位是&#34;随机&#34;,如果你想要随机分配位,那么有更好的选择。