我怎样才能像 C 一样在 perl 中使用方括号?
How can I use square brackets in perl like C?
昨天 Computerphile 上传了一个关于 code golf 和 bitshift 变体的视频,我对这个生成音乐的程序非常着迷。
这是我对视频中 code 的格式化版本。
int g(int sample, int x, int t, int overdrive) {
return (
(
3 & x & (
sample *
(
(
3 & sample >> 16
?
"BY}6YB6%"
:
"Qj}6jQ6%"
)[t % 8]
+
51
) >> overdrive
)
) << 4
);
}
int main(int n, int s) {
for (int sample=0 ;; sample++)
putchar(
g(sample, 1, n=sample >> 14, 12)
+
g(sample, s=sample >> 17, n^sample >> 13, 10)
+
g(sample, s/3, n + ((sample >> 11) % 3), 10)
+
g(sample, s/5, 8 + n-((sample >> 10) % 3), 9)
);
}
我想尝试将程序转换为 纯 perl,这是我的尝试。
sub g {
return (
(
3 & $_[1] & (
$_[0] *
(
(
3 & $_[0] >> 16
?
"BY}6YB6%"
:
"Qj}6jQ6%"
)[$_[2] % 8]
+
51
) >> $_[3]
)
) << 4
);
}
for($i=0;;$i++){
print pack('C',
g($i, 1, $n=$i >> 14, 12)
+
g($i, $s=$i >> 17, $n^$i >> 13, 10)
+
g($i, $s/3, $n + (($i >> 11) % 3), 10)
+
g($i, $s/5, 8 + $n-(($i >> 10) % 3), 9)
);
}
根据 putchar 手册,该值在写入时会在内部转换为 unsigned char
。所以我在 perl 中使用 pack 函数和 C
模板,它是一个无符号字符。但是,当我将两个程序的结果通过管道传输到 aplay
时,它们不会产生相同的音乐。
如果我使用内联 C 并从 perl 调用函数 g
它确实可以正常工作。
use Inline C => <<'END_C';
int g(int sample, int x, int t, int overdrive) {
return (
(
3 & x & (
sample *
(
(
3 & sample >> 16
?
"BY}6YB6%"
:
"Qj}6jQ6%"
)[t % 8]
+
51
) >> overdrive
)
) << 4
);
}
END_C
for($i=0;;$i++){
print pack('C',
g($i, 1, $n=$i >> 14, 12)
+
g($i, $s=$i >> 17, $n^$i >> 13, 10)
+
g($i, $s/3, $n + (($i >> 11) % 3), 10)
+
g($i, $s/5, 8 + $n-(($i >> 10) % 3), 9)
);
}
我唯一的解释是 [$_[2] % 8]
没有按照我认为的 perl 进行操作。
如何让程序在 perl 和 C 中产生相同的音乐?在 windows 上,如果安装了 sox,则可以使用 perl theprogram.pl | sox -c 1 -b 8 -e unsigned -t raw -r 8k - -t waveaudio 0
。
字符串不是 perl 中的数组,您需要用调用 substr() 函数来替换数组访问:
...
ord(substr((
3 & $_[0] >> 16
?
"BY}6YB6%"
:
"Qj}6jQ6%"
), $_[2] % 8, 1))
...
效率更高:
# Outside the sub.
my $a1 = [ unpack 'C*', "BY}6YB6%" ];
my $a2 = [ unpack 'C*', "Qj}6jQ6%" ];
...
${ 3 & $_[0] >> 16 ? $a1 : $a2 }[ $_[2] % 8 ]
...
昨天 Computerphile 上传了一个关于 code golf 和 bitshift 变体的视频,我对这个生成音乐的程序非常着迷。 这是我对视频中 code 的格式化版本。
int g(int sample, int x, int t, int overdrive) {
return (
(
3 & x & (
sample *
(
(
3 & sample >> 16
?
"BY}6YB6%"
:
"Qj}6jQ6%"
)[t % 8]
+
51
) >> overdrive
)
) << 4
);
}
int main(int n, int s) {
for (int sample=0 ;; sample++)
putchar(
g(sample, 1, n=sample >> 14, 12)
+
g(sample, s=sample >> 17, n^sample >> 13, 10)
+
g(sample, s/3, n + ((sample >> 11) % 3), 10)
+
g(sample, s/5, 8 + n-((sample >> 10) % 3), 9)
);
}
我想尝试将程序转换为 纯 perl,这是我的尝试。
sub g {
return (
(
3 & $_[1] & (
$_[0] *
(
(
3 & $_[0] >> 16
?
"BY}6YB6%"
:
"Qj}6jQ6%"
)[$_[2] % 8]
+
51
) >> $_[3]
)
) << 4
);
}
for($i=0;;$i++){
print pack('C',
g($i, 1, $n=$i >> 14, 12)
+
g($i, $s=$i >> 17, $n^$i >> 13, 10)
+
g($i, $s/3, $n + (($i >> 11) % 3), 10)
+
g($i, $s/5, 8 + $n-(($i >> 10) % 3), 9)
);
}
根据 putchar 手册,该值在写入时会在内部转换为 unsigned char
。所以我在 perl 中使用 pack 函数和 C
模板,它是一个无符号字符。但是,当我将两个程序的结果通过管道传输到 aplay
时,它们不会产生相同的音乐。
如果我使用内联 C 并从 perl 调用函数 g
它确实可以正常工作。
use Inline C => <<'END_C';
int g(int sample, int x, int t, int overdrive) {
return (
(
3 & x & (
sample *
(
(
3 & sample >> 16
?
"BY}6YB6%"
:
"Qj}6jQ6%"
)[t % 8]
+
51
) >> overdrive
)
) << 4
);
}
END_C
for($i=0;;$i++){
print pack('C',
g($i, 1, $n=$i >> 14, 12)
+
g($i, $s=$i >> 17, $n^$i >> 13, 10)
+
g($i, $s/3, $n + (($i >> 11) % 3), 10)
+
g($i, $s/5, 8 + $n-(($i >> 10) % 3), 9)
);
}
我唯一的解释是 [$_[2] % 8]
没有按照我认为的 perl 进行操作。
如何让程序在 perl 和 C 中产生相同的音乐?在 windows 上,如果安装了 sox,则可以使用 perl theprogram.pl | sox -c 1 -b 8 -e unsigned -t raw -r 8k - -t waveaudio 0
。
字符串不是 perl 中的数组,您需要用调用 substr() 函数来替换数组访问:
...
ord(substr((
3 & $_[0] >> 16
?
"BY}6YB6%"
:
"Qj}6jQ6%"
), $_[2] % 8, 1))
...
效率更高:
# Outside the sub.
my $a1 = [ unpack 'C*', "BY}6YB6%" ];
my $a2 = [ unpack 'C*', "Qj}6jQ6%" ];
...
${ 3 & $_[0] >> 16 ? $a1 : $a2 }[ $_[2] % 8 ]
...