C中双变量数据类型的算术位移

时间:2011-08-10 18:11:59

标签: c math pointers matrix shift

我正在尝试在C中对双数据类型进行算术位移。我想知道这是否是正确的方法:

注意:firdelay [] []在main中声明为     double firdelay [8] [12]

void function1(double firdelay[][12]) {
    int * shiftptr;

    // Cast address of element of 2D matrix (type double) to integer pointer
    *shiftptr = (int *) (&firdelay[0][5]); 

    // Dereference integer pointer and shift right by 12 bits
    *shiftptr >>= 12; 
}

6 个答案:

答案 0 :(得分:6)

按位移位浮点数据类型不会为您提供所需的结果。

在Simulink中,移位算术块仅对整数数据类型进行位移。如果为浮点类型提供它,则将输入信号除以2^N,其中N是掩码对话框中指定的要移位的位数。

编辑:
由于您无法执行任何浮点数学运算,因此您可以选择:

  • 理解浮点单精度数的layout,然后弄清楚如何按位操作它来实现除法。
  • 将您要移植的算法转换为使用定点数据类型而不是浮点数

我建议选项2,它比1

容易得多

答案 1 :(得分:4)

对浮点数据类型进行位移(重新解释为int)会给你带来胡言乱语(看看二进制表示here的图表,看看为什么)。

如果你想乘以2除以2的幂,那么你应该明确地这样做。

答案 2 :(得分:1)

根据措辞不好且非常不清楚的documentation,似乎Simulink中的“位移”需要两个浮点值的参数,并且具有将浮点值乘以2的效果。争论。

您可以使用ldexp(double_number, bits_to_pseudo_shift)来获取此行为。函数ldexp位于<math.h>

答案 3 :(得分:0)

没有正确的方法可以做到这一点。 <<的两个操作数必须是某种整数类型。

您正在做的是将double对象解释为(“type-punning”),就像它是int个对象一样,然后移动生成的int值。即使doubleint碰巧大小相同,也不太可能做任何有用的事情。 (即使它很有用,转换无符号值而不是有符号值也更有意义。)

答案 4 :(得分:0)

一个潜在的用例是,如果感兴趣,可以捕获尾数位,指数位和符号位。为此你可以使用union:

union doubleBits {
    double d;
    long l;
};

你可以设置你的双倍并在联合中设置它:

union doubleBits myUnion;
myUnion.d = myDouble;

在提取像这样的位之后,对位移的长部分进行位移:

myUnion.l >>= 1;

由于定义了double的每个部分的位数,这是提取底层位表示的一种方法。这是一个用例,希望获得原始底层位是可行的。我不熟悉Simulink,但是如果这可能是为什么double首先被移位的原因,这可能是在C中实现这种行为的一种方式。事实上它总是12位,这让我想到了,但是,如果有人认为值得指出其他偶然发现这个问题的人。

答案 5 :(得分:0)

有一种方法可以实现:只需将您的n添加到double的按位表示的指数部分即可。 使用“重新解释”或按位转换(例如,使用并集)将双精度型转换为long型。.从52到63(11位)中提取位。然后添加移位并将结果放回指数中。 您应考虑double(+ infinity,nan或零)的特殊值

double operator_shift_left(double a,int n)
{
    union 
    {
        long long l;
        double d;
    } r;
    r.d=a;
    switch(r.l)
    {
        case 0x0000000000000000: // 0
        case 0x8000000000000000: // -0
        case 0x7FF0000000000000: // pos infnity
        case 0xFFF0000000000000: // neg infnity
        case 0x7FF0000000000001: // Nan
        case 0x7FF8000000000001: // Nan
        case 0x7FFFFFFFFFFFFFFF: // Nan
            return a;
    }
    int nexp=(((r.l>>52)&0x7FF)+n); // new exponent
    if (nexp<0) // underflow 
    {
        r.l=r.l &  0x8000000000000000;
        // returns +/- 0
        return r.d;
    }
    if (nexp>2047) // overflow
    {
        r.l=(r.l & 0x8000000000000000)| 0x7FF0000000000000;
        // returns +/- infinity
        return r.d;
    }
    // returns the number with the new exponant

    r.l=(r.l & 0x800FFFFFFFFFFFFF)|(((long long)nexp)<<52); 
    return r.d;


}

(可能有一些x64处理器指令执行该操作?)