小数点表示的期间


16

编写一个函数,该函数采用单个正整数n并返回小数表示形式的周期1 / n

测试用例:

1 -> 1               # 1/1 = 1.0000...... = 1._0
2 -> 1               # 1/2 = 0.5000...... = 0.5_0
3 -> 1               # 1/3 = 0.3333...... = 0._3
7 -> 6               # 1/7 = 0.14285714.. = 0._142857
13 -> 6
14 -> 6
123 -> 5
345 -> 22
654 -> 108
12345 -> 822
67890 -> 120

这是。不允许直接返回该期间的内置或库。至少100000的号码应在合理的时间内(最多几分钟)工作。


这个问题指出“至少100000的数字应该在合理的时间内工作”,但是对于大于这个数字的程序,程序是否必须给出正确的答案?还是使用仅精确到100000的算法是可以接受的?
FireFly 2014年

1
@FireFly算法必须提供正确的答案。
霍华德

2
为什么1返回1?我会认为0?
Timtech,2014年

@Timtech1.00000000000000000000000000000000000
Cruncher

@Cruncher哦,谢谢,我明白了。
Timtech

Answers:


11

APL,19个字符/字节*

{(↑⍳⍨1∘↓)⌽⍵|10x*⍳⍵}

Nars2000。先前的版本在某些数字上是错误的,这应该是正确的。我手动检查了所有不超过50的数字。

再次感谢本·赖希Ben Reich)提出的10^i (mod x)

分解图

{                     ⍳⍵}   generate all naturals up to the argument ⍵
                 10x*       raise 10 to each of them, with unlimited precision
              ⍵|            compute the respective remainders mod ⍵
            ⌽               reverse the list
 (  ⍳⍨    )                 (fork) find the position of the first occurrence
  ↑                         of the fist element of the list
       1∘↓                  in the remainder of the list

例子

      {(↑⍳⍨1∘↓)⌽⍵|10x*⍳⍵}¨1 2 3 7 13 14 123 345 654 12345 67890
1 1 1 6 6 6 5 22 108 822 120

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
*:APL可以在它自己的(传统)被写入的单字节字符集即APL符号映射到上部128个字节值。因此,出于计分的目的,仅使用ASCII字符和APL符号的N个字符的程序可以认为是N个字节长。


我无法获得正确的答案,例如input 20。你能验证一下吗?
2014年

我遵循了您发布的示例。在您的示例中,1/2 = 0.5-> 1,所以自然地,1/20 = 0.05->2。您得到什么?
Tobia

正确答案为1,因为1/20 = 0.05_0_。
2014年

我知道了。给我一点,我将修改答案。
Tobia

4似乎也会给出错误的答案,因为10 != 100 (mod 4)
彼得·泰勒

7

高尔夫脚本(42 27)

{:x)1\[{.10*x%}*]-1%(?)}:P;

基准时间:5秒。基准测试代码:

'"The time is #{Time.now#1
}"'~ puts
[1 2 3 7 13 14 123 345 654 12345 67890 99991]{[P]p}%
'"The time is #{Time.now#2
}"'~ puts

感谢Ben Reich提供的回顾时期的核心思想10^i (mod x)

说明

该周期p定义为最小正整数,这样对于所有足够大的整数,i我们都有frac(10^i * 1/x) = frac(10^(i+p) * 1/x)。我们可以将其简化为frac(10^i / x) = frac(10^(i+p) / x)。现在,frac(a / x) = frac(b / x)iff a == b (mod x),所以我们正在寻找最小的正整数,以使所有足够大的i10^i == 10^(i+p) (mod x)

假设10^i == 10^(i+p) (mod x)。然后10^(i+1) == 10 * 10^i == 10 * 10^(i+p) == 10^(i+p+1) (mod x); 因此,一旦获得重复,我们就处于一个牢不可破的周期。

只有唯一的x(mod x),因此根据信孔原理,我们必须在的第一个x + 1值上有一个重复10^i (mod x)

因此,上面的代码所做的是计算*的x + 210^i (mod x)。然后保证最后一个重复。通过反转列表并进行搜索,我可以找到最近的一次。而且,因为我只进行一次搜索,所以这是伪线性时间。

*多余的是处理特殊情况x = 1,因为我不减少费用10^0 (mod x),所以我会寻找一个0in [1]


太棒了!由于存在更好的解决方案,因此我删除了答案!–
Ben Reich 2014年

7

Golfscript-26个字节

{:i.)+.,{;10*i%.}%i>|,}:f;

编辑:1如果小数结束,则更新为输出,而不是小数表示的长度。

一个相当有效的版本。值67890在大约10秒内运行,而99991在20秒左右运行。它比以前慢了一点(大约快了一半),因为迭代的范围已加倍,但忽略了前一半。

备用,也是26个字节

{:i.)+.n*{*i%.}%i>)^^,}:f;

这是通过遍历string来工作的"\n"*(2*i+1)i传递给函数的值在哪里。每次传递给块的值都是的序数值"\n",即10

)^^是一个变通办法。如上所述,当您从字符串中取消对字符的约束时,结果是删除的字符的序数值。但是,重新附加该值将附加该数字的字符串表示形式,而不是字符(相当不对称的行为),并且在我看来是设计缺陷。如果您确实想这样做,则首先进行字符串化只会花费一个字节。

最终值的额外副本已经在堆栈上,因此我再次删除了最终值),将其与字符串进行异或,然后再次对其进行异或,以便恢复由第一个异或添加或删除的所有字符。如果int op string被视为字符,而不是字符串表示形式,则)^^可以替换为|

请注意,虽然字符串(在Golfscript中存储为int数组)将显示每个字符mod 256的值,但是每个字符的值本身可能超出此范围。在测试唯一性(通过设置操作)或包含性(通过?)时,将比较的是实际值,而不是显示值。

当前Golfscript解释器的补丁文件:

61c61
<       to_gs
---
>       Gstring.new([self])

以上只会影响的行为string op int(反之亦然),其中op是之一
+-|&^。其他所有内容(包括的行为)均不受影响Gint`

以下24字节解决方案将变为有效:

{:i.)+.n*{*i%.}%i>|,}:f;

这也解决了许多其他非常丑陋的解决方法


Python-48个字节

f=lambda n:len(set(10**-~i%n for i in range(n)))

不是最有效的解决方案,但是对于小于100000的值是合理的。

FWIW,核心元素与我的生成十进制循环数的解决方案相同。

相同代码的更有效版本(70字节):

 def f(n):
  a=[];i=10%n
  while i not in a:a+=i,;i=i*10%n
  return len(a)

99991需要一秒钟以内。


@PeterTaylor它将or数组放在一个空字符串上。由于这是一个按操作设置的操作,因此所有重复项都将被预先删除。
原始人

但是空字符串是从哪里来的呢?如果要使该功能自成一体,我想您将不得不花费一个额外的字节并使其.|
彼得·泰勒

1
@PeterTaylor 固定
2014年

1
更改行为string int +会破坏很多程序。我不确定在该类型对上使用其他操作的频率。
彼得·泰勒

@PeterTaylor我同意,会的。但是请考虑:将int转换为char:[]+''+vs ''+。将int作为char附加到字符串:[]++vs +。将int作为字符串表示形式附加到string:+vs `+。在当前的实现中,它int''+是的同义词int`,考虑到必须强制转换为数组,然后如果需要使用ascii char强制转换为字符串的冗长性,这似乎是浪费的。
2014年

3

GolfScript,48 47 46

感谢@PeterTaylor砍掉了两个字符。

{2{1$1$%!{.@\/\d}*}:d~;5d;9{2$%}{10*9+}/+,}:f;

我尝试使用J,但是它总是给我各种各样的奇怪结果。

在线测试

这基本上是从数字中除以2和5(2和5是10的质因子,它们的倒数终止,并填充算法),然后是最小整数n,使得所得的数字除以10 ^ n-1为时期。


3
如果您知道哪个将是对函数的首次调用,则可以在其中内联定义。即代替{...}:d;...d您保存1个字符,即...{...}:d~
Peter Taylor

@PeterTaylor谢谢,没想到
波动率

1
在对Ben表示不离开f堆栈的评论后,我注意到您也在这样做。您确实应该添加一个;弹出功能,以便与其他语言进行公平比较。
彼得·泰勒

2
另一个微观优化:int array ,)\;可以缩短为int array +,
彼得·泰勒

2

Perl,52个字符

sub f{($p,%r)=1;1until$r{$p=$p*10%$_[0]}++;~~keys%r}

这是直接方法的简单实现。(幸运的是,直接方法也非常有效:由于采用了模运算,因此数学运算不必处理超过输入值10倍的数字。)

既然挑战指定了一个函数,我感到不得不(重新)初始化变量,这对于完整的程序我是不会打扰的。同样,~~如果可以确定该函数将在标量上下文中调用,则最终语句中的in也是不必要的。


尝试输入20会产生错误结果的输入。
2014年

2

Clojure, 102、117、115,106

未格式化:

(defn r([n](r{}(iterate #(mod(* % 10)n)10)0))([a[f & s]i](if(a f)(- i(a f))(recur(assoc a f i)s(inc i)))))

格式化:

(defn r
  ([n] (r {} (iterate #(mod (* % 10) n) 10) 0))
  ([a [f & s] i]
    (if (a f)
      (- i (a f))
      (recur
        (assoc a f i)
        s
        (inc i)))))

运行时间与周期成比例。在我的计算机上几乎是瞬时的样本值。

基本上,这将计算长除法的每个步骤后的减法结果。如果在任何时候该数字与之前计算出的数字相同,则检测到一个循环。


代码因输入而中断20。你能验证一下吗?
2014年

没错,以上解决方案有问题。要看看我能不能解决。
RedDeckWins 2014年

20的预期输出是多少?
RedDeckWins 2014年

正确的答案应该是1
霍华德

应该很好,第一个算法将在很多输入(例如12和20
失败。– RedDeckWins 2014年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.