1
votes

I have two variables: counter and frequency. I am using these two variables as such:

counter = counter >= frequency ? 0 : counter + 1;

As you can see, the counter counts up, until the point it matches the frequency, and then it resets to 0. At the moment, frequency is set to 100. So the counter should reach 99, and then reset to 0.

I am using this counter to rotate an image at a rate of 100 times a second:

private int counter = 0;
private int frequency = 100;
private DispatcherTimer dispatch = new DispatcherTimer();

public Timer()
{
    this.dispatch.Interval = TimeSpan.FromMilliseconds(1000 / frequency);
    this.dispatch.Tick += new EventHandler(updateTimer);
    this.dispatch.Start();
}

private void updateTimer(object sender, EventArgs e)
{
    counter = counter >= frequency ? 0 : counter + 1;
    saveImage.RenderTransform = new RotateTransform(counter * 3.6);
}

The script will rotate the image around a 360 degree plane. Since frequency is set to 100, it will go the full 360 degrees, since 100 * 3.6 is 360. This works great if the frequency is set to 100. However, if I change the frequency, it may not go the full 360 degrees; or it may even go more than 360 degrees.

A simple fix to this would be to change the rotation math to the following:

    saveImage.RenderTransform = new RotateTransform(counter * (360 / frequency));

However, doing this in actuality produces an odd result. The image never reaches the full 360 degree turn; and instead only reaches 300 degrees, before it eventually resets to 0. What is wrong with my math here?

1
Why don't you add a Debug.WriteLine(counter * 3.6) and see for yourself?CodeCaster
c * (360 /f) will use integer operations. 360/100 -> 3.6 -> 3Marc B

1 Answers

9
votes

You may have rounding issues. Be aware that if you want floating point results you need to do floating point math. In your code, you're mixing ints and doubles, which may result in (unexpected) integer divisions. For example 360 / frequency will not result in a floating point number, as both frequency and 360 are ints (for example 360 / 100 == 3!!).

Try changing your code to use floating point operations consistently as follows:

private double counter = 0.0;
private double frequency = 100.0;
private DispatcherTimer dispatch = new DispatcherTimer();

public Timer()
{
    // You may want integer division in this line to get full milliseconds
    this.dispatch.Interval = TimeSpan.FromMilliseconds((int)(1000.0 / frequency));
    this.dispatch.Tick += new EventHandler(updateTimer);
    this.dispatch.Start();
}

private void updateTimer(object sender, EventArgs e)
{
    counter = counter >= frequency ? 0.0 : counter + 1.0;
    saveImage.RenderTransform = new RotateTransform(counter * 3.6);
}

And the last example you gave should read:

saveImage.RenderTransform = new RotateTransform(counter * (360.0 / frequency));

with counter and frequency being doubles.


EDIT: It would suffice to change the last line to

saveImage.RenderTransform = new RotateTransform(counter * (360.0 / frequency));

and leave the variables as int. Your last line in updateTimer doesn't work as 3.6 is hardcoded, but depending on frequency counter * 3.6 may not reach/be greater than 360°.

Example:

frequency = 50
counter = 49
counter * 3.6 = 176.4

frequency = 150
counter = 149
counter * 3.6 = 536.4

So you always need to calculate the degrees to rotate in every step according to frequency and not hardcode them as if frequency was 100.