একটি পূর্ণসংখ্যার মোড়কে "পূর্বাবস্থায় ফেরাতে"


20

আমি বেশ কয়েক বছর আগে একটি আকর্ষণীয় তাত্ত্বিক সমস্যার মধ্যে পড়েছিলাম। আমি কখনই এর সমাধান খুঁজে পাইনি এবং আমি যখন ঘুমাই তখন তা আমাকে পীড়িত করে।

ধরা যাক আপনার কাছে একটি (সি #) অ্যাপ্লিকেশন রয়েছে যা কোনও এক্সকে কিছু সংখ্যক ধারণ করে, x বলে। (X এর মান স্থির নয়)। প্রোগ্রামটি যখন চালানো হয়, এক্সটি 33 দ্বারা গুণিত হয় এবং তারপরে একটি ফাইলে লেখা হয়।

বেসিক উত্স কোডটি এর মতো দেখাচ্ছে:

int x = getSomeInt();
x = x * 33;
file.WriteLine(x); // Writes x to the file in decimal format

কয়েক বছর পরে, আপনি আবিষ্কার করেছেন যে আপনার X এর মূল মূল্য দরকার। কিছু গণনা সহজ: কেবলমাত্র ফাইলটিতে সংখ্যাটি 33 দ্বারা ভাগ করুন However তবে অন্য ক্ষেত্রে, এক্স যথেষ্ট পরিমাণে বৃহত যে গুণটি একটি পূর্ণসংখ্যার ওভারফ্লো করে। ডক্স অনুসারে , সি # সংখ্যাটি কম না হওয়া পর্যন্ত হাই-অর্ডার বিটগুলি কেটে ফেলবে int.MaxValue। এক্ষেত্রে কি সম্ভব?

  1. এক্স নিজেই পুনরুদ্ধার করুন বা
  2. এক্স এর সম্ভাব্য মানগুলির একটি তালিকা পুনরুদ্ধার করবেন?

এটি আমার কাছে মনে হয় (যদিও আমার যুক্তিটি অবশ্যই ত্রুটিযুক্ত হতে পারে) যেহেতু একটি বা উভয়ই সম্ভব হওয়া উচিত, যেহেতু সংযোজনগুলির সরল ক্ষেত্রে (মূলত আপনি যদি 10 থেকে X যোগ করেন এবং এটি আবৃত হয়, আপনি 10 কে বিয়োগ করতে পারবেন এবং আবার এক্স দিয়ে বায়ু আপ করতে পারেন ) এবং গুণন কেবল পুনরায় সংযোজন। এছাড়াও সহায়তা (আমি বিশ্বাস করি) সত্য যে এক্স সকল ক্ষেত্রে একই মান দ্বারা গুণিত হয় - একটি ধ্রুবক 33।

বছরের পর বছর ধরে এই আমার খুলির চারপাশে নাচছে। এটি আমার কাছে ঘটবে, আমি এটির মাধ্যমে চিন্তা করার চেষ্টা করার জন্য কিছু সময় ব্যয় করব এবং তারপরে আমি কয়েক মাসের জন্য এটি ভুলে যাব। আমি এই সমস্যার তাড়া করতে করতে ক্লান্ত! কেউ কি অন্তর্দৃষ্টি দিতে পারেন?

(পার্শ্ব দ্রষ্টব্য: আমি কীভাবে এটি ট্যাগ করতে জানি না Sug পরামর্শগুলি স্বাগত।

সম্পাদনা: আমাকে স্পষ্ট করে বলি যে আমি যদি এক্স এর জন্য সম্ভাব্য মানগুলির একটি তালিকা পেতে পারি, তবে এটির মূল মানের সাথে সংকীর্ণ করতে আমার আরও অন্যান্য পরীক্ষা থাকতে পারে are


13
লাইন বরাবর কিছু en.wikipedia.org/wiki/Modular_multiplicative_inverse
rwong

1
@ রুং: আপনার মন্তব্যটিই সঠিক উত্তর।
কেভিন ক্লাইনে

হ্যাঁ, এবং ইউলার পদ্ধতি বিশেষ করে কার্যকর বলে মনে হয় যেহেতু এর গুণকনির্ণয় mমাত্র 2 ^ 32 বা 2 ^ 64, প্লাস এর exponentiation aমডিউল mসহজবোধ্য (শুধু উপেক্ষা ওভারফ্লো সেখানে)
MSalters

1
আমি মনে করি যে বিশেষ সমস্যাটি আসলে যৌক্তিক পুনর্গঠন
এমএসএলটাররা

1
@ এসএমএলটাররা: না, r*s^-1 mod mএটি আপনার কাছেই রয়েছে rএবং আপনার উভয়কেই খুঁজে বের করতে হবে s। এখানে, আমরা আছে r*s mod mএবং আমরা জানি কিন্তু r
ব্যবহারকারী 2357112

উত্তর:


50

1041204193 দ্বারা গুণ করুন।

যখন কোনও গুণটির ফলাফল কোনও ইনট্রে ফিট করে না, আপনি সঠিক ফলাফল পাবেন না, তবে আপনি সঠিক ফলাফল মডুলোর 2 ** 32 এর সমান একটি সংখ্যা পাবেন । এর অর্থ হ'ল আপনি যে সংখ্যাটি দিয়েছিলেন তার সংখ্যা যদি কপিরাইম হয় 2 ** 32 (যার অর্থ এটি বিজোড় হতে হবে), আপনি তার নম্বরটি ফিরে পেতে এর গুণক বিপরীত দ্বারা গুণিত করতে পারেন। ওল্ফ্রাম আলফা বা বর্ধিত ইউক্লিডিয়ান অ্যালগরিদম আমাদের 33 এর গুণিত বিপরীতমুখী মডুলো 2 ** 32 বলতে 1041204193 বলতে পারে So সুতরাং, 1041204193 দ্বারা গুণ করুন, এবং আপনার আসল এক্স ফিরে এসেছে।

যদি আমরা বলি, 33 এর পরিবর্তে 60, আমরা মূল সংখ্যাটি পুনরুদ্ধার করতে সক্ষম হব না, তবে আমরা এটি কয়েকটি সম্ভাবনায় সংকুচিত করতে সক্ষম হব। 60 কে 4 * 15 এ বিভক্ত করে 15 মড 2 ** 32 এর বিপরীতমুখীকরণ করে এবং এর দ্বারা গুণ করে আমরা সংখ্যার মাত্র 2 টি হাই-অর্ডার বিটকে জোর-বলের কাছে রেখে 4 বার মূল সংখ্যাটি পুনরুদ্ধার করতে পারি। ওল্ফ্রাম আলফা বিপর্যয়ের জন্য আমাদের 4008636143 দেয়, যা কোনও ইনট মধ্যে ফিট করে না, তবে এটি ঠিক আছে। আমরা কেবল 4008636143 মড 2 ** 32 এর সমান একটি সংখ্যা পেয়েছি বা যেকোন উপায়ে এটি জোর করে সংকলকটি আমাদের জন্য এটি করতে বাধ্য করি এবং ফলাফলটি 15 মড 2 ** 32 এর বিপরীতও হয়। ( আমরা -286331153 পেয়েছি ))


5
ওহ ছেলে। সুতরাং আমার কম্পিউটারটি মানচিত্র তৈরির কাজটি ইতিমধ্যে ইউক্লিড দ্বারা সম্পন্ন হয়েছিল।
v010dya

21
আপনার প্রথম বাক্যে আমি ফ্যাক্ট-অফ-ফ্যাক্ট-নেস পছন্দ করি। "ওহ, অবশ্যই এটি 1041204193, আপনার কি মুখস্থ নেই?" :
ডোরকনব

2
এটি বেশ কয়েকটি সংখ্যার জন্য কাজ করার উদাহরণ দেখানো সহায়ক হবে যেমন x * 33 ওভারফ্লো হয়নি এবং যেখানে এটি হয়েছে সেখানে একটি।
রব ওয়াটস

2
মন ফুঁকছে। কি দারুন.
মাইকেল গাজোন্ডা

4
33 মডুলো $ 2 ^ {32} $ এর বিপরীতটি খুঁজে পেতে আপনার কাছে ইউক্লিড বা ওল্ফ্রামআল্ফার (অবশ্যই!) দরকার নেই $ যেহেতু $ x = 32 = 2 ^ 5 n শূন্যপদযুক্ত (অর্ডার $ 7 $) মডুলো $ 2 ^ 32 $, আপনি কেবল জ্যামিতিক সিরিজ পরিচয় $ (1 + x) ^ {- 1} = 1-x + x apply প্রয়োগ করতে পারেন 2-x ^ 3 + \ সিডটস + এক্স ^ 6 $ (যার পরে ধারাবাহিকটি বন্ধ হয়ে যায়) $ 33 ^ {- 1} = 1-2 ^ 5 + 2 ^ {10} -2 ^ {15} + \ সিডটস + 2 ^ {30} $ যা 11 111110000011111000001111100001_2 = 1041204193_ {10} $ $
মার্ক ভ্যান লিউউইন

6

এটি ম্যাথ (sic) এসই-তে একটি প্রশ্ন হিসাবে সম্ভবত আরও উপযুক্ত। আপনি মূলত মডিউলার গাণিতিক নিয়ে কাজ করছেন, যেহেতু বাম-সর্বাধিক বিটগুলি বাদ দেওয়া একই জিনিস।

আমি ম্যাথের লোকেরা যেমন গণিতে (এস সি) এস ই তে রয়েছি তেমন ভাল নই, তবে আমি উত্তর দেওয়ার চেষ্টা করব।

আমাদের এখানে যা আছে তা হচ্ছে সংখ্যাটি 33 (3 * 11) দ্বারা গুণিত হচ্ছে এবং এটি আপনার মোডের সাথে একমাত্র সাধারণ ডিনোমিনেটরটি 1 That কারণ এটি সংজ্ঞায়িতভাবে কম্পিউটারে বিটগুলি দুটি হিসাবে দুটি শক্তি এবং এইভাবে আপনার মোড দু'জনের কিছু শক্তি

আপনি সারণিটি তৈরি করতে সক্ষম হবেন যেখানে প্রতিটি পূর্বের মানের জন্য আপনি নিম্নলিখিত মানটি গণনা করেন। এবং প্রশ্নটি হয়ে ওঠে যে নিম্নলিখিত সংখ্যাগুলি কেবল পূর্বের একটিতে মিল রয়েছে?

যদি এটি 33 না, তবে প্রধান বা কোনও প্রধানের শক্তি, আমি বিশ্বাস করি যে উত্তরটি হ্যাঁ হবে, তবে এই ক্ষেত্রে ... ম্যাথ.এসইতে জিজ্ঞাসা করুন!

প্রোগ্রাম্যাটিক পরীক্ষা

এটি সি ++ এ রয়েছে কারণ আমি সি # জানি না, তবে ধারণাটি এখনও ধারণ করে। এটি আপনার দেখাতে পারে বলে মনে হচ্ছে:

#include <iostream>
#include <map>

int main(void)
{
    unsigned short count = 0;
    unsigned short x = 0;
    std::map<unsigned short, unsigned short> nextprev;

    nextprev[0] = 0;
    while(++x) nextprev[x] = 0;

    unsigned short nextX;
    while(++x)
    {
            nextX = x*33;
            if(nextprev[nextX])
            {
                    std::cout << nextprev[nextX] << "*33==" << nextX << " && " << x << "*33==" << nextX << std::endl;
                    ++count;
            }
            else
            {
                    nextprev[nextX] = x;
                    //std::cout << x << "*33==" << nextX << std::endl;
            }
    }

    std::cout << count << " collisions found" << std::endl;

    return 0;
}

এই জাতীয় মানচিত্রটি বসানোর পরে, আপনি যদি পরেরটিটি জানেন তবে আপনি সর্বদা পূর্বের এক্স পেতে সক্ষম হবেন। সর্বকালে কেবলমাত্র একক মান থাকে।


একটি নে-নেতিবাচক ডেটাটাইপের সাথে কাজ করা আরও সহজ হবে কেন? কম্পিউটারে স্বাক্ষরিত এবং স্বাক্ষরবিহীন হ্যান্ডেলগুলি কি একইভাবে পরিচালিত হয় না, কেবল তাদের মানব আউটপুট ফর্ম্যাটটি কি আলাদা?
এক্সসিলেড

@ এক্সসিলেড ১৯৪৪ ভাল, এই সংখ্যাগুলি সম্পর্কে আমার পক্ষে চিন্তা করা সহজ।
v010dya

যথেষ্ট পরিমাণে xD হিউম্যান ফ্যাক্টর ~
এক্সেলযুক্ত

এটিকে আরও সুস্পষ্ট করার জন্য আমি অ-নেতিবাচক সম্পর্কে উক্ত বিবরণটি সরিয়েছি।
v010dya

1
@ এক্সসিলেড ১৯৪৪: স্বাক্ষরিত ডেটাটাইপগুলি মডুলার গাণিতিকের স্বাভাবিক নিয়ম অনুসরণ করে; স্বাক্ষরিত প্রকারগুলি না। বিশেষত, maxval+1কেবল স্বাক্ষরবিহীন প্রকারের জন্য 0।
এমসাল্টারস

2

এটি পাওয়ার একটি উপায় হ'ল বক্ষ শক্তি ব্যবহার করা। দুঃখিত, আমি সি # জানি না তবে সমাধানটি চিত্রিত করার জন্য নিম্নলিখিতটি সি-সিডু সিডো কোডটি রয়েছে:

for (x=0; x<=INT_MAX; x++) {
    if (x*33 == test_value) {
        printf("%d\n", x);
    }
}

প্রযুক্তিগতভাবে, আপনার যা প্রয়োজন তা x*33%(INT_MAX+1) == test_valueকিন্তু পূর্ণসংখ্যার ওভারফ্লো স্বয়ংক্রিয়ভাবে আপনার জন্য %অপারেশন করবে যদি না আপনার ভাষা স্বেচ্ছাসেবী যথার্থ পূর্ণসংখ্যা (বিগিন্ট) ব্যবহার করে।

এটি আপনাকে যা দেয় তা হ'ল মূল সংখ্যাটি হতে পারে numbers প্রথম মুদ্রিত নম্বরটি এমন এক নম্বর হবে যা এক প্রকারের ওভারফ্লো উত্পাদন করে। দ্বিতীয় সংখ্যাটি এমন সংখ্যা হবে যা দুটি বৃত্তাকার ওভারফ্লো উত্পাদন করে। এবং তাই ..

সুতরাং, যদি আপনি নিজের ডেটা আরও ভাল জানেন তবে আপনি আরও ভাল অনুমান করতে পারেন। উদাহরণস্বরূপ, সাধারণ ঘড়ির গণিত (প্রতি 12 টায় ওভারফ্লো) প্রথম সংখ্যাটিকে আরও বেশি করে দেখায় যেহেতু বেশিরভাগ লোকেরা আজকের ঘটনাগুলিতে আগ্রহী।


সি # মৌলিক ধরণের সাথে সি এর মতো আচরণ করে - অর্থাত্ intএকটি 4 বাইট স্বাক্ষরিত পূর্ণসংখ্যা যা মোড়ানো থাকে, সুতরাং আপনার উত্তরটি এখনও ভাল, যদিও আপনার কাছে প্রচুর ইনপুট থাকলে ব্রুট জোর করা সবচেয়ে ভাল উপায় না! :)
এক্সসেল্ড

হ্যাঁ, আমি এখান থেকে মডুলো বীজগণিত সংক্রান্ত বিধিগুলি দিয়ে কাগজে এটি করার চেষ্টা করেছি: math.stackexchange.com/questions/346271/… । তবে আমি এটি বের করার চেষ্টা করতে গিয়ে আটকে গেলাম এবং একটি নিষ্ঠুর-সমাধানের সমাধানটি শেষ
করলাম

আকর্ষণীয় নিবন্ধ, যদিও এটি ক্লিক করার জন্য আমাকে আরও গভীরতার সাথে এটি আরও অধ্যয়ন করতে হবে, আমি মনে করি।
এক্সসিলেড

@ স্লেবেটম্যান আমার কোডটি দেখুন। দেখে মনে হচ্ছে এটি 33
টির সাথে গুণনের ক্ষেত্রে কেবল একটিই

2
সংশোধন: সি এর intচারপাশে মোড়ানোর নিশ্চয়তা নেই (আপনার সংকলকের ডক্স দেখুন) see এটি স্বাক্ষরবিহীন প্রকারের ক্ষেত্রে সত্য।
টমাস এডিং

1

আপনি এসএমটি সলভার জেড 3 কে সূত্রের জন্য একটি সন্তোষজনক অ্যাসাইনমেন্ট দেওয়ার জন্য জিজ্ঞাসা করতে পারেন x * 33 = valueFromFile। এটি আপনার জন্য সেই সমীকরণটি উল্টে দেবে এবং আপনাকে সমস্ত সম্ভাব্য মান দেয় x। জেড 3 গুণমান সহ হুবহু বিটভেক্টর পাটিগণিত সমর্থন করে।

    public static void InvertMultiplication()
    {
        int multiplicationResult = new Random().Next();
        int knownFactor = 33;

        using (var context = new Context(new Dictionary<string, string>() { { "MODEL", "true" } }))
        {
            uint bitvectorSize = 32;
            var xExpr = context.MkBVConst("x", bitvectorSize);
            var yExpr = context.MkBVConst("y", bitvectorSize);
            var mulExpr = context.MkBVMul(xExpr, yExpr);
            var eqResultExpr = context.MkEq(mulExpr, context.MkBV(multiplicationResult, bitvectorSize));
            var eqXExpr = context.MkEq(xExpr, context.MkBV(knownFactor, bitvectorSize));

            var solver = context.MkSimpleSolver();
            solver.Assert(eqResultExpr);
            solver.Assert(eqXExpr);

            var status = solver.Check();
            Console.WriteLine(status);
            if (status == Status.SATISFIABLE)
            {
                Console.WriteLine(solver.Model);
                Console.WriteLine("{0} * {1} = {2}", solver.Model.Eval(xExpr), solver.Model.Eval(yExpr), solver.Model.Eval(mulExpr));
            }
        }
    }

আউটপুট এর মতো দেখাচ্ছে:

SATISFIABLE
(define-fun y () (_ BitVec 32)
  #xa33fec22)
(define-fun x () (_ BitVec 32)
  #x00000021)
33 * 2738875426 = 188575842

0

ফলাফলটি পূর্বাবস্থায়িত করতে আপনাকে একটি অ-শূন্য সীমাবদ্ধ সংখ্যা দেবে (সাধারণত অসীম তবে intএটি ℤ এর সীমাবদ্ধ উপসেট)। যদি এটি গ্রহণযোগ্য হয় তবে কেবল সংখ্যাগুলি তৈরি করুন (অন্যান্য উত্তর দেখুন)।

অন্যথায় আপনাকে পরিবর্তনশীলের ইতিহাসের (সীমাবদ্ধ বা অসীম দৈর্ঘ্যের) একটি তালিকা বজায় রাখতে হবে।


0

বরাবরের মতো, এখানে একজন বিজ্ঞানীর সমাধান এবং ইঞ্জিনিয়ারের সমাধান রয়েছে।

উপরে আপনি একটি বিজ্ঞানীর কাছ থেকে খুব ভাল সমাধান পাবেন যা সর্বদা কাজ করে তবে আপনার "গুণক বিপরীত" গণনা করা প্রয়োজন।

এখানে ইঞ্জিনিয়ারের একটি দ্রুত সমাধান দেওয়া হয়েছে, যা আপনাকে সমস্ত সম্ভাব্য সংখ্যার চেষ্টা করতে বাধ্য করবে না।

val multiplier = 33 //used with 0x23456789
val problemAsLong = (-1947051863).toLong & 0xFFFFFFFFL

val overflowBit = 0x100000000L
for(test <- 0 until multiplier) {
  if((problemAsLong + overflowBit * test) % multiplier == 0) {
    val originalLong = (problemAsLong + overflowBit * test) / multiplier
    val original = originalLong.toInt
    println(s"$original (test = $test)")
  }
}

ধারণা কি?

  1. আমরা উপচে পড়েছি, সুতরাং পুনরুদ্ধার করতে বৃহত্তর প্রকারগুলি ব্যবহার করুন ( Int -> Long)
  2. অতিরিক্ত প্রবাহের কারণে আমরা সম্ভবত কিছু বিট হারিয়েছি, আসুন সেগুলি পুনরুদ্ধার করুন
  3. ওভারফ্লো এর চেয়ে বেশি ছিল না Int.MaxValue * multiplier

সম্পূর্ণ সম্পাদনযোগ্য কোডটি http://ideone.com/zVMbGV এ অবস্থিত

বিবরণ:

  • val problemAsLong = (-1947051863).toLong & 0xFFFFFFFFL
    এখানে আমরা আমাদের সঞ্চিত নম্বর লং এ রূপান্তর করি, তবে যেহেতু ইন্ট এবং লং স্বাক্ষরিত হয় তাই আমাদের এটি সঠিকভাবে করতে হবে।
    সুতরাং আমরা বিটওয়াইস এবং ইন্টের বিট সহ সংখ্যাটি সীমাবদ্ধ করি।
  • val overflowBit = 0x100000000L
    এই বিট বা এর গুণটি প্রাথমিক গুণ দ্বারা হারিয়ে যেতে পারে।
    এটি ইন্টার রেঞ্জের বাইরে প্রথম।
  • for(test <- 0 until multiplier)
    তৃতীয় আইডিয়া অনুসারে সর্বাধিক ওভারফ্লোটি গুণক দ্বারা সীমাবদ্ধ, সুতরাং আমাদের প্রকৃত প্রয়োজনের চেয়ে বেশি চেষ্টা করবেন না।
  • if((problemAsLong + overflowBit * test) % multiplier == 0)
    সম্ভবত হারিয়ে যাওয়া ওভারফ্লো যুক্ত করে পরীক্ষা করে দেখুন আমরা একটি সমাধানে আসি
  • val original = originalLong.toInt
    আসল সমস্যাটি ইন্টার রেঞ্জে ছিল, সুতরাং আসুন আমরা এটিতে ফিরে আসি। অন্যথায় আমরা ভুলভাবে নম্বরগুলি পুনরুদ্ধার করতে পারি, যা নেতিবাচক ছিল।
  • println(s"$original (test = $test)")
    প্রথম সমাধানের পরে ভাঙ্গবেন না, কারণ অন্যান্য সম্ভাব্য সমাধান হতে পারে।

PS: 3 য় আইডিয়া কঠোরভাবে সঠিক নয়, তবে বোধগম্য হতে বামে।
Int.MaxValueহয় 0x7FFFFFFF, তবে সর্বাধিক ওভারফ্লো হয় 0xFFFFFFFF * multiplier
সুতরাং সঠিক পাঠ্যটি হবে "ওভারফ্লো এর চেয়ে বেশি ছিল না -1 * multiplier"।
এটি সঠিক, তবে সবাই এটি বুঝতে পারবে না।

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