الاستكمال الخطي

من ويكي
اذهب إلى: تصفح، ابحث

الاستكمال الخطي linear interpolation أحد أهم الأدوات الرياضية في الرسوميات، حيث يمكنك من تخزين عدد محدود من المعلومات كنقاط واشتقاق تفاصيل أكثر عن طريق استكمال القيم التي بين هذه النقاط خطياً، مثلاً في الشكل في يسار الصورة هناك لون أحمر في طرف المستطيل العلوي ولون أزرق في أسفله، الألوان التي بينهما استكملت خطياً بين هذين اللونين عن طريق استكمال كل مركب لوني على حدة، اللون الذي في منتصف المستطيل نصفه أحمر ونصفه أزرق، في المظللات في المعالجات الرسومية والمكتبات الرسومية ستجد دالة تقوم بهذا العمل اسمها lerp(a, b, t) اختصاراً linear interpolation حيث تأخذ قيمة t بين الصفر والواحد، حينما تكون قيمة t = 0 فإن lerp(a, b, 0) = a ولو كانت قيمة t = 1 فإن lerp(a, b, 1) = b، ولو كانت t = 0.5 فإن lerp(a, b, 0.5) = a * 0.5 + b * 0.5، في هذا المقال سنتعلم كيف نشتق هذه الدالة.


الاستكمال الخطي.png

لو كان لدينا قيمتين [math]a[/math] و [math]b[/math] ونريد الاستكمال خطياً بين النقطتين باستخدام المتغير [math]t \in \mathbb{R}[/math] في المدى [math][0, 1][/math] بحيث [math]f(t = 0) = a[/math] و [math]f(t = 1) = b[/math]، لو نظرت للرسم البياني في اليمين ستجد أن أمامنا خط مستقيم ميله [math]m = (b - a) / (1 - 0)[/math]، ونعرف أن دالة الخط المستقيم [math]f(x) = mx + c[/math]، هنا سنسمي المتغير [math]t[/math] بدلاً من [math]x[/math] تماشياً مع العرف، ونعرف أن النقطة [math]c[/math] تمثل نقطة التقاطع مع المحور الثاني وفي حالتنا هي [math]a[/math]، إذاً معادلة الاستكمال الخطي هي ([math]a[/math] و [math]b[/math] ثوابت، فقط [math]t[/math] المتغيرة بين الصفر والواحد):

[bmath]\mathrm{lerp}(t) = (b - a) t + a[/bmath]

حيث أن [math]t \in \mathbb{R} \in [0, 1][/math].

كون الكمبيوتر يستخدم غالباً أعداد الفاصلة العائمة التي تخزن القيم مقربة، فإن التعبير [math](b - a) t + a[/math] بصيغته هذه يعاني من مشكلة في التقريب في الحد [math](b - a)[/math]، فلو كانت قيمة [math]b[/math] صغيرة جداً مقارنة بقيمة [math]a[/math] وكانت قيمة [math]t = 1[/math]، وقتها فإن lerp(a, b, 1) = 0، انظر ماذا سينتج لو جربت مثلاً باستخدام Python[١]:

>>> def lerp(a, b, t):
...     return (b - a) * t + a
...
>>>
>>> lerp(-2e16, 2, 1)
0.0
>>>

كيف حدث هذا:

b - a = 2 - (-2e16) = 2e16 # خطأ في التقريب بسبب استخدام أعداد الفاصلة العائمة

(b - a) * t = 2e16 * 1 = 2e16

(b - a) * t + a = 2e16 * 1 + (-2e16) = 2e16 - 2e16 = 0 # المحصلة النهائية صفر

يمكننا تفادي هذا الخطأ في التقريب عن طريق إعادة ترتيب المعادلة إلى:

[bmath]\begin{align}\mathrm{lerp}(t) &= (b - a) t + a \\ &= bt + at + a \\ \\ \mathrm{lerp}(t) &= bt + a(1 - t)\end{align}[/bmath]

الآن لو اجربنا مرة أخرى باستخدام الصيغة الجديدة فسنحصل على النتيجة الصحيحة:

>>> def lerp(a, b, t):
...     return b * t + a * (1 - t)
...
>>>
>>> lerp(-2e16, 2, 1)
2.0
>>>
  1. 2e16 = [math]2^{16}[/math]