1

What is the difference between the static methods Int32.Min and Int32.MinMagnitude, that were introduced in .NET 7? Their signature and description is the same:

// Compares two values to compute which is lesser.
public static int Min (int x, int y);

// Compares two values to compute which is lesser.
public static int MinMagnitude (int x, int y);
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104

3 Answers3

4

MinMagnitude() compares the absolute values of the inputs. When x and y are positive, it works exactly like Min(). If either or both of them are negative then the sign(s) will be ignored for the comparison, but are kept on the return value.

Some examples:

Debug.Assert(int.MinMagnitude( 10,  1) ==  1);
Debug.Assert(int.MinMagnitude(-10,  1) ==  1);
Debug.Assert(int.MinMagnitude( 10, -1) == -1);
Debug.Assert(int.MinMagnitude(-10, -1) == -1);

One special case is when comparing numbers of equal absolute value, but different sign. Then it returns the negative of the common absolute value:

Debug.Assert(int.MinMagnitude(-1,  1) == -1);
Debug.Assert(int.MinMagnitude( 1, -1) == -1);

Have a look at the source code here.

Good Night Nerd Pride
  • 8,245
  • 4
  • 49
  • 65
1

Based on the implementation for Int32:

  public static int MinMagnitude(int x, int y)
  {
        int absX = x;

        if (absX < 0)
        {
            absX = -absX;

            if (absX < 0)
            {
                return y;
            }
        }

        int absY = y;

        if (absY < 0)
        {
            absY = -absY;

            if (absY < 0)
            {
                return x;
            }
        }

        if (absX < absY)
        {
            return x;
        } 
        if (absX == absY)
        {
            return IsNegative(x) ? x : y;
        }
        return y;
  }

This method returns number with minimal absolute value, i.e. magnitude (if equal - the negative of the two preferred).

UPD

I can't get access to IEEE 754 2019 where minimumMagnitude is defined, but from the PDF on "The Removal/Demotion of MinNum and MaxNum Operations from IEEE 754™-2018", the original minNumMag was defined as:

minNumMag(x, y) is the canonicalized number x if | x| < | y|, y if | y| < | x|, otherwise minNum(x,y).

As the doc states - reason for removal was non-associativity for NaN handling which, I understand is "fixed" in the new standard.

For this the double implementation can give mode detail, I think:

public static double MinMagnitude(double x, double y)
{
    // This matches the IEEE 754:2019 `minimumMagnitude` function
    //
    // It propagates NaN inputs back to the caller and
    // otherwise returns the input with a lesser magnitude.
    // It treats +0 as lesser than -0 as per the specification.
 
    double ax = Abs(x);
    double ay = Abs(y);
 
    if ((ax < ay) || double.IsNaN(ax))
    {
        return x;
    }
 
    if (ax == ay)
    {
        return double.IsNegative(x) ? x : y;
    }
 
    return y;
}
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • 1
    Guru Stron I removed my outdated comments to keep the answer clean. Btw, although your answer is more scientific, I accepted @GoodNightNerdPride's [answer](https://stackoverflow.com/a/74429063/11178549) because it offers a more practical explanation of the difference IMHO. – Theodor Zoulias Nov 14 '22 at 14:02
  • 1
    @TheodorZoulias Yes, NP =) I've added my answer case original version of GoodNightNerdPride's one was not fully correct in terms of explanation. – Guru Stron Nov 14 '22 at 15:00
0

It's a method on the newly-introduced interface INumberBase<TSelf>, and is documented as:

Compares two values to compute which is lesser.

And has the remark:

For IFloatingPointIeee754<TSelf> this method matches the IEEE 754:2019 minimumMagnitude function. This requires NaN inputs to be propagated back to the caller and for -0.0 to be treated as less than +0.0.

So that remark would proves the documentation of the method to be wrong, as it returns the value with the lesser magnitude, being the compared absolute values.

So if you want absolute comparisons, or if you do floating point math and want NaN or positive/negative zero comparisons as described, then use MinMagnitude() instead of Min().

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • *"...if you do floating point math..."* -- To be honest I am interested exclusively about the difference between `Min` and `MinMagnitude` in the context of 32-bit integers. AFAIK floating point math are not applicable to integers. – Theodor Zoulias Nov 14 '22 at 09:32
  • Yeah but it's an interface that's applied to all built-in numeric types, and there were more parts to that sentence. – CodeCaster Nov 14 '22 at 09:35
  • Removing the parts that I am not interested for: *"So if you want absolute comparisons then use `MinMagnitude()` instead of `Min()`."* -- Honestly if I want to compare the absolute values I will do `int.Abs(x).CompareTo(int.Abs(y));`. The semantics of the `MinMagnitude` method for integers seems to be a mess. – Theodor Zoulias Nov 14 '22 at 09:40
  • 1
    They aren't clear to me either, but I'm not a mathematician nor well-versed in floating point math. I think we can agree the documentation is lacking. – CodeCaster Nov 14 '22 at 09:42
  • @TheodorZoulias I think this method is just a byproduct of [the generic math APIs](https://github.com/dotnet/designs/pull/205), and should not be used in general. You may notice the strange comparison in the source (`if (absX < 0)` inside another `if (absX < 0)`) which is used to check `NaN` (`f != f`) for a floating number. – shingo Nov 14 '22 at 09:49
  • @shingo I am tempted to self-answer my question, with something like: *"The `Int32.Min` is a method equivalent with the `Math.Min`, that does what you expect it to do. The `Int32.MinMagnitude` is an abomination that you should forget about it. The more that you try to understand it, the more brain cells that are dying in your head."* – Theodor Zoulias Nov 14 '22 at 09:55
  • 1
    It's about consistency in the overall implementation of the interfaces. With Int32, it resolves in the minimum absolute member, which also resolves `MinMagnitudeNumber`, different in floating point values. The implementation may seem inconsistent because Int32 has no NaN and if you test `float.MinMagnitude(-0.0f, +0.0f)`, with `float.IsNegative(float.MinMagnitude(-0.0f, +0.0f))` you get `true`, while `int.IsNegative(int.MinMagnitude(-0, +0))` you get `false`. How would you implement the `INumberBase` interface, in relation to IntX? – Jimi Nov 14 '22 at 10:00
  • @Jimi I would implement it with a big fat `throw new NotSupportedException()`. – Theodor Zoulias Nov 14 '22 at 10:06
  • 1
    Well, it actually appears to be supported. Would you use Math.Min + Math.Abs instead? That's using a different paradigm and *may* be subject to two's complement exceptions. .Net 7 targets a much *wider audience*, hence the use of wider documented standards – Jimi Nov 14 '22 at 10:16
  • @Jimi fair enough. Apparently I am not part of the target audience of the `Int32.MinMagnitude` API. I am OK with this. – Theodor Zoulias Nov 14 '22 at 10:20
  • @TheodorZoulias I clearly forgot to mention what that *different paradigm* is, in practice. Now that interfaces have all those `static abstract` Properties / Methods, you can use derived `INumberBase` interfaces in generics, specifically `INumber`, so you can write, e.g., `T Operations(IEnumerable numbers) where T : INumber { T value = T.Zero; /* operations */ return value; }`. You can pass a collection of Int32 or Double etc. numbers to the method. It should be more clear why I said *It's about consistency in the overall implementation of the interfaces* – Jimi Nov 18 '22 at 05:18