Run this code:
using System;
public class App
{
public static void Main()
{
Decimal a = 57675350989891243676868034224m;
ShowModulus(a, 7);
Console.WriteLine();
ShowModulus(a, 8);
}
public static void ShowModulus(Decimal a, int m)
{
for (int i = 0; i < m; ++i)
{
a++;
Console.WriteLine("{0} % {1} = {2}", a, m, a % m);
}
}
}
And you'll get this output:
57675350989891243676868034225 % 7 = -2
57675350989891243676868034226 % 7 = -1
57675350989891243676868034227 % 7 = 0
57675350989891243676868034228 % 7 = 1
57675350989891243676868034229 % 7 = 2
57675350989891243676868034230 % 7 = 3
57675350989891243676868034231 % 7 = -3
57675350989891243676868034225 % 8 = 1
57675350989891243676868034226 % 8 = 2
57675350989891243676868034227 % 8 = 3
57675350989891243676868034228 % 8 = 4
57675350989891243676868034229 % 8 = 5
57675350989891243676868034230 % 8 = 6
57675350989891243676868034231 % 8 = 7
57675350989891243676868034232 % 8 = 0
I may not know much, but I know that something is wrong there: the way negative numbers are showing up is inconsistent. Frankly, I don't think they should be there at all, but if they are, you'd expect similar patterns between mod 7 and mod 8. Try it with numbers other than 57675350989891243676868034225, and for moduluses (moduli?) other than 7 and 8, too. It breaks for those as well.
This appears to be a bug in the Decimal.Modulus routine - caveat emptor. Oh, and it's still broken in the Whidbey version I'm running (40607). I tried to submit the bug over on the new MSDN Product Feedback Center, but I get an error every time I try to submit. D'oh!
Frankly, this would scare the crap out of me if I were writing financial or scientific software that relied on System.Decimal. In my case the apparent workaround is easy (add the modulus to the result if the result is less than zero), but my confidence in the algorithm is pretty low.
Send me email and tell me more about the error you get when you try to submit. Obviously, if we saw what you're seeing, we wouldn't have shipped!
ReplyDeleteFor the record, I followed up with Sara in an email. Turns out that my "problem" is that I was using Mozilla Firefox. The web page appears not to work with Firefox - but I was able to submit using IE.
ReplyDeleteC:\User\SnippetCompiler> "c:\windows\microsoft.net\framework\v1.1.4322\csc.exe" /t:exe /utf8output /R:"C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorlib.dll" /R:"C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.dll"
ReplyDeleteThe above post is the results of a run I made using SnippetCompiler that confirms Craig's results. Sorry for the extra post but I accidentally overwrote my introductory commentary when I did my paste of the output. John
ReplyDeleteSorry to hear you had problems with Product Feedback Center... it's not as simple as Firefox, since I was able to post a bug using FireFox 0.91 this morning. I know Sara has offered help, but if there's anything I can do, I'm happy to help!
ReplyDeleteLooking at Rotor, the remainder calculation seems to be implemented by using the formula d1 - (floor(d1/d2) * d2). If you try decimal d1 = 57675350989891243676868034225m; decimal d2 = 7; Console.WriteLine(d1 - (Decimal.Floor(Decimal.Divide(d1, d2)) * d2));
ReplyDeleteI agree that a large integer library is a better idea than floating point math. But since Decimal *is* the CLR's large integer library (sort of) I'd expect it to work. In any event, if what you describe is true, then I'd say there's a bug in Decimal.Divi
ReplyDeleteRegarding Decimal.Divide, I tried the following code: decimal d1 = 57675350989891243676868034225m; decimal d2 = 7; decimal d3 = Decimal.Divide(d1, d2); Console.WriteLine("{0} / {1} == {2}", d1, d2, d3); This prints "57675350989891243676868
ReplyDeleteDecimal is not a floating point number. It is a fixed point number. From the docs: =============== The Decimal value type represents decimal numbers ranging from positive 79,228,162,514,264,337,593,543,950,335 to negative 79,228,162,514,264,337,593,543,9
ReplyDeleteAlthough, after considering your comments some more, I think you're right, and in this case it's the docs (and my previous comment) that are wrong: Decimal is *called* a fixed point type, but I think it's *actually* a floating point type, as you say. In
ReplyDeleteIs the bug in Whidbey only? Or even in the Visual Studio 2003?
ReplyDeleteBoth. Try it for yourself - though: only takes a second to write the code.
ReplyDeleteYup... I just verified it on VS 2003. Any news on what Microsoft is doing about it?
ReplyDeleteNope. Given that it's been broken for a long time, I wouldn't hold out too much hope on it getting fixed, either. :p
ReplyDeleteI have just tried this on an early version of Whidbey Bet2, and it is working correctly for me.
ReplyDelete