我正在尝试在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;
}
答案 0 :(得分:6)
按位移位浮点数据类型不会为您提供所需的结果。
在Simulink中,移位算术块仅对整数数据类型进行位移。如果为浮点类型提供它,则将输入信号除以2^N
,其中N是掩码对话框中指定的要移位的位数。
编辑:
由于您无法执行任何浮点数学运算,因此您可以选择:
我建议选项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
值。即使double
和int
碰巧大小相同,也不太可能做任何有用的事情。 (即使它很有用,转换无符号值而不是有符号值也更有意义。)
答案 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处理器指令执行该操作?)