Potential additions to the Math class [Katy King]


In preparation for the next version of the product, we’ve collected suggestions for additions to the Math class and related classes.  To give you an idea of the kinds of things people ask us for, here are a list of some of the requests we’ve received.  We’re curious to know which of  these (if any) seem interesting to this audience, and why?  (Namely, what are you working on that you could leverage the specific capability listed?)  Is there anything missing from the list which would be useful?

  • Implement single-precision trig (and other) overloads.  For many functions that currently take a Double, add overloads that take a Single.
  • Inverse hyperbolic functions (ACosh, ASinh, and ATanh)
  • More trig functions (csc, sec, cot)
  • Min and Max overloads that take more than two arguments
  • Other functions that take a variable number of args – Sum() and Average(), for example
  • Complex number support
  • Bitshifting – RightShift and LeftShift on integral types (not currently available in VB)
  • Arbitrary-precision decimal numbers (BigDecimal)
  • Factorial
  • Permutations, Combinations (see <http://mathforum.org/dr.math/faq/faq.comb.perm.html> for definitions)
  • Math.Pow() overload for Decimal
  • Convert between degrees and radians
  • Support for vectors and vector math (probably not in the Math class)
  • Add new values to the MidpointRounding enum – which ones?
  • Provide a different math model for operations, that throws instead of obeying IEEE (returning NaN/Infinity).  (Note that it is extremely unlikely that we will change our model at this point.)
Comments (36)

  1. John says:

    All of the above sound good. In many languages, the Math routines are the stepchild no one loves; it would be great for Whidbey to set the standard on this.

    The one thing that I would find really cool, (though like vector math it would be a separate set of classes rather than in the Math class), would be support for Directed Acyclic Graphs (DAGs).

    Your programmers will know what they are and the things they can be used for much better than I can explain, but I worked for a company that made extensive use of them (for example, in the user mgmt and workflow modules) in its B2B product, and they allowed for so many things that would be difficult or impossible using hierarchies and other structures.

    If your team were intersted enough, I could give more detailed examples. WinFS uses DAGs, and they’re also useful for many types of theoretical comp sci.

    It’s exactly the sort of wheel that is not easy to invent, and yet is reinvented over and over. Microsoft providing a standard, high-performance implementation would be great and, at least temporarily, give the .Net BCL a feature unique among its competitors.

  2. russ says:

    The current version of VB does support bitshifting and I have production code in use that uses the bitshift operators.

    This must be an old suggestion from someone who was using the 1.0 (VB 2002) release instead of 1.1 (VB 2003).

  3. Keith Hill says:

    Most of the mentioned features are nice especially the inverse hyperbolics and converting between degrees, radians and gradians. You might also consider adding support for comparing floating point values within a default (and a specified) epsilon – think AlmostEquals. 🙂

  4. JD says:

    Biggest gains for me out of that list:

    1. BigDecimal; when you nee dit, you need it, and you really miss not having it.

    2. Radians/Degrees; more limited in broad appeal, but very handy and better for th Framework to offer it IMHO.

    3. Min/Max/Sum + vector operations: I see these as a more general need. Don’t know if Math class is the best place for them, but with iterators now in C# it would be great for me to have an iterator for a series and be able to compute a sum/avg/min/max etc over the series. Please do this generically with an IEnumerable and not just for arrays or a certain number of explicit paramters.

    4. Overhauling floating point. You mention this is unlikely, but it should be given serious thought. IEEE semantics can just plain suck if someone really doesn’t want them. From a programmer point of view, why can I have checked/unchecked sections of code as with ints? Maybe the compiler does funny business behind the scenes, fine. All I can say is that problems with floating point handling are common because ‘intuitive’ things don’t make sense to developer. I would work through scenarios in a usability lab and really see how hard it is, even for university-educated grads who are Einstein developers. Then make it easier.

  5. Eran Kampf says:

    If you’re planning on adding vector math routins and complex numbers why not also add quaternions (usefull for 3D applications) etc…

    In fact, I dont see why the managed directx math routins can’t be a part of the framework (Some of us want to use 3D math and geometry routins without using DirectX…)

  6. chris says:

    It would be great if you could provide a rounding method that rounds up for >=.5 and down otherwise. We use this in the European financial sector.

    e.g.

    public static decimal Round(decimal d)

    {

    return decimal.Truncate((d<0.0m)?(d-0.5m):(d+0.5m));

    }

    Thanks.

  7. lexp says:

    Vector and vector operations, Matrix and matrix operations(+, -, *, det). It would be great to have all implementation of Vector and Matrix generic-based.

  8. Luc Cluitmans says:

    I think that having support for arbitrary precision integers in the framework would be a great idea. Putting that support in the Math class is a bad idea however.

    If you would implement arbitrary precision arithmetic, think about the areas where it would be used. The only area that I can think of that requires arbitrary precision integer arithmetic (that can not be done with System.Decimal) is the implementation of an ever increasing amount of cryptography-related algorithms.

    It is important to realize what the most important operations in that field are. Efficient execution of operations modulo some base is probably the most obvious one, and some way of capturing the pre-computations necessary to make those calculations efficient needs to be provided. In particular modular exponentiation and modular inversion should be provided. Also, prime testing and prime generation are features often required in such applications.

  9. Mads Houmann says:

    Take a look at the C/C++ floating point support

    MSDN: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_floating.2d.point_support.asp

    There is quite a lot missing from the Math class, which in much more essential than convenience stuff like degrees to radians

  10. RonO says:

    Conversion between degrees and radians would be the biggest win for us. We do a lot of it now (and thus have routines for it), but to offload this effort to the Framework would help clean up our namespace.

    Many of the others would be nice, but I can’t quite put my finger on a business case for them at the moment.

  11. David says:

    Permutations and combinations.

    BigDecimal.

    Radians/degrees conversion.

  12. PeterT says:

    The most useful for me would be:

    1. Conversion between decimal and degrees. This would be convenient. In fact my preferred embodiment would be to encapsulate this in an "Angle" class with properties "Degrees" and "Radians". I’ve been on a number of projects that have had bugs related to incorrect interpretation of a "double".

    2. Variable argument versions of: Sum(), Average(), Min(), Max()

    3. Single precision trig functions. Would be convenient.

    4. Complex Number support. Don’t need it now, but would sure prefer not to write or source my own if/when I do.

    5. Vector and vector math. This might be useful if:

    a. There is also a matrix class, or I can implement my own by wrapping vector class in a straightforward manner.

    b. Performance is close to an unmanaged implementation. My experience is that my hand-tuned unsafe C# implementation of a vector-matrix multiplication was still a factor of 2 slower than using P/Invoke with a native C implementation.

  13. Samuel Jack says:

    I want to add my vote to Min and Max taking more than two arguments.

  14. Mark Mullin says:

    Hmmm –

    singleprec trig – xlnt

    hyperbolics – check

    more trig – check, keeps me out of the receipes book 🙂

    list base min & max – yeah, thats nice

    sum() is nice – average() mebbe, but what if I need other measures like median, stddev, etc – a more generalized stats class might be nice

    complex numbers – oh great, go out and steal math’s version of hello world. oh, ok – it’s useful

    bitshifting – why not just get rid of VB ? 🙂 I would add to this a mechanism to make it easier to convert floats to longs and a mechanism to convert doubles to longlongs – some of us have math routines where we need to set constants very exactly – your testers most likely have this need too

    bignums – love em

    factorials – as long as it’s optimized

    perms and combs – nahh – factorials is already pushing it – do this only if you want to do an algebra lib, and then there’s a lot of other stuff you need to consider

    decimal pow – hmm, why not make decimal completely symettric ?

    convert between degrees and radians – you don’t need a function for this, just a couple of constant properties giving multipliers – if you’re looking at making degrees wrap, i.e. 0 = 360, thats a different AND NASTY issue – graphics guys run into this a lot when we do texture wraps, solution requires context – hence I’d just stick with providing convienience constant multipliers

    vectors and vector math – hmmm, I have those and they’re big classs, and as soon as you do vectors, matrices come too – yes in general, but it’s a big challenge dot , cross, triple cross, normalization, polar to cartesian and v.v., basis vectors, basis function, etc – very big list, and then come even stranger things

    midpoint rounding – expose control for full IEEE 764 mechanisms

    NO NO NO NO don’t change math model – HaNs are perfect, if we need to throw

    if(value != value)

    throw("math all bollixed") works fine

    Other issues

    SIMD!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    Other means to optimize calc pipeline

    In general, most of us who need the high level stuff have done it – what we could really use is having the low level run optimally – giving us a way to set up parallelized simd would be a huge gain

  15. Craig says:

    BigInt would be my #1 request.

  16. Jeffrey Sax says:

    Here’s my opinion. + is good, – is not so good.

    – Single-precision trig (and other) overloads. Not very useful. I believe most calculations should be done (but not necessarily stored) in Double precision anyway.

    ++ Inverse hyperbolic functions. Yes, please. This is clearly missing.

    — More trig functions (csc, sec, cot). Not very useful: they have a very simple expression in terms of sin,cos, etc. Most expressions are easier to read with sin, cos than with csc, sec anyway.

    ++ Min and Max overloads that take more than two arguments. Definite yes. System.Math is the only place to put these.

    + Sum() and Average(), for example. Useful but not a priority.

    + Complex number support. Sounds good, but it’s hard to do this right.

    o Arbitrary-precision decimal numbers (BigDecimal): this is already available through the J# library (vjslib.dll)

    o+ Factorial, Permutations, Combinations: useful.

    ++ Math.Pow() overload for Decimal: Yes, and what about Math.Pow for integer powers?

    – Convert between degrees and radians: define the conversion factor as a constant?

    + Support for vectors and vector math (probably not in the Math class). Many .NET assumptions don’t hold for vectors, with severe performance penalties if you ignore this.

    + Add new values to the MidpointRounding enum – which ones? Simply provide the 4 ‘standard’ rouding modes wherever available: up, down, to zero, to nearest/even.

    ++ Provide a different math model for operations, that throws instead of obeying IEEE (returning NaN/Infinity). This is IEEE default behavior. Could be extremely useful, along with "sticky bits", but exceptions would have to be made a lot cheaper for this to live up to its potential.

    Other items I would like to see:

    +++++ Have the JIT inline value type methods.

    +++ Support for floating-point exception flags ("sticky bits")

    ++ More meaningful constants for Single and Double: NegativeZero and constants related to range and precision, including the ‘actual’ Epsilon. (See float.h for inspiration.)

    + Three more functions: Expm1 (Exp(x)-1 for higher precision when x is around 0), Log1p (Log(1+x) for x around 0) and hypot(x, y).

    + Support for setting rounding modes.

  17. You must know, the number one "gotcha" about Math on the newsgroups is Round? No one expects that function to do bankers rounding, and mathematically it is usually useless.

    I like these new items but I do not think Vector or Matrix should go into the System dll.

  18. Shital Shah says:

    What else? Well, you have barely got anything more then basic math functionality and you are just giving few negligible additions. I’d love to see support for Matrices, Vectors, MathML (may be somewhere in Avalon) and everything else that would enable me to create advanced math functionality of calculator like HP48GX or TIs. It’s funny that library designer always tend to insist that these are not the "core" or base level stuff and its not their responsibility to provide this functionality. This is usually because the code they already have is not readily expandable to accomodate these advance concepts or just may be general lack of skills on how to implement advanced math functionality. But if you had hired real mathematical programmers likes of the one at Mathematica they would have put this in the box from day one in probably 6 months. You may have little idea how many people struggle with these and end up creating their own versions for these basic structures and wasting thousands of hours in duplicating the functionality. It’s funny that computers were first invented to do all these complex calculations (perhaps thats why they were called "computing machines") but now we almost always end up with just basic trignometry and algebra in libraries provided by so called modern plateforms and nothing more. It’s a pitty because much of the code to do this, including solving equations or even proving undergrad math theorems, is available for free and could be easily integrated in to base library. I think if you beef up Math namespace in .Net, you will get tremendous attention from acadamia which usually tends to choose Java/C++.

  19. Kit George [Msft] says:

    So much cool feedback here all, we really appreciate it, thanks. On Rounding by the way, check out the new overloads in recent bits, and you’ll notice we have a new overload which allows you tou round the traditional way 😉

  20. Jeffrey Sax says:

    Shital, your criticism miss two crucial points. Java’s numerical support is worse than .NET’s. Also, the BCL is an excellent general purpose library. Like it or not, numerical computing is not mainstream.

    The issue I have is with the platform itself, which should be broad enough to support specialized applications. Some design decisions in .NET are extremely questionable from a numerical performance perspective. These should be addressed first. My list of top issues:

    – inlining of value type methods. It seems they didn’t address the #1 performance scenario for value types.

    – the CLR throws arithmetic exceptions, which are way too expensive to be useful in numerical computations.

    – compliance with the IEEE-754/IEC 60559 standard is minimal. No rounding modes, no exception flags, no traps.

    – reference types with value semantics are assumed to be immutable. This is manageable for strings (thanks to StringBuilder) but doesn’t work at all for vectors and matrices.

    – example: C# does not support overloading of compound assignment operators. x+=y is always interpreted as x = x+y. This leaves 2 choices: take a huge performance hit (up to 50x), or don’t use operator overloading (even though math objects are primary candidates for overloading).

    None of these are BCL issues, so a comment on the BCL team blog may not be the best place to list them. Then again, it shows what must happen before some functionality can be included in the BCL.

  21. Szokelizer says:

    Matrix math and rounding options would be a great thing…

  22. Monroe Thomas says:

    We really need to have interfaces that define permissable mathematical operations that types can support. This will allow us to build very cool generic algorithms, along with the very cool generic containers.

    See: http://www.lambda-computing.com/publications/articles/generics/

  23. Matthew W. Jackson says:

    I really would like to see single-precision versions of the math functions, but I can see two potential problems with that:

    Aren’t all the calculations done at the same precision anyway? Unless there’s a special operator for single-precision floating point sine, putting overloads on there might give the illusion that you’ll get better performance. I’d love to be wrong here, but isn’t single-precision only helpful for saving space?

    Also, this would potentially break source-code compatability. Wouldn’t the following code change?

    BinaryWriter writer = …;

    float number = …;

    writer.Write(Math.Sin(number));

    Currently, this would involve an implicit cast up to double, and a double would be written. With a single-precision overload, a float would be written.

  24. Matthew W. Jackson says:

    Oh.. Anyway, I’d vote for more trig and hyperbolic functions (for completeness…really…that’s important to me in a library).

    The Min and Max overloads could be handled in a nice generics algorithms library that worked for all IComparable<T>, so you can leave those out, if you must.

    Sum and Average seems pretty silly…everybody should know how to do that (maybe put them in Micorosft.VisualBasic?)

    BigInteger and BigDecimal would be great, but they would need to be complete and well-performing. Please consider this. I mean, Java has it.

    BitShifting seems silly. Even VB has it now, and multiplcation works in most cases. Perhaps Bit Rotating, but that can also be implemented with Bit Shifting (but is the JIT smart enough to optimize a bit-rotate on x86?).

    Permutations and Combinations should be part of a nice statistical library. I guess Sum, Average, StandardDeviation and the like should go there (yeah…I guess Sum and Average would be okay in a Stats library).

    Math.Pow(decimal) should be in for completeness. Seems like an oversight, to me.

    Radian/Degree conversion…I could take it or leave it. You have Math.PI, which is all I ever need. You don’t really want to open the floodgates for all unit conversions, do you?

    Vectors and Vector Math…no…I don’t have faith that it would be done right…and if you do make them, then DON’T design them like System.Drawing.Point/PointF/Size/SizeF with tons of missing/screwed up operators and weird semmantics. I’m not too happy with DirectX’s implementation of Vector, either, but it’s a start. Besides, Vector really needs to be part of a larger math package…it’s just the beginning. Maybe I’d accept it if you let me write it. 🙂

    More MidpointRounding values would be great. I’m surprised rounding-up isn’t supported, as that’s what most school kids are taught. I’d propose that and rounding down (for completeness–again important), as well as some accepted pseudo-random rounding for high statistical accuracy.

    And a throwing math model would be nice, too. In C# I’d suggest a syntax such as "checked float { … }" similar to "checked { … }". That way a new keyword wouldn’t be needed, and existing checked/unchecked code dealing with integers wouldn’t break if they contained floating-point operations.

  25. "x+=y is always interpreted as x = x+y."

    Uh, because that is the way it is supposed to work…

    x+=y is just a shorter way of saying x=x+y. It would be stupid to change the behavior. Having the += operator not do addition would be confusing.

  26. Jeffrey Sax says:

    Matt,

    Of course the result of x += y should be that x equals x+y.

    The difference is that x += y now always creates a new instance. You don’t "add y to x", you "give x the result of x+y."

    Aside from the slight semantic difference, this is also a performance trap. It’s widely documented that += is not to be used for string concatenation inside loops. Ok, for strings we have StringBuilder, but that solution isn’t feasible for all such "large value types" (i.e. reference types with value semantics). Two primary examples are vectors and matrices.

    So I want in C# what C++/CLI does: allow me to optimize when I want to (i.e. override +=), and use the default behavior when I don’t care to optimize.

  27. Andrew Sujdak says:

    As somebody who writes lots of numerical PDE stuff in the financial derivatives industry, I can tell you a few things:

    1. The guys selling numerical libraries DO NOT GET the concept of a well designed API. Most of them still come from the C world and there are very few .dlls out there that actually even have a native interface to .NET (ie no COM). Given that you didn’t have support for this stuff in the beginning, anybody doing any sort of numerics work either wrote their own custom stuff or used somebody else’s. The single best thing you could do is go out and beat up the third party vendors about their API designs. They’re terrible. Maybe MS API certification or something? Realistically, you guys aren’t ever (nor should you) going to be doing anything like implementing FFT or something. So if you really want to improve offerings for numerics, put the right kind of "positive pressure" on the 3rd parties.

    2. As a result of #1, you have to be really careful about coming up with new monolithic objects at this point. Most library guys actually develop their own vector and matrix classes. Personally, I’d prefer that any vector and matrix support offered by the framework come in the form of either operator overloading of value-type arrays in the framework or through additional static methods. My personal linear algebra library setup is called from my namespace System.MathX.LinearAlgebra, and contains only static methods.

    3. Complex numbers would be a very nice feature, but my understanding is that right now there’s some kind of inlining problem with structs or something that makes them perform poorly… In any case, my industry doesn’t really need complex numbers but most engineers use them all the time.

    I tried to stick to things that I felt actually added something that others had not said.

  28. Pazu says:

    1) Min and Max overloads that take more than two arguments – important, also take array[]; general feature

    Other functions that take a variable number of args – Sum() and Average(), and Product(), again on args[] and on normal arays

    Math.Pow() overload for Decimal – yes, this is important

    2) My tips – mybe not for Math – more support for converts to/from hexnumbers

  29. Katy King says:

    Thanks for the great feedback, all! We will take this into account when planning new features.

  30. How about everything from "Numerical Recipies in C" seen here: http://www.library.cornell.edu/nr/bookcpdf.html

  31. Raph says:

    I work for a major UK bank, and we’re currently switching away from .NET exactly because the product lacks these features. (eg decimal.pow with fractional powers)

    C# is a great language, but it does not have financially robust maths – we need to be able to place any decimal to any power. We need to specify rounding rules (eg when dealing with Swiss Francs or Argentinian Pesos). Replicating the J2SE5 BigDecimal is a start, but performance is key. Take a look at ArciMath, for example.

    Please, please, please solve this intelligently. Don’t overload System.Math with more statics; instead, use generics and interfaces to push math operator logic (eg power()) onto the classes where IT BELONGS.

    Whilst you’re at it, why not push operator overloads (eg +, -, *, etc) on to interfaces so we can create true value objects in code (such as Money) which are TESTABLE.