शुभ दिन, Khabrovites! मुझे इस परियोजना में एमएस एसक्यूएल सर्वर में कम्प्यूटेशनल सटीकता का सामना करना पड़ा और मुझे प्रतीत होता है कि सहज संचालन करते समय काफी सहज व्यवहार नहीं मिला।
बीज प्रश्न के लिए (बिना प्रदर्शन के इसका उत्तर देने का प्रयास करें):
ऑपरेशन का परिणाम क्या होगा?
declare @var1 decimal(38,10) = 0.0000007, @var2 decimal(38,10) = 1; select @var1 * @var2;
कट के तहत उत्तर और स्पष्टीकरण
तो पहला जवाब:
0.000001कौन सा?
वास्तव में, उत्तर काफी सरल है, लेकिन यह आसान नहीं है। बात यह है कि दशमलव संख्याओं के साथ अंकगणितीय संचालन करते समय, परिणाम मूल मूल्यों की तुलना में बहुत बड़ा हो सकता है, उदाहरण के लिए, यदि आप 10 ^ 6 और 10 ^ 6 को गुणा करते हैं, तो हमें 10 ^ 12 मिलते हैं। यह पहले से ही मूल मान से 6 अंक अधिक है। इसी तरह विभाजन के साथ। इसलिए, MS SQL जब परिणामी अभिव्यक्ति के प्रकार की गणना करता है
तो निम्नलिखित नियम लागू होते हैं :
आपरेशन
| परिणाम सटीक
| परिणाम पैमाने *
|
---|
e1 + e2
| अधिकतम (s1, s2) + अधिकतम (p1-s1, P2-s2) + 1
| अधिकतम (s1, s2)
|
e1 - ई 2
| अधिकतम (s1, s2) + अधिकतम (p1-s1, P2-s2) + 1
| अधिकतम (s1, s2)
|
e1 * e2
| p1 + P2 + 1
| s1 + s2
|
e1 / ई 2
| p1 - s1 + s2 + अधिकतम (6, s1 + P2 + 1)
| अधिकतम (6, s1 + P2 + 1)
|
e1 {यूनिअन | EXCEPT | INTERSECT} e2
| अधिकतम (s1, s2) + अधिकतम (p1-s1, P2-s2)
| अधिकतम (s1, s2)
|
e1% ई 2
| मिनट (p1-s1, P2 -s2) + अधिकतम (s1, s2)
| अधिकतम (s1, s2)
|
* सटीक और परिणाम के पैमाने का निरपेक्ष अधिकतम 38 होता है। यदि सटीक का मान 38 से अधिक हो जाता है, तो परिणाम के अभिन्न अंग के छंटनी को रोकने के लिए संबंधित पैमाने को कम कर दिया जाता है।
दस्तावेज़ में कोई विस्तृत विवरण नहीं है कि गोलाई कैसे होती है और किस सीमा तक होती है, लेकिन प्रयोगात्मक रूप से मैं दशमलव (38.6) से अधिक गोलाई प्राप्त करने में सक्षम नहीं रहा हूं।
इसलिए शुरुआत में अभिव्यक्ति का परिणाम:
0.000001 ठीक 6 दशमलव स्थानों पर। निराधार नहीं होने के लिए, हम निम्नलिखित क्वेरी को निष्पादित करते हैं:
declare @var1 decimal(38,10) = 0.0000007, @var2 decimal(38,10) = 1, @res sql_variant; set @res = @var1 * @var2; select @res, SQL_VARIANT_PROPERTY(@res, 'BaseType') as BaseType, SQL_VARIANT_PROPERTY(@res, 'Precision') as Precision, SQL_VARIANT_PROPERTY(@res, 'Scale') as Scale;
हमें निम्न परिणाम मिलते हैं:
रेस
| BaseType
| शुद्धता
| स्केल
|
---|
0.000001
| दशमलव
| 38
| 6
|
इसके साथ कैसे रहना है?
आपको इस और हमेशा (हमेशा हमेशा!) के साथ आना होगा। बहुत सटीकता से सटीकता सेट करें। हमारे मामले में, ऐसी स्क्रिप्ट अपेक्षित परिणाम देगी:
declare @var1 decimal(18,10) = 0.0000007, @var2 decimal(18,10) = 1, @res sql_variant; set @res = @var1 * @var2; select @res, SQL_VARIANT_PROPERTY(@res, 'BaseType') as BaseType, SQL_VARIANT_PROPERTY(@res, 'Precision') as Precision, SQL_VARIANT_PROPERTY(@res, 'Scale') as Scale;
रेस
| BaseType
| शुद्धता
| स्केल
|
---|
.00000070000000000000
| दशमलव
| 37
| 20
|
एक आफ्टरवर्ड के बजाय
और अंत में, कुछ और एसक्यूएल जादू। इस तरह की स्क्रिप्ट के निष्पादन का परिणाम क्या होगा:
declare @var1 decimal(38,10) = 0.0000007, @var2 int = 1; select @var1 * @var2, @var1 * 1;
जवाब है@ var1 * @ var2 = 0.000001
@ var1 * 1 = 0.00000070
पुनश्च: आपको एकत्रीकरण संचालन के साथ सावधान रहने की भी आवश्यकता है, क्योंकि वे परिणाम की सटीकता को भी बदलते हैं।
यहाँ समस्या का वर्णन करने वाला
एक अच्छा लेख है।