This is not strictly related to ASP.NET, but more of a global .NET issue. After a lot of thought I have come to decide that the System.Math class is very poorly implemented (in terms of the results and efficiency many of its methods). For example:
///
public static long Max(long val1, long val2) {
return (val1>=val2)?val1:val2;
}
The double and float implementations of Math.Max are much better. I realize that usually >= is implemented as ! (val1 < val2), but it is still a waste when all we need to know is one value greater or not. Anyway, that's nothing big and for all I know there
is a good reason (though the good reason is not used in the Math.Max(double | float) case then!). The main reason I am whining is because of the implmentation of Math.Cos, which I very recently ran into a problem with. This problem may not even be easily correctable,
but I think it is worth noting anyway.
Now, most people may let this go as a limitation of the digits that can be evaluated (15 or 17 for a double I believe?) in an 8 byte floating point number, but it still becomes a very big problem with multiplying by very large numbers (as I do in my line of
work), such as 1e30.
The result is no surprise when you notice the value of Math.Cos(Math.PI / 2), but is quite a HUGE difference from 0, the obvious correct answer. To be honest I was not sure if this is something that plaqued languages prior to .NET, so I tested the cmath include
file in C++ (#include in VS.NET) to quickly test it:
cout << (cos(3.14159265358979323846 / 2) * 1e30);
Low and behold it displays exactly 6.12303e+013. So it apparently is a limitation of the precision. I can work around this by testing for PI when I plug in. Now, the biggest problem with the Math lib that I see is the Rounding methodology. I have never seen
Mathematician that said 0.5 rounded, is rounded to 0, while 1.5 is rounded to 2! Now, >= 1.5 is 2, and >= 0.5 is 1. What is causing this pull to make the number even? Crude discrimination of odd numbers? Seriously though, if I ever need to directly use the
Round method, I will be making my own ugly, and probably poorly implemented version of it in order to achieve sensible results. This springs to mind (could be expanded to allow rounding past the decimal through simple multiplication and division):
Your post has gone unanswered for a long time because, anyone that has studied programming knows that a computer system has a finite number of bits. This means that it can only handle numbers of finite lenght. In math you have fractions that go on to infinity,
but these numbers can not be represented in a computer system so they are truncated to a certain number of digits. This makes it hard to compare two fractional numbers.
So, you mention that you use large numbers in your work. One solution is to write your own data types and define math operations. I had done a project trying to accuratly compute the 1 million digits of pi. I implemented a new class that could handle numbers
that had upto 100 digits. Then defined addition, sub, mult, etc... Functions such as cos , sin, need to be expanded into fourier series and calculated that way. Multiplication is done using FFT, but there are several other methods too. I know that there are
a few classes already written to do this, so just google on the matter.
Anyhow this has nothing to do with .NET or microsoft as a matter of fact. This is just the way computers are. You think this is hard, then try to get a floating point calculation working in hardware! That's where you learn why things are the way they are
:).
I had stopped visiting asp.net (the site) awhile ago and I missed this reply, but I was reading through my recent history and I happened to notice this.
I did and do realize the lack of precision makes for mistakes (I even mentioned it), especially when dealing with the geometry functions and I was comparing the library to the cmath lib, and even pointed out that they were implemented similarly.
The major point of my post was that a lot of the functions implemented in the Math library were poorly implemented (the code used to be available and the top Max function example was just one example, which should have simply done:
return val1 > val2 ? val1 : val2;
. It wasn't even a big deal, but I was pointing it out for the revisions in future versions and the expected generic versions in C# 2.0). On top of that, the Round function was implemented extremely poorly in that it rounds in a very unexpected manner
(towards even numbers).
The Round function actually uses a fairly standard technique for rounding often referred to as Bankers Rounding.
The purpose of bankers rounding is to minimize "creep" that might occur if you always rounded up or always rounded down.
Interesting find, I had never heard of Bankers Rounding. Also, thanks for pointing out the new overloads, which I probably might have missed for awhile as I avoided Math.Round like the plague.
pickyh3d
Star
9696 Points
1955 Posts
Better Implementation of Math library
Dec 01, 2004 03:38 PM|LINK
/// public static long Max(long val1, long val2) { return (val1>=val2)?val1:val2; }The double and float implementations of Math.Max are much better. I realize that usually >= is implemented as ! (val1 < val2), but it is still a waste when all we need to know is one value greater or not. Anyway, that's nothing big and for all I know there is a good reason (though the good reason is not used in the Math.Max(double | float) case then!). The main reason I am whining is because of the implmentation of Math.Cos, which I very recently ran into a problem with. This problem may not even be easily correctable, but I think it is worth noting anyway.Math.Cos(Math.PI / 2).ToString("e") = 6.123032e-017Now, most people may let this go as a limitation of the digits that can be evaluated (15 or 17 for a double I believe?) in an 8 byte floating point number, but it still becomes a very big problem with multiplying by very large numbers (as I do in my line of work), such as 1e30.(Math.Cos(Math.PI / 2) * 1e30).ToString("e") = 6.123032e+013The result is no surprise when you notice the value of Math.Cos(Math.PI / 2), but is quite a HUGE difference from 0, the obvious correct answer. To be honest I was not sure if this is something that plaqued languages prior to .NET, so I tested the cmath include file in C++ (#include in VS.NET) to quickly test it: Low and behold it displays exactly 6.12303e+013. So it apparently is a limitation of the precision. I can work around this by testing for PI when I plug in. Now, the biggest problem with the Math lib that I see is the Rounding methodology. I have never seen Mathematician that said 0.5 rounded, is rounded to 0, while 1.5 is rounded to 2! Now, >= 1.5 is 2, and >= 0.5 is 1. What is causing this pull to make the number even? Crude discrimination of odd numbers? Seriously though, if I ever need to directly use the Round method, I will be making my own ugly, and probably poorly implemented version of it in order to achieve sensible results. This springs to mind (could be expanded to allow rounding past the decimal through simple multiplication and division):double Round( double dblValue ) { double dblFloored = Math.Floor(dblValue); // avoid a bunch of calls return (dblValue - dblFloored) < 0.5 ? dblFloored : (dblFloored + 1); }FireFox
Member
55 Points
11 Posts
Re: Better Implementation of Math library
May 03, 2006 08:13 PM|LINK
Well let me start with: Welcome to computers!
Your post has gone unanswered for a long time because, anyone that has studied programming knows that a computer system has a finite number of bits. This means that it can only handle numbers of finite lenght. In math you have fractions that go on to infinity, but these numbers can not be represented in a computer system so they are truncated to a certain number of digits. This makes it hard to compare two fractional numbers.
So, you mention that you use large numbers in your work. One solution is to write your own data types and define math operations. I had done a project trying to accuratly compute the 1 million digits of pi. I implemented a new class that could handle numbers that had upto 100 digits. Then defined addition, sub, mult, etc... Functions such as cos , sin, need to be expanded into fourier series and calculated that way. Multiplication is done using FFT, but there are several other methods too. I know that there are a few classes already written to do this, so just google on the matter.
Anyhow this has nothing to do with .NET or microsoft as a matter of fact. This is just the way computers are. You think this is hard, then try to get a floating point calculation working in hardware! That's where you learn why things are the way they are :).
Best of luck!
pickyh3d
Star
9696 Points
1955 Posts
Re: Better Implementation of Math library
Dec 07, 2006 08:25 PM|LINK
I had stopped visiting asp.net (the site) awhile ago and I missed this reply, but I was reading through my recent history and I happened to notice this.
I did and do realize the lack of precision makes for mistakes (I even mentioned it), especially when dealing with the geometry functions and I was comparing the library to the cmath lib, and even pointed out that they were implemented similarly.
The major point of my post was that a lot of the functions implemented in the Math library were poorly implemented (the code used to be available and the top Max function example was just one example, which should have simply done:
. It wasn't even a big deal, but I was pointing it out for the revisions in future versions and the expected generic versions in C# 2.0). On top of that, the Round function was implemented extremely poorly in that it rounds in a very unexpected manner (towards even numbers).
mbanavige
All-Star
134971 Points
15423 Posts
ASPInsiders
Moderator
MVP
Re: Better Implementation of Math library
Dec 13, 2006 03:12 AM|LINK
The Round function actually uses a fairly standard technique for rounding often referred to as Bankers Rounding.
The purpose of bankers rounding is to minimize "creep" that might occur if you always rounded up or always rounded down.
You can read about it here:
http://en.wikipedia.org/wiki/Rounding
http://blogs.msdn.com/ericlippert/archive/2003/09/26/53107.aspx
.Net 2.0 add new overloads to allow you to control the rounding style:
http://msdn2.microsoft.com/en-us/library/ms131274.aspx
pickyh3d
Star
9696 Points
1955 Posts
Re: Better Implementation of Math library
Dec 13, 2006 06:50 PM|LINK
Interesting find, I had never heard of Bankers Rounding. Also, thanks for pointing out the new overloads, which I probably might have missed for awhile as I avoided Math.Round like the plague.