c - 如果固定部分和小数部分分开存储,如何将定点数相乘?

标签 c math addition

我想将两个小数长度不同的定点数相乘。 定点部分和小数部分分开存储:

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;

最佳答案

您需要决定小数部分的实际比例因子是多少。对于您的特定示例,看起来合适的因子可能是 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_fxdp_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 的比例因子,a_frx 将是 13107,b_frx 将是 25853 或 25854。)

关于c - 如果固定部分和小数部分分开存储,如何将定点数相乘?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58622209/

相关文章:

Javascript 通过加法编辑输入值

c - 声明时初始化和下一步初始化有什么区别?

c - 从函数返回指针作为静态变量

c# - 如何将 float 舍入到最接近的 n 倍数?

java - 给定整数集的子集,其和为常量 N : Java

javascript - 为什么我不能在 JavaScript 中对 4 个变量进行加法运算,但可以对 3 个变量进行加法运算?

c# - 如何创建一个仅使用加法和 2 个变量进行除法的递归函数

c - Go 语言使用 C 的内部结构

c - 在 C 中释放动态字符串/行的数组

iphone - 二维线段变形算法