Algorithm 检测重复小数的算法?

Algorithm 检测重复小数的算法?,algorithm,rational-numbers,Algorithm,Rational Numbers,有没有一种算法可以解决以下问题 如果除法的结果是重复的十进制(二进制) 如果重复,重复从哪个数字(表示为2的幂)开始 什么数字重复 一些例子: 1/2 = 1/10 = 0.1 // 1 = false, 2 = N/A, 3 = N/A, 4 = N/A 1/3 = 1/11 = 0.010101... // 1 = true, 2 = -2, 3 = 10 2/3 = 10/11 = 0.101010... // 1 = true, 2 = -1, 3 = 10 4/3 = 100/11 =

有没有一种算法可以解决以下问题

  • 如果除法的结果是重复的十进制(二进制)
  • 如果重复,重复从哪个数字(表示为2的幂)开始
  • 什么数字重复
  • 一些例子:

    1/2 = 1/10 = 0.1 // 1 = false, 2 = N/A, 3 = N/A, 4 = N/A
    1/3 = 1/11 = 0.010101... // 1 = true, 2 = -2, 3 = 10
    2/3 = 10/11 = 0.101010... // 1 = true, 2 = -1, 3 = 10
    4/3 = 100/11 = 1.010101... // 1 = true, 2 = 0, 3 = 10
    1/5 = 1/101 = 0.001100110011... // 1 = true, 2 = -3, 3 = 1100
    
    有办法做到这一点吗?效率是一个大问题。对算法的描述比代码更可取,但我会接受我能得到的答案

    同样值得注意的是,基地不是什么大问题;我可以将算法转换为二进制(或者,如果它是以256为基数使用
    char
    s,我就可以使用它)。我这样说是因为如果你在解释的话,你可能更容易用10进制来解释:)

  • 如果除数不是2的幂(通常,包含不与表示基共享的素因子)
  • 重复周期长度将由股息的最大素因子驱动(但与该因子表示的长度无关——见十进制中的1/7),但第一个周期长度可能与重复单位不同(例如,11/28=1/4+1/7十进制)
  • 实际循环将取决于分子

  • 请查看,特别是关于分数的周期。

    我可以给出一个提示-以10为底的重复小数都是分母至少有一个素数因子而不是2和5的分数。如果分母不包含质数因子2或5,则它们总是可以用所有9的分母表示。然后提名人是重复部分,9的数量是重复部分的长度

    3     _
    - = 0.3
    9
    
    1   142857     ______
    - = ------ = 0.142857
    7   999999
    
    如果分母中有两个或五个素因子,则重复部分不从第一个位置开始

    17    17        ______
    -- = ----- = 0.4857142
    35   5 * 7
    
    但我记不起如何推导非重复部分及其长度

    这似乎很好地解释了基数2。只有分母幂为二的分数是不重复的。这可以通过断言分母中只设置了一个位来轻松检查

    1/2 =   1/10   = 0.1
    1/4 =   1/100  = 0.01
    3/4 =  11/100  = 0.11
    5/8 = 101/1000 = 0.101
    
    所有分母为奇数的分数都应重复,且模式及其长度可通过以
    2^n-1
    的形式表示分母分数获得

                                                         __
     1/3            =  1/(2^2-1) =        1/11       = 0.01
                                                         __
     2/3            =  2/(2^2-1) =       10/11       = 0.10
                           __
     4/3  => 1 + 1/3 =>  1.01
                           __
    10/3  => 3 + 1/3 => 11.01
                                                         ____
     1/5  =   3/15  =  3/(2^4-1) =       11/1111     = 0.0011
                                                         ________
    11/17 = 165/255 = 11/(2^8-1) = 10100101/11111111 = 0.10100101
    

    至于基数10,我不知道如何处理包含但不是2的幂的分母-例如12=
    3*2^2

    首先,你的一个例子是错误的。
    1/5
    的重复部分是
    0011
    而不是
    1100
    ,它从小数部分的最开头开始

    重复小数类似于:

    a/b=c+d(2-n+2-n-k+2-n-2k+…)
    =c+2-n*d/(1-2-k)

    其中
    n
    d
    是您想要的

    比如说,

    1/10(dec)=1/1010(bin)=0.000110011…//1=true,2=-1,3=0011

    可以用以下公式表示:

    a=1,b=10(dec),c=0,d=0.0011(bin),n=1,k=4
    (1-2-k)=0.1111


    因此,
    1/10=0.1*0.0011/0.1111
    。重复十进制表示法的关键部分通过除以
    (2n-1)
    或其2的任意倍数生成。所以你可以找到一种方法来表达你的分母(比如建立常数表),或者做一个大的数字除法(这是相对缓慢的),然后找到循环。没有快速的方法可以做到这一点。

    要找到重复模式,只需跟踪您使用的值:

    1/5 = 1/101:
    
    1 < 101 => 0
    (decimal separator here)
    10 < 101 => 0
    100 < 101 => 0
    1000 >= 101 => 1
    
      1000 - 101 = 11
    
    110 >= 101 => 1
    
      110 - 101 = 1
    
    10 -> match
    
    编辑:
    C#中的示例:

    你可以做一个测试,注意剩下的部分。余数的结构将为您提供任何有理小数的结构:

  • 最后一个余数是零:它是一个没有任何重复部分的十进制数
  • 第一个余数和最后一个余数相等:小数点正后方重复
  • 第一个和第一个余数之间的距离等于最后一个是非重复数字,余数是重复部分
  • 一般来说,距离将为您提供每个零件的位数

    您可以在方法
    decompose()
    中看到用C++编写的算法


    228142/62265
    ,它有一个1776位数的周期

    +1谢谢你的评论。这使我对这个问题有了一些了解。特别是周期长度和实际周期由不同因素驱动的想法非常重要。我知道这对于储存循环很重要,但我不认为计算循环是很重要的。但是,我仍然不知道如何计算这些信息。您还使用了哪些条件来获得结果?为什么重复的数字不是“01”、“01”、“10”和“0011”?@Guffa我的推理是把1放在第一位,因为前导零不是[有效][1],而尾随零是。如果数字类似于“111.010101…”,那么重复的数字将是“01”,因为在这种情况下,前0是重要的。[1] :@Guffa(继续)这对我来说并不重要。如果您告诉我如何以返回“01”、“01”、“01”和“0011”的方式执行此操作,我将很高兴。:)听起来像;-)+根据这个逻辑,在基数2中,重复小数是分母的素数因子不是2的分数(我知道这一点)。我不知道如果他们有一个素因子1,它是从第一个位置以外的地方开始的(这是有用的信息!)。我不确定这是否解决了他的问题,因为有些分数在一定数量的数字之后重复,例如5/6=.8333333。因此,在您的模型下,它将使用8来查找重复。@letseatunch:5/6=101/110=0.11010101010。。。如果运行FindPattern(5,6),它会发现模式从数字-2开始重复,长度为2。我花了一点时间才理解您的代码,因为我对C不太了解,但我认为这是e
    "0011" from the second bit
    "0110" from the third bit
    "1100" from the fourth bit
    
    void FindPattern(int n1, int n2) {
       int digit = -1;
       while (n1 >= n2) {
          n2 <<= 1;
          digit++;
       }
       Dictionary<int, int> states = new Dictionary<int, int>();
       bool found = false;
       while (n1 > 0 || digit >= 0) {
          if (digit == -1) Console.Write('.');
          n1 <<= 1;
          if (states.ContainsKey(n1)) {
             Console.WriteLine(digit >= 0 ? new String('0', digit + 1) : String.Empty);
             Console.WriteLine("Repeat from digit {0} length {1}.", states[n1], states[n1] - digit);
             found = true;
             break;
          }
          states.Add(n1, digit);
          if (n1 < n2) {
             Console.Write('0');
          } else {
             Console.Write('1');
             n1 -= n2;
          }
          digit--;
       }
       if (!found) {
          Console.WriteLine();
          Console.WriteLine("No repeat.");
       }
    }
    
    .1
    No repeat.
    .01
    Repeat from digit -1 length 2.
    .10
    Repeat from digit -1 length 2.
    1.0
    Repeat from digit 0 length 2.
    .0011
    Repeat from digit -1 length 4.