2012-12-04 35 views
2

我需要根據非常數因子將一個單位的值轉換爲另一個單位。到1073676289的輸入值範圍從0和從0到1155625.轉換的範圍的數值範圍可以這樣描述:定點乘法

output = input * (range/1073676289) 

我自己的初始固定點實現感覺有點笨拙:

// Input values (examples) 
unsigned int input = 536838144; // min 0, max 1073676289 
unsigned int range = 1155625; // min 0, max 1155625 

// Conversion 
unsigned int tmp = (input >> 16) * ((range) >> 3u); 
unsigned int output = (tmp/((1073676289) >> 16u)) << 3u; 

我的代碼可以改進得更簡單或更準確嗎?

+0

你想要的輸出範圍是什麼? (是(a * b)<= 1.0?如果a * b <= 1.102(* 2^n)的最大值被允許,事情會更快)(並且很明顯float/double是不成問題的) –

回答

0

你不會得到任何簡單的再output = input * (range/1073676289)

正如下面的評論中指出,如果你restircted到整數運算然後range < 1073676289range/1073676289 == 0這樣你會好去的:

output = range < 1073676289 ? 0 : input 

如果這不是你想要什麼,你真正想要的精度,然後

output = (input * range)/1073676289 

將要走的路。

如果你需要做很多這些,那麼我建議你使用double並讓你的編譯器引導你的操作。精度也可以。

+3

因爲'range'總是小於1073676289而且你正在使用整數除法; 'output = input *(range/1073676289)'將與'output = input * 0'相同。 – Brendan

+1

我不認爲'a *(b/c)'等於'(a * b)/ c'。 –

+1

對不起,如果我一直不清楚,但我不能使用浮點值(也不是雙打)。 – Vandhunden

4

問題是input * range會溢出一個32位整數。通過使用64位整數修復該問題。

uint64_least_t tmp; 
tmp = input; 
tmp = tmp * range; 
tmp = tmp/1073676289ul; 
output = temp; 
6

這會給你沒有浮點值,結果最好的精度將四捨五入到最接近的整數值:

output = (input * (long long) range + 536838144)/1073676289; 
+1

「圓到最近」的偏差爲+1 – Brendan

+1

爲什麼要添加536838144? – banuj

+2

@banuj:536838144是1073676289的一半;並導致最終結果四捨五入到最接近的整數而不是截斷。例如,'1073676288/1073676289 = 0',但是'(1073676288 + 536838144)/ 1073676289 = 1'。 – Brendan

3

快速出去一趟谷歌帶來了http://sourceforge.net/projects/fixedptc/我注意

它是一個頭文件中的ac庫,用於管理32或64位整數的定點數學。

實驗用下面的代碼一點點:

#include <stdio.h> 
#include <stdint.h> 

#define FIXEDPT_BITS  64 

#include "fixedptc.h" 

int main(int argc, char ** argv) 
{ 
    unsigned int input = 536838144; // min 0, max 1073676289 
    unsigned int range = 1155625; // min 0, max 1155625 

    // Conversion 
    unsigned int tmp = (input >> 16) * ((range) >> 3u); 
    unsigned int output = (tmp/((1073676289) >> 16u)) << 3u; 

    double output2 = (double)input * ((double)range/1073676289.0); 

    uint32_t output3 = fixedpt_toint(fixedpt_xmul(fixedpt_fromint(input), fixedpt_xdiv(fixedpt_fromint(range), fixedpt_fromint(1073676289)))); 

    printf("baseline = %g, better = %d, library = %d\n", output2, output, output3); 

    return 0; 
} 

給我弄了以下結果:

baseline = 577812, better = 577776, library = 577812 

顯示更高的精確度(相匹配的浮點),比你用你的代碼獲得。引擎蓋下它沒有做任何事情非常複雜(沒有在​​32位工作在所有)

/* Multiplies two fixedpt numbers, returns the result. */ 
static inline fixedpt 
fixedpt_mul(fixedpt A, fixedpt B) 
{ 
    return (((fixedptd)A * (fixedptd)B) >> FIXEDPT_FBITS); 
} 


/* Divides two fixedpt numbers, returns the result. */ 
static inline fixedpt 
fixedpt_div(fixedpt A, fixedpt B) 
{ 
    return (((fixedptd)A << FIXEDPT_FBITS)/(fixedptd)B); 
} 

但它確實表明,你可以得到你想要的精確度。你只需要64位就可以做到這一點