小数点表示的期间


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),所以我们正在寻找最小的正整数,以使所有足够大的i:10^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 + 2值10^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.