7

我正在尝试在 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; 
}
4

6 回答 6

6

按位移动浮点数据类型不会给你你正在寻找的结果。

在 Simulink 中,Shift Arithmetic 模块仅对整数数据类型进行位移。如果给它一个浮点类型,它会将输入信号除以2^N其中 N 是在掩码对话框中指定的要移位的位数。

编辑:
由于您没有能力执行任何浮点数学运算,因此您的选择是:

我推荐选项 2,它比 1 容易得多

于 2011-08-10T18:24:04.597 回答
4

对浮点数据类型(重新解释为 int)进行位移会给您带来乱码(请查看此处的二进制表示图以了解原因)。

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

于 2011-08-10T18:17:43.933 回答
1

根据措辞不佳且非常不清楚的文档,Simulink 中的“位移”似乎需要两个浮点值参数,并且具有将浮点值乘以两个提高参数差的效果。

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

于 2011-08-10T18:30:20.293 回答
0

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

你正在做的是解释(“类型双关”)一个double对象,就好像它是一个int对象,然后移动结果int值。即使大小相同,这doubleint不太可能做任何有用的事情。(即使它很有用,移动无符号值而不是有符号值更有意义)。

于 2011-08-10T18:19:04.273 回答
0

一个潜在的用例是用于捕获尾数位、指数位和符号位(如果有兴趣)。为此,您可以使用联合:

union doubleBits {
    double d;
    long l;
};

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

union doubleBits myUnion;
myUnion.d = myDouble;

并在提取位后对联合的长部分进行位移,如下所示:

myUnion.l >>= 1;

由于定义了双精度的每个部分的位数,这是提取底层位表示的一种方法。这是一种可以获取原始底层位的用例。我对 Simulink 不熟悉,但如果这可能就是为什么首先要移动双精度,这可能是在 C 中实现这种行为的一种方法。它总是 12 位的事实让我不这么认为,但是以防万一认为值得为其他偶然发现这个问题的人指出。

于 2017-03-13T03:13:10.617 回答
0

有一种方法可以实现这一点:只需将您的 n 添加到双精度位表示的指数部分。使用“重新解释”或按位转换(例如使用联合)将双精度数转换为长整数。从 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 处理器指令可以做到这一点?)

于 2019-05-29T10:20:14.230 回答