在C中将二进制继续转换为小数

时间:2019-12-27 17:35:26

标签: c bignum

我实现了对2的平方根的逐位计算。每回合它将输出小数部分的一位,例如

1 0 1 1 0 1 0 1

我想将此输出转换为十进制数字:

4 1 4 2 1 3 6

我面临的问题是,通常这样工作:

1 * 2^-1 + 0 * 2^-2 + 1 * 2^-3

我想完全避免使用小数,因为我想使用整数将二进制从十进制转换为十进制。另外,我想在计算完每个十进制数字后立即打印。

转换为十六进制很简单,因为我只需要等待4位。是否有一个聪明的方法可以转换为base10,它只能观察整个输出的一部分,理想情况下可以从方程中删除数字,一旦确定,它就不会再改变了,即

1   0
2   0,25
3   0,375
4   0,375
5   0,40625
6   0,40625
7   0,4140625
8   0,4140625

处理完第8位后,我很确定4是第一个十进制小数位。因此,我想从等式中删除0.4的补全项,以减少需要注意的位数。

3 个答案:

答案 0 :(得分:2)

  

是否存在一种聪明的方法来转换为base10,一旦我们确定它不会再改变(?),就可以只观察整个输出的一部分,并且理想地从等式中除去数字。

是的,最终在实践中,但是从理论上讲,在某些情况下没有。

这类似于Table-maker's dilemma

请考虑以下处理接近0.05的值。只要二进制序列是.0001 1001 1001 1001 1001 ...,我们就不能知道十进制等效值为0.04999999 ...或0.05000000 ...非零。

int main(void) {
  double a;
  a = nextafter(0.05, 0);
  printf("%20a %.20f\n", a, a);
  a = 0.05;
  printf("%20a %.20f\n", a, a);
  a = nextafter(0.05, 1);
  printf("%20a %.20f\n", a, a);
  return 0;
}

0x1.9999999999999p-5 0.04999999999999999584
0x1.999999999999ap-5 0.05000000000000000278
0x1.999999999999bp-5 0.05000000000000000971

代码可以分析二进制小数位的输入序列,然后在每个位之后询问两个问题:“如果其余位都为0,则十进制是什么?”和“如果其余位都为1”,则什么?是十进制吗?”。在许多情况下,答案将共享共同的前导有效数字。但是,如上所述,只要收到1001,就没有通用的有效十进制数字。

通常的“输出”是将永远显示的小数位数上限。在那种情况下,代码仅呈现一个 rounded 结果,即使二进制输入序列保持1001,也可以在有限的时间内推导出结果  ad nauseam

答案 1 :(得分:1)

  

我面临的问题是,通常这样工作:

     

1 * 2 ^ -1 + 0 * 2 ^ -2 + 1 * 2 ^ -3等

1/2 = 5/10和1/4 = 25/100,依此类推,这意味着您将需要使用5的幂并将值乘以10的幂

给定0 1 1 0 1

[1] 0 * 5 = 0

[2] 0 * 10 +1 * 25 = 25

[3] 25 * 10 +1 * 125 = 375

[4] 375 * 10 + 0 * 625 = 3750

[5] 3750 * 10 +1 * 3125 = 40625

编辑:

  

是否有一个聪明的方法可以转换为base10,它只能观察整个输出的一部分,并且理想情况下,从方程中删除数字,一旦确定,它就不再改变了

在这种情况下,实际上可能会弹出最高有效数字(MSD)。这会有点长,但是请忍受我

考虑值X和Y:

  1. 如果X的位数与Y的位数相同,则MSD将更改。
    10000 + 10000 = 20000
  1. 如果Y的位数比X小1个或多个,则MSD 可以更改。
    19000 + 1000  = 20000
    19900 +  100  = 20000

因此,第一点是不言而喻的,但第二点是使我们能够弹出MSD的内容。我们需要知道的第一件事是,我们添加的值会在每次迭代中不断地被分成两半。这意味着如果仅考虑MSD,base10中的最大值为9,这将产生序列

    9 > 4 > 2 > 1 > 0

如果我们将这些值加起来等于16,但是如果我们尝试考虑下一位数字的值(例如9.9或9.999),则该值实际上接近20,但不超过20。这意味着如果X具有n位数字,而Y具有n-1位数字,则X的MSD仍然可以更改。但是,如果X有n位数字,而Y有n-2位数字,只要X的n-1位数字小于8,则MSD不会改变(否则它将是8 + 2 = 10或9 + 2 = 11表示MSD将更改)。这是一些例子

假设X是sqrt(2)的运行总和,Y是5 ^ n:

 1. If X = 10000 and Y = 9000 then the MSD of X can change.
 2. If X = 10000 and Y =  900 then the MSD of X will not change.
 3. If X = 19000 and Y =  900 then the MSD of X can change.
 4. If X = 18000 and Y =  999 then the MSD of X can change.
 5. If X = 17999 and Y =  999 then the MSD of X will not change.
 6. If X = 19990 and Y =    9 then the MSD of X can change.

在上面的示例中,在点#2和#5上,已经可以弹出1。但是对于第6点,可能有19990 + 9 + 4 = 20003,但这也意味着2和0都可以在发生之后弹出。

这是sqrt(2)的模拟

i          Out                      X                  Y     flag
-------------------------------------------------------------------
1                                   0                  5       0
2                                  25                 25       1
3                                 375                125       1
4                               3,750                625       0
5                              40,625              3,125       1
6                             406,250             15,625       0
7            4                140,625             78,125       1
8            4              1,406,250            390,625       0
9            4             14,062,500          1,953,125       0
10          41             40,625,000          9,765,625       0
11          41            406,250,000         48,828,125       0
12          41          4,062,500,000        244,140,625       0
13          41         41,845,703,125      1,220,703,125       1
14         414         18,457,031,250      6,103,515,625       0
15         414        184,570,312,500     30,517,578,125       0
16         414      1,998,291,015,625    152,587,890,625       1
17        4142      0,745,849,609,375    762,939,453,125       1

答案 2 :(得分:0)

您可以使用乘除法来减少浮点运算。 1 0 1 1 等效于1*2^0+0*2^1+2^(-2)+2^(-3)可以简化为(1*2^3+0*2^2+1*2^1+1*2^0)/(2^3),仅除法运算仍为浮点算术,其余均为整数算术运算。乘以2即可通过左移实现。