سؤال

في C89، الطابق () بإرجاع مزدوجة. هي التالية مضمونة للعمل؟

double d = floor(3.0 + 0.5);
int x = (int) d;
assert(x == 3);

وقلقي هو أن نتيجة الدور قد لا يكون للتمثيل بالضبط في IEEE 754. لذا د يحصل شيء من هذا القبيل 2.99999، و x ينتهي به الأمر إلى 2.

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

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

المحلول

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

نصائح أخرى

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

(وبالإضافة إلى ذلك، والإجابة مهرداد هو الصحيح ل[إينتس] 32 بت. وفي مترجم مع ضعف 64 بت <م> و وكثافة العمليات 64 بت، وكنت قد حصلت على المزيد من المشاكل بالطبع ...)

وتحرير: لعلك تعني "نتيجة النظرية من الطابق ()، أي أكبر قيمة عدد صحيح أقل من أو تساوي حجة، قد لا يكون للتمثيل كما عدد صحيح". وهذا بالتأكيد صحيح. طريقة بسيطة لتبين هذا للنظام حيث كثافة العمليات هو 32 بت:

int max = 0x7fffffff;
double number = max;
number += 10.0;
double f = floor(number);
int oops = (int) f;

لا أستطيع أن أتذكر مرتجلا ما C يفعل عندما تحويلات من النقطة العائمة إلى تجاوز عدد صحيح ... ولكن سيحدث هنا.

وتحرير: هناك حالات أخرى مثيرة للاهتمام للنظر أيضا. وفيما يلي بعض C # رمز والنتائج - كنت أتصور على الأقل <م> مماثلة أشياء يمكن أن يحدث في C. في C #، يتم تعريف double لتكون 64 بت وذلك هو long

using System;
class Test
{
    static void Main()
    {
        FloorSameInteger(long.MaxValue/2);
        FloorSameInteger(long.MaxValue-2);
    }

    static void FloorSameInteger(long original)
    {
        double convertedToDouble = original;
        double flooredToDouble = Math.Floor(convertedToDouble);
        long flooredToLong = (long) flooredToDouble;

        Console.WriteLine("Original value: {0}", original);
        Console.WriteLine("Converted to double: {0}", convertedToDouble);
        Console.WriteLine("Floored (as double): {0}", flooredToDouble);
        Console.WriteLine("Converted back to long: {0}", flooredToLong);
        Console.WriteLine();
    }
}

والنتائج:

<اقتباس فقرة>   

وقيمة الأصل: 4611686018427387903
  تحويلها إلى ضعف:   4.61168601842739E + 18 طوابق
(كما مزدوج): 4.61168601842739E + 18
  تحويلها مرة أخرى إلى فترة طويلة:   4611686018427387904
  
  القيمة الأصلية: 9223372036854775805
  تحويلها إلى ضعف:   9.22337203685478E + 18 طوابق
(كما مزدوج): 9.22337203685478E + 18
  تحويلها مرة أخرى إلى فترة طويلة:   -9223372036854775808

وبعبارة أخرى:

(long) floor((double) original)

وليس دائما نفس original. هذا لا ينبغي أن تأتي أي مفاجأة - هناك قيم أكثر طويلة من الضعف (في ضوء القيم نان) والكثير من الزوجي ليست صحيحة، لذلك لا يمكننا أن نتوقع كل فترة طويلة ليكون للتمثيل بالضبط. ومع ذلك، فإن جميع الأعداد الصحيحة 32 بت <م> هي للتمثيل كما الزوجي.

وأعتقد أنك قليلا عن الخلط بين ما تريد أن تسأل. floor(3 + 0.5) ليس مثالا جيدا للغاية، لأن 3، 0،5، ومجموعهما كلها للتمثيل بالضبط في أي العالم الحقيقي العائمة شكل نقطة. سوف floor(0.1 + 0.9) يكون مثالا أفضل، والسؤال الحقيقي هنا ليس ما إذا كانت نتيجة floor هي للتمثيل بالضبط، ولكن هل عدم دقة الأرقام <م> قبل داعيا floor سيؤدي إلى قيمة الإرجاع مختلفة عن ما كنت تتوقعها، وكان جميع الأرقام كانت على وجه الدقة. في هذه الحالة، وأعتقد أن الجواب هو نعم، ولكن ذلك يعتمد كثيرا على الأرقام الخاصة بك.

وأدعو الآخرين إلى انتقاد هذا النهج لو كان سيئا، ولكن واحد الحلول الممكنة قد يكون لمضاعفة عدد الخاص بك عن طريق (1.0+0x1p-52) أو شيئا من هذا القبيل قبل أن استدعاء floor (ربما باستخدام nextafter سيكون أفضل). وهذا يمكن أن تعوض عن الحالات التي يسبب خطأ في مكان ثنائي الأخير من عدد لتنخفض فقط وليس بالضبط على قيمة عددية، لكنها لن تشكل الأخطاء التي تراكمت على مدى عدد من العمليات. إذا كنت بحاجة إلى هذا المستوى من رقمية الاستقرار / دقة، تحتاج إما إلى القيام ببعض تحليل عميق أو استخدام الدقة التعسفي أو مكتبة بالضبط-الرياضيات التي يمكن التعامل مع الأرقام الخاصة بك بشكل صحيح.

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