我想将两个具有不同小数长度的定点数相乘。 定点部分和小数部分分别存储:
123 . 4
fix . frac
sint32 . sint32
我使用两个变量,一个用于固定部分,一个用于小数部分。
我尝试使用Karatsuba算法。但这仅适用于固定长度的小数。这两个数字的分数部分是变化的。它们可能是相同的,但是对此没有任何保证。 当然,最大可能值为(2 ^ 32)-1。
将123.4与56.789相乘的最佳方法是什么?
// a = 123.4
signed int a_fxd = 123;
signed int a_frx = 4;
// b = 56.789
signed int b_fxd = 56
signed int b_frc = 789;
答案 0 :(得分:2)
您需要确定小数部分的实际比例因子是多少。对于您的特定示例,看起来合适的因子可能是1/1000或0.001。这意味着56.789表示为56 + 789×0.001。但这意味着123.4将表示为12 + 400×0.001。也就是说,您输入的问题有误:a_frx
为400,而不是4。
我不知道Karatsuba's algorithm,而且我怀疑它真的不适用于此问题。我只知道我在小学赚的钱。
让我们用sc
表示比例因子。所以我们的乘法实际上是
( a_fxd + a_frx * sc ) * ( b_fxd + b_frx * sc )
乘以这个,我们得到
a_fxd * b_fxd + a_fxd * b_frx * sc + a_frx * b_fxd * sc + a_frx * b_frx * sc * sc
收集术语,我们有
a_fxd * b_fxd + (a_fxd * b_frx + a_frx * b_fxd + a_frx * b_frx * sc) * sc
因此,如果我们将产品表示为p_fxd
和p_frx
,看起来我们将拥有
p_fxd = a_fxd * b_fxd
p_frx = a_fxd * b_frx + a_frx * b_fxd + a_frx * b_frx * sc
让我们插入实际值:
p_fxd = 123 * 56 = 6888
p_frx = 123 * 789 + 400 * 56 + 400 * 789 * 0.001 = 119762.600
但是还有一个额外的问题,因为实际上p_frx
应该是0..999范围内的整数。因此,我们需要丢弃.600并携带119。所以最终结果是
p_fxd = 6888 + 119 = 7007
p_frx = 762
这对应正确的结果123.4×56.789 = 7007.762。
...实际上,正确正确结果为7007.7626,或四舍五入为三位数7007.763。因此严格来说,我们不应该舍弃在p_frx
中结束的.600,我们应该四舍五入。
当我们考虑负数的可能性时,可能还会有一些额外的皱纹需要照顾。
最后,可以选择比例因子。实际上,我在这里使用的0.001并不是一个现实的值。对于通用算法,您可能会使用诸如1/10000或1/1000000000或1/32768或1/65536之类的东西。 (使用2的幂表示较大的范围,并且通常可以提高计算效率,但分数部分不那么明显,而十进制表示形式的转换效率较低。例如,如果使用的比例因子为1/32768,{{1} }为13107,而a_frx
为25853或25854。)