c位随机舍入



我有这段C代码,它将二进制64的值随机舍入到二进制32. 问题是我不太懂代码。我知道它直接对浮点数进行操作,但我不知道发生了什么。你能告诉我一些真知灼见吗?

float function(double x){
uint64_t temp = *(uint64_t*)&x;
uint32_t r = (rand() * (0xFFFFFFFF/RAND_MAX)) % 0x1FFFFFFF;
temp += r;
temp = temp & 0xFFFFFFFFE0000000;
return (float)*(double *)&temp;
}

位掩码代表什么?(我的直觉告诉我它与指数和尾数如何以二进制格式表示有关,但我无法想象它)
为什么随机变量r是这样计算的?
如何通过代码进行交互?

uint64_t temp =(uint64_t)&x;

这是一个糟糕的尝试,以获得代表doublex的位。这是不好的,因为它违反了C的混叠规则(C 2018 6.5 7)。正确的代码是uint64_t temp; memcpy(&temp, &x, sizeof temp);uint64_t temp = (union { double d; uint64_t u; }) { x } .d;。前者将x的字节复制到temp中,后者使用复合文字创建一个临时对象,该对象是一个联合,它使用该对象来重新解释这些位。这两种方法都被C标准所支持。

uint32_t r = (rand() * (0xFFFFFFFF/RAND_MAX)) % 0x1FFFFFFF;

* (0xFFFFFFFF/RAND_MAX))尝试将rand的结果缩放到区间[0,FFFFFFFF16]。它可能做得并不完美。然后% 0x1FFFFFFF将其减小到区间[0,1fffffff16)。注意闭合的)]——这是一个不包括1FFFFFFF16的半开间隔。这里有一些问题:

  • 这可能是一个打字错误;& 0x1FFFFFFF将干净地提取低29位,产生完全闭合间隔[0,1fffffff16]的结果。使用%有不同的结果,没有明显的数学目的,并且强制进行耗时的划分。
  • 对于%&,没有明显的理由首先缩放到FFFFFFFF16;一个人可能会直接进入期望的最终间隔。
  • 这只产生阳性结果;这个数字只会增加或保持不变,而不会减少。这可能是人们所希望的,但原因尚不清楚。在这一点和其他方面缺乏文档说明代码质量不高。

temp += r;

这将随机数添加到double的低位。有时,它会导致进位到上位。(如果上面的位都是1,也可以进到指数域)

temp = temp & 0xFFFFFFFFE0000000;

清除低29位。floatdouble常用的IEEE-754 binary32和binary64格式中,float有效位为24位(其中23编码在主有效位字段中),double有效位为53位(其中52编码在主有效位字段中),因此差异为29。因此,如果指数在float范围内,那么清除double编码中的低29位将产生一个完全可以表示为float的数字。

清除这些位的目的可能是为了防止在转换到float的过程中第二次向上舍入。上一行temp += r;中的add可能导致了有效位数的上位进位,因此其意图可能是确保数字只增加一个单位,而不是两个。

return (float)*(double *)&temp;

与上面的第一行一样,将比特重新解释为double是一个错误的尝试。(之后它被强制转换为float,这对于标准C来说是不必要的,因为return语句的操作数会自动转换为函数的返回类型,但是,如果使用严格的代码检查,它可能会沉默关于窄化转换的警告。)正确的代码应该是memcpy(&x, &temp, sizeof x); return x;return (union { uint64_t u; double d }) { temp } .u;

相关内容

  • 没有找到相关文章

最新更新