
Нэг тооноос болж дэлбэрсэн пуужин

Г.Энгүүнбаяр
Багш


Г.Энгүүнбаяр
Багш
Програм бичиж байхад алдаа гарах нь ердийн зүйл. Улаан бичиг гараад ирнэ, бид алдаагаа хайж олоод засна, дахиад ажиллуулна. Гэхдээ дахин ажиллуулах боломж огт байдаггүй програм ч бий. Пуужин дотор ажилладаг програм яг ийм.
1996 оны 6-р сарын 4-нд Европынхон шинэ пуужин Ариан-5-аа анх удаа хөөргөсөн. Арав орчим жил бүтээсэн, өмнөх Ариан-4-өөсөө хамаагүй хүчтэй пуужин байв. Дотор нь дэлхийн соронзон орныг судлах дөрвөн хиймэл дагуул явж байлаа.
Хөөргөх талбай дээр зогсож буй Ариан-5 пуужин. Энэ зураг 2021 онд авагдсан. Зураг: NASA/Bill Ingalls
Эхний 37 секунд хэвийн нисэв. Тэгснээ пуужин гэнэт хажуу тийшээ огцом эргэж, ачааллаа дааж чадалгүй задарч эхэлсэн. Удалгүй өөрийгөө устгах төхөөрөмж нь ажиллаж, пуужин агаарт тэсэрсэн. Хэдэн зуун сая долларын пуужин, хиймэл дагуулууд нэг минут хүрэхгүй хугацаанд үгүй болов.
Ослыг шалгасан хүмүүс шалтгааныг нь удалгүй олсон. Пуужингийн програм нэг тоог өөрт нь багтахгүй жижиг зайд хадгалах гэж оролдсон байжээ.
Пуужин хаашаа, ямар хурдтай явж байгаагаа мэдэхийн тулд тусгай төхөөрөмжтэй байдаг. Ариан-5 дээр ийм хоёр төхөөрөмж байсан, нэг нь үндсэн, нөгөө нь нөөц. Тэдгээрийн доторх програм хэвтээ чиглэлийн хурдтай холбоотой нэг утгыг байнга тооцоолж байв.
Програм тоо бүрт санах ойгоос тодорхой хэмжээний зай гаргадаг. Тэр утгыг эхлээд хоёртын 64 оронтой том зайд бутархай тоогоор хадгалчихаад, дараа нь хоёртын 16 оронтой жижиг зайд бүхэл тоо болгож хийдэг байжээ. 16 оронтой тэмдэгтэй бүхэл тоонд хамгийн ихдээ 32767 л багтана. Түүнээс том тоо орохгүй.
Ариан-4 дээр энэ асуудал гарч байгаагүй. Тэр пуужин харьцангуй удаан хурдасдаг тул утга нь хэзээ ч тийм томордоггүй байв. Харин Ариан-5-ын хэвтээ хурд тав орчим дахин хурдан өсдөг. Ингээд 37 дахь секундэд утга 32767-оос давж, програм алдаа заагаад зогссон. Үүнийг тоо халих гэж нэрлэдэг.
Хуучин машины тоолуурыг санаад үз. 99999 км явсан машин дахиад нэг км явахад тоолуур нь 00000 болчихдог. Машин шинэ болчихоогүй, зүгээр л тоолуурт зургаа дахь орон байхгүй.
Тоолуур дүүрээд тэг рүүгээ эргэж байгаа нь. Зураг: Hellbus, Wikimedia Commons
Тоо халихыг Python дээр өөрсдөө харж болно. Python хэлний ердийн тоо халидаггүй болохоор 16 оронтой зайг ctypes ашиглан дуурайлгая.
import ctypes
hurd = 40000
x = ctypes.c_int16(hurd)
print(x.value) # -2553640000 гэж хийсэн тоо маань -25536 болчихлоо. Python энд дуугүйхэн буруу тоо гаргаж байна. Харин Ариан-5-ын програмыг бичсэн Ада хэл ийм үед алдааны дохио өгдөг. Дохио нь гарсан ч түүнийг хүлээж аваад юу хийхийг програмд заагаагүй байсан тул төхөөрөмж бүхэлдээ унтарсан.
Нөөц төхөөрөмж байсан юм чинь түүн рүүгээ шилжчихгүй яасан юм бэ гэж бодож байгаа байх. Шилжих гэсэн ч болоогүй. Нөөц төхөөрөмж яг ижил програмтай, яг ижил мэдээлэл авч байсан болохоор түүн дээр ч мөн адил алдаа гарч, үндсэнээсээ 0.07 секунд орчмын өмнө аль хэдийн унтарчихсан байжээ. Нэг програмыг хоёр хуулбарлавал түүний алдааг ч бас хоёр хуулбарлана.
Үүний дараа бүр ч муу зүйл болсон. Хоёр төхөөрөмж унтрахдаа алдааны тайлан илгээсэн бөгөөд нислэгийг удирддаг гол төхөөрөмж тэр тайланг хурд, чиглэлийн жинхэнэ мэдээлэл гэж уншчихсан. Тэгээд хөдөлгүүрүүдийн цоргыг огцом эргүүлж, пуужинг замаас нь гаргасан.
Бас нэг гашуун баримт бий. Алдаа гаргасан тэр тооцоо хөөрсний дараа Ариан-5-д огт хэрэггүй байсан. Энэ бол хөөрөхөөс өмнө төхөөрөмжийг тохируулахад л хэрэглэгддэг хэсэг. Ариан-4 дээр тодорхой шалтгаанаар хөөрсний дараа ч 40 орчим секунд ажиллуулдаг байсныг шинэ пуужин руу програмаа шилжүүлэхдээ хэн ч өөрчлөөгүй.
Програмд ийм тоо хувиргалт долоо байсан. Тэдгээрийн дөрвийг нь л алдаанаас хамгаалж, үлдсэн гурвыг нь төхөөрөмжийн ачааллыг багасгах гэж орхижээ. "Энэ утга хэзээ ч тийм том болохгүй" гэсэн бодол Ариан-4 дээр үнэн байсан. Харин Ариан-5-ын жинхэнэ нислэгийн замаар уг хэсгийг хэн ч туршиж үзээгүй. Ослын дараа тэр замаар загварчилж үзэхэд алдаа яг хэвээрээ давтагдсан.
Ийм алдаа зөвхөн пуужинд гардаг юм биш. Бидний өдөр бүр хэрэглэдэг зүйлс дээр ч тааралдсаар байна.
2014 онд YouTube нэгэн хөгжилтэй мэдэгдэл хийсэн. Psy-гийн "Gangnam Style" бичлэгийг үзсэн тоо 2147483647-оос давсан гэнэ. Энэ бол хоёртын 32 оронтой тэмдэгтэй бүхэл тоонд багтах хамгийн том тоо. YouTube-ийнхэн "нэг бичлэгийг ийм олон удаа үзнэ гэж бодоогүй" гэж хошигнож, тоолуураа 64 оронтой болгосноо мэдэгдсэн. Үнэндээ тэд үүнийг урьдчилан харж, хэдэн сарын өмнө аль хэдийн сольчихсон байсан тул юу ч эвдрээгүй. Халихаас өмнө нь анзаарвал ингээд л амархан шийдэгддэг.
Харин Боинг 787 онгоцны түүх арай айдастай. 2015 онд АНУ-ын агаарын тээврийн хяналтын байгууллага бүх 787 онгоцонд анхааруулга гаргасан. Онгоцны цахилгаан үүсгүүрийг удирддаг төхөөрөмжүүдийн доторх тоолуур 248 хоног тасралтгүй ажилласны дараа халиж, бүх үүсгүүр зэрэг унтрах аюултай байжээ. Програм нь засагдах хүртэл онгоцнуудыг 120 хоног тутамд нэг удаа бүрэн унтрааж асаа гэж үүрэг болгосон. Тийм ээ, "унтраагаад асаачих" гэдэг зөвлөгөө онгоцонд ч хэрэг болдог юм байна.
248 гэдэг тоо хаанаас гарсан бол? Нарийн тайлбарыг нь нийтэлж байгаагүй ч нэг сонирхолтой тооцоо бий. Хэрэв тоолуур секундийн зуун хуваарь бүрт нэгээр нэмэгддэг 32 оронтой тоо байсан гэж үзвэл 2147483647-г 100-д хуваагаад, нэг хоногийн 86400 секундэд хуваахад яг 248 хоног гарна.
Одоо бидэнд шууд хамаатай нэг асуудал руу оръё. Олон төхөөрөмж, програм цагийг 1970 оны 1-р сарын 1-нээс хойш хэдэн секунд өнгөрснөөр тоолдог. Энэ тоог удаан хугацаанд хоёртын 32 оронтой тэмдэгтэй бүхэл тоонд хадгалж ирсэн.
32 оронтой тоонд хамгийн ихдээ 2147483647 багтана гэж дээр ярьсан. 1970 оноос хойш тэр хэмжээний секунд өнгөрөх агшин бол 2038 оны 1-р сарын 19, Улаанбаатарын цагаар 11:14:07. Үүнээс нэг секундийн дараа хуучин програмуудын тоолуур халиж, огноо нь гэнэт 1901 оны 12-р сар руу үсэрнэ. Үүнийг 2038 оны асуудал гэдэг.
Хоёртын 32 оронтой цагийн тоолуур дүүрэхэд огноо 1901 он руу үсэрч байгаа нь. Зураг: Monaneko, Wikimedia Commons
Үүнийг бас Python дээр шалгаж болно.
import ctypes, datetime
ehlel = datetime.datetime(1970, 1, 1)
t = ctypes.c_int32(2**31).value
print(t) # -2147483648
print(ehlel + datetime.timedelta(seconds=t)) # 1901-12-13 20:45:52Сайн мэдээ гэвэл ихэнх шинэ төхөөрөмж аль хэдийн 64 оронтой цаг руу шилжсэн. 64 оронтой тоолуур хэдэн зуун тэрбум жил хүрэлцэнэ. Гэхдээ хуучин, дотроо жижиг програмтай төхөөрөмжүүд одоо ч олон бий. 2038 он гэхэд та нар томчууд болчихсон, магадгүй яг энэ асуудлыг засаж суугаа мэргэжилтэн нь байх ч юм билүү.
Бүх алдаа тоо халихаас болдоггүй. Заримдаа тоо нь зөв, харин хэмжих нэгж нь буруу байдаг.
1999 оны 9-р сарын 23-нд Ангараг гарагийн уур амьсгалыг судлах ёстой Америкийн хиймэл дагуул есөн сар гаруй нисээд Ангарагт хүрч ирсэн. Гарагийг тойрох замд орохын тулд хөдөлгүүрээ асаагаад гарагийн ард орсон. Тэгээд дахиж хэзээ ч дуу гараагүй.
Ангараг гарагийн уур амьсгалыг судлах ёстой байсан хиймэл дагуулыг зураачийн төсөөлснөөр. Зураг: NASA/JPL
Шалгаж үзэхэд хөдөлгүүрийн түлхэлтийг тооцдог газрын програмыг нэг баг, нислэгийн замыг тооцдог програмыг өөр баг бичсэн байжээ. Нэг нь Америкт хэрэглэдэг фунтаар, нөгөө нь дэлхий нийтийн хэрэглэдэг ньютоноор тооцож байв. Нэг фунт хүч 4.45 ньютонтой тэнцүү. Тэгэхээр нэг програмын илгээсэн тоог нөгөө нь 4.45 дахин бага гэж ойлгож байсан хэрэг.
Энэ жижиг зөрүү хэдэн сарын турш хуримтлагдсаар, хиймэл дагуул Ангарагийн гадаргаас 140 орчим км өндөрт байх ёстой байтал 57 км хүртэл дөхөж очсон. Ийм намхан нисэхэд агаар мандал нь түүнийг шатаасан эсвэл хаа нэг тийш шидсэн байх магадлалтай. 125 сая орчим долларын төхөөрөмж ингэж алга болсон.
Энд хоёр програм тус бүрдээ зөв ажиллаж байсан. Буруу нь тэдний хооронд байсан. Хоёр баг "энэ тоо ямар нэгжтэй вэ" гэдгээ бичгээр тохирсон байсан ч хэн ч нэг нэгнийхээ ажлыг тэр тохиролцоотой тулгаж шалгаагүй.
Эдгээр түүх зөвхөн пуужин, онгоц хийдэг хүмүүст хамаатай юм шиг санагдаж магадгүй. Гэхдээ бид ч гэсэн өмнө нь бичсэн програмаа, эсвэл бусдын бичсэн хэсгийг авч хэрэглэх нь элбэг. Тэр болгонд "энэ програм ямар нөхцөлд зориулж бичигдсэн бэ" гэж асуух хэрэгтэй. Ариан-4-ийн програм буруу байгаагүй. Зүгээр л өөр пуужинд зориулж бичигдсэн байсан.
Туршилт ч мөн адил. Шинэ пуужингийн нислэгийн мэдээллээр ганц удаа ажиллуулж үзсэн бол алдаа газар дээрээ илэрч, юу ч алдахгүй байсан. Програм маань ажиллаж байгаа юм шиг харагдах нь хангалтгүй, бодит нөхцөлтэй ойролцоо өгөгдлөөр шалгаж үзэх хэрэгтэй.
Ангарагийн хиймэл дагуулын түүх өөр нэг зүйл заадаг. Хоёр хүн юм уу хоёр баг хамтарч ажиллахдаа нэг нэгэндээ ямар хэлбэрээр мэдээлэл дамжуулахаа тодорхой тохирох хэрэгтэй. Секунд үү, минут уу, метр үү, км уу. Энгийн асуулт мэт боловч асуухгүй өнгөрөхөд ийм л юм болдог.
Тоо ямар хэмжээний зайд хадгалагдаж байгаа, хамгийн ихдээ хэд хүрч болохыг бодож дадах нь бас хэрэгтэй. Python дээр энэ нь бараг мэдрэгддэггүй ч C хэл дээр бичих юм уу жижиг төхөөрөмж програмчлах үед заавал тааралдана. YouTube-ийнхэн шиг халихаас нь өмнө анзаарвал хамгийн сайн.
Ариан-5 дараа нь алдаагаа засаж, 100 гаруй удаа нисч, 2021 онд Жеймс Уэббийн сансрын дуранг хүртэл сансарт гаргасан.
2021 оны 12-р сарын 25. Ариан-5 Жеймс Уэббийн сансрын дуранг сансарт гаргаж байна. Зураг: NASA/Bill Ingalls
Тэгэхээр нэг алдаа бүх юмыг дуусгадаггүй. Гэхдээ 32767-оос давсан ганц тоо хэчнээн үнэтэй тусдгийг санаж явбал илүүдэхгүй.
Гэрийн даалгавар маягаар хоёр зүйл үлдээе. Нэгдүгээрт, Ариан-5-ын жишээн дэх hurd-ын утгыг 32767, 32768, 70000 болгоод ажиллуулаад үзээрэй. Яагаад ийм тоо гарч байгааг тайлбарлаж чадвал гол санааг нь ойлгосон гэсэн үг. Санамж: 16 оронд нийт 65536 өөр утга багтдаг. Хоёрдугаарт, 2038 оны жишээн дэх 2**31-ийг 2**31 - 1 болгоод ажиллуулбал ямар огноо гарахыг эхлээд таагаад, дараа нь шалгаарай.