मैं एकता में एक निष्क्रिय/क्लिक गेम बना रहा हूं, और एक कस्टम प्रारूप है जिसे मैं खेल के सभी नंबरों को प्रदर्शित करना चाहता हूं। हजारों के लिए के, लाखों के लिए एम, अरबों के लिए बी, आदि। टॉवर ऑफ हीरोज नामक गेम से नीचे उदाहरण देखें।

उदाहरण

इन नंबरों और इकाइयों का प्रदर्शन बहुत अच्छा काम करता है। हालाँकि, जहाँ मैं एक मुद्दे में भाग रहा हूँ, वह खेल में मनमाने ढंग से बड़ी संख्या में होने के मेरे निर्णय के साथ है। मैं दोहरे की बाधाओं से सीमित नहीं होना चाहता था, और अपने स्वयं के समाधान के साथ आने की चुनौती चाहता था। मैं ऐसा करने में सक्षम था, और यहां तक ​​​​कि मेरे समाधान के साथ काम करने के लिए अधिकांश गणित संचालन भी प्राप्त करता था। जोड़, घटाव, गुणा और घातांक सभी पर्याप्त रूप से काम करते हैं। लेकिन मैं विभाजन के लिए तर्क/गणित नहीं समझ सकता ...

इसलिए, मैं अपने प्रत्येक गेम वेरिएबल के लिए युगल की सूची का उपयोग कर रहा हूं। उदाहरण: List<double> money = new List<double>(); एक सूची होगी जिसमें खिलाड़ी के पास वर्तमान में मौजूद धन होगा। प्रत्येक स्थिति 0-999 तक सीमित है। स्थिति 0 "1" का प्रतिनिधित्व करता है, स्थिति 1 हजारों, स्थिति 2 लाखों, आदि, सूची जितनी बड़ी होनी चाहिए उतनी बड़ी हो रही है। तो अगर हमारे पास था:

List<double> money = new List<double>()
{
    10,  //1's
    50,  //thousands (K)
    200  //millions (M)
         //etc.
};

यह $200,050,010 होगा, या मेरे गेम के नोटेशन में: 200M050K। (मैं केवल सबसे बड़ी इकाई, या कभी-कभी सबसे बड़ी दो इकाइयाँ प्रदर्शित करता हूँ)

उदाहरण के लिए, मेरे द्वारा काम करने की अतिरिक्त विधि यहां दी गई है:

     //SuperAdd
public List<double> SuperAdd(List<double> baseValue, List<double> valueBeingAdded)
{
    //declairing a new list to house the result
    List<double> resultValue = new List<double>();

    //making copies to not affect originals
    List<double> baseValueCopy = baseValue;
    List<double> valueBeingAddedCopy = valueBeingAdded;

    //increase the # of tiers in our result list until it matches the largest of the two being added
    while (resultValue.Count < Mathf.Max(valueBeingAddedCopy.Count, baseValueCopy.Count))
    {
        resultValue.Add(0);

        //if needed adjust the size of the two lists being added together so they match
        if (valueBeingAddedCopy.Count < baseValueCopy.Count) valueBeingAddedCopy.Add(0);
        if (valueBeingAddedCopy.Count > baseValueCopy.Count) baseValueCopy.Add(0);

    }

    //add all the respective tiers together
    for (int i = 0; i < resultValue.Count; i++)
    {
        //add all the tiers together
        resultValue[i] = baseValueCopy[i] + valueBeingAddedCopy[i];           
    }

    //check for any carry overs needed (>=1000)
    for (int i = 0; i < resultValue.Count; i++)
    {
        //where this is true we need to carry over to next tier
        if(resultValue[i] >= 1000)
        {
            //check if we are on the last existing tier
            if(i + 1 == resultValue.Count)
            {
                //add an empty tier
                resultValue.Add(0);
            }

            //calculate how many thousands need to be carried over, and what the remainder is
            double nextTierAdder = Math.Floor(resultValue[i] / 1000);
            double currentTierRemainder = resultValue[i] % 1000;

            //apply both
            resultValue[i] = currentTierRemainder;
            resultValue[i + 1] += nextTierAdder;                
        }
    }

    //remove any empty blanks from the ends of the resultValue list
    for (int i = resultValue.Count - 1; i > 0; i--)
    {
        if (resultValue[i] == 0) resultValue.RemoveAt(i);
        else break;
    }

    //return resultValue
    return resultValue;
}

तो, मैं जो हासिल करना चाहता हूं वह विभाजन, छद्म कोड के लिए एक समान विधि है:

    public List<double> SuperDivide(List<double> baseValue1, List<double> baseValue2)
{
    //code goes here

    return result;
}

मेरे पास अब तक प्लेसहोल्डर के रूप में कुछ जंक कोड है जब तक कि मैं एक सही समाधान नहीं निकालता जो एक सूची लौटाएगा।

        //SuperDivide result = bv1 / bv2
//this is currently only useful when the values are near one another in size
public double SuperDivide(List<double> baseValue1, List<double> baseValue2)
{
    double result;

    //check if one input list is way bigger than the other, and return a simplified result
    //the 100 is because double has a max of 1.7x10^308, each position in our lists holds 1x10^3
    if(baseValue1.Count - 100 > baseValue2.Count)
    {
        result = Math.Pow(10, 300);
        return result;
    }
    if(baseValue2.Count - 10 > baseValue1.Count)
    {
        result = 0.00000000001; //arbitrary small # that isn't quite 0
        return result;
    }

    //get the stopping position for the for loops (clamped at 5 due to double having a precision of 15 digits)
    int stopPos1 = baseValue1.Count - Mathf.Clamp(baseValue1.Count, 1, 5);
    int stopPos2 = baseValue2.Count - Mathf.Clamp(baseValue2.Count, 1, 5);        

    //empty strings to hold the #'s
    string bv1String = "";
    string bv2String = "";

    //create a string of the largest digits in bv1
    if (stopPos1 > 1)
    {
        //create a string of the largest digits in bv1
        for (int i = baseValue1.Count - 1; i >= stopPos1; i--)
        {
            if (i == baseValue1.Count - 1)
            {
                bv1String = baseValue1[i].ToString();
            }
            else
            {
                if (baseValue1[i] < 10) bv1String = bv1String + "00" + baseValue1[i].ToString();
                else if (baseValue1[i] < 100) bv1String = bv1String + "0" + baseValue1[i].ToString();
                else bv1String = bv1String + baseValue1[i].ToString();
            }
        }
    }

    else
    {
        //create a string of the largest digits in bv1
        for (int i = baseValue1.Count - 1; i >= 0; i--)
        {
            if (i == baseValue1.Count - 1)
            {
                bv1String = baseValue1[i].ToString();
            }
            else
            {
                if (baseValue1[i] < 10) bv1String = bv1String + "00" + baseValue1[i].ToString();
                else if (baseValue1[i] < 100) bv1String = bv1String + "0" + baseValue1[i].ToString();
                else bv1String = bv1String + baseValue1[i].ToString();
            }
        }
    }

    //create a string of the largest digits in bv1
    if (stopPos2 > 1)
    {
        //create a string of the largest digits in bv2
        for (int i = baseValue2.Count - 1; i >= stopPos2; i--)
        {
            if (i == baseValue2.Count - 1)
            {
                bv2String = baseValue2[i].ToString();
            }
            else
            {
                if (baseValue2[i] < 10) bv2String = bv2String + "00" + baseValue2[i].ToString();
                else if (baseValue2[i] < 100) bv2String = bv2String + "0" + baseValue2[i].ToString();
                else bv2String = bv2String + baseValue2[i].ToString();
            }
        }
    }

    else
    {
        //create a string of the largest digits in bv2
        for (int i = baseValue2.Count - 1; i >= 0; i--)
        {
            if (i == baseValue2.Count - 1)
            {
                bv2String = baseValue2[i].ToString();
            }
            else
            {
                if (baseValue2[i] < 10) bv2String = bv2String + "00" + baseValue2[i].ToString();
                else if (baseValue2[i] < 100) bv2String = bv2String + "0" + baseValue2[i].ToString();
                else bv2String = bv2String + baseValue2[i].ToString();
            }
        }
    }

    //create numbers for the input lists
    double bv1Double = double.Parse(bv1String);
    double bv2Double = double.Parse(bv2String);

    //adjust for one being bigger than the other, only by relative amount though
    //only needed when one of them has 6+ tiers
    if (baseValue1.Count > 5 && baseValue2.Count > 5)
    {
        if (baseValue1.Count > baseValue2.Count)
        {
            bv1Double *= Math.Pow(1000, baseValue1.Count - baseValue2.Count);
        }
        else if (baseValue1.Count < baseValue2.Count)
        {
            bv1Double *= Math.Pow(1000, baseValue2.Count - baseValue1.Count);
        }
    }

    //calculate result
    result = bv1Double / bv2Double;

    return result;
}

प्रशन:

(1) अगर कोई मुझे विशेष डिवीजन के गणित/तर्क के लिए सही दिशा में इंगित कर सकता है, तो शायद मैं कोडिंग को संभाल सकता हूं।

(2) क्या कोड सुझावों की तलाश में एक और पोस्ट बनाना/इसमें मेरी अन्य गणित विधियों को जोड़ना उचित होगा? (मैं एक स्व-सिखाया नौसिखिया हूं और जानता हूं कि इन तरीकों में मैं बहुत से सुधार कर सकता हूं)

2
plasmas222 17 अगस्त 2019, 20:05

2 जवाब

सबसे बढ़िया उत्तर

यदि आप अपना कस्टम स्वरूपण रखना चाहते हैं और BigInteger पर स्विच नहीं करना चाहते हैं, तो आपके मौजूदा जोड़ और घटाव ऑपरेटरों का उपयोग करके विभाजित करने का एक व्यवहार्य तरीका हो सकता है।

चूंकि आपके मान पूर्णांकों की सूची में संग्रहीत हैं, इसलिए आपको प्रत्येक संख्या के लिए उस सूची के माध्यम से चलना चाहिए और लंबा विभाजन करना चाहिए। मैं अपने फोन पर हूं इसलिए मैं एक कोड उदाहरण प्रदान नहीं कर सकता, लेकिन तर्क कुछ हद तक सीधा है।

https://en.wikipedia.org/wiki/Long_division

मान लें कि गणना 300/20 . है

पहला कदम 300 का पहला उपसमुच्चय ज्ञात करना है जो 20 के बराबर या उससे बड़ा है। वह 30 होगा।

तब आप भागफल ज्ञात करते हैं और शेषफल की गणना करते हैं, जो क्रमशः 1 और 10 है।

फिर आप अगली संख्या को 300 (जो कि 0 है) से शेषफल (10) में जोड़ दें। यह आपको 100 देगा। फिर आप वही काम करते हैं जिसके परिणामस्वरूप 5 का भागफल और शेष 0 होता है।

शेष शून्य होने का अर्थ है कि गणना पूर्ण हो गई है। फिर आप उन सभी qoutients को जोड़ते हैं जिनकी आपने गणना की है और आपके पास परिणाम ("1" + "5" = "15") है

भागफल और शेषफल ज्ञात करने के लिए आप यूक्लिडियन डिवीजन का उपयोग कर सकते हैं जो केवल आपके मौजूदा जोड़ और घटाव ऑपरेटरों का भी उपयोग करता है। https://en.wikipedia.org/wiki/Division_algorithm एन / डी = (भागफल, शेष)

कलन विधि:

R = N, Q = 0
while(N > D)
{
    R= R - D
    Q ++
}

विकिपीडिया में कुछ अच्छे दृश्य हैं और शायद इसे स्पष्ट करते हैं। मुख्य उपाय यह है कि आप केवल जोड़ और घटाव का उपयोग करते हुए अपने मौजूदा ऑपरेटरों का उपयोग करके इस एल्गोरिथ्म को लागू करने में सक्षम होना चाहिए।

0
Nicklas C. 18 अगस्त 2019, 01:02

निकलस के सुझाव के साथ, मैं कोड के निम्नलिखित भाग को एक साथ रखने में सक्षम था। मैंने काफी परीक्षण किया और मुझे पूरा विश्वास है कि यह ज्यादातर/सब सही है। अनुवर्ती प्रश्न यह होने वाला था कि परीक्षण के दौरान मैंने पाया कि संचालन के परिणामस्वरूप बहुत बड़ा उत्तर (उदा: 10 ट्रिलियन/5) लंबा समय लगेगा। कुछ मिनटों के लिए सोचने के बाद मैं बड़े पैमाने पर समय की बचत के लिए एक अच्छा समाधान लेकर आया। अब यह मूर्खतापूर्ण बड़े परिणाम तुरन्त उगल देगा।

        //assumes both inputs are positive and > 0
public List<double> SuperDivide(List<double> numerator, List<double> denominator)
{
    //here we are going to adopt the notation used on the wiki page for long division
    //inputs are numerator/denominator
    //outputs are (Q,R) quotient and remainder

    //create and set the Q to 0
    List<double> quotient = new List<double>
    {
        0
    };

    //create a list of value 1
    List<double> one = new List<double>
    {
        1
    };

    //declairing a new list to house the result
    List<double> resultValue = new List<double>();

    //empty strings to hold the #'s
    string denomString = "";
    string remainderString = "";

    //create and set the R = N
    List<double> remainder = new List<double>();
    for (int i = 0; i < numerator.Count; i++)
    {
        remainder.Add(numerator[i]);
    }

    //getting a starting value
    string compareResult = WhichIsBigger(remainder, denominator);

    //calculate Q and R: while R >= D
    while(compareResult =="A" || compareResult == "Equal")
    {
        //get the multiplier we can use to save calcs on big # results (xxxxxxxxxxxxxxxxxxx / yyyy)
        List<double> testResult = DivTester(remainder, denominator);

        //create a var for D * X, where X is the testResult
        List<double> denomMult = SuperMultiply(denominator, testResult);

        //Q = Q + X
        quotient = SuperAdd(quotient, testResult);

        //R = R - DX
        remainder = SuperSubtract(remainder, denomMult);

        compareResult = WhichIsBigger(remainder, denominator);
    }

    //if R = 0, return Q
    if(remainder.Count == 1 && remainder[0] == 0)
    {
        return quotient; 
    }

    //else return Q + (R/D)
    else
    {
        //get the stopping position for the for loops (clamped at 5 due to double having a precision of 15 digits)
        int stopPosR = remainder.Count - Mathf.Clamp(remainder.Count, 1, 5);
        int stopPosD = denominator.Count - Mathf.Clamp(denominator.Count, 1, 5);

        //create a string of the largest digits in R
        if (stopPosR > 1)
        {
            for (int i = remainder.Count - 1; i >= stopPosR; i--)
            {
                //starting tier (largest #)
                if (i == remainder.Count - 1)
                {
                    remainderString = remainder[i].ToString();
                }
                else
                {
                    if (remainder[i] < 10) remainderString = remainderString + "00" + remainder[i].ToString();
                    else if (remainder[i] < 100) remainderString = remainderString + "0" + remainder[i].ToString();
                    else remainderString = remainderString + remainder[i].ToString();
                }
            }
        }
        else
        {
            for (int i = remainder.Count - 1; i >= 0; i--)
            {
                //starting tier (largest #)
                if (i == remainder.Count - 1)
                {
                    remainderString = remainder[i].ToString();
                }
                else
                {
                    if (remainder[i] < 10) remainderString = remainderString + "00" + remainder[i].ToString();
                    else if (remainder[i] < 100) remainderString = remainderString + "0" + remainder[i].ToString();
                    else remainderString = remainderString + remainder[i].ToString();
                }
            }
        }

        //create a string of the largest digits in D
        if (stopPosD > 1)
        {
            for (int i = denominator.Count - 1; i >= stopPosD; i--)
            {
                if (i == denominator.Count - 1)
                {
                    denomString = denominator[i].ToString();
                }
                else
                {
                    if (denominator[i] < 10) denomString = denomString + "00" + denominator[i].ToString();
                    else if (denominator[i] < 100) denomString = denomString + "0" + denominator[i].ToString();
                    else denomString = denomString + denominator[i].ToString();
                }
            }
        }
        else
        {
            for (int i = denominator.Count - 1; i >= 0; i--)
            {
                if (i == denominator.Count - 1)
                {
                    denomString = denominator[i].ToString();
                }
                else
                {
                    if (denominator[i] < 10) denomString = denomString + "00" + denominator[i].ToString();
                    else if (denominator[i] < 100) denomString = denomString + "0" + denominator[i].ToString();
                    else denomString = denomString + denominator[i].ToString();
                }
            }

        }

        //create numbers for divsion of R/D
        double remainderDoub = double.Parse(remainderString);
        double denomDoub = double.Parse(denomString);

        //adjust for one being bigger than the other, only by relative amount though
        //only needed when one of them has 6+ tiers
        if (remainder.Count > 5 && denominator.Count > 5)
        {
            if (remainder.Count > denominator.Count)
            {
                remainderDoub *= Math.Pow(1000, remainder.Count - denominator.Count);
            }
            else if (remainder.Count < denominator.Count)
            {
                denomDoub *= Math.Pow(1000, denominator.Count - remainder.Count);
            }
        }

        resultValue.Add(remainderDoub / denomDoub);

        resultValue = SuperAdd(resultValue, quotient);

        return resultValue;
    }
}

और DivTester विधि:

        //I'm sure there are much more effecient ways to determine this multiplier...
private List<double> DivTester(List<double> rem, List<double> denom)
{
    //declairing a new list for testing, starting value of 1
    List<double> ten = new List<double>()
    {
        10
    };

    //create and set the dCopy = denom
    List<double> dCopy = new List<double>();
    for (int i = 0; i < denom.Count; i++)
    {
        dCopy.Add(denom[i]);
    }

    //create and set the testerPass = 1
    List<double> testerPass = new List<double>()
    {
        1
    };

    //getting a starting value
    string compareResult = WhichIsBigger(rem, dCopy);

    while(compareResult == "A")
    {
        dCopy = SuperMultiply(dCopy, ten);

        //check and see if it is still successfull
        compareResult = WhichIsBigger(rem, dCopy);

        //if it passes, multiple testerPass by ten
        if (compareResult == "A")
        {
            testerPass = SuperMultiply(testerPass, ten);
        }
    }

    //return the largest multipler (10^X) that can be safely used
    return testerPass;        
}
0
plasmas222 21 अगस्त 2019, 05:14