قضايا التقريب مع تخصيص مبالغ الدولار عبر العديد من الناس

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

  •  06-09-2019
  •  | 
  •  

سؤال

ما هي أفضل طريقة لحل هذه المشكلة في التعليمات البرمجية؟

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

هنا مثال محدد:

وعاء # 1 987،654.32
وعاء # 2 123،456.78

يحصل الشخص رقم 1 على مبلغ تخصيص: 345،678.89
يحصل الشخص رقم 2 مبلغ تخصيص: 460،599.73
شخص # 3 يحصل على مبلغ تخصيص: 304،832.48

منطقي كما يلي (الرمز في C #):

foreach (Person person in People)
{
    decimal percentage = person.AllocationAmount / totalOfAllPots;

    decimal personAmountRunningTotal = person.AllocationAmount;

    foreach (Pot pot in pots)
    {
        decimal potAllocationAmount = Math.Round(percentage * pot.Amount, 2);
        personAmountRunningTotal -= potAllocationAmount;

        PersonPotAssignment ppa = new PersonPotAssignment();
        ppa.Amount = potAllocationAmount;

        person.PendingPotAssignments.Add(ppa);
    }

    foreach (PersonPotAssignment ppa in person.PendingPotAssignments)
    {
        if (personAmountRunningTotal > 0) //Under Allocated
        {
            ppa.Amount += .01M;
            personAmountRunningTotal += .01M;
        }
        else if (personAmountRunningTotal < 0) //Over Allocated
        {
            ppa.Amount -= .01M;
            personAmountRunningTotal -= .01M;
        }
    }
}

النتائج التي أحصل عليها هي كما يلي:

وعاء # 1، الشخص رقم 1 = 307،270.13
وعاء # 1، شخص # 2 = 409،421.99
وعاء # 1، الشخص رقم 3 = 270،962.21
وعاء # 1 المجموع = 987،654.33 (1 بنس خارج)

وعاء # 2، شخص # 1 = 38،408.76
وعاء # 2، شخص # 2 = 51،177.74
وعاء # 2، شخص # 3 = 33،870.27
الإجمالي رقم 2 = 123،456.77 (1 بنس خارج)

إجماليات وعاء يجب أن تتطابق مع المجاميع الأصلية.

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

سيتم تقدير أي مساعدة إلى حد كبير.

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

المحلول

يحدث هذا في الحسابات المالية كثيرا عند التقريب إلى أقرب قرش. لن يعمل أي قدر من التغيير والتبديل خوارزمية تقريب العمليات الفردية لكل حالة.

يجب أن يكون لديك تراكم يتتبع المبلغ المخصص بعد عملية التقريب والتوزيع. في نهاية المخصصات، يمكنك التحقق من المتراكب ضد النتائج الفعلية (لخص معا) وتوزيع البقعة البقعة.

في مثال الرياضيات أدناه، إذا كنت تأخذ 0.133 وإضافته إلى 0.13 وأضف 3 مرات، تحصل على قرش أقل مما لو قمت بإضافة 0.133 3 مرات أولا ثم جولة.

 0.13    0.133
 0.13    0.133
+0.13   +0.133
_____   ______
 0.39    0.399 -> 0.40

نصائح أخرى

هل حاولت ربط سلوك التقريب بالحجة المنتوسطية؟

public static decimal Round( decimal d, MidpointRounding mode )

+1 لحل مات Spradley.

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

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

ما يجب القيام به عند تقسيم الأموال مشكلة معمرة. تقدم مارتن فاولر بعض التعليق هنا (أعتقد أن هناك مزيد من التفاصيل في فعله الفعلي poeaa كتاب):

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

class Money... 
    public Money[] divide(int denominator) {
        BigInteger bigDenominator = BigInteger.valueOf(denominator);
        Money[] result = new Money[denominator];
        BigInteger simpleResult = amount.divide(bigDenominator);
        for (int i = 0; i < denominator ; i++) {
            result[i] = new Money(simpleResult, currency, true);
        }
        int remainder = amount.subtract(simpleResult.multiply(bigDenominator)).intValue();
        for (int i=0; i < remainder; i++) {
            result[i] = result[i].add(new Money(BigInteger.valueOf(1), currency, true));
        }
        return result;
    }

بالتأكيد الرياضيات.

أود أن أقترح لا تقريب نتيجة الحساب، ولكن إذا كنت بحاجة إلى عرض، ثم جولة إلى أقرب قرش. أو يمكنك استخدام البنسات بأصغر قاسما، وبالتالي عند العرض، قم بتقسيم كل شيء بنسبة 100.

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