【问题标题】:How to quadruple an unsigned number using bit-wise and logic operator in C如何使用 C 中的按位和逻辑运算符将无符号数四倍
【发布时间】:2016-02-03 04:05:23
【问题描述】:

目标:

4x ( 4.400000095 ) = 17.60000038
  • 合法操作:任何整数/无符号操作,包括。 ||,&&。如果,同时
  • 最大操作数:30
  • 返回表达式 x + x + x + x for 的位级等效项
  • 浮点参数 f.

我的代码:

unsigned 4x(unsigned uf) {
unsigned expn = (uf >> 23) & 0xFF;
unsigned sign = uf & 0x80000000;
unsigned frac = uf & 0x007FFFFF;
if (expn == 255 || (expn == 0 && frac == 0))  
    return uf;
if (expn) {
    expn << 2;
} else if (frac == 0x7FFFFF) {
    frac >> 2;
    expn << 2;
} else {
    frac <<= 2;
}

return (sign) | (expn << 23) | (frac);

}

您可以猜到,我的代码不起作用。不是将输入翻两番,而是将输入翻了一番。我不知道为什么,因为分数和指数总是右移/左移 2 而不是 1。我在 32 位机器中使用单精度浮点值。

【问题讨论】:

  • 除了亚法线和接近无穷大,代码只需要将指数增加2。
  • 您不能以这种方式操作浮点数。另外,4x 不是合法的函数名。
  • 双方都赞赏
  • 您有 2 个基本选项。第一个是包含unsignedfloat 值的联合,这将允许您通过对unsigned 表示进行操作来避免违反严格别名 的精神。下一个是通过声明一个指向浮点地址的指向无符号的指针的技术违规。如果你被允许使用工会,那就是要走的路。
  • 你的标题说你想要4 * x;你的例子说你想要 4.4 * 4 = 17.6,给或取一些分数;你的评论表明你想要x * x * x * x(又名x ** 4其中**是从Fortran借来的伪幂运算符)。你的意思是x + x + x + x?请清楚你想要什么——相互矛盾的信息很难给出一个好的答案。

标签: c floating-point precision unsigned


【解决方案1】:

注意

expn << 2;

不修改expn。你可能想要

expn <<= 2;

同上

frac >> 2;
expn << 2;

但是,正如@chux 指出的那样,您只需将指数加 2,而不是将指数乘以 4。

【讨论】:

    【解决方案2】:

    一些未经测试的代码 - 将其留给 OP。 (GTG)

    棘手的一点是处理当 *4 变为正常时的次正常数。还要注意溢出到无穷大的大值。如果你想忽略次法线,只需expn += 2 并检查溢出。

    另一种方法是expn += 2 用于正常数字。对于亚正常情况,转移frac &lt;&lt;= 2并处理变为正常的情况。

    代码大约是 30 个操作。

    #include <stdint.h>
    
    float x4(float x) {
      // Use union to access the bits.  Leap-of-faith here (float is 32 bits, endian)
      union {
        float f;
        uint32_t u32;
      } u;
      u.f = x;
      uint32_t expn = (u.u32 >> 23) & 0xFF;
      uint32_t sign = u.u32 & 0x80000000;
      uint32_t frac = u.u32 & 0x007FFFFF;
    
      // Nan Inf
      if (expn == 255) return u.f;
    
      if (expn == 0) {
        expn++;  // Bring sub-normal into normal expo range
      } else {
        frac += 0x800000; // restore implied bit
      }
    
      // *4
      frac <<= 2;
    
      // normalize - this usually iterates twice, less for sub-normals
      while (frac > 0xFFFFFF) {
        expn++;
        frac >>= 1; // 1's will not be shifted out as 2 LSB are 0 so no later rounding
      }
    
      // overflow to inf
      if (expn >= 255) {
        expn = 255;
        frac = 0;
      } else if (frac & 0x800000) {
        frac ^= 0x800000; // clear implied bit
      } else {
        // still sub-normal
        expn--;  // should now be 0
      }
    
      u.u32 = sign | (expn << 23) | frac;
      return u.f;   
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-20
      • 2012-10-01
      相关资源
      最近更新 更多