كيف يتم حساب المكمل باستخدام عوامل تشغيل روبي؟

StackOverflow https://stackoverflow.com/questions/1201681

سؤال

ماذا اريد:

assert_equal 6, ones_complement(9)   # 1001 => 0110
assert_equal 0, ones_complement(15)  # 1111 => 0000
assert_equal 2, ones_complement(1)   # 01 => 10

حجم الإدخال غير ثابت كما هو الحال في 4 بت أو 8 بت.بل هو تيار ثنائي.

ما أراه:

v = "1001".to_i(2)                 => 9

هناك عامل التقليب قليلا ~

(~v).to_s(2)                       => "-1010"
sprintf("%b", ~v)                  => "..10110"
~v                                 => -10

أعتقد أن الأمر له علاقة باستخدام جزء واحد لتخزين العلامة أو شيء من هذا القبيل ...يمكن للشخص أن يفسر هذا الإخراج؟كيف يمكنني الحصول على مكمل واحد دون اللجوء إلى معالجة السلسلة مثل قطع آخر حرف n من إخراج sprintf للحصول على "0110" أو استبدال 0 بـ 1 والعكس صحيح

هل كانت مفيدة؟

المحلول

وهذا يبدو وكأنه كنت ترغب فقط في الوجه أربعة بت (طول الإدخال) - لذلك ربما كنت ترغب في XOR مع 1111

.

نصائح أخرى

وروبي فقط بتخزين (وقعت) عدد. تمثيل الداخلي هذا الرقم غير ذي صلة: أنه قد يكون FixNum، BigNum أو أي شيء آخر. ولذلك، فإن عدد البتات في رقم هو أيضا غير معروف: فهو مجرد رقم على كل حال. وهذا يتعارض مع مثلا C، حيث عدد صحيح من المحتمل أن يكون 32 بت (الثابتة).

فماذا المشغل ~ تفعل بعد ذلك؟ أهلا وسهلا، فقط شيء من هذا القبيل:

class Numeric
    def ~
        return -self - 1
    end
end

... لأن هذا هو ما '~' يمثل عند النظر إلى الأرقام تكملة 2 ل.

وهكذا ما هو مفقود من بيان الدخل الخاص بك هو عدد البتات تريد التبديل: 32-بت ~ يختلف عن عام ~ مثل ذلك في روبي

والآن إذا كنت ترغب فقط في بت الوجه ن بت يمكنك أن تفعل شيئا مثل:

class Numeric
    def ones_complement(bits)
        self ^ ((1 << bits) - 1)
    end
end

... ولكن لديك لتحديد عدد البتات على الوجه. وهذا لن يؤثر على العلم علامة، منذ أن واحدا خارج متناول يديك مع XOR:)

يرى هذا السؤال لماذا.

إحدى مشكلات طريقتك هي أن إجابتك المتوقعة تكون صحيحة فقط إذا قمت بقلب البتات الأربعة المهمة فقط: 1001 -> 0110.

ولكن يتم تخزين الرقم بأصفار بادئة، ويقوم عامل التشغيل ~ بقلب جميع البتات البادئة أيضًا: 00001001 -> 11110110.ثم يتم تفسير الرقم 1 البادئ على أنه علامة سلبية.

تحتاج حقًا إلى تحديد الوظيفة التي من المفترض أن تفعلها بأرقام مثل 0b101 و 0b11011 قبل أن تقرر كيفية تنفيذها.إذا كنت تريد فقط قلب 4 بتات، فيمكنك القيام بذلك v^0b1111, ، كما هو مقترح في إجابة أخرى.ولكن إذا كنت تريد قلب جميع البتات المهمة، فسيصبح الأمر أكثر تعقيدًا.

يحرر

إليك طريقة واحدة لقلب جميع البتات المهمة:

def maskbits n
  b=1
  prev=n;
  mask=prev|(prev>>1)
  while (mask!=prev)
    prev=mask;
    mask|=(mask>>(b*=2))
  end
  mask
end

def ones_complement n
  n^maskbits(n)
end

هذا يعطي

p ones_complement(9).to_s(2)  #>>"110" 
p ones_complement(15).to_s(2) #>>"0"
p ones_complement(1).to_s(2)  #>>"0"

هذا لا يعطي الناتج المطلوب لـ ones_compliment(1)، لأنه يعامل 1 على أنه "1" وليس "01".لا أعرف كيف يمكن للوظيفة استنتاج عدد الأصفار البادئة التي تريدها دون أخذ العرض كوسيطة.

ما تقومون به (باستخدام ~) عامل، هو في الواقع تكملة واحد. كنت تحصل على تلك القيم التي كنت لا تتوقع بسبب الطريقة يتم تفسير عدد من روبي.

ما عليك القيام به فعلا سوف يعتمد على ما كنت تستخدم هذا ل. وهذا هو القول، لماذا تحتاج تكملة 1 ل؟

إذا كنت تعمل مع السلاسل التي يمكن القيام بها:

s = "0110"
s.gsub("\d") {|bit| bit=="1"?"0":"1"}

إذا كنت تعمل مع الأرقام، سيكون لديك لتحديد عدد البتات كبيرة للأسباب التالية:
0110 = 6؛ 1001 = 9؛
110 = 6؛ 001 = 1؛

وحتى، وتجاهل علامة، ربما عليك أن التعامل مع هذا.

وتذكر أن كنت تحصل على مكمل واحد في الوقت الراهن مع ~ إذا كنت تمر في Fixnum: عدد البتات التي تمثل العدد كمية ثابتة في مترجم وبالتالي هناك الرائدة 0 في الجبهة من تمثيل ثنائي عدد 9 (ثنائي 1001). يمكنك العثور على هذا العدد من البتات من خلال دراسة حجم أي Fixnum. (يتم إرجاع الإجابة في بايت)

1.size            #=> 4
2147483647.size   #=> 4

~ ويعرف أيضا أكثر من Bignum. في هذه الحالة فإنه يتصرف كما لو كان مقلوب كل من البتات التي تم تحديدها في Bignum، ومن ثم إذا كانت هناك سلسلة لانهائية من 1 في الجبهة من أن Bignum. يمكنك، يشق تصور BITSTREAM الخاص بك إلى Bignum وعكس كل شيء. ولكن سوف تحتاج إلى معرفة حجم BITSTREAM قبل انعكاس للحصول على نتيجة مفيدة من بعد هو مقلوب منه.

للرد على السؤال كما يطرح ذلك الحق قبالة الخفافيش، يمكنك العثور على أكبر قوة من 2 أقل من المدخلات الخاصة بك، مضاعفة ذلك، طرح 1، ثم XOR نتيجة ذلك مع المدخلات الخاصة بك ودائما الحصول على تكملة منها من مجرد بت كبيرة في عدد المدخلات الخاصة بك.

def sig_ones_complement(num)
  significant_bits = num.to_s(2).length
  next_smallest_pow_2 = 2**(significant_bits-1)
  xor_mask = (2*next_smallest_pow_2)-1
  return num ^ xor_mask
end
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top