2012-10-29 20 views
0

我一直在網上搜索幾天,以找到解決以下問題的方法。數字在雙重轉換爲空格時丟失了標誌

在我的程序中,我正在將兩個16位.wav文件中的數據塊讀入聲音緩衝區(類型爲short的數組),爲此我在堆上分配了內存。將數據轉換爲double以實現fftw功能,然後處理並縮小並投射到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)); 

所計算的互相關的值是double型和有積極或消極的跡象。通過縮小它們,標誌不會改變。但是當我將它們投到short時,到達collection_array的數字都是正數。

的數組被聲明爲short,還不如unsigned short和縮放後的值在一定範圍的short可容納(你必須相信我在這一個,因爲我不希望發佈所有我代碼保持郵件可讀)。我不關心小數部分的截斷,我不需要進一步計算,但是符號應該保持不變。

下面是輸入和輸出值一個小例子(示出的是在陣列中的第一個10個值):

input: 157 
input: 4058 
input: -1526 
input: 1444 
input: -774 
input: -1507 
input: -1615 
input: -1895 
input: -987 
input: -1729 

// converted to double 
as double: 157 
as double: 4058 
as double: -1526 
as double: 1444 
as double: -774 
as double: -1507 
as double: -1615 
as double: -1895 
as double: -987 
as double: -1729 

// after the computations 
after scaling: -2.99445 
after scaling: -42.6612 
after scaling: -57.0962 
after scaling: 41.0415 
after scaling: -18.3168 
after scaling: 43.5853 
after scaling: -14.3663 
after scaling: -3.58456 
after scaling: -46.3902 
after scaling: 16.0804 

// in the collection array and before writing to disk 
collection [short(round*(final_one))]: 3 
collection [short(round*(final_one))]: 43 
collection [short(round*(final_one))]: 57 
collection [short(round*(final_one))]: 41 
collection [short(round*(final_one))]: 18 
collection [short(round*(final_one))]: 44 
collection [short(round*(final_one))]: 14 
collection [short(round*(final_one))]: 4 
collection [short(round*(final_one))]: 46 
collection [short(round*(final_one))]: 16 

我的問題是,爲何標誌不保留?我錯過了一些內部轉換嗎?我在其他帖子中找不到我的問題的答案。如果我錯過了,請讓我知道,如果我給你留下了重要的信息。謝謝你的幫助!

乾杯, 芒果

下面是測試。OUPUTS代碼:

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

由於aleguna我發現跡象以下計算消失。我完全錯過了那個步驟final_one = fabs(final_one)。我已經把它放在一個測試中,完全忘記了它。

謝謝大家的意見和解答。事實證明,我只是愚蠢的。對不起。

+0

你試圖使用lrint? – didierc

+0

如果我理解正確,我用'lrint'替換'round'(因爲我將'double'值傳遞給它)並重試。相同的結果。感謝提示。 –

+1

什麼是collectioncount *(ARRAYLENGTH)?爲什麼不使用'ptr [offset]'符號,這更容易理解,而不是'*(ptr + offset)'符號? – didierc

回答

3

你在哪個平臺上運行這個平臺?我在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; 
    } 

輸出

a = -2.99445 b = -3 

所以我能想到的兩種方案

  1. 您還沒有我們顯示的縮放和轉換之間的一些代碼,以短
  2. 你運行一些異國情調具有非標準雙重表示的平臺
+0

我正在使用WinXP 32位。該代碼在MinGW中使用g ++編寫並運行NetBeans 7.1.2中的測試。我做了同樣的測試,並得出了和你一樣的結果。我在這裏編譯了你的代碼,並再次得到相同的結果。這就是爲什麼我對上面的代碼感到迷茫。縮放和轉換之間不再有計算或排列。 –

+0

@ bat-mango,請顯示打印出來的代碼 – 2012-10-29 12:30:29

+0

我編輯了我上面的原始文章,並提供了在每一步打印出數組內容的循環。 –

-2

通常,短爲2字節長,而雙爲8字節長。將double加到short會導致高位字節的丟失。即使2個字節足夠用於沒有符號的實際數據,也可以通過符號擴展來釋放存儲在高位字節中的符號信息。

+0

感謝您的解釋。你能給我一個線索,我可以在類型轉換期間閱讀關於內部進行中的更多信息嗎?所以我不會再犯這些錯誤......謝謝! –

+0

你可以從這裏開始:http://en.wikipedia.org/wiki/Sign_extension – SomeWittyUsername

+2

這是不正確的 - 他不是通過指針投射 - 他只是施加一個簡短的雙重結果,這應該是好的*只要該值不在短*的範圍之外。 –

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

} 

給了我下面的結果:

-2 
-42 
-57 
41 
-18 
43 
-14 
-3 
-46 
16 
+0

我將結果添加到您的答案中,但尚未顯示,但它們分別是-2,-42,-57,41,-18,43,-14,-3,-46和16.標誌保持原樣。爲什麼不在我上面的轉換中? –

+0

好吧,顯然你的編譯器在雙轉換到短轉換時工作正常。所以問題在別處。那麼'collectioncount'呢? – didierc

+0

是的,問題是子程序中的一行代碼原本不應該改變任何值。我已經把這條線路進行了測試,然後忘記了這一點。我已經吸取了教訓。謝謝你的幫助! –

相關問題