2012-12-04 33 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位就可以做到这一点