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);
答案 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中,除少数特殊情况外,不允许使用不同类型访问一种类型的内存。
您可以通过在编译器中禁用严格别名,或使用union
或memcpy
来解决此问题。
(此外,您的代码依赖unsigned
与float
的大小相同,但一般情况下并非如此。
但假设您确实解决了这些问题,那么您的代码正在测试最重要的一点。在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;,如果你想要随机分配位,那么有更好的选择。