计算欧拉的上位函数


27

背景

欧拉欧拉 函数φ(n)较少定义为整数的数目大于或等于n互质到n,即,可能的值的数目x0 < x <= n为其 gcd(n, x) == 1。我们有 一个 欧拉 - 相关 的挑战 面前,但从来没有一个这只是计算它。

上位函数到整数的映射是OEIS A000010

挑战

给定一个整数n > 0,计算φ(n)。您可以通过命令行参数,标准输入,函数参数或其他任何合理的方式接受输入。您可以通过标准输出,返回值或其他任何合理的方式给出输出。可接受匿名函数。您可能会假设输入不会溢出存储整数的自然方法,例如int在C中,但是您必须支持最多255个输入。 如果您的语言具有内置的totient函数,则可能无法使用它。

例子

φ(1) => 1
φ(2) => 1
φ(3) => 2
φ(8) => 4
φ(9) => 6
φ(26) => 12
φ(44) => 20
φ(105) => 48

以字节为单位的最短答案将获胜。如果您的语言使用的编码不是UTF-8,请在答案中提及。


4
嗯,前几天有这个。我认为重复的应用程序不会产生足够的影响,但是如果有什么事情我会关闭另一个,因为我也不认为重复的应用程序会增加任何东西。也就是说,最大的不同是一个允许内置,而另一个不允许。
Martin Ender

禁止内置命令显然对答案没有影响。
Julie Pelletier

2
@JuliePelletier为什么?否则,我的Mathematica回答将缩短19个字节:EulerPhi
马丁·恩德

允许使用@JuliePelletier GCD,因为计算GCD并非要解决的预期问题。当然,这可能会增加这些答案的字节数,但并不能使挑战更好。我将进行澄清。
bkul

Answers:


13

Mathematica,27个 22字节

Range@#~GCD~#~Count~1&

接受并返回整数的未命名函数。

除了@用于函数调用的前缀表示法和~...~(左关联的)中缀表示法之外,这里没有太多要解释的内容,因此上述内容与以下内容相同:

Count[GCD[Range[#], #], 1] &

11

MATL,7个字节

t:Zd1=s

您可以使用TryItOnline。最简单的想法是将向量设为1到N,然后将每个元素的gcd取为N(Zd执行gcd)。然后,找出哪些元素等于1,并对向量求和以获得答案。


内置函数_Zp供那些想知道的人使用。
大卫(David

11

J,9个字节

(-~:)&.q:

这是基于Jsoftware关于Totient 函数的文章

给定n = p 1 e 1p 2 e 2 ∙∙∙ p k e k,其中p kn的素,则张力函数φ(n)=φ(p 1 e 1)∙φ(p 2 e 2)∙∙∙φ(p ķ Ë ķ)=(p 1 - 1)p 1 ë 1 - 1 ∙(p 2 - 1)p 2ë 2 - 1 ∙∙∙( p ķ - 1) p ķ ë ķ - 1

用法

   f =: (-~:)&.q:
   (,.f"0) 1 2 3 8 9 26 44 105
  1  1
  2  1
  3  2
  8  4
  9  6
 26 12
 44 20
105 48
   f 12345
6576

说明

(-~:)&.q:  Input: integer n
       q:  Prime decomposition. Get the prime factors whose product is n
(   )&     Operate on them
  ~:         Nub-sieve. Create a mask where 1 is the first occurrence
             of a unique value and 0 elsewhere
 -           Subtract elementwise between the prime factors and the mask
     &.q:  Perform the inverse of prime decomposition (Product of the values)

利用totient是可乘的这一事实,使用递归在J中提出另一个解决方案:)
Leaky Nun

@LeakyNun我认为没有简单的方法可以进行分解,因为即使使用迭代形式也[:*/@({.(^-(^<:)){:)2&p:需要24个字节,即使使用内置函数来获取素数和指数也是如此。也许有更短的方法,但我看不到。
英里

8

果冻,4个字节

Rgċ1

在线尝试!

说明

Rgċ1   Main monadic chain. Argument: z

R      Yield [1 2 3 .. z].
 g     gcd (of each) (with z).
  ċ1   Count the number of occurrences of 1.

内置

ÆṪ

在线尝试!

说明

ÆṪ   Main monadic chain. Argument: z

ÆṪ   Totient of z.

8

Haskell,28个字节

f n=sum[1|1<-gcd n<$>[1..n]]

使用Haskell的常数模式匹配。这里的技巧是打高尔夫球的相当标准,但我将向广大观众解释。

该表达式gcd n<$>[1..n]映射gcd n[1..n]。换句话说,它计算从到的每个数字的gcdwith :n1n

[gcd n i|i<-[1..n]]

从这里开始,所需的输出是1条目数,但是Haskell缺少count功能。filter保留1'并获取结果的惯用方式length,这对于打高尔夫球来说太长了。

而是filter使用列表推导式[1|1<-l]和结果list 来模拟l。通常,列表推导将值绑定到变量中[x*x|x<-l],例如in ,但是Haskell允许匹配模式,在这种情况下为constant 1

因此,在的每个匹配项上[1|1<-l]生成一个,可以有效地仅提取原始列表的。调用它可以得到它的长度。111sum


我认为这是我真正理解的第一个Haskell答案。这是一种很酷的语言,但与大多数其他语言有很大不同
bkul

哇,我希望模式匹配在理解列表中必须详尽无遗。谢谢你的把戏。
达米安

8

Python 2,44字节

f=lambda n,d=1:d/n or-f(d)*(n%d<1)-~f(n,d+1)

少打高尔夫球:

f=lambda n:n-sum(f(d)for d in range(1,n)if n%d<1)

使用除数的Euler端点的n总和为的公式n

在此处输入图片说明

ϕ(n)然后可以递减计算出的值n减去非平凡除数之和。实际上,这是对身份函数进行莫比乌斯反演。我在高尔夫球中使用了相同的方法来计算Möbius函数

感谢Dennis使用更好的基本情况节省了1个字节,+n+1为每个n循环扩展了in的初始值,方法如下-~



6

正则表达式(ECMAScript),131字节

至少有-12个字节归功于Deadcode(在聊天中)

(?=((xx+)(?=\2+$)|x+)+)(?=((x*?)(?=\1*$)(?=(\4xx+?)(\5*(?!(xx+)\7+$)\5)?$)(?=((x*)(?=\5\9*$)x)(\8*)$)x*(?=(?=\5$)\1|\5\10)x)+)\10|x

在线尝试!

输出是匹配的长度。

ECMAScript正则表达式使计数非常困难。在循环外定义的任何backref在循环期间将保持不变,在循环内定义的任何backref在循环时将被重置。因此,跨循环迭代传递状态的唯一方法是使用当前匹配位置。那是一个整数,只能减少(嗯,位置增加了,但是尾巴的长度减少了,这就是我们可以做的数学运算)。

鉴于这些限制,简单地计算互质数似乎是不可能的。取而代之的是,我们使用欧拉公式来计算上装量。

这是伪代码中的样子:

N = input
Z = largest prime factor of N
P = 0

do:
   P = smallest number > P that’s a prime factor of N
   N = N - (N / P)
while P != Z

return N

关于此有两点可疑之处。

首先,我们不保存输入,仅保存当前产品,那么我们如何获取输入的主要因素呢?诀窍在于(N-(N / P))具有与N相同的素数>P。它可能会获得<P的新素数,但是无论如何我们都忽略了这些。请注意,这仅是有效的,因为我们从最小到最大迭代素数,否则将失败。

其次,我们必须记住循环迭代中的两个数字(P和N,因为它是常数,所以Z不计数),我只是说那是不可能的!幸运的是,我们可以将这两个数字合并为一个。请注意,在循环开始时,N始终是Z的倍数,而P始终小于Z。因此,我们只记得N + P,然后以模取P。

这是稍微更详细的伪代码:

N = input
Z = largest prime factor of N

do:
   P = N % Z
   N = N - P
   P = smallest number > P that’s a prime factor of N
   N = N - (N / P) + P
while P != Z

return N - Z

这是评论的正则表达式:

# \1 = largest prime factor of N
# Computed by repeatedly dividing N by its smallest factor
(?= ( (xx+) (?=\2+$) | x+ )+ )

(?=
        # Main loop!
        (
                # \4 = N % \1, N -= \4
                (x*?) (?=\1*$)

                # \5 = next prime factor of N
                (?= (\4xx+?) (\5* (?!(xx+)\7+$) \5)? $ )

                # \8 = N / \5, \9 = \8 - 1, \10 = N - \8
                (?= ((x*) (?=\5\9*$) x) (\8*) $ )

                x*
                (?=
                        # if \5 = \1, break.
                        (?=\5$) \1
                |
                        # else, N = (\5 - 1) + (N - B)
                        \5\10
                )
                x
        )+
) \10

而且作为奖励...

正则表达式(ECMAScript 2018,匹配数),23字节

x(?<!^\1*(?=\1*$)(x+x))

在线尝试!

输出为匹配数。ECMAScript 2018引入了变长后向查找(从右到左评估),这使得可以简单地计算与输入互质数的所有数字。

事实证明,这是Leaky Nun的Retina解决方案所使用的独立方法,而regex的长度甚至相同(并且可以互换)。我将其留在此处,是因为这种方法可以在ECMAScript 2018(而不仅仅是.NET)中工作可能会引起人们的兴趣。

                        # Implicitly iterate from the input to 0
x                       # Don’t match 0
 (?<!                 ) # Match iff there is no...
                 (x+x)  # integer >= 2...
         (?=\1*$)       # that divides the current number...
     ^\1*               # and also divides the input

5

J,11个字节

+/@(1=+.)i.

用法

>> f =: +/@(1=+.)i.
>> f 44
<< 20

>>STDIN和<<STDOUT 在哪里。

说明

+/ @ ( 1 = +. ) i.
               │
   ┌───────────┴┐
 +/@(1=+.)      i.
   │
 ┌─┼──┐
+/ @ 1=+.
    ┌─┼─┐
    1 = +.

>> (i.) 44            NB. generate range
<< 0 1 2 3 4 ... 43
>> (+.i.) 44          NB. calculate gcd of each with input
<< 44 1 2 1 4 ... 1
>> ((1=+.)i.) 44      NB. then test if each is one (1 if yes, 0 if no)
<< 0 1 0 1 0 ... 1
>> (+/@(1=+.)i.) 44   NB. sum of all the tests
<< 20

您是如何获得垂直树表示的?我以为它只产生水平。
英里

@miles我自己输入的。
Leaky Nun

5

Python> = 3.5,76 64 58字节

感谢LeakyNun打高尔夫球12(!)字节。

感谢Sp3000打高尔夫球6个字节。

import math
lambda n:sum(math.gcd(n,x)<2for x in range(n))

我喜欢Python的可读性。即使通过打高尔夫球,这也是有道理的。


1
lambda n:sum(gcd(n,x)<2for x in range(n))
Leaky Nun

哦,Python终于添加gcd到了数学模块中!我不知道
rubik

4

Perl 6的 26个24  22字节

{[+] (^$^n Xgcd $n) X== 1}
{+grep 2>*,(^$_ Xgcd$_)}
{[+] 2 X>(^$_ Xgcd$_)}

说明:

{
  [+] # reduce using &infix:<+>
    2
    X[>] # crossed compared using &infix:«>»
    (
      ^$_    # up to the input ( excludes input )
      X[gcd] # crossed using &infix:<gcd>
      $_     # the input
    )
}

例:

#! /usr/bin/env perl6
use v6.c;

my  = {[+] 2 X>(^$_ Xgcd$_)};

say φ(1) # 1
say φ(2) # 1
say φ(3) # 2
say φ(8) # 4
say φ(9) # 6
say φ(26) # 12
say φ(44) # 20
say φ(105) # 48

say φ 12345 # 6576


4

朱莉娅,25个字节

!n=sum(i->gcd(i,n)<2,1:n)

它很简单- sum函数使您可以给它一个求和之前要应用的函数-基本上等于running map然后then sum。这直接计算出小于的相对质数的数量n


4

Python 2,57字节

f=lambda n,k=1,m=1:n*(k>n)or f(n-(n%k<m%k)*n/k,k+1,m*k*k)

Ideone上进行测试

背景

根据欧拉的产品公式

欧拉的产品配方

其中φ表示欧拉的张力函数,而p仅在素数上变化。

为了确定素数,我们使用威尔逊定理的推论

威尔逊定理的推论

怎么运行的

在任何时候,变量m都将等于k-1的阶乘的平方。实际上,我们将参数命名为默认值k = 1m = 0!2 = 1

只要k≤n,则n*(k>n)求值为0or执行以下代码。

回想一下,如果m为质数,m%k则结果为1,否则为0。这意味着当且仅当两个k都是素数且x可被k整除时,它才会产生Truex%k<m%k

在这种情况下,(n%k<m%k)*n/k得出n / k,然后从n中减去它,就用Euler乘积公式将其先前的值替换为n(1-1 / k)。否则,(n%k<m%k)*n/k产量0n保持不变。

在计算完上述值之后,我们将k递增,并将m乘以k 2的“旧”值,从而保持km之间的期望关系,然后使用更新的参数递归调用f

一旦k超过n,则n*(k>n)求值为n,由函数返回。


4

Ruby,32个字节

->n{(1..n).count{|i|i.gcd(n)<2}}

一个接受整数n的lambda,并返回范围(1..n)与n互质的整数的计数。


您好,欢迎来到PPCG!这是一篇很棒的第一篇文章。
NoOneIsHere

欢迎来到编程难题和Code Golf!这是一个很好的第一个解决方案,请继续努力!
bkul

谢谢,不是那么短,我想知道是否有可能改进它。
Redouane Red Red

3

Brachylog,25个字节

:{:1e.$pdL,?$pd:LcCdC}fl.

说明

Brachylog还没有内置GCD,因此我们检查这两个数字是否没有共同的主要因素。

  • 主要谓词:

    :{...}fl.             Find all variables which satisfy predicate 1 when given to it as
                          output and with Input as input.
                          Unify the Output with the length of the resulting list
    
  • 谓词1:

    :1e.                  Unify Output with a number between Input and 1
        $pdL              L is the list of prime factors of Output with no duplicates
            ,
             ?$pd:LcC     C is the concatenation of the list of prime factors of Input with
                          no duplicates and of L
                     dC   C with duplicates removed is still C
    

3

Pyth,6个字节

smq1iQ

在线尝试!

/iLQQ1

在线尝试!

说明

smq1iQ     input as Q
smq1iQdQ   implicitly fill variables

 m     Q   for d in [0 1 2 3 .. Q-1]:
    iQd        gcd of Q and d
  q1           equals 1? (1 if yes, 0 if no)
s          sum of the results


/iLQQ1     input as Q

 iLQQ      gcd of each in [0 1 2 3 .. Q-1] with Q
/    1     count the number of occurrences of 1

3

PowerShell v2 +,72字节

param($n)1..$n|%{$a=$_;$b=$n;while($b){$a,$b=$b,($a%$b)};$o+=!($a-1)};$o

PowerShell没有可用的GCD功能,因此我不得不自己动手做。

这需要输入$n,然后从1到范围,$n并将其通过管道传递到循环中|%{...}。每次迭代我们设置了两个辅助变量$a$b,然后执行一个GCD while循环。我们正在检查其每次迭代$b仍然不为零,然后保存$a%$b$b和以前的值$b,以$a用于下一个循环。然后,我们在输出变量中累积是否$a等于。一旦for循环完成,我们将放置在管道上并且输出是隐式的。1$o$o

作为while循环工作原理的一个示例,请考虑$n=20并开始$_=8。第一个检查具有$b=20,因此我们进入循环。我们首先计算$a%$b8%20 = 8$b同时20将设置为$a。选中8=0,然后输入第二个迭代。然后我们计算20%8 = 4并将其设置为$b,然后设置$a8。选中4=0,然后输入第三次迭代。我们计算8%4 = 0并将其设置为$b,然后设置$a4。检查0=0并退出循环,因此GCD(8,20)$a = 4。因此,!($a-1) = !(4-1) = !(3) = 0所以$o += 0我们不算那个。


3

因子,50字节

[ dup iota swap '[ _ gcd nip 1 = ] filter length ]

生成一个范围(iotan,并将n 咖喱 成一个函数,该函数将对所有0 <= x <= n的值获取gcd xn,测试结果是否为1。根据gcd xn的结果是否为1 过滤原始范围,并取其长度


[ dup iota swap '[ _ gcd nip 1 = ] map sum ]节省6个字节(我认为-对Factor不太有经验)。
bkul

@bkul感谢您的建议!:D不幸的是,t/fFactor中的数字和(符号)之间没有任何兼容性,因此,实现的唯一方法是使用[ dup iota swap '[ _ gcd nip 1 = 1 0 ? ] map sum ],它与当前解决方案的确切长度相同。

啊 强大的输入功能再次出现。
bkul

@bkul嗯,我很感激强类型,并TYPED:实际因素代码:P


2

视网膜,36 29字节

感谢Martin Ender提供7个字节。

.+
$*
(?!(11+)\1*$(?<=^\1+)).

在线尝试!

说明

有两个阶段(命令)。

第一阶段

.+
$*

这是一个简单的正则表达式替换,将输入转换为那么多输入。

例如,5将转换为11111

第二阶段

(?!(11+)\1*$(?<=^\1+)).

此正则表达式尝试匹配满足条件的位置(与输入互质),然后返回匹配数。


除非在前瞻范围内,Lookbehind不会回溯?
Leaky Nun

环视一般不会回退。
Martin Ender

那么正则表达式如何测试每个除数?
Leaky Nun

1
那么,他们这样做,只要你不离开他们原路返回。只要引擎在环视范围内,它就会尽一切可能使环视匹配(或者在负环视情况下失败)。但是,一旦环视传递,发动机将无法原路返回到它,如果任何失败后(除非它然后也开始原路返回的东西环视,并有重新评估一切反正)。
Martin Ender


2

Common Lisp,58个字节

(defun o(x)(loop for i from 1 to x if (=(gcd x i)1)sum 1))

这是一个简单的循环,它将1计数到给定的n,如果gcd = 1,则将其加和。我使用函数名称o,因为t是真正的布尔值。不是最短的,而是相当简单的。


CL是否没有某种匿名功能?

2

MATLAB /八度,21字节

@(n)sum(gcd(n,1:n)<2)

创建一个匿名函数ans,该函数可以使用整数n作为唯一输入来调用:ans(n)

在线演示




2

C(gcc)67 65字节

f(x,a,b,y,z){for(z=y=x;a=y--;z-=b>1)for(b=x;a^=b^=a^=b%=a;);x=z;}

在线尝试!

编辑:删除了临时变量。

Edit2:-1感谢@HowChen

少打高尔夫球

f(x,a,b,y,z){
  // counts y NOT coprime with x and subtract
  for(z=y=x;a=y--;z-=b>1)
    // compute GCD
    for(b=x;a^=b^=a^=b%=a;);
  x=z;
}

1

其实11个位元组

;╗R`╜g`M1@c

在线尝试!

说明

;╗R`╜g`M1@c   register stack             remarks

                       44
;                      44 44
 ╗            44       44
  R           44       [1 2 3 .. 44]
       M      44       10                for example
    ╜         44       10 44
     g        44       2
              44       [1 2 1 .. 44]     gcd of each with register
        1     44       [1 2 1 .. 44] 1
         @    44       1 [1 2 1 .. 44]
          c   44       20                count

内置

在线尝试!


您也可以选择使用;╗R`╜g1=`MΣ相同的字节数
Mego,2016年

1

JavaScript(ES6),67个字节

f=n=>[...Array(n)].reduce(r=>r+=g(n,++i)<2,i=0,g=(a,b)=>b?g(b,a%b):a)

1

APL,7个字节

+/1=⊢∨⍳

这是一个单子函数列,在右边带一个整数。这里的方法很明显:求和(+/)输入的GCD次数与从1到输入的数字(⊢∨⍳)等于1(1=)。

在这里尝试


1

Haskell,31个 30字节

\n->sum[1|x<-[1..n],gcd n x<2]

感谢@Damien,节省了1个字节。

选择gcd = 1的值,将每个值映射为1,然后求和。


您可以替换==1<2
Damien
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.