أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول

Floating Point للمبتدئ: ليه 0.1 + 0.2 ≠ 0.3 في كل لغات البرمجة

📅 ٢٨ أبريل ٢٠٢٦⏱ 5 دقائق قراءة
Floating Point للمبتدئ: ليه 0.1 + 0.2 ≠ 0.3 في كل لغات البرمجة

هذا المقال يتطلب مستوى مبتدئ.

فتحت Console المتصفح وكتبت 0.1 + 0.2، فجالك 0.30000000000000004. مش غلط في المتصفح، ولا غلط في JavaScript. لو جربت نفس المعادلة في Python أو Java أو Go أو Swift، النتيجة هتكون نفسها بالظبط. السبب في الكمبيوتر نفسه، مش في اللغة.

Floating Point: السبب الحقيقي وراء الأرقام الغريبة

المقال ده بيشرحلك ليه الكمبيوتر بيعمل كده، وإمتى المشكلة دي ممكن تكسر تطبيقك (خصوصًا لو بيتعامل مع نقود)، وإيه الحلول العملية اللي تقدر تطبقها في 5 دقائق.

شاشة كمبيوتر تعرض أرقامًا بدقة عشرية متعددة لتوضيح مشكلة Floating Point

مثال بسيط: المسطرة الناقصة

قبل ما ندخل في التعريف العلمي، خد المثال ده:

عندك مسطرة طولها 10 سنتيمتر، ومعلّم عليها فقط كل ربع سنتيمتر (0.25, 0.5, 0.75, 1.0…). طلبت منك ترسم خط طوله ثلث سنتيمتر بالظبط (0.333…). هتحاول، هتلاقي إن العلامة دي مش موجودة على المسطرة. اضطريت تختار أقرب علامة متاحة، يعني 0.25 أو 0.5. النتيجة قريبة من ثلث، لكن مش ثلث بالظبط.

الكمبيوتر بيعمل نفس الكلام، لكن بـ نظام ثنائي (binary). علامات مسطرته كلها قوى الرقم 2: نص (1/2)، ربع (1/4)، ثُمُن (1/8)، ربع الـ ثُمُن (1/16)، وهكذا. الرقم 0.1 ما يقعش بالظبط على أي علامة من دول. فالكمبيوتر بيخزّن أقرب رقم ممكن، اللي بيكون 0.1000000000000000055511151231257827021181583404541015625. الفرق صغير جدًا، لكنه موجود.

لما تجمع تقريبين (0.1 + 0.2)، الفروق الصغيرة دي بتتراكم، فبتطلع نتيجة 0.30000000000000004 بدل 0.3 المضبوط.

التعريف العلمي: IEEE 754

IEEE 754 معيار عالمي صدر سنة 1985 بيحدّد إزاي الكمبيوتر يخزّن ويحسب الأرقام العشرية. كل لغة برمجة بتستخدمه تقريبًا، عشان كده النتيجة واحدة في كل اللغات.

المعيار بيقسّم أي رقم عشري لـ 3 أجزاء داخل الذاكرة:

  • sign bit — bit واحد بيحدد لو الرقم موجب ولا سالب
  • exponent — مجموعة bits بتحدد المدى (الأس)
  • mantissa — مجموعة bits بتخزن الأرقام المعنوية

في النوع الأكثر شيوعًا (double precision أو float64) اللي JavaScript بتستخدمه افتراضيًا لكل الأرقام، الرقم بياخد 64 bit مقسومين كده: 1 sign + 11 exponent + 52 mantissa.

المشكلة إن 0.1 في النظام الثنائي بيتحوّل لكسر دوري لانهائي (زي 0.333… في النظام العشري). لما الكمبيوتر بيقصّه عند 52 bit، بيحصل rounding، والنتيجة بتفرق عن 0.1 الحقيقي بفرق صغير جدًا (تقريبًا 5.55 × 10⁻¹⁸).

آلة حاسبة وأوراق مالية لتوضيح أهمية دقة الأرقام في حسابات النقود

الكود اللي بيوريك المشكلة في 30 ثانية

JavaScript
// JavaScript
console.log(0.1 + 0.2);
// 0.30000000000000004

console.log(0.1 + 0.2 === 0.3);
// false

console.log((0.1 + 0.2).toFixed(20));
// "0.30000000000000004441"
Python
# Python
print(0.1 + 0.2)
# 0.30000000000000004

print(0.1 + 0.2 == 0.3)
# False

جرّب الكود ده دلوقتي في أي لغة عندك. هتلاقي نفس النتيجة بالظبط.

الحل الأول: ما تقارنش الأرقام العشرية مباشرة

بدل ما تستخدم === للمقارنة، استخدم هامش خطأ صغير اسمه epsilon:

JavaScript
function equals(a, b, epsilon = 1e-9) {
  return Math.abs(a - b) < epsilon;
}

equals(0.1 + 0.2, 0.3); // true

المنطق هنا بسيط: لو الفرق بين الرقمين أقل من رقم صغير جدًا (1e-9 = جزء من بليون)، اعتبرهم متساويين. ده بيشتغل تمام لمعظم التطبيقات العادية.

الحل الثاني: استخدم أرقام صحيحة في حسابات النقود

ده الحل الأهم في تطبيقات real-world. ما تخزنش الأسعار كـ float أبدًا. خزنها كأرقام صحيحة بأصغر وحدة (قروش بدل جنيهات، cents بدل dollars):

JavaScript
// غلط: 
const price1 = 0.10;
const price2 = 0.20;
const total = price1 + price2; // 0.30000000000000004

// صح:
const price1 = 10; // 10 قروش
const price2 = 20; // 20 قرش
const total = price1 + price2; // 30 بالظبط

// عند العرض:
const display = (total / 100).toFixed(2); // "0.30"

الطريقة دي بيستخدمها Stripe و PayPal في APIs بتاعتهم: كل المبالغ بترجع كأرقام صحيحة بالـ cents.

الحل الثالث: مكتبات decimal

لو محتاج دقة حقيقية ومرونة في العمليات (ضرب نسب مئوية، قسمة، إلخ)، استخدم مكتبة decimal مخصصة:

JavaScript
// JavaScript: decimal.js
import Decimal from 'decimal.js';

const result = new Decimal(0.1).plus(0.2);
console.log(result.toString()); // "0.3"
Python
# Python: decimal module (مدمج)
from decimal import Decimal

result = Decimal('0.1') + Decimal('0.2')
print(result) # 0.3

trade-offs: كل حل وثمنه

  • epsilon comparison: بسيط وسريع. الثمن: لازم تختار epsilon مناسب لطبيعة بياناتك. 1e-9 ممكن يكون كبير لحسابات علمية دقيقة.
  • integer math (قروش): دقيق 100% وسريع. الثمن: لازم تتذكر تقسم على 100 عند العرض، وتضرب في 100 عند الإدخال. شوية تعقيد إضافي في الكود.
  • decimal libraries: دقة كاملة ومرونة كاملة. الثمن: أبطأ بحوالي 10× من Float العادي، وحجم الـ bundle بيزيد ~30KB في JavaScript.

متى لا تستخدم هذه الحلول

مش كل التطبيقات محتاجة دقة 100%. الأخطاء الصغيرة دي ما لهاش تأثير في الحالات دي:

  • الرسوم البيانية والـ animations: فرق 10⁻¹⁵ في إحداثيات pixel ما لهوش أي تأثير بصري.
  • حسابات إحصائية تقريبية: لو بتحسب متوسط 1000 رقم، خطأ نصف بليون ما لهوش معنى.
  • قياسات الأداء (CPU%, latency): Float عادي كافي.
  • الذكاء الاصطناعي و machine learning: بل العكس، float32 بيكفي و float16 شائع للسرعة.

استخدم decimal أو integer math بس لما الدقة فعلًا مهمة: نقود، حسابات بنكية، طب، علوم دقيقة، blockchain.

الخطوة التالية

افتح أكبر تطبيق عندك بيتعامل مع نقود. اعمل بحث في الكود عن العمليات على متغيرات Float (price * 0.15، amount + tax). لو لاقيت سطر زي Math.round(price * 0.15 * 100) / 100، ده علامة واضحة إن في حد كان عارف بالمشكلة بس عملها workaround بدل حل جذري. حوّلها لـ integer math من الأصل، أو استخدم decimal library. ابدأ بأهم endpoint بيشتغل عليه نقود.

المصادر

  • IEEE 754-2019 Standard for Floating-Point Arithmetic — IEEE Standards Association
  • "What Every Computer Scientist Should Know About Floating-Point Arithmetic" — David Goldberg, ACM Computing Surveys, 1991
  • ECMA-262 (JavaScript Language Specification), Section 6.1.6.1 — The Number Type
  • Python Documentation — Floating Point Arithmetic: Issues and Limitations (docs.python.org/3/tutorial/floatingpoint.html)
  • Stripe API Reference — Amounts in smallest currency unit (stripe.com/docs/currencies)
  • 0.30000000000000004.com — Demo للمشكلة في كل لغات البرمجة

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة