如何将一个int32的原始位重新解释为一个float32?
我现在正在用C 语言生成一个随机浮点数。
显然这是一件挺难的事,因为似乎没有真正的库来完成这个,只能通过stdlib的 rand() 这样的变通方法,
但这些方法常常会丢失精度,且无法覆盖IEEE 754的 32位浮点数的完整取值范围。
所以我的想法是用 rand() 生成一个32位的随机整数,然后让C 语言据此把它转换成一个浮点数。
换句话说,我想先生成一个随机的int32,再把这个整型位模式对应的浮点数值取出来。
示例:
1000 0100 1010 1010 1001 0111 1001 1110= -2069194850
(32位二进制补码整数)1000 0100 1010 1010 1001 0111 1001 1110= -4.01060463243591921024016E-36
(IEEE 754的 32位浮点数)
既然底层都是32位,那么一定有办法让C 把这些原始位按 float 解释,而不是按 int,对吗?
但如果要做这样的原始位操作,真的可行吗?
我在找一个类似这样的函数:
float make_float_from_int32(int32_t);
解决方案
你可以很容易地写出代码,把32位的 int 的位重新解释为一个float,使用 union 或 memcpy,且没有额外开销:
#include <stdint.h>
#include <string.h>
static_assert(sizeof(float) == sizeof(int32_t), "unsupported architecture: float and int32_t have different sizes");
float reinterpret_int32(int32_t x) {
float f;
memcpy(&f, &x, sizeof f);
return f;
}
但请注意以下几点:
rand()产生一个均匀分布的伪随机数集合,取值范围在0到RAND_MAX之间,可能小于INT_MAX。- 如果
int是32位,那么在最理想的情况下也许只有31位随机数;但某些平台将RAND_MAX定义得更小,甚至小到32767,因此只有15位随机数。即使把两个随机值组合在一起,也可能得到少于32位的随机数。 - 将这些位重新解释为一个
float将产生取值范围和分布都截然不同的随机浮点数,例如仅正数,或者落在一个非常小的取值区间内。 - 生成的
float值中很大一部分将是NaN,计算时不应使用它们,尤其是如果它们是signaling NaN,可能会触发浮点异常。 float与int的大小甚至可能不同,尽管这并不常见,同时位序和float的表示形式也可能不同。
如果你想在给定范围内得到均匀分布的 float 值,请使用除法:
#include <stdlib.h>
// produce a random float in a closed range
float rand_float1(float low, float high) {
return low + (high - low) * rand() / RAND_MAX;
}
// produce a random float in a half open range (low included, high excluded)
// this function should be faster as the divisor is a power of 2
float rand_float2(float low, float high) {
return low + (high - low) * rand() / ((long long)RAND_MAX + 1);
}
如果在你的目标系统上 double 运行起来很快,那么你将得到更好的精度:
#include <stdlib.h>
// produce a random float in a closed range
float rand_float1(float low, float high) {
return (float)(low + (double)(high - low) * rand() / RAND_MAX);
}
// produce a random float in a half open range (low included, high excluded)
// this function should be faster as the divisor is a power of 2
float rand_float2(float low, float high) {
return low + (double)(high - low) * rand() / ((long long)RAND_MAX + 1);
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。