ನೈಜ ಪ್ರಕಾರದ ಅವಾಸ್ತವ ವೈಶಿಷ್ಟ್ಯಗಳು, ಅಥವಾ ರಿಯಲ್ ಜೊತೆ ಜಾಗರೂಕರಾಗಿರಿ

ಪ್ರಕಟಣೆಯ ನಂತರ ಲೇಖನಗಳು PostgreSQL ನಲ್ಲಿ ಟೈಪ್ ಮಾಡುವ ವೈಶಿಷ್ಟ್ಯಗಳ ಬಗ್ಗೆ, ಮೊದಲ ಕಾಮೆಂಟ್ ನೈಜ ಸಂಖ್ಯೆಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವ ತೊಂದರೆಗಳ ಬಗ್ಗೆ. ಅವರು ರಿಯಲ್ ಪ್ರಕಾರವನ್ನು ಎಷ್ಟು ಬಾರಿ ಬಳಸುತ್ತಾರೆ ಎಂಬುದನ್ನು ನೋಡಲು ನನಗೆ ಲಭ್ಯವಿರುವ SQL ಪ್ರಶ್ನೆಗಳ ಕೋಡ್ ಅನ್ನು ತ್ವರಿತವಾಗಿ ನೋಡಲು ನಾನು ನಿರ್ಧರಿಸಿದೆ. ಇದು ಸಾಕಷ್ಟು ಬಾರಿ ಬಳಸಲ್ಪಡುತ್ತದೆ ಎಂದು ತಿರುಗುತ್ತದೆ, ಮತ್ತು ಅಭಿವರ್ಧಕರು ಯಾವಾಗಲೂ ಅದರ ಹಿಂದಿನ ಅಪಾಯಗಳನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದಿಲ್ಲ. ಕಂಪ್ಯೂಟರ್ ಮೆಮೊರಿಯಲ್ಲಿ ನೈಜ ಸಂಖ್ಯೆಗಳನ್ನು ಸಂಗ್ರಹಿಸುವ ವೈಶಿಷ್ಟ್ಯಗಳ ಬಗ್ಗೆ ಮತ್ತು ಅವರೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವ ಬಗ್ಗೆ ಇಂಟರ್ನೆಟ್ ಮತ್ತು ಹ್ಯಾಬ್ರೆಯಲ್ಲಿ ಸಾಕಷ್ಟು ಉತ್ತಮ ಲೇಖನಗಳಿವೆ ಎಂಬ ಅಂಶದ ಹೊರತಾಗಿಯೂ ಇದು. ಆದ್ದರಿಂದ, ಈ ಲೇಖನದಲ್ಲಿ ನಾನು ಅಂತಹ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು PostgreSQL ಗೆ ಅನ್ವಯಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತೇನೆ ಮತ್ತು ಅವುಗಳಿಗೆ ಸಂಬಂಧಿಸಿದ ತೊಂದರೆಗಳನ್ನು ತ್ವರಿತವಾಗಿ ನೋಡಲು ಪ್ರಯತ್ನಿಸುತ್ತೇನೆ, ಇದರಿಂದ SQL ಕ್ವೆರಿ ಡೆವಲಪರ್‌ಗಳಿಗೆ ಅವುಗಳನ್ನು ತಪ್ಪಿಸಲು ಸುಲಭವಾಗುತ್ತದೆ.

PostgreSQL ದಸ್ತಾವೇಜನ್ನು ಸಂಕ್ಷಿಪ್ತವಾಗಿ ಹೇಳುತ್ತದೆ: "ಅಂತಹ ದೋಷಗಳ ನಿರ್ವಹಣೆ ಮತ್ತು ಗಣನೆಯ ಸಮಯದಲ್ಲಿ ಅವುಗಳ ಪ್ರಸರಣವು ಗಣಿತ ಮತ್ತು ಕಂಪ್ಯೂಟರ್ ವಿಜ್ಞಾನದ ಸಂಪೂರ್ಣ ಶಾಖೆಯ ವಿಷಯವಾಗಿದೆ ಮತ್ತು ಇಲ್ಲಿ ಒಳಗೊಂಡಿಲ್ಲ" (ಐಇಇಇ 754 ಮಾನದಂಡಕ್ಕೆ ಓದುಗರನ್ನು ಬುದ್ಧಿವಂತಿಕೆಯಿಂದ ಉಲ್ಲೇಖಿಸುವಾಗ). ಇಲ್ಲಿ ಯಾವ ರೀತಿಯ ದೋಷಗಳನ್ನು ಅರ್ಥೈಸಲಾಗಿದೆ? ಅವುಗಳನ್ನು ಕ್ರಮವಾಗಿ ಚರ್ಚಿಸೋಣ ಮತ್ತು ನಾನು ಮತ್ತೆ ಪೆನ್ ಅನ್ನು ಏಕೆ ತೆಗೆದುಕೊಂಡೆ ಎಂಬುದು ಶೀಘ್ರದಲ್ಲೇ ಸ್ಪಷ್ಟವಾಗುತ್ತದೆ.

ಉದಾಹರಣೆಗೆ ಸರಳ ವಿನಂತಿಯನ್ನು ತೆಗೆದುಕೊಳ್ಳೋಣ:

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

ಪರಿಣಾಮವಾಗಿ, ನಾವು ವಿಶೇಷವಾದದ್ದನ್ನು ನೋಡುವುದಿಲ್ಲ - ನಾವು ನಿರೀಕ್ಷಿತ 0.1 ಅನ್ನು ಪಡೆಯುತ್ತೇವೆ. ಆದರೆ ಈಗ ಅದನ್ನು 0.1 ಗೆ ಹೋಲಿಸೋಣ:

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

ಸಮಾನವಾಗಿಲ್ಲ! ಎಂತಹ ಪವಾಡಗಳು! ಆದರೆ ಮುಂದೆ, ಹೆಚ್ಚು. ಯಾರೋ ಹೇಳುತ್ತಾರೆ, REAL ಭಿನ್ನರಾಶಿಗಳೊಂದಿಗೆ ಕೆಟ್ಟದಾಗಿ ವರ್ತಿಸುತ್ತದೆ ಎಂದು ನನಗೆ ತಿಳಿದಿದೆ, ಆದ್ದರಿಂದ ನಾನು ಅಲ್ಲಿ ಸಂಪೂರ್ಣ ಸಂಖ್ಯೆಗಳನ್ನು ನಮೂದಿಸುತ್ತೇನೆ ಮತ್ತು ಎಲ್ಲವೂ ಖಂಡಿತವಾಗಿಯೂ ಅವರೊಂದಿಗೆ ಚೆನ್ನಾಗಿರುತ್ತದೆ. ಸರಿ, 123 ಸಂಖ್ಯೆಯನ್ನು ನಿಜಕ್ಕೆ ಬಿತ್ತರಿಸೋಣ:

********* ЗАПРОС *********
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

ಕಾಮೆಂಟ್ ಅನ್ನು ಸೇರಿಸಿ