দীর্ঘ গুণ, একবারে 8 বিট


13

আপনাকে একটি 16-বিট মেশিন দেওয়া হয়েছে এবং নির্বিচার আকারের পূর্ণসংখ্যার গুণক প্রয়োগ করার কথা বলা হয়েছে। আপনার রেজিস্টারগুলিতে কেবল 16-বিট সংখ্যা থাকতে পারে এবং সবচেয়ে বড় গুণগুলি দুটি 8-বিট ইনপুট নেয় এবং 16-বিটের ফলাফল উত্পন্ন করে।

আপনার প্রোগ্রামটি অবশ্যই দুটি স্বেচ্ছাচারিত আকারের ধনাত্মক সংখ্যা এবং তাদের পণ্য আউটপুট হিসাবে নিতে হবে। প্রতিটি ইনপুট নম্বর তার নিজস্ব লাইনে একটি স্বল্প-এন্ডিয়ান বাইট অ্যারে হিসাবে এনকোড থাকে যেখানে প্রতিটি বাইট 2-অঙ্কের হেক্স নম্বর হয়। আউটপুট একইভাবে ফর্ম্যাট করা আবশ্যক। একটি উদাহরণ দিয়ে সম্ভবত সবচেয়ে ভাল ব্যাখ্যা করা হয়েছে:

ইনপুট

1f 4a 07
63 a3

আউটপুট

fd 66 03 a7 04

যা গুণটিকে 477727 * 41827 = 19981887229 এনকোড করে।

আপনি ধরে নিতে পারেন যে প্রতিটি ইনপুট সংখ্যার শেষ (সর্বাধিক তাৎপর্যপূর্ণ) বাইটটি নঞ্জেরো এবং আপনার আউটপুট সংখ্যার শেষ অংশটি ননজারো হতে হবে। উভয় ইনপুট সংখ্যা সর্বাধিক 100 বাইট দীর্ঘ হবে।

ক্ষুদ্রতম কোড জিতেছে।

মনে রাখবেন, আপনার ব্যবহারের মঞ্জুরি দেওয়া সবচেয়ে বড় গুণটি হ'ল 1 বাইট * 1 বাইট এবং 2 বাইটের চেয়ে বড় কোনও পূর্ণসংখ্যার প্রকার নেই!


এটি ভাষাগুলির পক্ষে অত্যন্ত গুরুত্বপূর্ণ, যেখানে হাস্কেলের মতো কোনও ডিফল্ট 8-বিট টাইপ নেই।
FUZxxl

1
সংযোজন সম্পর্কে কী? আমরা কি একটি তৈরি সালিশি আকারের সংযোজন ফাংশন থাকার ভান করতে পারি? যদি না হয় তবে আমরা কী যুক্ত করতে পারি?
টিমউই

@ টিমউই: আপনি একবারে 16 বিট চান এমন কিছু করতে পারেন। যোগ, শিফট, যাই হোক না কেন। নিজেকে সংশ্লেষিত করতে আপনার যে কোনও বৃহত্তর ক্রিয়াকলাপ প্রয়োজন।
কীথ র্যান্ডাল

সঠিক বাইট ক্রমের জন্য +1
12

উত্তর:


13

পার্ল, 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

এখন আপনি সমস্ত রেখাটি অতিক্রম করেছেন যেখানে বাম সংখ্যাটি সমান । এই ক্ষেত্রে এটি কেবল only. (আমি কোডে স্ট্রাইক-মাধ্যমে করতে পারি না, তাই আমি কেবল এটি সরিয়ে ফেলব)) অবশেষে, আপনি বাকী সমস্ত সংখ্যা ডানদিকে যুক্ত করুন:

13     47
 3    188
 1    376
     ----
      611

এবং এটি সঠিক উত্তর। 13 × 47 = 611।

এখন, যেহেতু আপনি সব কম্পিউটার Geeks, আপনি বুঝতে পেরেছি করবে কি আমরা আসলে বাম এবং ডান কলামে করছেন x >> 1এবং y << 1যথাক্রমে। তদ্ব্যতীত, আমরা yকেবল যোগ যদি 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যা নির্বিচারে আকারের, তাই আমাদের এটিকে একটি লুপেও পরিবর্তন করতে হবে to আমরা পার্লে এটি করব।

এখন পার্লকে সবকিছু অনুবাদ করুন:

  • $xএবং $yহেক্স ফর্ম্যাটের ইনপুটগুলি হ'ল তাই তাদের মধ্যে প্রথমে কমপক্ষে উল্লেখযোগ্য বাইট রয়েছে ।

  • সুতরাং, পরিবর্তে x >> 8আমি না $x =~ s/.. *//s। আমার স্পেস + স্টার লাগবে কারণ শেষ বাইটে এটির জায়গা নাও থাকতে পারে (স্পেস + ব্যবহার করতে পারে ?)। এটি স্বয়ংক্রিয়ভাবে সরানো বাইট ( x & 255) এ প্রবেশ করে $&

  • y << 8সহজভাবে $y = "00$y"

  • resultআসলে একটি সংখ্যাসূচক অ্যারে @r। শেষে, প্রতিটি উপাদানের @rউত্তরের একটি বাইট থাকে তবে গণনার অর্ধেক অংশে এটিতে একাধিক বাইট থাকতে পারে। আমি নীচে আপনাকে প্রমাণ করব যে প্রতিটি মান কখনই দুটি বাইট (16 বিট) এর বেশি হয় না এবং ফলাফলটি সর্বদা শেষে একটি বাইট হয়।

সুতরাং এখানে পার্ল কোডটি নিচু করা হয়েছে এবং মন্তব্য করা হয়েছে:

# 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

এখন প্রমাণের জন্য যে এটি সর্বদা বাইট আউটপুট করে এবং গণনা কখনই দুটি বাইটের চেয়ে বেশি মান উৎপন্ন করে না । আমি এটি whileলুপের মাধ্যমে অন্তর্ভুক্ত করে প্রমাণ করব :

  • খালি @r(কারণ এটা সব এটা কোন মান আছে) শুরুতে পরিষ্কারভাবে এটা 0xFF চেয়ে মান বেশি। এটি বেস কেস সমাপ্ত করে।

  • এখন, @rপ্রতিটি whileপুনরাবৃত্তির শুরুতে কেবলমাত্র একক বাইট রয়েছে :

    • forলুপ স্পষ্টভাবে &=255 সঙ্গে ফলাফলের অ্যারের মধ্যে সব মান গুলি গত এক ছাড়া তাই আমরা শুধু তাই গত এক তাকান প্রয়োজন।

    • আমরা জানি যে আমরা সর্বদা থেকে কেবলমাত্র একটি বাইট অপসারণ করি $xএবং $y:

      • সুতরাং, $e*hexদুটি একক-বাইট মানগুলির একটি গুণ, যার অর্থ এটি সীমার মধ্যে 0 — 0xFE01

      • ইন্ডাকটিভ হাইপোথিসিস দ্বারা, $r[$i]একটি বাইট হয়; সুতরাং, $s = $r[$i] += $e*hexপরিসীমা মধ্যে 0 — 0xFF00

      • অতএব, $s >> 8সর্বদা একটি বাইট হয়।

    • $yলুপের 00প্রতিটি পুনরাবৃত্তিতে একটি বাড়তি বাড়ায় while:

      • অতএব, whileলুপের প্রতিটি পুনরাবৃত্তিতে , অভ্যন্তরীণ forলুপটি আগের whileপুনরাবৃত্তির চেয়ে আরও একটি পুনরাবৃত্তির জন্য চালিত হয় ।

      • অতএব, লুপের $r[++$i] += $s >> 8সর্বশেষ পুনরাবৃত্তিতে forসর্বদা যুক্ত $s >> 8হয় 0এবং আমরা ইতিমধ্যে $s >> 8এটি সর্বদা একটি বাইট হিসাবে প্রতিষ্ঠিত করেছি ।

    • অতএব, লুপের @rশেষে সঞ্চিত সর্বশেষ forমানটিও একটি একক বাইট।

এটি একটি দুর্দান্ত এবং উত্তেজনাপূর্ণ চ্যালেঞ্জ শেষ করে। এটি পোস্ট করার জন্য অনেক ধন্যবাদ!


4

সি সমাধান

এই সমাধানটি কোনও ইনপুট বৈধতা দেয় না। এটি কেবলমাত্র হালকাভাবে পরীক্ষা করা হয়েছে। গতি সত্যিই বিবেচনা ছিল না। ম্যালোকের স্মৃতি এবং এটি কতটা দখল করে সে সম্পর্কে বিশেষভাবে চালাক নয়। যথেষ্ট হওয়ার গ্যারান্টিযুক্ত এবং প্রয়োজনের চেয়ে আরও বেশি।

মি () একটি স্ট্রিং গ্রহণ করে, স্ট্রিংয়ে দুটি নতুন লাইন প্রত্যাশা করে, প্রতিটি সংখ্যার পরে একটি করে। কেবল সংখ্যা, ছোট হাতের অক্ষর, স্পেস এবং নিউলাইনগুলি আশা করে। হেক্স অঙ্কগুলি সর্বদা জুটি হওয়ার প্রত্যাশা করে।

কোনও গুণক অপারেশন কখনও ব্যবহার করা হয় না (জেনে শুনে)। স্থানান্তর 8 বিট ভেরিয়েবলে সঞ্চালিত হয়। এক 16 বিট সংযোজন সম্পাদন করা হয়। 32-বিট ডেটা ধরণের নেই।

হাত দ্বারা সঙ্কুচিত, এবং শুধুমাত্র হালকা। সম্পাদনা: আরও অবলম্বন, কম অক্ষর: ডি জিসিসি সহ সতর্কতা সহ কম্পাইল করে।

অক্ষর: 675

typedef unsigned char u8;
#define x calloc
#define f for
#define l p++
#define E *p>57?*p-87:*p-48
#define g(a) --i;--a;continue
void m(u8*d){short n=0,m=0,a,b,i,k,s;u8*t,*q,*r,*p=d,o;f(;*p!=10;n++,l){}l;f(;*p
!=10;m++,l){}t=x(n,1);q=x(m,1);r=x(n,1);p=d;a=n;i=0;f(;*p!=10;i++,l){if(*p==32){
g(a);}t[i]=E;t[i]<<=4;l;t[i]|=E;}a/=2;b=m;i=0;l;f(;*p!=10;i++,l){if(*p==32){g(b)
;}q[i]=E;q[i]<<=4;l;q[i]|=E;}b/=2;f(k=0;k<8*b;k++){if(q[0]&1){o=0;f(i=0;i<n;i++)
{s=o+t[i]+r[i];o=s>>8;r[i]=s&255;}}f(i=n;i;i--){o=t[i-1]>>7&1;t[i-1]*=2;if(i!=n)
t[i]|=o;}f(i=0;i<m;i++){o=q[i]&1;q[i]/=2;if(i)q[i-1]|=(o<<7);}}k=(r[a+b-1]==0)?a
+b-1:b+a;f(i=0;i<k;i++){printf("%02x ",r[i]);}putchar(10);}

আপনি এটি দিয়ে পরীক্ষা করতে পারেন:

int main(void){
  m("1f 4a 07\n63 a3\n");
  m("ff ff ff ff\nff ff ff ff\n");
  m("10 20 30 40\n50 60 70\n");
  m("01 02 03 04 05 06\n01 01 01\n");
  m("00 00 00 00 00 00 00 00 00 00 00 00 01\n00 00 00 00 00 00 00 00 02\n");
  return 0;
}

ফলাফল:

$ ./long 
fd 66 03 a7 04 
01 00 00 00 fe ff ff ff 
00 05 10 22 34 2d 1c 
01 03 06 09 0c 0f 0b 06 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 

3

OCaml + ব্যাটারি, 362 টি অক্ষর

একটি স্ট্যান্ডার্ড ও (এন * মি) স্কুলপতির গুণিত অ্যালগরিদম। নোট করুন যে চ্যালেঞ্জের প্রয়োজনীয়তাগুলি পূরণ করার জন্য, অপারেশনগুলি স্ট্রিংয়ের বাইটে করা হয়, যা ওসিএএমএলে (সুবিধাজনকভাবে, এই ক্ষেত্রে) পরিবর্তনযোগ্য। এটিও লক্ষ করুন যে s2 (2 ^ 8 - 1) + (2 ^ 8 - 1) ^ 2 = (2 ^ 8 - 1) (2 ^ 8 + 1) = 2 ^ 16 - 1 থেকে সংগ্রহকারী কখনও 16 বিট উপচে পড়বে না ।

let(@)=List.map
let m a b=Char.(String.(let e s=of_list(((^)"0x"|-to_int|-chr)@nsplit s" ")in
let a,b=e a,e b in let m,n=length a,length b in let c=make(m+n)'\000'in
iteri(fun i d->let s,x=ref 0,code d in iteri(fun j e->let y=code e in
s:=!s+code c.[i+j]+x*y;c.[i+j]<-chr(!s mod
256);s:=!s/256)b;c.[i+n]<-chr!s)a;join" "((code|-Printf.sprintf"%02x")@to_list c)))

উদাহরণ স্বরূপ,

# m "1f 4a 07" "63 a3" ;;
- : string = "fd 66 03 a7 04"

# m "ff ff ff ff" "ff ff ff ff" ;;
- : string = "01 00 00 00 fe ff ff ff"

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.