உண்மையான வகைகளின் உண்மையற்ற அம்சங்கள், அல்லது REAL உடன் கவனமாக இருங்கள்

வெளியீட்டிற்குப் பிறகு கட்டுரைகள் PostgreSQL இல் தட்டச்சு செய்யும் அம்சங்களைப் பற்றி, முதல் கருத்து உண்மையான எண்களுடன் வேலை செய்வதில் உள்ள சிரமங்களைப் பற்றியது. உண்மையான வகையை எவ்வளவு அடிக்கடி பயன்படுத்துகிறார்கள் என்பதைப் பார்க்க, எனக்குக் கிடைக்கும் 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) ஆக தோன்றுகிறது. இதன் விளைவாக, கணினி நினைவகத்தில் இந்த எண்ணின் இறுதி மதிப்பு பிட் ஆழத்தைப் பொறுத்து மாறுபடும்.

கணினி நினைவகத்தில் உண்மையான எண்கள் எவ்வாறு சேமிக்கப்படுகின்றன என்பதை நினைவில் கொள்ள வேண்டிய நேரம் இது. பொதுவாக, ஒரு உண்மையான எண் மூன்று முக்கிய பகுதிகளைக் கொண்டுள்ளது - அடையாளம், மாண்டிசா மற்றும் அடுக்கு. அடையாளம் கூட்டல் அல்லது கழித்தல் இருக்கலாம், எனவே அதற்கு ஒரு பிட் ஒதுக்கப்படுகிறது. ஆனால் மாண்டிசா மற்றும் அடுக்குகளின் எண்ணிக்கை உண்மையான வகையால் தீர்மானிக்கப்படுகிறது. எனவே, உண்மையான வகைக்கு, மாண்டிசாவின் நீளம் 23 பிட்கள் (1 க்கு சமமான ஒரு பிட் மன்டிசாவின் தொடக்கத்தில் மறைமுகமாக சேர்க்கப்பட்டுள்ளது, மற்றும் முடிவு 24), மற்றும் அடுக்கு 8 பிட்கள் ஆகும். மொத்தம் 32 பிட்கள் அல்லது 4 பைட்டுகள். மேலும் இரட்டை துல்லிய வகைக்கு, மாண்டிசாவின் நீளம் 52 பிட்களாகவும், அடுக்கு 11 பிட்களாகவும், மொத்தம் 64 பிட்கள் அல்லது 8 பைட்டுகளாக இருக்கும். மிதக்கும் புள்ளி எண்களுக்கான உயர் துல்லியத்தை PostgreSQL ஆதரிக்காது.

நமது தசம எண் 0.1ஐ உண்மையான மற்றும் இரட்டை துல்லிய வகைகளாகப் பேக் செய்வோம். அதிவேகத்தின் அடையாளமும் மதிப்பும் ஒரே மாதிரியாக இருப்பதால், நாம் மாண்டிசாவில் கவனம் செலுத்துவோம் (அதிவேகத்தின் மதிப்புகள் மற்றும் பூஜ்ஜிய உண்மையான மதிப்புகளை சேமிப்பதில் வெளிப்படையான அம்சங்களை நான் வேண்டுமென்றே தவிர்க்கிறேன், ஏனெனில் அவை புரிந்துகொள்வதை சிக்கலாக்கி சாரத்திலிருந்து திசைதிருப்புகின்றன. பிரச்சனையின், ஆர்வமிருந்தால், IEEE 754 தரநிலையைப் பார்க்கவும்). நமக்கு என்ன கிடைக்கும்? மேல் வரியில் நான் உண்மையான வகைக்கான “மன்டிசா” ஐக் கொடுப்பேன் (கடைசி பிட்டை 1 ஆல் ரவுண்டிங் மூலம் அருகிலுள்ள பிரதிநிதித்துவ எண்ணுடன், இல்லையெனில் அது 0.099999 ஆக இருக்கும்...), மற்றும் கீழ் வரியில் - க்கு இரட்டை துல்லிய வகை:

0.000110011001100110011001101
0.00011001100110011001100110011001100110011001100110011001

வெளிப்படையாக இவை இரண்டு முற்றிலும் வேறுபட்ட எண்கள்! எனவே, ஒப்பிடும் போது, ​​முதல் எண் பூஜ்ஜியங்களுடன் திணிக்கப்படும், எனவே, இரண்டாவது விட அதிகமாக இருக்கும் (கணக்கில் ரவுண்டிங் எடுத்து - தடிமனாக குறிக்கப்பட்ட ஒன்று). இது எங்கள் உதாரணங்களிலிருந்து தெளிவின்மையை விளக்குகிறது. இரண்டாவது எடுத்துக்காட்டில், வெளிப்படையாகக் குறிப்பிடப்பட்ட எண் 0.1 இரட்டை துல்லிய வகைக்கு அனுப்பப்படுகிறது, பின்னர் உண்மையான வகை எண்ணுடன் ஒப்பிடப்படுகிறது. இரண்டும் ஒரே வகையாகக் குறைக்கப்பட்டு, மேலே நாம் பார்ப்பது எங்களிடம் உள்ளது. வினவலை மாற்றியமைப்போம், இதனால் எல்லாம் சரியான இடத்தில் வரும்:

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

உண்மையில், 0.1 எண்ணை உண்மையான மற்றும் இரட்டை துல்லியமாக இரட்டைக் குறைப்பதன் மூலம், புதிருக்கான பதிலைப் பெறுகிறோம்:

********* ЗАПРОС *********
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 строка)

அவ்வளவுதான். அற்புதங்கள் எதுவும் இல்லை என்று மாறிவிடும். ஆனால் விவரிக்கப்பட்டுள்ள அனைத்தும் உண்மையான வகை உங்களுக்கு உண்மையில் எவ்வளவு தேவை என்பதைப் பற்றி சிந்திக்க ஒரு நல்ல காரணம். ஒருவேளை அதன் பயன்பாட்டின் மிகப்பெரிய நன்மை, அறியப்பட்ட துல்லியமான இழப்புடன் கணக்கீடுகளின் வேகம் ஆகும். ஆனால் இந்த வகையை அடிக்கடி பயன்படுத்துவதை நியாயப்படுத்தும் உலகளாவிய சூழ்நிலை இதுவாக இருக்குமா? நினைக்காதே.

ஆதாரம்: www.habr.com

கருத்தைச் சேர்