ትክክለኛ ያልሆኑ የእውነተኛ ዓይነቶች ባህሪዎች ፣ ወይም ከ REAL ጋር ይጠንቀቁ

ከታተመ በኋላ መጣጥፎች በ PostgreSQL ውስጥ ስለ መተየብ ባህሪዎች ፣ የመጀመሪያው አስተያየት ከእውነተኛ ቁጥሮች ጋር ስለ መሥራት ችግሮች ነበር። ምን ያህል ጊዜ REAL አይነት እንደሚጠቀሙ ለማየት ለእኔ የሚገኙትን የSQL መጠይቆች ኮድ ለማየት ወሰንኩ። እሱ ብዙ ጊዜ ጥቅም ላይ ይውላል ፣ እና ገንቢዎች ሁል ጊዜ ከጀርባው ያሉትን አደጋዎች አይረዱም። እና ምንም እንኳን ይህ ምንም እንኳን በኮምፒተር ማህደረ ትውስታ ውስጥ እውነተኛ ቁጥሮችን ስለ ማከማቸት እና ከእነሱ ጋር ስለመስራት በበይነመረብ እና በሀበሬ ላይ ብዙ ጥሩ መጣጥፎች ቢኖሩም። ስለዚህ, በዚህ ጽሑፍ ውስጥ እንደዚህ ያሉ ባህሪያትን በ PostgreSQL ላይ ለመተግበር እሞክራለሁ, እና ከእነሱ ጋር የተያያዙ ችግሮችን በፍጥነት ለመመልከት እሞክራለሁ, ስለዚህም የ SQL መጠይቅ ገንቢዎች እነሱን ለማስወገድ ቀላል ይሆንላቸዋል.

የ PostgreSQL ዶክመንቴሽን በአጭሩ እንዲህ ይላል፡- “እንዲህ ያሉ ስህተቶችን ማስተዳደር እና በስሌት ጊዜ ስርጭታቸው የጠቅላላ የሂሳብ እና የኮምፒዩተር ሳይንስ ዘርፍ ርዕሰ ጉዳይ ነው፣ እና እዚህ አልተሸፈነም” (አንባቢን በጥበብ ወደ IEEE 754 መስፈርት ሲያመለክት)። እዚህ ምን ዓይነት ስህተቶች ማለት ነው? እነሱን በቅደም ተከተል እንወያይባቸው እና ለምን እንደገና ብዕሩን እንዳነሳሁ በቅርቡ ግልፅ ይሆናል ።

ለምሳሌ ቀላል ጥያቄን እንውሰድ፡-

********* ЗАПРОС *********
SELECT 0.1::REAL;
**************************
float4
--------
    0.1
(1 строка)

በውጤቱም, ምንም ልዩ ነገር አናይም - የሚጠበቀውን 0.1 እናገኛለን. አሁን ግን ከ0.1 ጋር እናወዳድረው፡-

********* ЗАПРОС *********
SELECT 0.1::REAL = 0.1;
**************************
?column?
----------
f
(1 строка)

እኩል አይደለም! እንዴት ያለ ተአምር ነው! ግን የበለጠ ፣ የበለጠ። አንድ ሰው እንዲህ ይላል፣ REAL ከክፍልፋዮች ጋር መጥፎ ጠባይ እንዳለው አውቃለሁ፣ ስለዚህ እዚያ ሙሉ ቁጥሮችን አስገባለሁ፣ እና ሁሉም ነገር በእርግጠኝነት ከእነሱ ጋር ጥሩ ይሆናል። እሺ፣ ቁጥሩን 123 ወደ REAL እንወረውረው፡-

********* ЗАПРОС *********
SELECT 123456789::REAL::INT;
**************************
   int4   
-----------
123456792
(1 строка)

እና ተጨማሪ 3 ሆነ! ያ ብቻ ነው፣ የውሂብ ጎታው በመጨረሻ እንዴት እንደሚቆጠር ረስቶታል! ወይስ የሆነ ነገር እየተግባባን ነው? እስቲ እንገምተው።

በመጀመሪያ ፣ ቁሳቁሱን እናስታውስ። እንደሚታወቀው ማንኛውም የአስርዮሽ ቁጥር ወደ አስር ሃይሎች ሊሰፋ ይችላል። ስለዚህ ቁጥሩ 123.456 ከ1*102+2*101+3*100+4*10-1+5*10-2+6*10-3 ጋር እኩል ይሆናል። ነገር ግን ኮምፒዩተሩ ከቁጥሮች ጋር በሁለትዮሽ መልክ ይሰራል, ስለዚህ በሁለት ሃይሎች ውስጥ በማስፋፊያ መልክ መወከል አለባቸው. ስለዚህ, ቁጥር 5.625 በሁለትዮሽ ውስጥ እንደ 101.101 ይወከላል እና ከ 1 * 22 + 0 * 21 + 1 * 20 + 1 * 2-1 + 0 * 2-2 + 1 * 2-3 ጋር እኩል ይሆናል. እና የሁለት አዎንታዊ ሃይሎች ሁል ጊዜ ሙሉ የአስርዮሽ ቁጥሮችን (1 ፣ 2 ፣ 4 ፣ 8 ፣ 16 ፣ ወዘተ) ከሰጡ ፣ በአሉታዊዎቹ ሁሉም ነገር የበለጠ የተወሳሰበ ነው (0.5 ፣ 0.25 ፣ 0.125 ፣ 0,0625 ፣ ወዘተ.)። ችግሩ ያ ነው። እያንዳንዱ አስርዮሽ እንደ ውሱን ሁለትዮሽ ክፍልፋይ ሊወከል አይችልም።. ስለዚህ የእኛ ታዋቂው 0.1 በሁለትዮሽ ክፍልፋይ መልክ እንደ ወቅታዊ እሴት 0.0 (0011) ይመስላል። ስለዚህ በኮምፒዩተር ማህደረ ትውስታ ውስጥ ያለው የዚህ ቁጥር የመጨረሻ ዋጋ እንደ ቢት ጥልቀት ይለያያል።

እውነተኛ ቁጥሮች በኮምፒተር ማህደረ ትውስታ ውስጥ እንዴት እንደሚከማቹ ለማስታወስ ጊዜው አሁን ነው። በአጠቃላይ እውነተኛ ቁጥር ሦስት ዋና ዋና ክፍሎችን ያቀፈ ነው - ምልክት ፣ ማንቲሳ እና አርቢ። ምልክቱ ሲደመር ወይም ሲቀነስ ሊሆን ይችላል፣ ስለዚህ አንድ ቢት ለእሱ ተመድቧል። ነገር ግን የማንቲሳ እና ገላጭ የቢቶች ብዛት የሚወሰነው በእውነተኛው ዓይነት ነው። ስለዚህ, ለ REAL አይነት, የማንቲሳ ርዝመት 23 ቢት ነው (አንድ ቢት ከ 1 ጋር እኩል የሆነ ወደ ማንቲሳ መጀመሪያ ላይ በተዘዋዋሪ ተጨምሯል, ውጤቱም 24 ነው), እና ገላጭ 8 ቢት ነው. አጠቃላይ 32 ቢት ወይም 4 ባይት ነው። እና ለDOUBLE PRECISION አይነት የማንቲሳ ርዝመት 52 ቢት እና አርቢው 11 ቢት በድምሩ 64 ቢት ወይም 8 ባይት ይሆናል። PostgreSQL ለተንሳፋፊ ነጥብ ቁጥሮች ከፍተኛ ትክክለኛነትን አይደግፍም።

የአስርዮሽ ቁጥራችንን 0.1 ወደ እውነተኛ እና ባለ ሁለትዮሽ PRECISION አይነቶች እናሽግው። የአርቢው ምልክት እና ዋጋ አንድ አይነት ስለሆነ በማንቲሳ ላይ እናተኩራለን (የገለጻ እና ዜሮ እውነተኛ እሴቶችን የማከማቸት ግልፅ ያልሆኑ ባህሪዎችን ሆን ብዬ እተወዋለሁ ፣ ምክንያቱም እነሱ መረዳትን ስለሚያወሳስቡ እና ከዋናው ነገር ትኩረትን ስለሚከፋፍሉ የችግሩ ፣ ፍላጎት ካለው ፣ የ IEEE 754 ደረጃን ይመልከቱ)። ምን እናገኛለን? በላይኛው መስመር ላይ “ማንቲሳ”ን ለሪኤኤል ዓይነት እሰጣለሁ (የመጨረሻውን ቢት በ 1 ወደ ቅርብ ወደሚገኘው ቁጥር ማጠጋጋትን ከግምት ውስጥ በማስገባት ፣ አለበለዚያ 0.099999 ይሆናል…) ፣ እና በታችኛው መስመር - ለ DOUBLE PRECISION አይነት፡-

0.000110011001100110011001101
0.00011001100110011001100110011001100110011001100110011001

በእርግጥ እነዚህ ሁለት ሙሉ በሙሉ የተለያዩ ቁጥሮች ናቸው! ስለዚህ, ሲነፃፀሩ, የመጀመሪያው ቁጥር በዜሮዎች የተሞላ እና, ስለዚህም, ከሁለተኛው ይበልጣል (ማጠጋጋትን ግምት ውስጥ በማስገባት - በደማቅ ምልክት የተደረገበት). ይህ ከምሳሌዎቻችን አሻሚነትን ያብራራል. በሁለተኛው ምሳሌ፣ በግልጽ የተገለጸው ቁጥር 0.1 ወደ DOUBLE PRECISION ዓይነት ይጣላል፣ እና ከዚያ ከ REAL ዓይነት ቁጥር ጋር ይነጻጸራል። ሁለቱም ወደ አንድ አይነት ይቀንሳሉ, እና ከላይ የምናየው በትክክል አለን. ሁሉም ነገር ወደ ቦታው እንዲወድቅ ጥያቄውን እናስተካክለው፡-

********* ЗАПРОС *********
SELECT 0.1::REAL > 0.1::DOUBLE PRECISION;
**************************
?column?
----------
t
(1 строка)

እና በእርግጥ ፣ የቁጥር 0.1 በእጥፍ ወደ እውነተኛ እና ድርብ PRECISION በመቀነስ ፣ ለእንቆቅልሹ መልስ እናገኛለን።

********* ЗАПРОС *********
SELECT 0.1::REAL::DOUBLE PRECISION;
**************************

      float8       
-------------------
0.100000001490116
(1 строка)

ይህ ደግሞ ከላይ ያለውን ሦስተኛውን ምሳሌ ያብራራል. ቁጥሩ 123 ቀላል ነው። ማንቲሳን ወደ 24 ቢት ማስገባት የማይቻል ነው (23 ግልጽ + 1 በተዘዋዋሪ)። ወደ 24 ቢት ሊገባ የሚችለው ከፍተኛው ኢንቲጀር 224-1 = 16 ነው።ስለዚህ ቁጥራችን 777 ወደሚቀርበው 215 ተጠጋግሯል።

********* ЗАПРОС *********
SELECT 123456789::DOUBLE PRECISION::INT;
**************************
   int4   
-----------
123456789
(1 строка)

ይኼው ነው. ምንም ተአምራት አለመኖሩን ያሳያል. ነገር ግን የተገለጸው ነገር ሁሉ ለእውነተኛው አይነት ምን ያህል እንደሚያስፈልግ ለማሰብ ጥሩ ምክንያት ነው። ምናልባት አጠቃቀሙ ትልቁ ጥቅም ከሚታወቅ ትክክለኛነት ማጣት ጋር የሂሳብ ፍጥነት ነው። ግን ይህ እንደዚህ ዓይነቱን አዘውትሮ መጠቀምን የሚያረጋግጥ ዓለም አቀፋዊ ሁኔታ ነውን? አታስብ።

ምንጭ: hab.com

አስተያየት ያክሉ