如何使用C中位方式和逻辑运算符来翻两番一个无符号数 [英] How to quadruple an unsigned number using bit-wise and logic operator in C

查看:235
本文介绍了如何使用C中位方式和逻辑运算符来翻两番一个无符号数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标:

  4倍(4.400000095)= 17.60000038


  

      
  • 法律OPS:任意整数/无符号运算含。 ||,&安培;&放;.此外,如果,而

  •   
  • 最大OPS:30

  •   
  • 返回位水平相当于前$的对$ pssion X + X + X + X为

  •   
  • 浮点参数F。

  •   

我的code:

 符号4X(无符号UF){
无符号EXPN =(UF>> 23)及0xFF的;
无符号的符号= UF&安培; 0x80000000的;
无符号压裂= UF&安培; 0x007FFFFF;
如果(EXPN == || 255(EXPN == 0安培;&安培;压裂== 0))
    返回UF;
如果(EXPN){
    EXPN<< 2;
}否则如果(压裂== 0x7FFFFF){
    压裂>> 2;
    EXPN<< 2;
}其他{
    压裂&所述;&下; = 2;
}返回(标志)| (EXPN<< 23)| (压裂);

}

正如您可以猜到,我的code不起作用。代替四倍的输入,所述输入被加倍。我不知道为什么,因为小数和指数总是被左/右按2,而不是1进出口单precision浮点值的工作在32位机器移位。


解决方案

一些未经检验的code - 留到OP。 (GTG)

棘手位处理分普通号,当* 4趋于正常。同时还要注意这个溢出到无穷大的值。如果你想忽略子法线,只是 EXPN + = 2 和检查溢出。

另一种方法是 EXPN + = 2 正常的数字。对于子法线,移压裂<< = 2 和处理案件趋于正常。

code为约30欢声笑语。

 的#include< stdint.h>浮X4(浮X){
  //使用union来访问位。跨越式的信仰在这里(浮点为32位,尾数)
  工会{
    浮F;
    uint32_t的U32;
  } U;
  u.f = X;
  uint32_t的EXPN =(u.u32>> 23)及0xFF的;
  uint32_t的签名= u.u32&安培; 0x80000000的;
  uint32_t的压裂= u.u32&安培; 0x007FFFFF;  //楠天道酬勤
  如果(EXPN == 255)返回u.f;  如果(EXPN == 0){
    EXPN ++; //把分一般为正常范围世博会
  }其他{
    压裂+ =从0x800000; //恢复隐含位
  }  // * 4
  压裂&所述;&下; = 2;  //规范化 - 这通常两次迭代,少子法线
  而(压裂> 0XFFFFFF){
    EXPN ++;
    压裂>> = 1; // 1的将不被移出为2 LSB是0,因此最迟四舍五入
  }  //溢出INF
  如果(EXPN> = 255){
    EXPN = 255;
    压裂= 0;
  }否则如果(压裂&安培;从0x800000){
    压裂^ =从0x800000; //明确隐含位
  }其他{
    //仍低于正常
    expn--; //现在应该0
  }  u.u32等号(=)| (EXPN<< 23)|压裂;
  返回u.f;
}

Goal:

4x ( 4.400000095 ) = 17.60000038

  • Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
  • Max ops: 30
  • Return bit-level equivalent of expression x + x + x + x for
  • floating point argument f.

My code:

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);

}

As you can guess, my code does not work. Instead of quadrupling the input, the input is doubled. I don't know why since the fraction and exponent are always being right / left shifted by 2 instead of 1. Im working with single precision floating point values in 32 bit machines.

解决方案

Some untested code - leave that for OP. (GTG)

The tricky bit is dealing with sub-normal numbers that when *4 become normal. Also watch for large values that overflow to infinity. If you want to ignore sub-normals, just expn += 2 and check for overflow.

Another approach would expn += 2 for normal numbers. For sub-normals, shift the frac <<= 2 and handle cases that become normal.

Code is about 30 ops.

#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;   
}

这篇关于如何使用C中位方式和逻辑运算符来翻两番一个无符号数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆