Perl, 137 karakter
($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
Uyarılar
- Bazen
00sonucun sonuna fazladan bir bayt yazdırır . Tabii ki bu ekstra baytta bile sonuç hala doğrudur.
- Sonuçtaki son onaltılık bayttan sonra fazladan bir boşluk yazdırır.
açıklama
Açıklama biraz uzun olacak, ama bence buradaki insanların çoğu bunu ilginç bulacak.
Her şeyden önce, 10 yaşındayken, aşağıdaki küçük numarayı öğrettim. Bununla iki pozitif sayıyı çarpabilirsiniz. Bunu 13 × 47 örneğini kullanarak açıklayacağım. İlk sayıyı 13 yazarak ve 1'e ulaşana kadar 2'ye (her seferinde aşağı doğru) bölerek başlıyorsunuz :
13
6
3
1
Şimdi, 13'ün yanında başka bir sayı olan 47'yi yazıyorsunuz ve aynı sayıda 2 ile çarpmaya devam ediyorsunuz :
13 47
6 94
3 188
1 376
Soldaki sayısıdır Artık tüm satırları üstünü bile . Bu durumda, bu sadece 6.
13 47
3 188
1 376
----
611
Ve bu doğru cevap. 13 × 47 = 611.
Şimdi, hepiniz bilgisayar meraklıları olduğunuz için, aslında sol ve sağ sütunlarda yaptığımızın sırasıyla x >> 1ve olduğunu fark etmiş olacaksınız y << 1. Ayrıca, ysadece eğer x & 1 == 1. Bu, doğrudan sözde kodda yazacağım bir algoritmaya doğrudan çevirir:
input x, y
result = 0
while x > 0:
if x & 1 == 1:
result = result + y
x = x >> 1
y = y << 1
print result
ifBir çarpma kullanmak için yeniden yazabiliriz ve sonra bunu kolayca değiştirebiliriz, böylece bit-bit yerine bayt-bayt temelinde çalışır:
input x, y
result = 0
while x > 0:
result = result + (y * (x & 255))
x = x >> 8
y = y << 8
print result
Bu hala ykeyfi boyutta bir çarpma içerir , bu yüzden bunu da bir döngüye dönüştürmeliyiz. Bunu Perl'de yapacağız.
Şimdi her şeyi Perl'e çevirin:
$xve $ysahip oldukları, yani altıgen biçiminde girişler en önemli biti önce .
Böylece, x >> 8ben yerine $x =~ s/.. *//s. Son bayt üzerinde bir boşluk olmayabilir çünkü boşluk + yıldıza ihtiyacım var (boşluk + ?da kullanabilirsiniz ). Bu, kaldırılan baytı ( x & 255) otomatik olarak koyar $&.
y << 8basitçe $y = "00$y".
resultAslında sayısal bir dizidir @r. Sonunda, öğesinin her bir elemanı @rcevabın bir baytını içerir, ancak hesaplamanın yarısında birden fazla bayt içerebilir. Her bir değerin asla iki bayttan (16 bit) fazla olmadığını ve sonucun her zaman sonunda bir bayt olduğunu size kanıtlayacağım .
İşte Perl kodu çözülmüş ve yorumlanmıştır:
# 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
Şimdi bunun her zaman bayt verdiğini ve hesaplamanın asla iki bayttan daha büyük değerler üretmediğini kanıtlamak için . Bunu whiledöngü üzerinde indüksiyonla kanıtlayacağım :
Boş @r(hepsi bir zamanlar içinde hiçbir değerlere sahip olduğundan) başlangıç kısmında açıkça o 0xFF daha değerler büyük ise. Bu temel durumu sonuçlandırır.
Şimdi, @rher whileyinelemenin başında yalnızca tek bayt içeren şu değer verilir :
forDöngü açıkça &=255 ile sonuç dizide tüm değerleri s sonuncusu hariç sadece o sonuncusu bakmak gerekir bu yüzden.
Her zaman yalnızca bir bayt kaldırdığımızı biliyoruz $xve $y:
Bu nedenle, $e*hexiki tek bayt değerin çarpımıdır, yani aralıkta olduğu anlamına gelir 0 — 0xFE01.
Endüktif hipotezle $r[$i]bir bayttır; bu nedenle $s = $r[$i] += $e*hexaralıktadır 0 — 0xFF00.
Bu nedenle, $s >> 8her zaman bir bayttır.
$ydöngünün 00her yinelemesinde ekstra büyür while:
Bu nedenle, whiledöngünün her yinelemesinde , iç fordöngü önceki whileyinelemeden daha fazla bir yineleme için çalışır .
Bu nedenle, $r[++$i] += $s >> 8son tekrarında fordöngü hep ekler $s >> 8için 0ve biz bunu çoktan $s >> 8hep bir byte olduğunu.
Bu nedenle, döngünün @rsonunda depolanan son değer forde tek bir bayttır.
Bu harika ve heyecan verici bir meydan okumaya son verir. Gönderdiğiniz için çok teşekkürler!