KSP-ModularManagement / ModuleManager

ModuleManager is a mod that let you write patches that edit other parts at load time.
http://ksp.lisias.net/add-ons/ModuleManager
GNU General Public License v3.0
11 stars 5 forks source link

Using BCD in Module Manager **EXPERIMENTAL** #19

Open Lisias opened 1 year ago

Lisias commented 1 year ago

A fellow Kerbonaut approached me in Forum with this suggestion for improvement:

I wrote pretty simple code that shouldn't be too hard to implement in MM to use decimal floats for calculation when it can be represented in decimal and use double for when it can't.

using System;

public class Program
{
    static bool DecEval(double num)
    {
        bool Pass = true;   

        double UpLimit = 7.9E+28;
        double DownLimit = 1E-12;
        if (num > UpLimit || num < UpLimit*-1 || (num < DownLimit && num > DownLimit*-1 && num != 0))
        {
            Pass = false;
        }

        return Pass;
    }
    static string Clean0(string str)
    {
        int WorkingIndex = str.Length-1;
        if (str.IndexOf('.') != -1)
        {
            while (true)
            {
                if (str[WorkingIndex] == '0')
                {
                    str = str.Substring(0,WorkingIndex);
                    WorkingIndex = str.Length-1;
                } else if(str[WorkingIndex] == '.') {
                    str = str.Substring(0,WorkingIndex);
                    break;
                } else {break;}
            }
        }

        return str;
    }
    public static void Main()
    {
        String NumString1 = "-7.75"; // strings to mimic how ModuleManager starts and saves these numbers
        String NumString2 = "7.65";
        double Num1 = Convert.ToDouble(NumString1);
        double Num2 = Convert.ToDouble(NumString2);
        double Num3 = 0;

        decimal DecNum1 = 0;
        decimal DecNum2 = 0;
        decimal DecNum3 = 0;

        if (DecEval(Num1) && DecEval(Num2) && DecEval(Num1+Num2))
        {
            // string scientific notation to decimal doesn't work, so we have to go through a double float.
            // The way C# works should prevent any inaccuracies stimming from it, though, as most numbers with 13 digits or less will have a unique value and convert from double properly.
            // If they don't, well... it won't be less accurate than only double mathematics.
            if (NumString1.ToUpper().IndexOf('E') == -1) 
            {
                DecNum1 = Convert.ToDecimal(NumString1);
            } else {
                DecNum1 = Convert.ToDecimal(Num1);
            }

            if (NumString2.ToUpper().IndexOf('E') == -1)
            {
                DecNum2 = Convert.ToDecimal(NumString2);
            } else {
                DecNum2 = Convert.ToDecimal(Num2);
            }
            DecNum3 = DecNum1 + DecNum2;
        } else {
            Num3 = Num1+Num2;
        }

        if (Num3 == 0)
        {
            Console.WriteLine("Returning decimal {0}", Clean0(Convert.ToString(DecNum3)));
        } else {
            Console.WriteLine("Returning double {0}", Convert.ToString(Num3));
        }
    }
}

Source: https://dotnetfiddle.net/e2MC24

It sounds logical, but I need to consider that besides being a good idea using Big Numbers instear of floats when possible, this would make MM/L to behave differentlu from Forum's, and I'm unsure if this is a good idea.

The feature is solid, however - it's how MM should be doing things since ever.

zer0Kerbal commented 1 year ago

the forum's MM is dead. Nothing has been done on it that I can see in _how long??? and probably nothing will with the probably pre-release of KSP2 in less than a month.

Lisias commented 1 year ago

Fellow Kerbonaut updated his reference code.

using System;
using System.Globalization;

public class Program
{
    static bool DecEval(double num)
    {
        bool Pass = true;   
        double UpLimit = 7.9E+28;
        double DownLimit = 1E-12;
        if (num > UpLimit || num < UpLimit*-1 || (num < DownLimit && num > DownLimit*-1 && num != 0))
        {
            Pass = false;
        }
        return Pass;
    }
    static string Clean0(string str)
    {
        int WorkingIndex = str.Length-1;
        if (str.IndexOf('.') != -1)
        {
            while (true)
            {
                if (str[WorkingIndex] == '0')
                {
                    str = str.Substring(0,WorkingIndex);
                    WorkingIndex = str.Length-1;
                } else if(str[WorkingIndex] == '.') {
                    str = str.Substring(0,WorkingIndex);
                    break;
                } else {break;}
            }
        }
        return str;
    }
    static string SMath(string NumString1, string Operator, string NumString2)
    {
        double Num1 = Convert.ToDouble(NumString1);
        double Num2 = Convert.ToDouble(NumString2);
        double Num3 = 0;
        decimal DecNum1 = 0;
        decimal DecNum2 = 0;
        decimal DecNum3 = 0;
        bool FirstPass = false;
        if (DecEval(Num1) && DecEval(Num2))
        {
            FirstPass = true;
            // string scientific notation to decimal doesn't work, so we have to go through a double float.
            // The way C# works should prevent any inaccuracies stimming from it, though, as most numbers with 13 digits or less will have a unique value and convert from double properly.
            // If they don't, well... it won't be less accurate than only double mathematics.
            if (NumString1.ToUpper().IndexOf('E') == -1) 
            {
                DecNum1 = Convert.ToDecimal(NumString1);
            } else {
                DecNum1 = Convert.ToDecimal(Num1);
            }
            if (NumString2.ToUpper().IndexOf('E') == -1)
            {
                DecNum2 = Convert.ToDecimal(NumString2);
            } else {
                DecNum2 = Convert.ToDecimal(Num2);
            }
        }
        if (Operator == "+")
        {
            if (FirstPass && DecEval(Num1 + Num2))
            {
                DecNum3 = DecNum1 + DecNum2;
            } else {
                Num3 = Num1 + Num2;
            }   
        } else if (Operator == "-")
        {
            if (FirstPass && DecEval(Num1-Num2))
            {
                DecNum3 = DecNum1 - DecNum2;
            } else {
                Num3 = Num1 - Num2;
            }   
        } else if (Operator == "*")
        {
            if (FirstPass && DecEval(Num1 * Num2))
            {
                DecNum3 = DecNum1 * DecNum2;
            } else {
                Num3 = Num1 * Num2;
            }   
        } else if (Operator == "/")
        {
            if (FirstPass && DecEval(Num1 / Num2))
            {
                DecNum3 = DecNum1 / DecNum2;
            } else {
                Num3 = Num1 / Num2;
            }   
        }
        if (Num3 == 0)
        {
            return Clean0(DecNum3.ToString(CultureInfo.InvariantCulture));
        } else {
            return Num3.ToString(CultureInfo.InvariantCulture);
        }
    }
    public static void Main()
    {
        Console.WriteLine(SMath("-7.75", "+", "7.65"));
        Console.WriteLine(SMath("-7.75", "-", "7.65"));
        Console.WriteLine(SMath("-7.75", "*", "7.65"));
        Console.WriteLine(SMath("-7.75", "/", "7.65"));
    }
}

Again, this is not exactly the code that will be use, but it demonstrates the feature.