Re: Bad math when using * operator along with Math.pow
From: Ianier Munoz (ianier[nospam)
Date: 08/16/04
- Previous message: Jay: "Re: Help from Lars...PLEASE??"
- In reply to: Nick Hauenstein: "Re: Bad math when using * operator along with Math.pow"
- Next in thread: Nick Hauenstein: "Re: Bad math when using * operator along with Math.pow"
- Messages sorted by: [ date ] [ thread ]
Date: Mon, 16 Aug 2004 05:52:58 +0200
java.math.BigDecimal will give you some more control over precision.
However, you'll have to implement the trig functions by yourself ( e.g.
sin(x) = x - x^3/3! + x^5/5! - x^7/7! ... +/- x^n/n! )
Regards,
-- Ianier Munoz http://www.chronotron.com "Nick Hauenstein" <root@spudge.com> wrote in message news:%232BOHuwgEHA.2812@tk2msftngp13.phx.gbl... > 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
- Previous message: Jay: "Re: Help from Lars...PLEASE??"
- In reply to: Nick Hauenstein: "Re: Bad math when using * operator along with Math.pow"
- Next in thread: Nick Hauenstein: "Re: Bad math when using * operator along with Math.pow"
- Messages sorted by: [ date ] [ thread ]