Modulo ऑपरेटर (%) C # में विभिन्न .NET संस्करणों के लिए एक अलग परिणाम देता है


89

मैं पासवर्ड के लिए स्ट्रिंग बनाने के लिए उपयोगकर्ता के इनपुट को एन्क्रिप्ट कर रहा हूं। लेकिन कोड की एक पंक्ति फ्रेमवर्क के विभिन्न संस्करणों में अलग-अलग परिणाम देती है। उपयोगकर्ता द्वारा दबाए गए कुंजी के मूल्य के साथ आंशिक कोड:

मुख्य दबाया गया: 1. चर ascii49 है। कुछ गणना के बाद 'ई' और 'एन' का मूल्य:

e = 103, 
n = 143,

Math.Pow(ascii, e) % n

उपरोक्त कोड का परिणाम:

  • .NET 3.5 (C #) में

    Math.Pow(ascii, e) % n

    देता है 9.0

  • .NET 4 (C #) में

    Math.Pow(ascii, e) % n

    देता है 77.0

Math.Pow() दोनों संस्करणों में सही (समान) परिणाम देता है।

क्या कारण है, और क्या कोई समाधान है?


12
बेशक, सवाल के दोनों जवाब गलत हैं। तथ्य यह है कि आप इस बारे में परवाह नहीं करते हैं, अच्छी तरह से, चिंताजनक है।
डेविड हेफर्नन

34
आपको कई कदम पीछे जाने की जरूरत है। "मैं पासवर्ड के लिए स्ट्रिंग बनाने के लिए उपयोगकर्ता के इनपुट को एन्क्रिप्ट कर रहा हूं" यह हिस्सा पहले से ही संदिग्ध है। आप वास्तव में क्या करना चाहते हैं? क्या आप एन्क्रिप्टेड या हैशेड फॉर्म में पासवर्ड स्टोर करना चाहते हैं? क्या आप यादृच्छिक मूल्य उत्पन्न करने के लिए इसे एन्ट्रॉपी के रूप में उपयोग करना चाहते हैं? आपके सुरक्षा लक्ष्य क्या हैं?
कोडइन्चोस

49
हालांकि यह प्रश्न फ्लोटिंग पॉइंट अंकगणित के साथ एक दिलचस्प मुद्दे को दिखाता है, अगर ओपी का लक्ष्य "पासवर्ड के लिए स्ट्रिंग उत्पन्न करने के लिए उपयोगकर्ता के इनपुट को एन्क्रिप्ट करना" है, तो मुझे नहीं लगता कि अपना स्वयं का एन्क्रिप्शन रोल करना एक अच्छा विचार है, इसलिए मैं अनुशंसा नहीं करूंगा वास्तव में किसी भी उत्तर को लागू करना।
हैरिसन पाइन

18
अच्छा प्रदर्शन क्यों अन्य भाषाओं में %फ़्लोटिंग-पॉइंट संख्याओं के उपयोग से मना किया गया है ।
बेन वोइगट

5
हालांकि उत्तर अच्छे हैं, उनमें से कोई भी इस सवाल का जवाब नहीं देता है कि .NET 3.5 और 4 के बीच क्या बदलाव आया है जो अलग व्यवहार का कारण बन रहा है।
एमएसएल

जवाबों:


160

Math.Powडबल-सटीक फ़्लोटिंग-पॉइंट संख्या पर काम करता है; इस प्रकार, आपको सटीक होने के लिए परिणाम के पहले 15-17 अंकों से अधिक की उम्मीद नहीं करनी चाहिए :

सभी फ़्लोटिंग-पॉइंट नंबरों में भी सीमित संख्या में महत्वपूर्ण अंक होते हैं, जो यह भी निर्धारित करता है कि फ़्लोटिंग-पॉइंट मान वास्तव में एक वास्तविक संख्या का अनुमान कैसे लगाता है। एक Doubleमान सटीकता के 15 दशमलव अंकों तक होता है, हालांकि आंतरिक रूप से अधिकतम 17 अंक बनाए जाते हैं।

हालांकि, मोडुलो अंकगणित को सटीक होने के लिए सभी अंकों की आवश्यकता होती है। आपके मामले में, आप ४ १० की गणना कर रहे हैं , जिसके परिणाम में ,५ अंक होते हैं, जिससे आपके दोनों उत्तरों में मोडुलो ऑपरेशन व्यर्थ हो जाता है।

सही मान का पता लगाने के लिए, आपको मनमानी-सटीक अंकगणित का उपयोग करना चाहिए, जैसा कि BigIntegerकक्षा द्वारा प्रदान किया गया है (.NET 4.0 में प्रस्तुत किया गया है)।

int val = (int)(BigInteger.Pow(49, 103) % 143);   // gives 114

संपादित करें : जैसा कि नीचे की टिप्पणियों में मार्क पीटर्स द्वारा कहा गया है, आपको इस BigInteger.ModPowपद्धति का उपयोग करना चाहिए , जो विशेष रूप से इस तरह के ऑपरेशन के लिए करना है:

int val = (int)BigInteger.ModPow(49, 103, 143);   // gives 114

20
वास्तविक समस्या को इंगित करने के लिए +1, अर्थात् प्रश्न में कोड गलत है
डेविड हेफर्नन

36
यह ध्यान देने योग्य है कि BigInteger इस ऑपरेशन के लिए लगभग 5 गुना तेजी से एक ModPow () विधि प्रदान करता है (जो अभी मेरे त्वरित परीक्षण में) करता है।
मार्क पीटर्स

8
+1 संपादित के साथ। ModPow सिर्फ तेज नहीं है, यह संख्यात्मक रूप से स्थिर है!
रे

2
@ मेकर नहीं, उत्तर अर्थहीन है , अमान्य नहीं है ।
कोड़ी ग्रे

3
@ makerofthings7: मैं सिद्धांत रूप में आपसे सहमत हूं। हालांकि, संसेचन फ्लोटिंग-पॉइंट अंकगणित के लिए अंतर्निहित है, और डेवलपर्स को सामान्य रूप से संचालन पर प्रतिबंध लगाने की तुलना में जोखिमों के बारे में जागरूक होने की अपेक्षा करना अधिक व्यावहारिक माना जाता है। अगर कोई सही मायने में "सुरक्षित" होना चाहता था, तो भाषा को भी फ्लोटिंग-पॉइंट समानता की तुलना करने से रोकना होगा, ताकि 1.0 - 0.9 - 0.1 == 0.0मूल्यांकन करने जैसे अप्रत्याशित परिणामों से बचा जा सके false
डगलस

72

इस तथ्य के अलावा कि आपका हैशिंग फ़ंक्शन बहुत अच्छा नहीं है * , आपके कोड के साथ सबसे बड़ी समस्या यह नहीं है कि यह .NET के संस्करण के आधार पर एक अलग संख्या लौटाता है, लेकिन यह कि दोनों ही मामलों में यह पूरी तरह से व्यर्थ संख्या देता है: समस्या का सही उत्तर है

49 103 मॉड 143 = 114 है। ( वुल्फराम अल्फा के लिए लिंक )

इस उत्तर की गणना करने के लिए आप इस कोड का उपयोग कर सकते हैं:

private static int PowMod(int a, int b, int mod) {
    if (b == 0) {
        return 1;
    }
    var tmp = PowMod(a, b/2, mod);
    tmp *= tmp;
    if (b%2 != 0) {
        tmp *= a;
    }
    return tmp%mod;
}

आपके गणना करने का एक अलग परिणाम उत्पन्न करने का कारण यह है कि एक उत्तर का उत्पादन करने के लिए, आप एक मध्यवर्ती मान का उपयोग करते हैं जो 49 103 नंबर के अधिकांश महत्वपूर्ण अंकों को गिराता है : इसके 175 अंकों में से केवल पहले 16 सही हैं!

1230824813134842807283798520430636310264067713738977819859474030746648511411697029659004340261471771152928833391663821316264359104254030819694748088798262075483562075061997649

शेष 159 अंक सभी गलत हैं। हालाँकि, मॉड ऑपरेशन, एक परिणाम की तलाश करता है जिसके लिए हर एक अंक को सही होना आवश्यक है, जिसमें बहुत अंतिम वाले भी शामिल हैं। इसलिए, यहां तक ​​कि शुद्धतम में सबसे बेहतर सुधार Math.Pow.NET 4 में लागू किया गया हो सकता है, जिसके परिणामस्वरूप आपकी गणना में भारी अंतर होगा, जो अनिवार्य रूप से एक मनमाना परिणाम पैदा करता है।

* चूंकि यह सवाल पासवर्ड हैशिंग के संदर्भ में उच्च शक्तियों के पूर्णांक को बढ़ाने के बारे में बात करता है, इसलिए यह निर्णय लेने से पहले इस उत्तर लिंक को पढ़ना एक बहुत अच्छा विचार हो सकता है कि क्या आपके वर्तमान दृष्टिकोण को संभावित रूप से बेहतर के लिए बदल दिया जाना चाहिए।


20
अच्छा उत्तर। वास्तविक बिंदु यह है कि यह एक भयानक हैश फ़ंक्शन है। ओपी को समाधान पर पुनर्विचार करने और अधिक उपयुक्त एल्गोरिथ्म का उपयोग करने की आवश्यकता है।
david.pfx

1
आइजैक न्यूटन: क्या यह संभव है कि चंद्रमा पृथ्वी पर उसी तरह आकर्षित हो जिस तरह से सेब पृथ्वी की ओर आकर्षित होता है? @ david.pfx: असली मुद्दा यह है कि यह सेब लेने का एक भयानक तरीका है। न्यूटन को समाधान पर पुनर्विचार करने की आवश्यकता है और शायद एक आदमी को सीढ़ी के साथ काम पर रखना है।
jwg

2
@jwg डेविड की टिप्पणी को एक कारण के लिए कई upvotes मिले। मूल प्रश्न ने यह स्पष्ट कर दिया कि एल्गोरिथ्म का उपयोग हैश पासवर्ड के लिए किया जा रहा था, और यह वास्तव में उस उद्देश्य के लिए एक भयानक एल्गोरिथ्म है - यह .NET फ्रेमवर्क के संस्करणों के बीच टूटने की अत्यधिक संभावना है, जैसा कि पहले ही प्रदर्शित किया जा चुका है। कोई भी उत्तर जो यह उल्लेख नहीं करता है कि ओपी को अपने एल्गोरिथ्म को "फिक्स" करने के बजाय बदलने की आवश्यकता है, यह उसे एक असंतोष कर रहा है।
क्रिस

@ क्रिस टिप्पणी के लिए धन्यवाद, मैंने डेविड के सुझाव को शामिल करने के लिए संपादन किया। मैंने इसे आप के रूप में दृढ़ता से शब्द नहीं दिया, क्योंकि ओपी की प्रणाली एक खिलौना या कोड का एक फेंक-दूर का टुकड़ा हो सकता है जिसे वह अपने स्वयं के मनोरंजन के लिए बनाता है। धन्यवाद!
dasblinkenlight

27

आपको जो दिखाई दे रहा है, वह दोहरीकरण में त्रुटि है। Math.Powडबल और अंतर के साथ काम करता है:

.NET 2.0 और 3.5 => var powerResult = Math.Pow(ascii, e);रिटर्न:

1.2308248131348429E+174

.NET 4.0 और 4.5 => var powerResult = Math.Pow(ascii, e);रिटर्न:

1.2308248131348427E+174

अंतिम अंक को पहले देखें Eऔर इससे परिणाम में अंतर आ रहा है। यह मापांक ऑपरेटर नहीं है (%)


3
पवित्र गाय यह ओपीएस प्रश्न का केवल उत्तर है? मैंने सभी मेटा "blah blah security गलत सवाल पढ़ा है, जिसे मैं आपसे अधिक n00b जानता हूं" और फिर भी सोचता रहा कि "3.5 और 4.0 के बीच निरंतर विसंगति क्यों है? कभी चंद्रमा को देखते हुए आपके पैर की अंगुली को पत्थर पर मार दिया और पूछा कि किस तरह की चट्टान है? क्या यह है? "केवल यह बताया जाए कि" आपकी असली समस्या आपके पैरों में नहीं दिख रही है "या" एक रात में घर पर बने सैंडल पहनने पर आप क्या उम्मीद करते हैं? !!! "धन्यवाद!
माइकल पॉलुकोनिस

1
@MichaelPaulukonis: यह एक झूठी सादृश्य है। चट्टानों का अध्ययन एक वैध खोज है; स्थाई-सटीक डेटा प्रकारों का उपयोग करके मनमानी-सटीक अंकगणित का प्रदर्शन करना केवल सादा गलत है। मैं इसकी तुलना एक सॉफ्टवेयर रिक्रूटर से करता हूँ, जिससे पूछा गया है कि C # लिखने पर कुत्ते बिल्लियों से बदतर क्यों हैं। यदि आप एक प्राणीविज्ञानी हैं, तो प्रश्न कुछ योग्यता पकड़ सकता है; बाकी सभी के लिए, यह व्यर्थ है।
डगलस

24

फ़्लोटिंग-पॉइंट परिशुद्धता मशीन से मशीन तक और एक ही मशीन पर भी भिन्न हो सकती है ।

हालाँकि, .NET आपके ऐप्स के लिए एक वर्चुअल मशीन बनाता है ... लेकिन वर्जन से वर्जन में बदलाव होते हैं।

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


10

कोड खराब होने के तरीके के बारे में बहुत सारे उत्तर हैं। हालांकि, क्यों परिणाम अलग है…

इंटेल के FPUs इंटरमीडिएट के परिणाम के लिए अधिक सटीक प्राप्त करने के लिए आंतरिक रूप से 80-बिट प्रारूप का उपयोग करते हैं । इसलिए यदि प्रोसेसर में कोई मूल्य दर्ज है, तो यह 80 बिट्स हो जाता है, लेकिन जब इसे स्टैक पर लिखा जाता है, तो यह 64 बिट्स में संग्रहीत हो जाता है ।

मुझे उम्मीद है कि .NET के नए संस्करण के अपने जस्ट इन टाइम (JIT) संकलन में बेहतर ऑप्टिमाइज़र है, इसलिए यह स्टैक पर लिखने के बजाय एक रजिस्टर में एक मान रख रहा है और फिर इसे स्टैक से वापस पढ़ना है।

यह हो सकता है कि JIT अब स्टैक के बजाय एक रजिस्टर में एक मूल्य वापस कर सकता है। या एक रजिस्टर में एमओडी फ़ंक्शन के मूल्य को पास करें।

स्टैक ओवरफ्लो प्रश्न भी देखें 80-बिट विस्तारित परिशुद्धता डेटा प्रकार के अनुप्रयोग / लाभ क्या हैं?

अन्य प्रोसेसर, जैसे एआरएम इस कोड के लिए अलग-अलग परिणाम देंगे।


6

हो सकता है कि केवल पूर्णांक अंकगणित का उपयोग करके स्वयं इसकी गणना करना सबसे अच्छा हो। कुछ इस तरह:

int n = 143;
int e = 103;
int result = 1;
int ascii = (int) 'a';

for (i = 0; i < e; ++i) 
    result = result * ascii % n;

आप अन्य उत्तरों में पोस्ट किए गए BigInteger समाधान के प्रदर्शन के साथ प्रदर्शन की तुलना कर सकते हैं।


7
इसके लिए 103 गुणन और मापांक की आवश्यकता होगी। E2 = e * e% n, e4 = e2 * e2% n, e8 = e4 * e4% n, आदि की गणना करके कोई भी बेहतर कर सकता है और फिर परिणाम = e * e2% n * e4% n * e32% n * e64% एन। कुल 11 गुणा और मापांक कटौती। शामिल संख्याओं के आकार को देखते हुए, कुछ और मापांक कटौती को समाप्त कर सकता है, लेकिन यह 103 के संचालन को कम करने की तुलना में मामूली हो जाएगा 11.
सुपरकैट

2
@supercat अच्छा गणित, लेकिन व्यवहार में प्रासंगिक केवल अगर आप इसे टोस्टर पर चला रहे हैं।
एलेक्सीगार्डन

7
@alextgordon: या यदि कोई बड़े घातांक मान का उपयोग करने की योजना बना रहा है। घातांक मान को 65521 तक विस्तारित करते हुए अगर कोई शक्ति कटौती का उपयोग करता है, तो लगभग 28 गुणक और मापांक घट जाएंगे, यदि 65,520 एक नहीं होता है।
सुपरैट

एक सुलभ समाधान देने के लिए +1 जहां यह स्पष्ट है कि गणना कैसे की जाती है।
jwg

2
@ सुपरकैट: आप बिल्कुल सही कह रहे हैं। एल्गोरिथ्म में सुधार करना आसान है, जो प्रासंगिक है यदि या तो इसकी गणना अक्सर की जाती है या घातांक बड़े होते हैं। लेकिन मुख्य संदेश यह है कि पूर्णांक अंकगणित का उपयोग करके इसकी गणना की जा सकती है।
रोनाल्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.