अवशेष संख्या प्रणाली


26

बड़ी संख्या में चुनौतियों के कारण मैंने सोचा कि यह दिलचस्प हो सकता है।

इस चुनौती में, हम बड़े पूर्णांकों पर जोड़, घटाव और गुणा करने के लिए अवशेष संख्या प्रणाली (RNS) का उपयोग करेंगे।

आरएनएस क्या है

आरएनएस कई तरीकों में से एक है जो लोगों ने पूर्णांक की पहचान करने के लिए विकसित किया है। इस प्रणाली में, संख्याओं को अवशेषों के अनुक्रम द्वारा दर्शाया जाता है (जो एक मापांक ऑपरेशन के बाद परिणाम होते हैं (यानी पूर्णांक विभाजन के बाद शेष)। इस प्रणाली में, प्रत्येक पूर्णांक में कई अभ्यावेदन होते हैं। चीजों को सरल रखने के लिए, हम चीजों को सीमित करने जा रहे हैं ताकि प्रत्येक पूर्णांक को विशिष्ट रूप से दर्शाया जाए। मुझे लगता है कि यह बताना आसान है कि ठोस उदाहरण के साथ क्या हो रहा है।

आइए हम पहले तीन अभाज्य संख्याओं को देखें: 2, 3, 5. RNS प्रणाली में, हम इन तीन संख्याओं का उपयोग विशिष्ट रूप से किसी भी संख्या का प्रतिनिधित्व करने के लिए कर सकते हैं जो अवशेषों का उपयोग करते हुए 2 * 3 * 5 = 30 से कम है। 21 लें:

21 30 से कम है, इसलिए हम इसे 2, 3 और 5 के माध्यम से परिणाम के बाद इसका प्रतिनिधित्व कर सकते हैं, और (अर्थात 2, 3 और 5 द्वारा पूर्णांक विभाजन के बाद शेष)

हम पूर्णांक के निम्नलिखित अनुक्रम के साथ 21 की पहचान करेंगे:

21 ~ {21 मॉड 2, 21 मॉड 3, 21 मॉड 5} = {1, 0, 1}

और इसलिए हमारे आरएनएस सिस्टम में, "21" के बजाय, हम {1,0,1} का उपयोग करेंगे।

सामान्य रूप से पूर्णांक n को देखते हुए , हम n को { n mod 2, ..., n mod p_k } के रूप में दर्शाते हैं , जहाँ p_k सबसे छोटा अभाज्य है, जैसे n , p_k से कम या बराबर सभी primes के उत्पाद से कम है ।

एक अन्य उदाहरण है, हम 3412. है का कहना है कि हम यहाँ क्योंकि 2,3,5,7,11,13 उपयोग करने की आवश्यकता 2*3*5*7*11*13=30030है, जबकि, 2*3*5*7*11=2310जो बहुत छोटा है।

3412 ~ {3412 mod 2, 3412 mod 3, 3412, mod 5, ..., 3412 mod 13} = {0, 1, 2, 3, 2, 6}

आप ध्यान दें कि इस प्रणाली का उपयोग करके हम बहुत बड़ी संख्या में अपेक्षाकृत दर्द रहित रूप से प्रतिनिधित्व कर सकते हैं। {1, 2, 3, 4, 5, 6, 7, 8, ...} अवशेषों का उपयोग करते हुए, हम {2, 6, 30, 210, 2310, 30030, 510510, 9699690 ...} तक की संख्याओं का प्रतिनिधित्व कर सकते हैं। क्रमशः। ( यहाँ श्रृंखला है )

हमारा काम

हम इन अवशेषों का उपयोग बड़ी संख्या में +, - और * करने के लिए करेंगे। मैं नीचे इन प्रक्रियाओं का वर्णन करूंगा। अभी के लिए यहाँ इनपुट और आउटपुट स्पेक्स हैं।

इनपुट

आपको एक स्टडिन या फ़ंक्शन तर्क के माध्यम से दो (संभावित रूप से बहुत बड़ी) संख्या दी जाएगी। उन्हें आधार 10 अंकों के तार के रूप में दिया जाएगा।

समस्या को आगे बढ़ाने के उद्देश्यों के लिए, हम पहला इनपुट nऔर दूसरा कॉल करते हैं mN> m> = 0 मान लें

तुम भी दिया जाएगा +या -या *आपरेशन इंगित करने के लिए प्रदर्शन करने के लिए।

उत्पादन

आज्ञा देना x एक पूर्णांक है। हम [का उपयोग करेगा x ] RNS प्रतिनिधित्व के ऊपर वर्णित का उल्लेख करने के एक्स

आप आउटपुट के लिए हैं [n] <operator> [m] = [result]

आरएनएस में संचालन कैसे करें

ये ऑपरेशन अपेक्षाकृत सरल हैं। RNS संकेतन में दो संख्याओं को देखते हुए, उन्हें जोड़ना, घटाना या गुणा करना, बस दिए गए संचालन घटक-वार को निष्पादित करें और फिर मापांक लें।

अर्थात

{{2, 2, 3} + {1, 1, 4} = {(1 + 1) mod 2, (2 + 1) mod 3, (3 + 4) mod 5} = {0, 0, 2}

ध्यान दें कि यदि दो अलग-अलग संख्याओं का प्रतिनिधित्व करने के लिए उपयोग किए जाने वाले अवशेषों की संख्या समान नहीं है, तो संचालन करते समय, आपको "छोटी" संख्या का विस्तार करने की आवश्यकता होगी, ताकि उसके अवशेषों की संख्या समान हो। यह उसी प्रक्रिया का अनुसरण करता है। उदाहरण के लिए परीक्षण मामलों को देखें।

यदि परिणाम में इनपुट की तुलना में अधिक अवशेषों की आवश्यकता होती है तो वही होता है। फिर दोनों इनपुट को "विस्तारित" करने की आवश्यकता है।

महत्वपूर्ण विवरण

  • हम यहां बड़ी संख्या में काम करेंगे, लेकिन बड़े पैमाने पर नहीं। हम पहले 100 प्रिम्स के उत्पाद तक संख्याओं के लिए जिम्मेदार होंगे (नीचे देखें)। यह अंत करने के लिए, आपको पहले 100 प्राइम मुफ्त में दिए जाते हैं (कोई बाइट लागत नहीं) । आप उन्हें pअपनी भाषा में मुहावरेदार या कुछ मुहावरे में बाँध सकते हैं और फिर इस सरणी को अपने अंतिम कुल से आरंभ करने के लिए उपयोग किए जाने वाले बाइट्स की संख्या घटा सकते हैं। यह निश्चित रूप से इसका मतलब है कि वे हार्ड-कोडित हो सकते हैं या आप उन्हें बनाने के लिए बिल्ट-इन का उपयोग कर सकते हैं।

  • यदि किसी कारण से यह आपकी भाषा में प्रयुक्त डिफ़ॉल्ट पूर्णांक प्रतिनिधित्व है। यह ठीक है।

  • जब तक यह आपकी भाषा का डिफ़ॉल्ट न हो आप किसी भी आर्बिट्रिश प्रिसिजन इंटेगर टाइप का उपयोग नहीं कर सकते हैं। यदि यह डिफ़ॉल्ट है, तो आप इसका उपयोग पूर्णांकों को संग्रहीत करने के लिए नहीं कर सकते हैं जो आमतौर पर 64 बिट्स में फिट नहीं होंगे।

  • स्पष्ट होने के लिए, प्रत्येक पूर्णांक को हमेशा संभव सबसे कम अवशेषों के साथ दर्शाया जाएगा। यह इनपुट और आउटपुट दोनों के लिए जाता है।

  • मुझे लगता है कि अन्य चश्मा को इसे रोकना चाहिए, लेकिन यह निरर्थक होना चाहिए: आप इनपुट पर दिए गए ऑपरेशन को निष्पादित नहीं कर सकते हैं और फिर आरएनएस और फिर आउटपुट में सब कुछ बदल सकते हैं। आपको इनपुट को RNS में बदलना होगा और फिर आउटपुट का उत्पादन करने के लिए ऑपरेशन करना होगा।

परीक्षण के मामलों

  1. इनपुट:

n = 10
m = 4
+

आउटपुट:

{ 0, 1, 0 } + { 0, 1 } = { 0, 2, 4 }

स्पष्टीकरण:

सबसे पहले, अपने आरएनएस प्रतिनिधित्व के लिए प्रत्येक संख्या को बदल दें जैसा कि ऊपर वर्णित है:

10 ~ {0,1,0}और 4 ~ {0,1}। ध्यान दें कि जब हम घटक-वार करना चाहते हैं, तो 10इससे अधिक घटक होते हैं 4। इसलिए हमें छोटी संख्या को "विस्तारित" करना होगा। इसलिए हम संक्षेप में लिखेंगे 4 ~ {0,1} --> {0,1, 4 mod 5} = {0,1,4}। अब हम इसके अलावा आगे बढ़ते हैं और फिर मापांक लेते हैं।

  1. इनपुट
n=28
m=18
+

आउटपुट:

 [ 0, 1, 3 ] + [0, 0, 3 ] = [ 0, 1, 1, 4 ]
  1. इनपुट (कीबोर्ड पर मेरा चेहरा मैशिंग करना)
n=1231725471982371298419823012819231982571923
m=1288488183
*

आउटपुट (पठनीयता के लिए अलग लाइनों पर टूटा हुआ):

[1, 2, 3, 6, 2, 10, 2, 1, 12, 16, 7, 15, 34, 29, 31, 5, 55, 32, 66, 61, 3, 76, 52, 14, 65, 44, 99, 57 ] 
* 
[1, 0, 3, 3, 4, 8, 9, 10, 8, 0 ] 
= 
[1, 0, 4, 4, 8, 2, 1, 10, 4, 0, 17, 7, 27, 21, 44, 51, 56, 9, 6, 9, 12, 0, 52, 36, 43, 68, 99, 24, 96, 39, 96, 66, 125] 

n28 अपराधों की आवश्यकता है। mआवश्यकता १०. n*m३३ की आवश्यकता है।

  1. इनपुट
n=8709668761379269784034173446876636639594408083936553641753483991897255703964943107588335040121154680170867105541177741204814011615930342030904704147856733048115934632145172739949220591246493529224396454328521288726490
m=1699412683745170450115957274739962577420086093042490863793456500767137147999161679589295549397604032154933975242548831536518655879433595016
-

आउटपुट:

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 509]
-
[0, 2, 1, 6, 1, 12, 11, 18, 14, 28, 21, 36, 37, 42, 16, 52, 41, 60, 16, 70, 49, 78, 80, 88, 49, 100, 13, 106, 4, 112, 68, 130, 36, 138, 37, 150, 0, 162, 8, 172, 163, 180, 18, 192, 129, 198, 135, 222, 78, 228, 90, 238, 57, 250, 36, 262, 87, 270, 206, 280, 193, 292, 253, 310, 224, 316, 57, 336, 48, 348]
=
[0, 1, 4, 1, 10, 1, 6, 1, 9, 1, 10, 1, 4, 1, 31, 1, 18, 1, 51, 1, 24, 1, 3, 1, 48, 1, 90, 1, 105, 1, 59, 1, 101, 1, 112, 1, 0, 1, 159, 1, 16, 1, 173, 1, 68, 1, 76, 1, 149, 1, 143, 1, 184, 1, 221, 1, 182, 1, 71, 1, 90, 1, 54, 1, 89, 1, 274, 1, 299, 1, 266, 1, 228, 1, 340, 1, 170, 1, 107, 1, 340, 1, 88, 1, 157, 1, 143, 1, 22, 1, 22, 1, 58, 1, 296, 1, 371, 1, 140]

n100 primes का उपयोग करता है। m70 primes का उपयोग करता है। n-m99 primes का उपयोग करता है।

मैंने ChineseRemGAP पर चीनी रेमिनेडर प्रमेय के अंतर्निहित कार्यान्वयन का उपयोग करके इनकी जाँच की (जो मूल रूप से RNS संख्या लेता है और उन्हें आधार 10 पूर्णांक में बदल देता है)। मेरा मानना ​​है कि वे सही हैं। अगर कुछ गड़बड़ लगता है, तो कृपया मुझे बताएं।


देखभाल करने वालों के लिए, पहले 100 primes का उत्पाद है:

471193079990618495316248783476026042202057477340967552018863483961641533584503
422120528925670554468197243910409777715799180438028421831503871944494399049257
9030720635990538452312528339864352999310398481791730017201031090

यह संख्या उस अधिकतम संख्या से 1 बड़ी है जिसे हम दिए गए सिस्टम (और 100 मुख्य सीमा) का उपयोग करके दर्शा सकते हैं।

कुछ हद तक संबंधित


मुझे लगता है कि ऑपरेशन करना सबसे कठिन हिस्सा है, जिसके लिए मैं इस चुनौती के बारे में अजीब महसूस करता हूं।
njpipeorgan

@njpipeorgan मैं सहमत हूं, (a,b,o)=>a.map((v,i)=>eval(v+o+b[i]))उदाहरण के लिए , प्रदर्शन केवल ES6 में है। मुझे लगता है कि सबसे कठिन हिस्सा शायद मनमानी परिशुद्धता अंकगणित का उपयोग किए बिना परिणाम का प्रतिनिधित्व करने के लिए आवश्यक अपराधों की संख्या पा रहा है, हालांकि आरएनएस के लिए बाद में रूपांतरण बिल्कुल तुच्छ नहीं है।
नील

क्या मेरे पास इस तरह का इनपुट हो सकता है ( 1234,1234,+)?
clismique

@derpfacePython हाँ फ़ंक्शंस स्वीकार्य हैं
Liam

"बस दिए गए संचालन घटक-वार प्रदर्शन" - तो आउटपुट में अतिरिक्त घटक कहाँ से आते हैं?
smls

जवाबों:


6

गैप

कुछ पृष्ठभूमि: मैं स्वीकार करूंगा कि जब मैंने यह प्रश्न बनाया था, तो कई महीनों पहले, मेरे पास इस प्रश्न के कठिन भाग को हल करने के लिए कोई तरीका नहीं था: उपयोग करने के लिए सही संख्या में प्रिम्स का निर्धारण। हमारे पास इस साइट पर बहुत सारे बुद्धिमान लोग हैं, और मुझे वास्तव में उम्मीद थी कि कोई व्यक्ति इसे जल्दी से करने का एक तरीका निकालेगा। हालाँकि, जैसा कि ऐसा नहीं हुआ, मुझे यकीन भी नहीं था कि इस समस्या को हल करना वास्तव में संभव है। इसलिए, मुझे एक विधि तैयार करने के लिए समय निकालना पड़ा। मेरा मानना ​​है कि मैंने जो भी किया है वह इस चुनौती के किसी भी नियम को नहीं तोड़ता है, निश्चित रूप से मैं इस तथ्य को जांचना पसंद करूंगा।

मुझे की पसंद पर भी थोड़ा अफसोस है क्योंकि समाधान आमतौर पर गहराई से अधिक होते हैं, जो आमतौर पर टैग प्रारूप में फिट होते हैं। साइट के नियमों का पालन करने के लिए, इस पोस्ट के निचले भाग में मेरे समाधान का एक "गोल्फ" संस्करण है।


कोड

### The first 100 primes;
primes := Primes{[1..100]};

### In many of the functions below, the 'string' variable is a string of digits
###


### Returns the 'index' digit of 'string' as an integer
GetValueAsInt := function(string, index) 
    return IntChar(string[index]) - 48;
end;

### Used in the 'modulus' function. See that comment for more information. 
### Calculates the contribution to the modulus of a digit 'digit' in the 10^power place.
### 'integer' is the modulus
digit_contribution := function(digit, integer, power)
    local result, i;
    result := 1;
    for i in [0..power-1] do
        result := ( result * (10 mod integer) ) mod integer;
    od;
    result := (result * (digit mod integer) ) mod integer;
    return result;
end;

### This modulus function is used to calculate the modulus of large numbers without storing them
##### as large numbers.
### It does so by breaking them into digits, and calculating the contribution of each digit.
### e.g. 1234 mod 5 = (1000 mod 5)(1 mod 5) + (200 mod 5)(2 mod 5) + (10 mod 5)(3 mod 5) + (4 mod 5)
### It actually mods after every calculation to ensure that we never get a number larger
##### than the modulus ('integer') squared, which will never be even close to 10^64-1
modulus := function(string, integer)
    local i, result, digit, len;
    len := Length(string);
    result := 0;
    for i in [1..len] do
        digit :=  IntChar(string[i]) -48;
        result := ( result + digit_contribution(digit, integer, len-i) )  mod integer;
    od;
    return result;
end;

### This returns the product of the first i-1 primes (mod j). It must not (and does not)
##### ever store an integer larger than 2^64-1
phi_i := function(i,j)
    local index, result;
    result := 1;
    for index in [1..i-1] do
        result := ( result * primes[index] ) mod primes[j];
    od;
    return result;
end;

### Calculates the first residues of 'string' mod the first 100 primes
get_residues := function(string) 
    local p, result;
    result := [];
    for p in primes do
        Add( result, modulus(string, p) );  
    od; 
    return result;
end;

### Gets the ith element in the partial_chinese array, given the previous elements
### See the explanation section and partial_chinese function for more info
get_partial_i := function( i, residues, previous_array )
    local index, result;
    result := residues[i];
    for index in [1..Length(previous_array)] do
        result := ( result - previous_array[index]*phi_i(index,i) ) mod primes[i]; 
    od;     
    result := ( result / phi_i(i,i) ) mod primes[i];
    return result;
end;

### returns an array such that the sum of prod_primes(i)*array[i] is equal to the integer value
##### that is represented by the residues. (It basically just does the CRT without
##### actually summing everything.) prod_primes(i) is the product of the first i-1 primes 
### See the explanation for a bit more info
### This is what allows us to determine the minimal number of primes to represent a RNS number
partial_chinese := function( string )
    local array, i, residues;
    residues := get_residues(string);
    array := [];        
    for i in [1 .. Length(primes)] do
        Add( array, get_partial_i( i, residues, array ) );
    od;
    return array;   
end;

### Same as partial_chinese but takes input in a different form.
partial_chinese_from_residues := function(residues)
    local array, i;
    array := [];        
    for i in [1 .. Length(primes)] do
        Add( array, get_partial_i( i, residues, array ) );
    od;
    return array;
end;

### gives you the number of primes needed to represent an integer. Basically asks how 
##### many trailing zeros there are in the chinese array.
get_size := function(string)
    local array, i, len, result;
    array := partial_chinese(string);
    len := Length(array);
    for i in [0..len-1] do
        if  not (array[len-i] = 0) then
            return len -i;
        fi; 
    od; 
    Print("ERROR: get_size().\n");
    return 0;
end;

### Same as above but with different input format
get_size_from_residues := function(residues)
    local array, i, len, result;
    array := partial_chinese_from_residues(residues);
    len := Length(array);
    for i in [0..len-1] do
        if  not (array[len-i] = 0) then
            return len -i;
        fi; 
    od; 
    Print("ERROR: get_size().\n");
    return 0;
end;

### the actual function. inputs are all strings
f := function(in1, in2, opperation)
    local residues_1, residues_2, residues_result, i;
    residues_1 := get_residues(in1);
    residues_2 := get_residues(in2);
    residues_result := [];
    if opperation = "+" then
        for i in [1..Length(primes)] do
            Add( residues_result, ( residues_1[i] + residues_2[i] ) mod primes[i]);
        od;     
    elif opperation = "*" then
        for i in [1..Length(primes)] do
            Add( residues_result, ( residues_1[i] * residues_2[i] ) mod primes[i]);
        od;     
    elif opperation = "-" then
        for i in [1..Length(primes)] do
            Add( residues_result, ( residues_1[i] - residues_2[i] ) mod primes[i]);
        od;     
    fi;
    Print(residues_1{[1..get_size(in1)]}, " ", opperation, " ", residues_2{[1..get_size(in2)]}, " = ", residues_result{[1..get_size_from_residues(residues_result)]} );
end;

स्पष्टीकरण:

शुरू करने के लिए, हम दोनों इनपुट के लिए सभी 100 अवशेषों की गणना करते हैं। हम modulusकोड में फ़ंक्शन के साथ ऐसा करते हैं । मैंने सावधान रहने की कोशिश की ताकि हम modहर कदम के बाद अंतर्निहित फ़ंक्शन का उपयोग करें । यह सुनिश्चित करता है कि हमारे पास कभी भी एक संख्या नहीं है 540^2जो इससे बड़ा है , जो कि 100 वें प्रमुख वर्ग से 1 कम है।

हमारे पास सभी अवशेष होने के बाद, हम दिए गए ऑपरेशन और modप्रत्येक प्रविष्टि को फिर से कर सकते हैं । अब हमारे पास परिणाम के लिए एक अद्वितीय डिज़ाइनर है, लेकिन हमें उन प्रविष्टियों की न्यूनतम संख्या निर्धारित करने की आवश्यकता है जिनका उपयोग हमें परिणाम और प्रत्येक इनपुट का प्रतिनिधित्व करने के लिए करना है।

यह पता लगाना कि हमें वास्तव में कितने अवशेषों की आवश्यकता है, इस समस्या का सबसे कठिन हिस्सा है। इसे निर्धारित करने के लिए, हम चीनी अवशेष प्रमेय (CRT) के अधिकांश चरणों का निष्पादन करते हैं। हालाँकि, हमें स्पष्ट रूप से संशोधन करना होगा ताकि हम उन संख्याओं के साथ समाप्त न हों जो बहुत बड़ी हैं।

prod(i)पहले योगों का योग होने दें i-1। उदाहरण के लिए,

prod(1) = 1
prod(2) = 2
prod(3) = 6
prod(4) = 30
etc

आज्ञा देना Xपूर्णांक है। आज्ञा देना {r_i}के अवशेष हो X, वह यह है कि

r_i = X mod p_i

कहाँ p_iहै iवें प्रधानमंत्री। यह 1<i<=100हमारे मामले में है।

अब हम एक दृश्य को खोजने के लिए सीआरटी उपयोग करने के लिए जा रहे हैं {u_i}ऐसी है कि अधिक राशि iके prod(i) * u_iलिए बराबर है X। ध्यान दें कि प्रत्येक u_iभी तकनीकी रूप से एक अवशेष है, जैसा कि u_i < p_i। इसके अलावा, यदि X < prod(i)तब u_i = 0। यह महत्वपूर्ण महत्व का है। इसका मतलब है कि अनुगामी शून्य की जांच करके, हम यह निर्धारित कर सकते हैं कि r_iहमें वास्तव में कितने अवशेषों Xको आरएनएस में प्रतिनिधित्व करने की आवश्यकता है ।

यदि आप कुछ दृश्यों की जांच करना चाहते हैं u_i, तो partial_chineseफ़ंक्शन अनुक्रम को वापस कर देता है u_i

CRT के साथ खिलवाड़ करके, मैं u_iमूल्यों के लिए एक पुनरावर्ती सूत्र ढूंढने में सक्षम था , यह निर्धारित करने के मुद्दे को हल करके कि हमें कितने अवशेषों की आवश्यकता है।

सूत्र है:

u_i = [ r_i - SUM ] / prod(i)       (mod p_i)

कहाँ SUMसे अधिक योग है j in [1,i)की u_j * prod(i)

बेशक, prod(i)वास्तव में कुछ मामलों में गणना नहीं की जा सकती क्योंकि यह बहुत बड़ी है। इस उद्देश्य के लिए, मैंने phi_iफ़ंक्शन का उपयोग किया । यह फ़ंक्शन देता है prod(j) (mod p_i)। यह modहर कदम पर है, इसलिए हम वास्तव में कभी भी बहुत बड़ी चीज की गणना नहीं करते हैं।

यदि आप उत्सुक हैं कि यह सूत्र कहां से आता है, तो मैं CRT उदाहरणों के एक जोड़े को काम करने की सलाह दूंगा, जो विकिपीडिया पृष्ठ पर पाया जा सकता है ।

अंत में, प्रत्येक इनपुट के साथ-साथ हमारे आउटपुट के लिए, हम u_iअनुक्रम की गणना करते हैं और फिर अनुगामी शून्य का निर्धारण करते हैं। फिर हम r_iअवशेष अनुक्रमों के अंत में से कई को बाहर फेंक देते हैं ।


"गॉकेटेड" कोड, 2621 बाइट्स

primes:=Primes{[1..100]};GetValueAsInt:=function(string,index)return IntChar(string[index])-48;end;digit_contribution := function(digit, integer, power)local result, i;result:=1;for i in [0..power-1] do result := ( result * (10 mod integer) ) mod integer;od;result:=(result*(digit mod integer) ) mod integer;return result;end;modulus:=function(string, integer)local i,result,digit,len;len:=Length(string);result:=0;for i in [1..len] do digit:= IntChar(string[i])-48;result:=(result+digit_contribution(digit,integer,len-i)) mod integer;od;return result;end;phi_i:=function(i,j)local index,result;result:=1;for index in [1..i-1] do result:=(result*primes[index] ) mod primes[j];od;return result;end;get_residues:=function(string) local p,result;result:=[];for p in primes do Add(result,modulus(string,p));od;return result;end;get_partial_i:=function(i,residues,previous_array)local index,result;result:=residues[i];for index in [1..Length(previous_array)] do result:=(result-previous_array[index]*phi_i(index,i) ) mod primes[i];od;result:=(result/phi_i(i,i)) mod primes[i];return result;end;partial_chinese:=function(string)local array,i,residues;residues:=get_residues(string);array:=[];for i in [1 .. Length(primes)] do Add(array,get_partial_i(i,residues,array));od;return array;end;partial_chinese_from_residues:=function(residues)local array,i;array:=[];for i in [1..Length(primes)] do Add(array,get_partial_i(i,residues,array));od;return array;end;get_size:=function(string)local array,i,len,result;array:=partial_chinese(string);len:=Length(array);for i in [0..len-1] do if not (array[len-i] = 0) then return len-i;fi;od;Print("ERROR: get_size().\n");return 0;end;get_size_from_residues:=function(residues)local array,i,len,result;array:=partial_chinese_from_residues(residues);len:=Length(array);for i in [0..len-1] do if not (array[len-i]=0) then return len-i;fi;od;Print("ERROR: get_size().\n");return 0;end;f:=function(in1,in2,opperation)local residues_1,residues_2,residues_result,i;residues_1:=get_residues(in1);residues_2:=get_residues(in2);residues_result:=[];if opperation = "+" then for i in [1..Length(primes)] do Add(residues_result,(residues_1[i]+residues_2[i] ) mod primes[i]);od;elif opperation = "*" then for i in [1..Length(primes)] do Add(residues_result,(residues_1[i]*residues_2[i])mod primes[i]);od;elif opperation = "-" then for i in [1..Length(primes)] do Add(residues_result,(residues_1[i]-residues_2[i]) mod primes[i]);od;fi;Print(residues_1{[1..get_size(in1)]}, " ", opperation, " ", residues_2{[1..get_size(in2)]}, " = ", residues_result{[1..get_size_from_residues(residues_result)]} );end;

मैं उलझन में हूं क्योंकि नियमित आरएनएस जरूरत के अनुसार आयाम नहीं बदलता है, लेकिन क्या आप इनपुट से विस्तारित 100 अवशेष संख्या की गणना करके नियमों को नहीं मोड़ते हैं, बजाय केवल आवश्यक आयामों के और फिर संचालन करते हैं? "सबसे पहले, प्रत्येक संख्या को इसके RNS प्रतिनिधित्व के रूप में ऊपर वर्णित करें " मेरे लिए इसका मतलब है कि 'RNS' संख्या में कुछ भी होने से पहले केवल आवश्यक अवशेष होना चाहिए।
लाइनस

क्षमा करें @Linus, मैंने सोचा कि मैंने पहले ही इसका जवाब दिया। मैं आपसे सहमत हूं, लेकिन मुझे लगता है कि आवश्यक परिवर्तन (जो मैं करूंगा) अपेक्षाकृत तुच्छ है। जैसा कि मैं इसे देखता हूं, मुझे ऑपरेशन करने से पहले इनपुट की अवशेष लंबाई की गणना करने की आवश्यकता है। सभी तीन नंबरों के लिए सभी 100 प्राइम का उपयोग करके केवल इस तथ्य का लाभ उठाया जाता है कि सभी संख्याएं ऊपर से बंधी हुई हैं
Liam

@ लिनुस और आपके पहले प्रश्न के उत्तर में, आमतौर पर सभी संख्याएँ एक ही संख्या में अवशेषों का उपयोग करती हैं। इससे प्रश्न बहुत सरल हो जाएगा
Liam

2

गणितज्ञ, गोल्फ नहीं

rns[d_,l_]:=Table[Reap[
    FoldPairList[Sow@QuotientRemainder[10#+#2,Prime@i]&,0,d]
  ][[2,1,-1,2]],{i,l}];
plus[a_,b_]:=Mod[a+b,Prime@Range@Length@a];
subtract[a_,b_]:=Mod[a-b,Prime@Range@Length@a];
times[a_,b_]:=Mod[a b,Prime@Range@Length@a];
mag[f_]:=LengthWhile[FoldList[#/#2&,f,Prime@Range@100],#>1.1&];
ext[m_,n_,i_]:=Fold[Mod[1##,Prime@i]&,m,Prime@Range@n];
multi[e_,p_,t_]:=Tr@Position[Mod[e Range@p,p],p-t];
appx[d_] := N@FromDigits[{d~Take~UpTo[6], Length@d}]
  • फ़ंक्शन rns[d_,l_]आधार -10 पूर्णांक dको RNS पूर्णांक लंबाई में परिवर्तित करता है l

  • फ़ंक्शन plus/ times/ subtractजोड़ / गुणा / एक RNS पूर्णांक को दूसरे से / से घटाएं, जो दोनों एक ही लंबाई के हैं।

  • फ़ंक्शन आरएनएस प्रतिनिधित्व की लंबाई के निचले हिस्से के संदर्भ में mag[f_]फ्लोटिंग पॉइंट संख्या के अनुमानित परिमाण का अनुमान लगाता है f

  • समारोह ext[m_,n_,i_]के उत्पाद के विभाजन से शेष पता चल गया mऔर Prime[Range@n]द्वारा Prime[i]

  • फंक्शन multi[e_,p_,t_]सबसे छोटे गुणक को mसंतुष्ट करता हैDivisible[m*e+t,p]

  • फ़ंक्शन एक दशमलव पूर्णांक appx[d_]के पहले 6अंक लेते हैं और इसकी अनुमानित फ्लोटिंग पॉइंट वैल्यू देते हैं।


उपरोक्त कार्यों की मदद से, अब हम एक मुश्किल समस्या को हल करने में सक्षम हैं - परिणाम की लंबाई निर्धारित करने के लिए

सबसे पहले, मुझे स्पष्ट करना होगा कि पूर्णांक की आरएनएस लंबाई निर्धारित करना आसान काम नहीं है। छोटे पूर्णांकों के लिए, हम उन्हें सीधे primes के उत्पाद के साथ तुलना कर सकते हैं। लेकिन बहुत बड़े पूर्णांकों के लिए, क्योंकि यह आमतौर पर सटीक रूप से सटीक अपराधों के उत्पाद की गणना करने के लिए मना किया जाता है, इस तरह की तुलना अब काम नहीं करती है।

उदाहरण के लिए, यह देखते हुए कि प्राइम 1का उत्पाद 30है 3.16*10^46, लगभग पूर्णांकों की RNS लंबाई 3.16*10^46संभवतः 29या हो सकती है 30। फ़ंक्शन इन पूर्णांकों के लिए एक संदर्भ के रूप में magदेगा 29, यह दर्शाता है कि दोनों 29और 30संभव हैं।

एक बार परिमाण जानने के बाद, हम सीधे उस परिमाण के अनुसार पूर्णांक का प्रतिनिधित्व करते हैं, इसकी वास्तविक लंबाई की गणना करने की उम्मीद करते हैं। यहां ट्रिक मूल संख्या में कुछ नए नंबर जोड़ने और अपने RNS प्रतिनिधित्व को संशोधित करने के लिए है, जब तक कि प्रतिनिधित्व सभी शून्य न हो।

उदाहरण के लिए, mag[211.]है 4, और इसकी लंबाई 4प्रतिनिधित्व है {1, 1, 1, 1}

step 1:   {1,1,1,1} -> {0,2,2,2}  by adding  (1) * 1 = 1
step 2:   {0,2,2,2} -> {0,0,1,6}  by adding  (2) * 2 = 4
step 3:   {0,0,1,6} -> {0,0,0,2}  by adding  (2*3) * 4 = 24
step 4:   {0,0,0,2} -> {0,0,0,0}  by adding  (2*3*5) * 6 = 180
step 5:   calculate 211 + (1 + 4 + 24 + 180) ~ 420

कुछ संख्याओं को जोड़कर, हम 211उस छोटी संख्या में वृद्धि करते हैं जो 210( 2*3*5*7) द्वारा विभाज्य है । और अब हम निष्कर्ष निकालते हैं कि मूल संख्या इससे अधिक है 210, क्योंकि 420"लगभग" दो बार के बराबर है 210। यह कल्पना करना मुश्किल नहीं है कि अगर हम से शुरू करते हैं 209, तो अंतिम संख्या "लगभग" है 210

कार्य परिमाण का अनुमान लगाने के लिए length[f_,n_]फ्लोटिंग पॉइंट वैल्यू लेता है f, और इसके RNS प्रतिनिधित्व के आधार पर इसे सही करता है n

length[f_,n_]:=With[{g=mag@f},
    g+If[#==0,1,Round[(#+f)/Times@@Prime@Range@g]-1]&[
      FoldList[Times,1.,Prime[Range[g-1]]].
      FoldPairList[
        Block[{i=#2,m},
          {m=multi[ext[1,i-1,i],Prime@i,Part@##],rnsPlus[#,ext[m,i-1,#]&/@Range[g]]}
        ]&,n,Range[g]]]]

फ्लोटिंग पॉइंट वैल्यू के आधार पर अनुमानित परिणाम प्राप्त करने के लिए फ़ंक्शन सामान्य rnsOperation[a_,b_,op_,rnsop_]देता है rnsop[a,b]और opइसी सामान्य ऑपरेशन का उपयोग किया जाता है।

rnsOperation[a_,b_,op_,rnsop_]:=Block[{c=op[appx@a,appx@b],m},
    m=mag[c];m=length[c,rnsop[rns[a,m],rns[b,m]]];rnsop[rns[a,m],rns[b,m]]]

उदाहरण

rnsOperation[
    IntegerDigits@1231725471982371298419823012819231982571923,
    IntegerDigits@1288488183,
    Times, times]
(* {1,0,4,4,8,2,1,10,4,0,17,7,27,21,44,51,56,9,6,9,12,0,52,36,43,68,99,24,96,39,96,66,125} *)

1
दुर्भाग्य से, हमारे सहायता केंद्र में उल्लिखित नियमों को उपयोग में जीतने के मानदंडों के लिए एक गंभीर दावेदार होने के लिए सभी प्रस्तुतियाँ की आवश्यकता होती है। एक कोड गोल्फ प्रतियोगिता के लिए, इसका मतलब है कि सभी प्रस्तुतियाँ गोल्फ होनी चाहिए।
डेनिस

@ डेनिस मैं इस नियम के बारे में जानता हूं। हालांकि, गोल्फिंग के बिना भी, मुझे लगता है कि यह समस्या काफी कठिन और जटिल है, इसलिए कि गोल्फिंग के बजाय इस समस्या को हल करना मेरा उद्देश्य है।
njpipeorgan

यह शायद मेरे जावा प्रोग्राम की तुलना में छोटा नहीं है लेकिन लानत है: पी, हालांकि मेरा प्रोग्राम शायद बहुत तेज है।
उम्मीद है कि

1
मुझे ऐसा लगता है कि आप इसे गोल्फ करने में सक्षम हैं
रोहन झुनझुनवाला

2

पायथन 3 , 435 बाइट्स

यह चुनौती कुछ समय के लिए मेरी बकेट लिस्ट में रही है, लेकिन यह हाल ही की बात है: क) मैंने वास्तव में उत्तर देने के लिए समय और ध्यान दिया; और ख) वास्तव में लघुगणकों और चीनी अवशेष प्रमेय के कुछ अपवित्र संयोजन का उपयोग करके संख्याओं के आकार की गणना करने के लिए मेरे विचार का परीक्षण किया गया है (और प्राइमरों के आकार की तुलना करके संख्याओं की संख्या)। दुर्भाग्य से, उन लकड़ियों की संख्या निर्धारित करने की कोशिश करते हुए, जो उदाहरण के लिए, large_primorial + 3आवश्यकता होती है, इसका मतलब है कि मुझे फ्लोटिंग-पॉइंट समस्याओं के आसपास काम करने के तरीके खोजने थे।

और इसलिए, यह लियाम के उत्तर का एक बंदरगाह है ।

इसे ऑनलाइन आज़माएं!

from functools import reduce as R
G=range
d=lambda s:[R(lambda z,c:(z*10+int(c))%q,s,0)for q in p]
h=lambda j,i:R(lambda z,q:z*q%p[i],p[:j],1)
def s(r):
 a=[];z=99
 for i in G(100):
  P=p[i];u=r[i]
  for j in G(len(a)):u=(u-a[j]*h(j,i))%P
  for k in G(1,P):
   if h(i,i)*k%P<2:break
  a+=u*k%P,
 while(a[z]<1)*z:z-=1
 return r[:z+1]
def f(a,b,n):u=d(a);v=d(b);print(s(u),n,s(v),'=',s([eval(str(u[i])+n+str(v[i]))%p[i]for i in G(100)]))

व्याख्या

लियाम के जवाब को पोर्ट करने की कोशिश करते हुए, मैंने व्यक्तिगत रूप से पाया कि स्पष्टीकरण में से कुछ को भ्रमित किया गया था, इसलिए यह उनके एल्गोरिदम को समझाने का मेरा प्रयास है।

सबसे पहले, हम के अवशेष प्राप्त nऔर m

res1 = get_residues(n)
res2 = get_residues(m)

इसमें इनपुट स्ट्रिंग्स के सभी अंकों को मोड़ना और उन्हें 28 में से प्रत्येक के लिए हमारे सभी अपराधों की संख्याओं में बदलना है। [(20 + 8) mod 2, (20 + 8) mod 3, (20 + 8) mod 5, etc]

def get_residues(string):
    result = []
    for p in primes:
        result.append(reduce(lambda z, c:(z*10+int(c)) % p, string, 0))

फिर हम जोड़ियों को जोड़कर, गुणा करके या घटाकर जोड़ते हैं eval()

result = []
for i in range(len(primes)):
    result.append((eval(str(res1[i]) + op + str(res2[i])) % primes[i])

तब हमें अपने अवशेषों के आकार मिलते हैं, यानी हमें जिन न्यूनतम प्राइम्स की जरूरत होती है।

size1 = get_size(res1)
size2 = get_size(res2)
size3 = get_size(result)

आकार प्राप्त करना सबसे कठिन और सबसे कोड-गहन हिस्सा है। हम partial_chineseफ़ंक्शन का उपयोग करते हैं, जो हमें u_iआकार के साथ निर्धारित करने के लिए हमारे अनुक्रम प्राप्त करता है। u_iएक पल में अधिक ।

def get_size(residues):
    array = partial_chinese(residues)
    size = len(residues)-1
    while array[size] == 0 and size:
        size -= 1
    return size+1  # to prevent off-by-one errors from 0-indexing

अनुक्रम u_iकी गणना प्रत्येक अवशेषों को लेने r_i, योग को घटाने u_j * primorial(j) for j in [1, i), और फिर सभी मॉडुलो dividingद्वारा की जाती है । यही कारण है, । एक पल में हमारे प्राचीन और विभाजन कार्यों पर अधिक।primorial(i)primes[i]u_i = (r_i - SUM) / primorial(i)

def partial_chinese(residues):
    array = []
    for i in range(len(primes)):
        array.append(get_partial_i(i, residues, array))
    return array

def get_partial_i(i, residues, previous_array):
    result = residues[i]
    for j in range(len(previous_array)):
        result = (result - previous_array[j] * phi_i(j, i)) % primes[i]
    result = result * inverse(phi_i(i, i), primes[i]) % primes[i]
    return result

phi_i(j, i)गणना करता है primorial(j) mod primes[i]। डिवीजन सापेक्ष किसी भी प्रधानमंत्री pको आसानी से मैन्युअल रूप से गुणक प्रतिलोम के लिए जाँच द्वारा कार्यान्वित किया जाता के रूप में हम यह सुनिश्चित करें कि किसी भी संभव हो सकता है u_iकर रहा है 0 <= u_i < pपी coprime होने की गारंटी है और इसलिए एक गुणक उलटा की गारंटी है।

def phi_i(j, i):
    return reduce(lambda z, q: z * q % primes[i], primes[:j], 1)

def inverse(n, p):
    for i in range(1, p):
        if n * i % p == 1:
            return i

उस सब के साथ, हम अपना स्ट्रिंग प्रिंट करते हैं और हम कर रहे हैं।

print(res1[:size1], op, res2[:size2], "=", result[:size3])

आगे क्या होगा

इसे लागू करने में मजा आया। मैं अभी भी यह देखना चाहता हूं कि क्या मैं किसी अन्य उत्तर में किसी तरह से लघुगणक का उपयोग कर सकता हूं। और मैं इस कोड को लागू करना चाहता हूं या एक कार्यात्मक गोल्फ भाषा में एपीएल या जेली की तरह कुछ करना। किसी भी और सभी गोल्फ सुझाव और सुधार का स्वागत करते हैं!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.