Re: Bad math when using * operator along with Math.pow

From: Ianier Munoz (ianier[nospam)
Date: 08/16/04

  • Next message: Bob: "Equivalent of String.fromCharCode() method in J#"
    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 
    

  • Next message: Bob: "Equivalent of String.fromCharCode() method in J#"
  • Quantcast