متى يجب أن أستخدم الرقم المزدوج بدلاً من العلامة العشرية؟

StackOverflow https://stackoverflow.com/questions/803225

سؤال

يمكنني تسمية ثلاث مزايا للاستخدام double (أو float) بدلاً من decimal:

  1. يستخدم ذاكرة أقل.
  2. أسرع لأن عمليات الرياضيات ذات الفاصلة العائمة مدعومة أصلاً بواسطة المعالجات.
  3. يمكن أن تمثل مجموعة أكبر من الأرقام.

ولكن يبدو أن هذه المزايا تنطبق فقط على العمليات الحسابية المكثفة، مثل تلك الموجودة في برامج النمذجة.وبطبيعة الحال، لا ينبغي استخدام الزوجي عندما تكون الدقة مطلوبة، مثل الحسابات المالية.فهل هناك أي أسباب عملية للاختيار من أي وقت مضى double (أو float) بدلاً من decimal في التطبيقات "العادية"؟

تم التعديل للإضافة:شكرا لجميع الردود الرائعة التي تعلمت منها.

سؤال آخر:أشار عدد قليل من الأشخاص إلى أن الأعداد الزوجية يمكن أن تمثل الأعداد الحقيقية بشكل أكثر دقة.عندما أُعلن عن ذلك، أعتقد أنهم عادةً ما يمثلونهم بشكل أكثر دقة أيضًا.ولكن هل صحيح أن الدقة قد تنخفض (أحيانًا بشكل كبير) عند تنفيذ عمليات الفاصلة العائمة؟

هل كانت مفيدة؟

المحلول

أعتقد أنك لخصت المزايا بشكل جيد.لكنك تفتقد نقطة واحدة.ال decimal type هو أكثر دقة في التمثيل القاعدة 10 الأرقام (على سبيل المثالتلك المستخدمة في حسابات العملة/الحسابات المالية).بشكل عام، double سيوفر النوع دقة كبيرة على الأقل (يصححني شخص ما إذا كنت مخطئًا) وبالتأكيد سرعة أكبر للأرقام الحقيقية التعسفية.الاستنتاج البسيط هو:عند التفكير في ما يجب استخدامه، استخدمه دائمًا double إلا إذا كنت في حاجة إلى base 10 دقة ذلك decimal عروض.

يحرر:

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

  1. حقيقة أن بعض الأرقام (الكسور العشرية الأكثر وضوحًا) لا يمكن تمثيلها حقًا في شكل نقطة عائمة
  2. تحدث أخطاء التقريب، تمامًا كما لو كنت تجري العملية الحسابية يدويًا.يعتمد الأمر بشكل كبير على السياق (عدد العمليات التي تقوم بها) وما إذا كانت هذه الأخطاء كبيرة بما يكفي لتبرير الكثير من التفكير.

في جميع الحالات، إذا كنت تريد مقارنة رقمين بفاصلة عائمة ينبغي أن يكونا متكافئين من الناحية النظرية (ولكن تم التوصل إليهما باستخدام حسابات مختلفة)، فأنت بحاجة إلى السماح بدرجة معينة من التسامح (كم يختلف، ولكنه عادةً ما يكون صغيرًا جدًا) .

للحصول على نظرة عامة أكثر تفصيلاً عن الحالات المحددة التي يمكن أن تحدث فيها أخطاء في الدقة، راجع قسم الدقة في مقالة ويكيبيديا.أخيرًا، إذا كنت تريد مناقشة متعمقة (ورياضية) جدية حول أرقام/عمليات الفاصلة العائمة على مستوى الجهاز، فحاول قراءة المقالة المقتبسة كثيرًا ما يجب أن يعرفه كل عالم كمبيوتر عن حساب النقطة العائمة.

نصائح أخرى

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

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

  1. أنت تقوم بتجميع قيم الفاصلة العائمة (وفي هذه الحالة تكون أخطاء الدقة مركبة)
  2. يمكنك إنشاء قيم بناءً على قيمة النقطة العائمة (على سبيل المثال في خوارزمية عودية)
  3. أنت تجري عمليات حسابية باستخدام عدد كبير جدًا من الأرقام المهمة (على سبيل المثال، 123456789.1 * .000000000000000987654321)

يحرر

بحسب ال الوثائق المرجعية على الكسور العشرية C#:

ال عدد عشري تدل الكلمة الرئيسية على نوع بيانات 128 بت.بالمقارنة مع أنواع الفاصلة العائمة ، فإن النوع العشري له دقة أكبر ونطاق أصغر ، مما يجعله مناسبًا للحسابات المالية والنقدية.

لذا لتوضيح كلامي أعلاه:

أميل إلى تصميم العشرية في جميع الحالات ، والاعتماد على البروفيل لإعلامني بما إذا كانت العمليات على العشرية تسبب اختناقات أو تباطؤ.

لقد عملت فقط في الصناعات التي تكون فيها الكسور العشرية مواتية.إذا كنت تعمل على محركات فيزيائية أو رسومية، فمن الأفضل أن تصمم لنوع النقطة العائمة (عائمة أو مزدوجة).

الرقم العشري ليس دقيقًا بشكل لا نهائي (من المستحيل تمثيل دقة لا نهائية لغير التكامل في نوع بيانات بدائي)، ولكنه أكثر دقة بكثير من المزدوج:

  • العشري = 28-29 رقمًا مهمًا
  • مزدوج = 15-16 رقمًا مهمًا
  • تعويم = 7 أرقام مهمة

تحرير 2

للإستجابة ل كونراد رودولفتعليق، البند رقم 1 (أعلاه) صحيح بالتأكيد.تجميع عدم الدقة يضاعف بالفعل.انظر الكود أدناه للحصول على مثال:

private const float THREE_FIFTHS = 3f / 5f;
private const int ONE_MILLION = 1000000;

public static void Main(string[] args)
{
    Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToString("F10"));
    float asSingle = 0f;
    double asDouble = 0d;
    decimal asDecimal = 0M;

    for (int i = 0; i < ONE_MILLION; i++)
    {
        asSingle += THREE_FIFTHS;
        asDouble += THREE_FIFTHS;
        asDecimal += (decimal) THREE_FIFTHS;
    }
    Console.WriteLine("Six Hundred Thousand: {0:F10}", THREE_FIFTHS * ONE_MILLION);
    Console.WriteLine("Single: {0}", asSingle.ToString("F10"));
    Console.WriteLine("Double: {0}", asDouble.ToString("F10"));
    Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10"));
    Console.ReadLine();
}

هذا يخرج ما يلي:

Three Fifths: 0.6000000000
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 599999.9999886850
Decimal: 600000.0000000000

كما ترون، على الرغم من أننا نضيف من نفس المصدر الثابت، فإن نتائج المضاعفة أقل دقة (على الرغم من أنه من المحتمل أن يتم تقريبها بشكل صحيح)، ويكون التعويم أقل دقة بكثير، إلى النقطة التي تم فيها تقليلها إلى فقط رقمين مهمين.

استخدم العلامة العشرية للقيم ذات الأساس 10، على سبيل المثال.الحسابات المالية، كما اقترح آخرون.

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

على سبيل المثال، إذا كنت تريد حساب وزن كل سطر في المحفظة، فاستخدم الضعف لأن النتيجة ستضيف ما يصل إلى 100٪ تقريبًا.

في المثال التالي، doubleResult أقرب إلى 1 من decimalResult:

// Add one third + one third + one third with decimal
decimal decimalValue = 1M / 3M;
decimal decimalResult = decimalValue + decimalValue + decimalValue;
// Add one third + one third + one third with double
double doubleValue = 1D / 3D;
double doubleResult = doubleValue + doubleValue + doubleValue;

لذلك مرة أخرى أخذ مثال المحفظة:

  • القيمة السوقية لكل سطر في المحفظة هي قيمة نقدية ومن الأفضل تمثيلها على أنها قيمة عشرية.

  • عادةً ما يتم تمثيل وزن كل سطر في المحفظة (= القيمة السوقية / SUM (القيمة السوقية)) بشكل أفضل على أنه مزدوج.

استخدم العوامة المزدوجة أو العوامة عندما لا تحتاج إلى الدقة، على سبيل المثال، في إحدى ألعاب المنصات التي كتبتها، استخدمت العوامة لتخزين سرعات اللاعب.من الواضح أنني لا أحتاج إلى دقة فائقة هنا لأنني في النهاية أقوم بالتقريب إلى Int للرسم على الشاشة.

في بعض المحاسبة، فكر في إمكانية استخدام الأنواع المتكاملة بدلاً من ذلك أو بالاشتراك.على سبيل المثال، لنفترض أن القواعد التي تعمل بموجبها تتطلب ترحيل كل نتيجة حسابية بما لا يقل عن 6 منازل عشرية وسيتم تقريب النتيجة النهائية إلى أقرب قرش.

حساب 1/6 من 100 دولار أمريكي ينتج عنه 16.66666666666666 دولارًا أمريكيًا...، وبالتالي فإن القيمة المنقولة في ورقة العمل ستكون 16.666667 دولارًا أمريكيًا.يجب أن يؤدي كل من العدد المزدوج والعشري إلى الحصول على هذه النتيجة بدقة تصل إلى 6 منازل عشرية.ومع ذلك، يمكننا تجنب أي خطأ تراكمي عن طريق ترحيل النتيجة كعدد صحيح 16666667.ويمكن إجراء كل عملية حسابية لاحقة بنفس الدقة وترحيلها بالمثل.بالاستمرار في المثال، قمت بحساب ضريبة مبيعات تكساس على هذا المبلغ (16666667 * .0825 = 1375000).جمع الاثنين (إنها ورقة عمل قصيرة) 1666667 + 1375000 = 18041667.إن تحريك العلامة العشرية مرة أخرى يعطينا 18.041667، أو 18.04 دولارًا.

على الرغم من أن هذا المثال القصير لن ينتج عنه خطأ تراكمي باستخدام مزدوج أو عشري، فمن السهل إلى حد ما إظهار الحالات التي يؤدي فيها حساب العدد المزدوج أو العشري ببساطة إلى تراكم خطأ كبير.إذا كانت القواعد التي تعمل بموجبها تتطلب عددًا محدودًا من المنازل العشرية، فسيتم تخزين كل قيمة كعدد صحيح عن طريق الضرب في 10^(الرقم المطلوب للمنازل العشرية)، ثم القسمة على 10^(الرقم المطلوب للمنازل العشرية) للحصول على القيمة الفعلية سوف تتجنب القيمة أي خطأ تراكمي.

في الحالات التي لا تحدث فيها كسور البنسات (على سبيل المثال، آلة البيع)، لا يوجد سبب لاستخدام أنواع غير متكاملة على الإطلاق.ببساطة فكر في الأمر على أنه عد البنسات، وليس الدولارات.لقد رأيت رمزًا حيث كانت كل عملية حسابية تتضمن بنسات كاملة فقط، إلا أن استخدام المضاعفة أدى إلى حدوث أخطاء!عدد صحيح الرياضيات فقط إزالة هذه القضية.لذا فإن إجابتي غير التقليدية هي، عندما يكون ذلك ممكنًا، التخلي عن العدد المزدوج والعشري.

إذا كنت بحاجة إلى التبادل الثنائي مع لغات أو منصات أخرى، فقد تحتاج إلى استخدام float أو double، وهي موحدة.

ملحوظة:يعتمد هذا المنشور على معلومات حول إمكانيات النوع العشري من http://csharpin Deep.com/Articles/general/Decimal.aspx وتفسيري الخاص لما يعنيه ذلك.سأفترض أن Double هو دقة IEEE المزدوجة العادية.

ملاحظة 2:الأصغر والأكبر في هذا المنشور يشير إلى حجم العدد.

إيجابيات "العشري".

  • "الرقم العشري" يمكن أن يمثل بالضبط الأرقام التي يمكن كتابتها ككسور عشرية (قصيرة بما فيه الكفاية)، ولا يمكن كتابة الرقم المزدوج.يعد هذا أمرًا مهمًا في دفاتر الأستاذ المالية وما شابه ذلك حيث يكون من المهم أن تتطابق النتائج تمامًا مع ما قد يقدمه الإنسان الذي يقوم بالحسابات.
  • يحتوي "الرقم العشري" على جزء عشري أكبر بكثير من "المزدوج".وهذا يعني أنه بالنسبة للقيم الموجودة ضمن نطاقها الطبيعي، فإن "الرقم العشري" سيكون له دقة أعلى بكثير من الضعف.

سلبيات العلامة العشرية

  • سيكون أبطأ بكثير (ليس لدي معايير ولكن أعتقد على الأقل أنه ربما أكثر من ذلك)، ولن يستفيد النظام العشري من أي تسريع للأجهزة، كما أن العمليات الحسابية عليه ستتطلب عمليات ضرب/قسمة مكلفة نسبيًا على قوى 10 ( وهو أكثر تكلفة بكثير من الضرب والقسمة على قوى 2) لمطابقة الأس قبل الجمع/الطرح ولإعادة الأس إلى النطاق بعد الضرب/القسمة.
  • سوف يتجاوز الرقم العشري في وقت سابق من الإرادة المزدوجة.يمكن أن يمثل الرقم العشري أرقامًا تصل إلى ±2 فقط96-1 .بالمقارنة، يمكن أن يمثل الرقم المزدوج أرقامًا تصل إلى ±2 تقريبًا1024
  • العشري سوف يتدفق في وقت سابق.أصغر الأرقام التي يمكن تمثيلها بالنظام العشري هي ±10-28 .بالمقارنة، يمكن أن يمثل المضاعفة قيمًا تصل إلى 2-149 (حوالي 10-45) إذا كانت الأرقام الفرعية مدعومة و 2-126 (حوالي 10-38) إذا لم يكونوا كذلك.
  • يستهلك العدد العشري ضعف الذاكرة التي يستهلكها المضاعف.

رأيي هو أنه يجب عليك استخدام "الرقم العشري" افتراضيًا للعمل المالي والحالات الأخرى التي تكون فيها مطابقة الحسابات البشرية أمرًا مهمًا تمامًا ويجب عليك استخدام الاستخدام المزدوج كخيارك الافتراضي في بقية الوقت.

استخدم النقاط العائمة إذا كنت تقدر الأداء على الصحة.

اختر النوع الوظيفي لتطبيقك.إذا كنت بحاجة إلى الدقة كما هو الحال في التحليل المالي، فقد أجبت على سؤالك.ولكن إذا كان من الممكن تسوية طلبك بتقدير، فلا بأس بالمضاعفة.

هل يحتاج طلبك إلى عملية حسابية سريعة أم أنه سيكون لديه كل الوقت ليعطيك إجابة؟يعتمد الأمر حقًا على نوع التطبيق.

الرسم جائع؟تعويم أو مزدوج يكفي.تحليل البيانات المالية، نيزك يضرب كوكبًا من النوع الدقيق؟تلك تحتاج إلى القليل من الدقة :)

يحتوي النظام العشري على وحدات بايت أوسع، بينما يتم دعم وحدة المعالجة المركزية المزدوجة أصلاً.العدد العشري هو الأساس 10، لذلك يحدث تحويل من الرقم العشري إلى المزدوج أثناء حساب الرقم العشري.

For accounting - decimal
For finance - double
For heavy computation - double

ضع في اعتبارك أن .NET CLR يدعم Math.Pow(double,double) فقط.العلامة العشرية غير مدعومة.

.صافي الإطار 4

[SecuritySafeCritical]
public static extern double Pow(double x, double y);

سيتم إجراء تسلسل للقيم المزدوجة إلى التدوين العلمي بشكل افتراضي إذا كان هذا التدوين أقصر من العرض العشري.(على سبيل المثال.00000003 سيكون 3e-8) لن يتم إجراء تسلسل للقيم العشرية مطلقًا إلى التدوين العلمي.عند إجراء تسلسل للاستهلاك من قبل طرف خارجي، قد يكون هذا أحد الاعتبارات.

يعتمد على ما تحتاجه.

لأن float و double هما نوعان من البيانات الثنائية لديك بعض الصعوبات والأخطاء في تقريب الأرقام، على سبيل المثال، يتم تقريب الرقم double من 0.1 إلى 0.100000001490116، كما يتم تقريب الرقم double أيضًا من 1/3 إلى 0.33333334326441.ببساطة، ليس كل الأعداد الحقيقية لها تمثيل دقيق في الأنواع المزدوجة

لحسن الحظ، تدعم C# أيضًا ما يسمى بحساب الفاصلة العائمة العشرية، حيث يتم تمثيل الأرقام عبر النظام الرقمي العشري بدلاً من النظام الثنائي.وبالتالي، فإن العلامة العشرية العائمة الحسابية لا يفقد الدقة عند تخزين ومعالجة أرقام الفاصلة العائمة.وهذا يجعلها مناسبة للغاية للحسابات التي تتطلب مستوى عالٍ من الدقة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top