Perl,137个字符
($x,$y)=<>;while($x=~s/.. *//s){$e=hex$&;$i=0;$s=$r[$i]+=$e*hex,$r[$i]&=255,$r[++$i]+=$s>>8 for$y=~/.. */gs;$y="00$y"}printf'%02x 'x@r,@r
注意事项
- 有时
00
在结果末尾打印一个额外的字节。当然,即使有该额外的字节,结果仍然是正确的。
- 在结果的最后一个十六进制字节之后打印一个额外的空格。
说明
解释会有点长,但是我想这里的大多数人都会觉得很有趣。
首先,当我10岁时,我被教导以下小技巧。您可以将任意两个正数相乘。我将以13×47为例进行描述。首先写入第一个数字13,然后将其除以2(每次向下舍入),直到达到1:
13
6
3
1
现在,在13旁边,写下另一个数字47,并将其乘以 2相同的次数:
13 47
6 94
3 188
1 376
现在,您将左边的数字为偶数的所有线都划掉了。在这种情况下,这仅是6。(我无法在代码中删除线,因此我将其删除。)最后,在右侧添加所有剩余的数字:
13 47
3 188
1 376
----
611
这是正确的答案。13×47 = 611。
现在,由于您都是计算机极客,因此您已经意识到我们实际上在左右两列中分别执行的是x >> 1
和y << 1
。此外,我们添加y
唯一的if x & 1 == 1
。这直接转换为算法,我将在此处以伪代码编写该算法:
input x, y
result = 0
while x > 0:
if x & 1 == 1:
result = result + y
x = x >> 1
y = y << 1
print result
我们可以重写if
以使用乘法,然后我们可以轻松地更改它,以使其在逐字节而不是逐位的基础上工作:
input x, y
result = 0
while x > 0:
result = result + (y * (x & 255))
x = x >> 8
y = y << 8
print result
它仍然包含与的乘法y
,后者是任意大小的,因此我们也需要将其更改为循环。我们将在Perl中做到这一点。
现在将所有内容翻译为Perl:
$x
并且$y
是十六进制格式的输入,因此它们的最低有效字节在前。
因此,代替x >> 8
我做$x =~ s/.. *//s
。我需要空格+星号,因为最后一个字节上可能没有空格(也可以使用空格+ ?
)。这会自动将删除的字节(x & 255
)放入$&
。
y << 8
很简单$y = "00$y"
。
在result
实际上是一个数值数组,@r
。最后,的每个元素都@r
包含一个字节的答案,但是在计算的一半,它可能包含一个以上的字节。下面我将向您证明,每个值永远都不会超过两个字节(16位),并且结果始终是一个字节。
因此,这里是Perl代码的摘要和注释:
# Input x and y
($x, $y) = <>;
# Do the equivalent of $& = x & 255, x = x >> 8
while ($x =~ s/.. *//s)
{
# Let e = x & 255
$e = hex $&;
# For every byte in y... (notice this sets $_ to each byte)
$i = 0;
for ($y =~ /.. */gs)
{
# Do the multiplication of two single-byte values.
$s = $r[$i] += $e*hex,
# Truncate the value in $r[$i] to one byte. The rest of it is still in $s
$r[$i] &= 255,
# Move to the next array item and add the carry there.
$r[++$i] += $s >> 8
}
# Do the equivalent of y = y << 8
$y = "00$y"
}
# Output the result in hex format.
printf '%02x ' x @r, @r
现在为了证明它始终输出bytes,并且计算永远不会产生大于两个字节的值。我将通过while
循环归纳来证明这一点:
这结束了一个奇妙而令人兴奋的挑战。非常感谢您发布!