Perlin噪声随机梯度C函数中random值非零的原因咨询
关于Perlin噪声随机梯度向量C代码的疑问
我在维基百科上找到一段生成Perlin噪声随机梯度向量的C代码,刚接触C语言,编写测试代码时发现(3.14159265 / ~(~0u >> 1))的结果用printf("%f")输出始终为0,但原函数中random是该值与变量a的乘积,为什么random不会是0?
原代码
typedef struct { float x, y; } vector2; /* Create pseudorandom direction vector */ vector2 randomGradient(int ix, int iy) { // No precomputed gradients mean this works for any number of grid coordinates const unsigned w = 8 * sizeof(unsigned); const unsigned s = w / 2; // rotation width unsigned a = ix, b = iy; a *= 3284157443; b ^= a << s | a >> w-s; b *= 1911520717; a ^= b << s | b >> w-s; a *= 2048419325; float random = a * (3.14159265 / ~(~0u >> 1)); // in [0, 2*Pi] vector2 v; v.x = cos(random); v.y = sin(random); return v; }
测试代码
int main(){ float w = (3.14159265 / ~(~0u >> 1)); printf("%f\n", w); }
问题解析
1. 先搞懂~(~0u >> 1)的含义
~0u是无符号整数的全1值(比如32位系统下是0xFFFFFFFF,即UINT_MAX)~0u >> 1将全1值右移一位,得到0x7FFFFFFF(32位),等价于UINT_MAX / 2- 对这个结果取反
~(...),得到0x80000000(32位),也就是2^31,这是一个非常大的整数
2. 为什么测试代码输出0?
这是printf输出格式的问题:3.14159265 / 2^31的结果约为1.46e-9,是一个极小的数。而%f格式默认只显示小数点后6位,小于1e-6的数会被显示为0.000000。如果换成%e(科学计数法)或%g(自动选择格式),就能看到实际的极小值:
int main(){ float w = (3.14159265 / ~(~0u >> 1)); printf("%e\n", w); // 输出类似 1.464692e-09 }
3. 为什么原函数中random不会是0?
原函数里的random是a * (极小值),其中a是经过一系列位运算和乘法后的无符号整数:
a的取值范围是0到UINT_MAX(无符号整数的最大值)- 当
a=0时,random确实为0,但这种情况极少出现(因为位运算后的a几乎不会为0,除非输入的ix和iy刚好让所有运算后a归零) - 当
a≠0时,a * 极小值的结果会落在(0, 2π]区间内(因为UINT_MAX * 3.14159265 / 2^31 ≈ 2π),完全满足生成随机梯度向量的需求
内容的提问来源于stack exchange,提问作者pablo SquarePants
相关产品推荐
相关产品推荐

