Overflow boundary checking

  • C#
  • .NET 4.5

Es gibt 26 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    @jvbsl Ich habe deine Loesung noch um den MinValue check erweitert, der hat noch gefehlt:

    C#-Quellcode

    1. internal class Program
    2. {
    3. public static void Main(string[] args)
    4. {
    5. Console.WriteLine(Limits<long>.IsOverflowing(long.MinValue, (long) -10)); // true
    6. Console.WriteLine(Limits<long>.IsOverflowing(long.MaxValue, (long) 10)); // true
    7. Console.WriteLine(Limits<long>.IsOverflowing(long.MaxValue - 12, (long) 10)); // false
    8. Console.WriteLine(Limits<int>.IsOverflowing(int.MinValue, (int) -10)); // true
    9. Console.WriteLine(Limits<int>.IsOverflowing(int.MaxValue, (int) 10)); // true
    10. Console.WriteLine(Limits<int>.IsOverflowing(int.MaxValue - 5, (int) 2)); // false
    11. Console.WriteLine(Limits<long>.IsOverflowing(short.MinValue, (short) -10)); // true
    12. Console.WriteLine(Limits<long>.IsOverflowing(short.MaxValue, (short) 10)); // true
    13. Console.WriteLine(Limits<long>.IsOverflowing(short.MaxValue - 10, (short) 8)); // false
    14. }
    15. }
    16. static class Limits<T> where T : struct
    17. {
    18. private static readonly T MaxValue;
    19. private static readonly T MinValue;
    20. static Limits()
    21. {
    22. var type = typeof(T);
    23. var fld = type.GetField("MaxValue", BindingFlags.Public | BindingFlags.Static);
    24. if (fld != null)
    25. MaxValue = (T) fld.GetValue(null);
    26. fld = type.GetField("MinValue", BindingFlags.Public | BindingFlags.Static);
    27. if (fld != null)
    28. MinValue = (T) fld.GetValue(null);
    29. }
    30. public static bool IsOverflowing<T>(T a, T b) where T : struct
    31. {
    32. decimal v1 = (decimal) Convert.ChangeType(a, typeof(decimal));
    33. decimal v2 = (decimal) Convert.ChangeType(b, typeof(decimal));
    34. decimal maxVal = (decimal) Convert.ChangeType(Limits<T>.MaxValue, typeof(decimal));
    35. decimal minVal = (decimal) Convert.ChangeType(Limits<T>.MinValue, typeof(decimal));
    36. return (v1 + v2) > maxVal || (v1 + v2) < minVal;
    37. }
    38. }


    Mich wuerde trotzdem brennend interessieren wie man das noch erweitern kann das auch floatingpoint operations unterstuetzt werden, d.h. float und double.
    C# Developer
    Learning C++
    Das sind Spezialfälle. Schau einfach wie double Überläufe behandelt.

    Addiere zum double.Max Werte hinzu und schau was passiert.

    Du kannst exemplarisch prüfen ob ein Wert "Infinity" ist. Gibt weitere Fälle die abgedeckt sein müssen.

    Grüße.
    _
    DotNETWork (Generische Tcp-Klasse, verschlüsselt!)
    MonogameMinecraftClone (Minecraft-Klon)
    NeuroEvolution (Implementation zweier Lernmethoden für neuronale Netze)
    du machsts außerdem komplexer als es ist. Die IsOverflowing funktion kann aus der Klasse raus, dann brauchst du den generischen Typen nicht mit angeben und es verhält sich wie bei Überladungen.
    Weiters gilt (long)-10 -> -10L, abgesehen, davon, dass du den Typ Long nicht mitangeben musst, wenn bereits der andere Parameter long ist, denn dann wird automatisch auf long hochgekastet über die implizite Konvertierung...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---

    Rikudo schrieb:

    floatingpoint operations
    Im Gleitkomma-Prozessor rechnet der eh mit LongDouble (80 Bit, konnte man unter C++ nich explizit deklarieren).
    double.IsNan(value) und double.IsInfinity(value) ist eine handhabbare Möglichkeit, das zu testen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!
    @jvbsl @RodFromGermany @φConst

    Danke fuer die Tipps. Also irgendwie haut das nicht so ganz hin...
    Ich habe versucht auf Nan und Infinity zu pruefen aber das klappt nicht.

    C#-Quellcode

    1. private static bool IsOverflowing<T>(T value)
    2. {
    3. if (typeof(T) == typeof(double))
    4. {
    5. double val = Convert.ToDouble(value);
    6. if (double.IsInfinity(val)|| double.IsNaN(val))
    7. return true;
    8. }
    9. if (typeof(T) == typeof(float))
    10. {
    11. float val = Convert.ToSingle(value);
    12. if (float.IsInfinity(val)|| float.IsNaN(val))
    13. return true;
    14. }
    15. return true;
    16. }

    Wenn nicht so wie soll man es sonst pruefen. Muss doch irgendwie moglich sein.
    Ich wurde namlich gerne in die Funktion die @jvbsl geschrieben hat support fur floatingpoint types einfuegen.
    Fuer int's klappts ja bereits gut.
    C# Developer
    Learning C++

    C#-Quellcode

    1. static class PrimitiveInfo<T> where T : struct
    2. {
    3. public static readonly bool IsFloatingPoint;
    4. static PrimitiveInfo()
    5. {
    6. var typeCode = Type.GetTypeCode(typeof(T));
    7. IsFloatingPoint = typeCode == TypeCode.Single || typeCode == TypeCode.Double;;// decimal basiert auf integer Zahlen || typeCode == TypeCode.Decimal;
    8. }
    9. }
    10. static class FloatingPointHelper<T> where T : struct
    11. {
    12. public static readonly Func<T,bool> IsInfinity;
    13. public static readonly Func<T,bool> IsNaN;
    14. static FloatingPointHelper()
    15. {
    16. var type = typeof(T);
    17. var meth = type.GetMethod("IsInfinity",BindingFlags.Public|BindingFlags.Static);
    18. if (meth != null)
    19. IsInfinity = (Func<T,bool>)Delegate.CreateDelegate(typeof(Func<T,bool>),meth);
    20. meth = type.GetMethod("IsNaN",BindingFlags.Public|BindingFlags.Static);
    21. if (meth != null)
    22. IsNaN = (Func<T,bool>)Delegate.CreateDelegate(typeof(Func<T,bool>),meth);
    23. }
    24. }


    Und die angepasste check funktion

    C#-Quellcode

    1. static bool checkOverflow<T>(T a,T b) where T : struct
    2. {
    3. if (PrimitiveInfo<T>.IsFloatingPoint)
    4. {
    5. var res = Arithmetic.Add(a, b);
    6. return FloatingPointHelper<T>.IsInfinity(res) || FloatingPointHelper<T>.IsNaN(res);
    7. }
    8. else
    9. {
    10. decimal v1 = Convert.ToDecimal(a); //alter Code hat über ein paar umwege am ende dasselbe aufgerufen, wir sparen uns somit ein paar aufrufe und boxings
    11. decimal v2 = Convert.ToDecimal(b);
    12. decimal res = v1+v2; // bei decimal overflow sollte eine exception fliegen
    13. return res > Limits<T>.MaxValueDecimal;
    14. }
    15. }


    Ich denke das MaxValueDecimal schaffst du ebenfalls zu schreiben ;)

    Die Arithmetic klasse solltest du dabei ansich ja eigt.
    Best Practice : Gleiche operationen fuer verschiedene Datentypen?

    Der gesamte Code sollte eigt. relativ performant sein und hab noch kleine Änderungen eingebaut...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---

    Rikudo schrieb:

    Ich habe versucht auf Nan und Infinity zu pruefen aber das klappt nicht.
    Dann stell zunächst Daten bereit, die den Test bestehen müssten und debugge das mal durch:

    VB.NET-Quellcode

    1. double dd = double.NaN;
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!