C 数字从双精度转换为短精度

C 数字从双精度转换为短精度,c,type-conversion,fftw,C,Type Conversion,Fftw,我已经在互联网上搜索了好几天,以找到以下问题的解决方案 在我的程序中,我正在将两个16位.wav文件中的数据块读入声音缓冲区(类型为short)中,并在堆上为其分配内存。对于fftw函数,数据被转换为double,并进行处理,然后缩小并转换为short,以便在将输出文件写入磁盘之前放入收集缓冲区。通过这种方式,我减少了访问硬盘的次数,因为我正在读取多个数据块(即在文件中移动),并且不想在每次迭代中写入磁盘 以下是我正在做的: short* sound_buffer_zero; short* so

我已经在互联网上搜索了好几天,以找到以下问题的解决方案

在我的程序中,我正在将两个16位.wav文件中的数据块读入声音缓冲区(类型为
short
)中,并在堆上为其分配内存。对于fftw函数,数据被转换为
double
,并进行处理,然后缩小并转换为
short
,以便在将输出文件写入磁盘之前放入收集缓冲区。通过这种方式,我减少了访问硬盘的次数,因为我正在读取多个数据块(即在文件中移动),并且不想在每次迭代中写入磁盘

以下是我正在做的:

short* sound_buffer_zero;
short* sound_buffer_one;
short* collection_buffer_one;
sound_buffer_zero = (short *) fftw_malloc(sizeof(short) * BUFFERSIZE); 
sound_buffer_one = (short *) fftw_malloc(sizeof(short) * BUFFERSIZE);
collection_buffer_one = (short *) fftw_malloc(sizeof(short) * COLLECTIONLENGTH);

// read BUFFERSIZE samples from file into sound_buffer
inFileZero.read((char*)sound_buffer_zero, sizeof(short)*BUFFERSIZE);
inFileOne.read((char*)sound_buffer_one, sizeof(short)*BUFFERSIZE);

// typecast the short int values of sound_buffer into double values
// and write them to in_
for(int p = 0; p < BUFFERSIZE; ++p) {
    *(in_zero + p) = (double)*(sound_buffer_zero + p);
    *(in_one + p) = (double)*(sound_buffer_one + p);
}

// cross correlation in the frequency domain
// FFT on input zero (output is f_zero)
fftw_execute(p_zero);

// FFT on input one (output is f_one)
fftw_execute(p_one);

// complex multiplication (output is almost_one, also array of type double)
fastCplxConjProd(almost_one, f_zero, f_one, COMPLEXLENGTH);

// IFFT on almost_one (output is out_one, array of double)
fftw_execute(pi_one);

// finalize the output array (sort the parts correctly, output is final_one, array of double)
// last half without first value becomes first half of final array
for(int i = ARRAYLENGTH/2 + 1; i < ARRAYLENGTH; ++i) {
    *(final_one + i - (ARRAYLENGTH/2 + 1)) = *(out_one + i);
}
// first half becomes second half of final array
for(int i = 0; i < ARRAYLENGTH/2; ++i) {
    *(final_one + i + (ARRAYLENGTH/2 - 1)) = *(out_one + i);
}

short* scaling_vector; 
scaling_vector = (short *) fftw_malloc(sizeof(short) * ARRAYLENGTH-1);

// fill the scaling_vector with the numbers from 1, 2, 3, ..., BUFFERSIZE, ..., 3, 2, 1
for(short i = 0; i < BUFFERSIZE; ++i) {
    *(scaling_vector + i) = i + 1;
    if(i + BUFFERSIZE > ARRAYLENGTH-1) break;
    *(scaling_vector + i + BUFFERSIZE) = BUFFERSIZE - i - 1;
}

// scale values in relation to their position in the output array
// to values suitable for short int for storage
for(int i = 0; i < ARRAYLENGTH-1; ++i) {
    *(final_one + i) = *(final_one + i) * SCALEFACTOR; // #define SCALEFACTOR SHRT_MAX/pow(2,42)
    *(final_one + i) = *(final_one + i) / *(scaling_vector + i);
}

// transform the double values of final_ into rounded short int values
// and write them to the collection buffer
for(int p = 0; p < ARRAYLENGTH-1; ++p) {
    *(collection_buffer_one + collectioncount*(ARRAYLENGTH) + p) = (short)round(*(final_one + p));
}

// write collection_buffer to disk
 outFileOne.write((char*)collection_buffer_one, sizeof(short)*collectioncount*(ARRAYLENGTH));
我的问题是,为什么不保留这些标志?我是否缺少一些内部转换?我在其他帖子中没有找到我的问题的答案。如果我错过了,请让我知道,如果我遗漏了重要的信息给你。谢谢你的帮助

干杯, 芒果

以下是测试输出的代码:

//contents of sound_buffer (input from file):
// test output
for(int i = 0; i < 10; ++i) {
    cout << "input: " << *(sound_buffer_zero + i) << endl;
}

// content of in_ after converting to double
// test output
for(int i = 0; i < 10; ++i) {
    cout << "as double: " << *(in_zero + i) << endl;
}

// contents of final_ after the scaling
// test output 
for(int i = 0; i < 10; ++i) {
    cout << "after scaling: " << *(final_one + i) << endl;
}

// contents of collection_buffer after converting to short
// test output
for(int i = 0; i < 10; ++i) {
    cout << "collection [short(round*(final_one))]: " << *(collection_buffer_one + i) << endl;
}
//声音缓冲区的内容(从文件输入):
//测试输出
对于(int i=0;i<10;++i){

cout正常情况下,short是2字节长,double是8字节长。将double转换为short会导致上层字节丢失。即使没有符号的实际数据只有2个字节,您也会通过符号扩展丢失上层字节中存储的符号信息。

您在哪个平台上运行此操作? 我在linux x86、gcc 3.4.2上做了一个小测试

   #include <iostream>
   #include <math.h>

   int main (int,  char*[])
   {
       double a = -2.99445;
       short b = (short)round(a);

       std::cout << "a = " << a << " b = " << b << std::endl;
      return 0;
   }
所以我可以想到两种情况

  • 您还没有向我们展示缩放和转换为短代码之间的一些代码
  • 您使用非标准的双重表示运行一些异国情调的平台

  • 在编译时完全没有优化,下面的代码如何在您的平台上运行

    #include <stdlib.h>
    #include <stdio.h>
    
    double a[10] = { 
      -2.99445,
      -42.6612,
      -57.0962,
      41.0415,
      -18.3168,
      43.5853,
      -14.3663,
      -3.58456,
      -46.3902,
      16.0804
    };
    
    int main(){
      int i;
      for (i=0;i<10;++i){
        short k = (short)*(a + i);
        printf("%d\n", k);
      }
    
    }
    


    如果我理解正确,我将
    round
    替换为
    lrint
    (因为我将
    double
    值传递给它),然后重试。结果相同。感谢您的提示。collectioncount*(ARRAYLENGTH)是什么?为什么不使用
    ptr[offset]
    符号,这比
    *(ptr+offset)更容易理解
    notation?@didierc我对
    *(ptr+offset)
    表示法非常满意,将其理解为
    “值(在这个地址)”
    除了对某些人的可读性之外,它是否会产生功能上的差异?如果是,我愿意更改它。collectioncount告诉我们在collection\u缓冲区数组中从何处开始写入下一次迭代的值。正如我上面提到的,在写入磁盘之前,我正在迭代文件并收集几次迭代的结果.没问题,我现在明白了。我在我的短测试程序中没有看到这种行为。你能发布一个小的、自包含的可编译示例,用一个数字来展示这个问题吗?谢谢你的解释。你能给我一个线索,我可以在哪里读到更多关于类型转换过程中内部发生的事情吗?这样我就不会再犯这些错误了…Th谢谢!你可以从这里开始:这是不对的-他不是通过指针施放-他只是将舍入的双结果施放到一个短值上,只要值不在短值的范围之外,这应该是好的。当浮点值转换为整型时,符号被保留,所以这不是这里发生的事情。@icepa谢谢。我真的刚刚开始理解这一点。我正在使用WinXP 32位。代码是在NetBeans 7.1.2中用MinGW中的g++编写和运行的。我做了相同的测试,得到了与您相同的结果。我只是在这里编译了您的代码,并再次产生相同的结果。这就是为什么我对上面的代码感到困惑。没有更多的计算缩放和转换之间的排列。@bat mango,请显示打印值的代码。我在上面编辑了我的原始帖子,并提供了在每个步骤打印数组内容的循环。@bat.mango,在循环中,您可以在循环中添加一个测试输出,smth like
    cout@aleguna,谢谢提示p、 这让我认识到,在将数值转换为短数值之前,符号已经丢失。我必须承认,确实还有两次计算,我没有预料到会改变数值。我现在明白了,我错在哪里。再次感谢!我在你的答案中添加了我的结果,尚未可见,但它们是-2,-42,-57,41,-18,43,-14,-3,-46,16。符号保持原样。为什么不在我上面的转换中呢?好的,显然你的编译器可以进行双到短的转换。所以问题出在别处。
    collectioncount
    ?是的,问题是子例程中的一行代码本来不应该改变任何值。我把这行代码放进去进行测试,然后再进行测试开始吧。我已经吸取了教训。谢谢你的帮助!@bat.mango:当然,没问题。别忘了结束这个问题!不行。我猜声誉不够。或者我该怎么做?我最近才加入。
    a = -2.99445 b = -3
    
    #include <stdlib.h>
    #include <stdio.h>
    
    double a[10] = { 
      -2.99445,
      -42.6612,
      -57.0962,
      41.0415,
      -18.3168,
      43.5853,
      -14.3663,
      -3.58456,
      -46.3902,
      16.0804
    };
    
    int main(){
      int i;
      for (i=0;i<10;++i){
        short k = (short)*(a + i);
        printf("%d\n", k);
      }
    
    }
    
    -2
    -42
    -57
    41
    -18
    43
    -14
    -3
    -46
    16