![]() | |
![]() |
| | Thread Tools | Search this Thread | Display Modes |
#1
| |||
| |||
|
#2
| |||
| |||
|
|
Check out this code. I need to be able to multiply a 15 digit decimal number by 10 to the power of 15, and come up with the correct answer. Easy enough for other languages to do, but J# seems to choke on it. Here's the code. private void button1_Click (Object sender, System.EventArgs e) { double dblPi = 3.14159265358979; double dblTheta = 121; double value = System.Math.Sin( (dblTheta / 180) * dblPi ); System.Console.Write(value); System.Console.Write("\n"); System.Console.Write(Math.pow(10, 15) * value); // Should return 857167300702113 // but instead returns 857167300702114 } My best guess is that it has something to do with the * operator. My guess is that it does some kind of crazy rounding, but looking at the code it doesn't make sense really. I made sure that the original value comes out right, and it does, and I trust the Math.pow function to come out right as well, but the combination of it all fails. I'm so puzzled. HELP! - Nick ************************************************** ******************** Sent via Fuzzy Software @ http://www.fuzzysoftware.com/ Comprehensive, categorised, searchable collection of links to ASP & ASP.NET resources... |
#3
| |||
| |||
|
|
Check out this code. I need to be able to multiply a 15 digit decimal number by 10 to the power of 15, and come up with the correct answer. Easy |
|
private void button1_Click (Object sender, System.EventArgs e) { double dblPi = 3.14159265358979; double dblTheta = 121; double value = System.Math.Sin( (dblTheta / 180) * dblPi ); System.Console.Write(value); System.Console.Write("\n"); System.Console.Write(Math.pow(10, 15) * value); // Should return 857167300702113 // but instead returns 857167300702114 } My best guess is that it has something to do with the * operator. My guess is that it does some kind of crazy rounding, but looking at the code it |
|
I'm so puzzled. HELP! - Nick ************************************************** ******************** Sent via Fuzzy Software @ http://www.fuzzysoftware.com/ Comprehensive, categorised, searchable collection of links to ASP & ASP.NET resources... |
#4
| |||
| |||
|
#5
| |||
| |||
|
#6
| |||
| |||
|
|
Thanks so much! I now can see what causes the code to freak out. However, I wonder if there is a way to code around this behavior, or to deal with it. Let me explain the importance first. The code itself is some test code I wrote up while searching out an elusive bug in a Pseudo-Random number generator for an encryption program. I need to be able to produce exactly the same random sets of numbers that other implementations of the generator produce so the encrypted data can be decrypted no matter who's implementation of the algorithm is used. I'm basing the J# version off a VB6 implementation, interestingly enough, and I want to ensure it is compatible with that. Thus Pi must be defined as it is in the code, because that's the precision to which it was represented also in the VB6 code. VB6 does the calculations as I'd expect without issue. The part where the J# code goes hey-wire is in the custom rounding routine (to get around .NET's banker's rounding). The reason for the rounding function is the results of the sin & cos functions have to be rounded to 15 digits to again match the precision in other implementations. *****Another thing that could eliminate this whole mess would be to get a reliable rounding function that can handle the data I throw at it.***** If you can figure this out, I'll name my firstborn after you! But if anyone feels like sifting through the code, here's the code for the rounding function: public static double OldRound(double value, int digits) { int sign = System.Math.Sign(value); double scale = Math.pow(10, digits); double round = System.Math.Abs(value); // BAD MATH RESULTS FROM THIS CALCULATION: round = round * scale; round = round + .5; round = Math.floor(round); round = round / scale; round = sign * round; return round; } If you're interested, here's the bit of code that calls the rounding function. Ignore any weird variable names (like sngPi when it's the double type), I just used all the same variable names as the VB implementation to keep everything straight when I was writing the port. private static double dblCenterY; private static double dblCenterX; // It is very important that these numbers are EXACTLY the same // in ALL implementations to allow universal compatibility. // MAGIC NUMBERS // KEEP PI TO THIS PRECISION, NO MORE, NO LESS private static double sngPi = 3.14159265358979; private static void Generate(double dblRadius, double dblTheta) { double sngMaxUpper = 2147483647; double sngMaxLower = -2147483648; // Basically what we're doing here is picking a point on a circle // centered at (dblCenterX, dblCenterY). This point will serve as // the center of the next circle used for this function. The // radius of the circle is given to the function, as well as the // angle the new point makes with the center of the orignal circle. // This angle and radius is ultimately what determines the new // point, and serve as our pseudo-random seeds double dblResultX; double dblResultY; dblResultX = (dblRadius * OldRound(System.Math.Cos((dblTheta / 180) * sngPi), 15)) + dblCenterX; dblResultY = (dblRadius * OldRound(System.Math.Sin((dblTheta / 180) * sngPi), 15)) + dblCenterY; if (dblResultX > sngMaxUpper || dblResultX < sngMaxLower) { // Re-center if new X coordinate is far off the boundary of the X-axis ReCenter(dblCenterY, 0); } else { // Otherwise, calculate the new X-coordinate dblCenterX = dblResultX; } if (dblResultY > sngMaxUpper || dblResultY < sngMaxLower) { // Re-center if new Y coordinate is far off the boundary of the Y-axis ReCenter(0,dblCenterX); } else { // Otherwise, calculate the new Y-coordinate dblCenterY = dblResultY; } } Or if you don't want to sort through that mess, I'll just propose the original problem (sample data all filled in, and simplified): private void button1_Click (Object sender, System.EventArgs e) { double dblPi = 3.14159265358979; double dblTheta = 121; double value = System.Math.Sin( (dblTheta / 180) * dblPi ); System.Console.Write(value); System.Console.Write("\n"); System.Console.Write(Math.pow(10, 15) * value); // Should return 857167300702113 // but instead returns 857167300702114 } What can I do to code around this? Thanks again so much, and thanks in advance to anyone who replies or solves this... - Nick |
![]() |
| Thread Tools | Search this Thread |
| Display Modes | |
| |