FizzBuzz Ruby 一行
FizzBuzz Ruby one-liner
Rosettacode.org 在 Ruby 中有这个出色的单行 FizzBuzz 解决方案。
1.upto(100){|n|puts'FizzBuzz '[i=n**4%-15,i+13]||n}
麻烦的是,我不明白。令我困惑的部分是“n 的 4 模 -15 次方”。有没有人有解释或参考解释?我想在其他问题中使用这种选择子串的方式。
有关 FizzBuzz 的更多信息,请参阅 [https://rosettacode.org/wiki/FizzBuzz]
相当棘手。
模数是一个周期函数。
您可以获得具有相同模式的更多周期函数,更改指数 (k) 和除数 (h):
y = x**k % h
或者只查看案例的 x,y 对:
h = 4 # exponent
k = -15 # divisor
xy = []
1.upto 100 do |n|
i= n**h % k
xy << [n, i]
end
p xy
选择y = x % 2
的基本示例:k = 1
和h = 2
,周期性很明显。
你得到一系列 1, 0, 1, 0, 1, ...
为了可视化本例中使用的函数,您可以在 ruby 中绘图,例如使用 gnuplot gem。
require 'gnuplot'
Gnuplot.open do |gp|
Gnuplot::Plot.new( gp ) do |plot|
plot.title "Periodic function for FizzBuzz"
x = (0..100).collect { |v| v }
p y = x.collect { |v| v ** 4 % -15 }
plot.data << Gnuplot::DataSet.new( [x, y] ) do |ds|
ds.with = "linespoints"
end
end
end
我不知道他们是如何发现提升到四次方的,但是 -15 是因为 FizzBuzz 处理 3 的倍数或 5 的倍数或 3 和 5 的倍数(即 15 的倍数) ...然后否定它最终会很好地处理负指数。我们可以看到它适用于 Modular Exponentiation。 内存高效方法 部分说:
c mod m = (a ⋅ b) mod m
c mod m = [(a mod m) ⋅ (b mod m)] mod m
在我们的例子中,c 是我们的 n,所以我们有
c ** 4 % m
使用law of exponents,我们知道(c ** e1) * (c ** e2) = c ** (e1 + e2)
,所以c ** 4 = (c ** 2) * (c ** 2)
,所以我们现在有一个a
和一个b
,它们都是c ** 2
。因此:
(c ** 4) % m = ((c ** 2) * (c ** 2)) % m
= (((c ** 2) % m) * ((c ** 2) % m)) % m
= (((c ** 2) % m) ** 2) % m
并再次执行相同的步骤:
(c ** 2) % m = (c * c) % m
= ((c % m) * (c % m)) % m
= ((c % m) ** 2) % m
最后:
(c ** 4) % m = ((((c % m) ** 2) % m) ** 2) % m
当m = -15
时,c % m
的唯一值是(-14..0)
,我们可以构建一个简单的table来查看。因为我们只对模的结果进行运算,所以我们只需要能够证明这 15 个数字有效:
c%m **2 %m **2 %m
-14 => 196 => -14 => 196 => -14
-13 => 169 => -11 => 121 => -14
-12 => 144 => -06 => 36 => -09
-11 => 121 => -14 => 196 => -14
-10 => 100 => -05 => 25 => -05
-09 => 81 => -09 => 81 => -09
-08 => 64 => -11 => 121 => -14
-07 => 49 => -11 => 121 => -14
-06 => 36 => -09 => 81 => -09
-05 => 25 => -05 => 25 => -05
-04 => 16 => -14 => 196 => -14
-03 => 9 => -06 => 36 => -09
-02 => 4 => -11 => 121 => -14
-01 => 1 => -14 => 196 => -14
00 => 0 => 00 => 0 => 00
现在,看看我们的 table,所有 3 的倍数的值都是 -09
,所有 5 的倍数的值都是 -05
,并且是3和5设置为00
;其他一切都是 -14
(如果我们使用 15 而不是 -15,我们将分别有 6、10、0 和 1,并且需要查找以将其转换为字符串索引)。用字符串 'FizzBuzz '
将 String#[]
的起始参数插入,我们得到:
'FizzBuzz '[-9] # => 'F'
'FizzBuzz '[-5] # => 'B'
'FizzBuzz '[0] # => 'F'
'FizzBuzz '[-14]# => nil
然后将这些数字加 13 得到长度:
'FizzBuzz '[-9, 4] # => "Fizz"
'FizzBuzz '[-5, 8] # => "Buzz "
'FizzBuzz '[0, 13] # => "FizzBuzz "
'FizzBuzz '[-14, -1] # => nil
我将尝试为@Simple Lime 的出色回答添加一个更简单的解释。
如果n
是3的倍数,我们记为3k
,现在:
(3k)^4 == 81(k^4)
81 % 15 == 6
让我们减去 15(因为它是模 -15)得到 -9。
同样,当 n
是 5 的倍数时,它是 625(k^4)
和 625 % 15 == 10
,减去后我们得到 -5。
否则,n 可能是 2、7、11 和 13 的倍数。在所有这些情况下,n^4 % 15 将是 1(参见 Simple Lime 的 table),-15 将得到我们-14。
Rosettacode.org 在 Ruby 中有这个出色的单行 FizzBuzz 解决方案。
1.upto(100){|n|puts'FizzBuzz '[i=n**4%-15,i+13]||n}
麻烦的是,我不明白。令我困惑的部分是“n 的 4 模 -15 次方”。有没有人有解释或参考解释?我想在其他问题中使用这种选择子串的方式。 有关 FizzBuzz 的更多信息,请参阅 [https://rosettacode.org/wiki/FizzBuzz]
相当棘手。
模数是一个周期函数。 您可以获得具有相同模式的更多周期函数,更改指数 (k) 和除数 (h):
y = x**k % h
或者只查看案例的 x,y 对:
h = 4 # exponent
k = -15 # divisor
xy = []
1.upto 100 do |n|
i= n**h % k
xy << [n, i]
end
p xy
选择y = x % 2
的基本示例:k = 1
和h = 2
,周期性很明显。
你得到一系列 1, 0, 1, 0, 1, ...
为了可视化本例中使用的函数,您可以在 ruby 中绘图,例如使用 gnuplot gem。
require 'gnuplot'
Gnuplot.open do |gp|
Gnuplot::Plot.new( gp ) do |plot|
plot.title "Periodic function for FizzBuzz"
x = (0..100).collect { |v| v }
p y = x.collect { |v| v ** 4 % -15 }
plot.data << Gnuplot::DataSet.new( [x, y] ) do |ds|
ds.with = "linespoints"
end
end
end
我不知道他们是如何发现提升到四次方的,但是 -15 是因为 FizzBuzz 处理 3 的倍数或 5 的倍数或 3 和 5 的倍数(即 15 的倍数) ...然后否定它最终会很好地处理负指数。我们可以看到它适用于 Modular Exponentiation。 内存高效方法 部分说:
c mod m = (a ⋅ b) mod m
c mod m = [(a mod m) ⋅ (b mod m)] mod m
在我们的例子中,c 是我们的 n,所以我们有
c ** 4 % m
使用law of exponents,我们知道(c ** e1) * (c ** e2) = c ** (e1 + e2)
,所以c ** 4 = (c ** 2) * (c ** 2)
,所以我们现在有一个a
和一个b
,它们都是c ** 2
。因此:
(c ** 4) % m = ((c ** 2) * (c ** 2)) % m
= (((c ** 2) % m) * ((c ** 2) % m)) % m
= (((c ** 2) % m) ** 2) % m
并再次执行相同的步骤:
(c ** 2) % m = (c * c) % m
= ((c % m) * (c % m)) % m
= ((c % m) ** 2) % m
最后:
(c ** 4) % m = ((((c % m) ** 2) % m) ** 2) % m
当m = -15
时,c % m
的唯一值是(-14..0)
,我们可以构建一个简单的table来查看。因为我们只对模的结果进行运算,所以我们只需要能够证明这 15 个数字有效:
c%m **2 %m **2 %m
-14 => 196 => -14 => 196 => -14
-13 => 169 => -11 => 121 => -14
-12 => 144 => -06 => 36 => -09
-11 => 121 => -14 => 196 => -14
-10 => 100 => -05 => 25 => -05
-09 => 81 => -09 => 81 => -09
-08 => 64 => -11 => 121 => -14
-07 => 49 => -11 => 121 => -14
-06 => 36 => -09 => 81 => -09
-05 => 25 => -05 => 25 => -05
-04 => 16 => -14 => 196 => -14
-03 => 9 => -06 => 36 => -09
-02 => 4 => -11 => 121 => -14
-01 => 1 => -14 => 196 => -14
00 => 0 => 00 => 0 => 00
现在,看看我们的 table,所有 3 的倍数的值都是 -09
,所有 5 的倍数的值都是 -05
,并且是3和5设置为00
;其他一切都是 -14
(如果我们使用 15 而不是 -15,我们将分别有 6、10、0 和 1,并且需要查找以将其转换为字符串索引)。用字符串 'FizzBuzz '
将 String#[]
的起始参数插入,我们得到:
'FizzBuzz '[-9] # => 'F'
'FizzBuzz '[-5] # => 'B'
'FizzBuzz '[0] # => 'F'
'FizzBuzz '[-14]# => nil
然后将这些数字加 13 得到长度:
'FizzBuzz '[-9, 4] # => "Fizz"
'FizzBuzz '[-5, 8] # => "Buzz "
'FizzBuzz '[0, 13] # => "FizzBuzz "
'FizzBuzz '[-14, -1] # => nil
我将尝试为@Simple Lime 的出色回答添加一个更简单的解释。
如果n
是3的倍数,我们记为3k
,现在:
(3k)^4 == 81(k^4)
81 % 15 == 6
让我们减去 15(因为它是模 -15)得到 -9。
同样,当 n
是 5 的倍数时,它是 625(k^4)
和 625 % 15 == 10
,减去后我们得到 -5。
否则,n 可能是 2、7、11 和 13 的倍数。在所有这些情况下,n^4 % 15 将是 1(参见 Simple Lime 的 table),-15 将得到我们-14。