Angle Normalization C# - c#

I have an Angle class that has this constructor
public Angle(int deg, // Degrees, minutes, seconds
int min, // (Signs should agree
int sec) // for conventional notation.)
{
/* //Bug degree normalization
while (deg <= -180) deg += 360;
while (deg > Math.PI) deg -= 360;
//correction end */
double seconds = sec + 60 * (min + 60 * deg);
value = seconds * Math.PI / 648000.0;
normalize();
}
and I have these values for testing that constructor
int[] degrees = { 0, 180, -180, Int32.MinValue / 60, 120+180*200000};
int[] minutes = { 0, 0, 0, 0,56};
int[] seconds = { 0, 0, 0, 0,10};
Console.WriteLine("Testing constructor Angle(int deg, int min)");
for (int i = 0; i < degrees.Length; i++)
{
p = new Angle(degrees[i], minutes[i], seconds[i]);
Console.WriteLine("p = " + p);
}
/*Testing constructor Angle(int deg, int min)
p = 0°0'0"
p = 180°0'0"
p = 180°0'0"
p = 0°8'0" incorrect output
p = -73°11'50" incorrect output expected 120 56 10
*/
I do not understand why there is a bug here ? and why did they use divide Int32.MinValue by 60 and 120+180*200000 as this format ?
the comments in the constructor is a correction for the code
UPDATE: Added the code of normalize()
// For compatibility with the math libraries and other software
// range is (-pi,pi] not [0,2pi), enforced by the following function:
void normalize()
{
double twoPi = Math.PI + Math.PI;
while (value <= -Math.PI) value += twoPi;
while (value > Math.PI) value -= twoPi;
}

The problem is in this piece of code:
double seconds = sec + 60 * (min + 60 * deg);
Although you are storing seconds as a double, the conversion from int to double is taking place after sec + 60 * (min + 60 * deg) is computed as an int.
The compiler will not choose double arithmetics for you based on the type you decide to store the result in. The compiler will choose the best operator overload based on the types of the operands which in this case are all int and look for a valid implicit conversion (in this case int to double) afterwards; therefore it is choosing int arithmetics and the operation will overflow in the last two test cases:
Int32.MinValue / 60 * 60 * 60 = Int32.MinValue * 60 < Int32.MinValue which will overflow.
120 + 180 * 200000 * 60 * 60 > Int32.MaxValue which will also overflow.
Your expected results for these two cases are probably not considering this behavior.
In order to solve this issue, change your code to:
double seconds = sec + 60 * (min + 60f * deg);
Explicitly setting 60 to a double typed literal constant (60f) will force the compiler to resolve all operations to double arithmetics.
Also, it is worth pointing out that your constructor logic has some other issues:
You should be validating the input data; should it be valid to specify negative minutes or seconds? IMO that doesn't seem reasonable. Only deg should be allowed to have a negative value. You should check for this condition and act accordingly: throw an exception (preferable) or normalize sign of min and sec based on the sign of deg (ugly and potentially confusing).
Your seconds calculation doesn't seem to be correct for negative angles (again, this is tied to the previous issue and whatever sign convention you have decided to implement). Unless the convention is that negative angles must have negative deg, min and sec, the way you are computing seconds is wrong because you are always adding the minutes and seconds terms no matter the sign of deg.
UPDATE There is one more issue in your code that I missed until I had the chance to test it. Some of your test cases are failing because double doesn't have enough resolution. I think your code needs some major refactoring; normalize() should be called first. This way you will always be managing tightly bounded values that can not cause overflows or precision loss.
This is the way I would do it:
public Angle(int deg, int min, int sec)
{
//Omitting input values check.
double seconds = sec + 60 * (min + 60 * normalize(deg));
value = seconds * Math.PI / 648000f;
}
private int normalize(int deg)
{
int normalizedDeg = deg % 360;
if (normalizedDeg <= -180)
normalizedDeg += 360;
else if (normalizedDeg > 180)
normalizedDeg -= 360;
return normalizedDeg;
}

// For compatibility with the math libraries and other software
// range is (-pi,pi] not [0,2pi), enforced by the following function:
void normalize()
{double twoPi = Math.PI + Math.PI;
while (value <= -Math.PI) value += twoPi;
while (value > Math.PI) value -= twoPi;
}
This is the normalize function that I have

while loops is generally a bad idea. If you deal with small values it's okay, but imagine you have some angle like 1e+25, that'd be 1.59e+24 iterations or about 100 million years to compute if you have a decent CPU.
How it should be done instead:
static double NormalizeDegree360(double value)
{
var result = value % 360.0;
return result > 0 ? result : result + 360;
}
static double NormalizeDegree180(double value)
{
return (((value + 180) % 360) + 360) % 360 - 180;
}
static double TwoPI = 2*System.Math.PI;
static double NormalizeRadians2Pi(double value)
{
var result = value % TwoPI;
return result > 0 ? result : result + TwoPI;
}
static double NormalizeRadiansPi(double value)
{
return (((value + System.Math.PI) % TwoPI) + TwoPI) % TwoPI - System.Math.PI;
}

They're using the very large negative and positive numbers to make sure that the normalization caps angles to the range [-180, 180] degrees properly.

Related

Time complexity for an analysis recursive algorithm

Any idea what the time complexity could be for this recursive algorithm please?
/* The function f(x) is unimodal over the range [min, max] and can be evaluated in Θ(1) time
* ε > 0 is the precision of the algorithm, typically ε is very small
* max > min
* n = (max - min)/ε, n > 0, where n is the problem size */
Algorithm(max, min){
if ((max - min) < ε){
return (max - min)/2 // return the answer
}
leftThird = (2 * min + max) / 3 // represents the point which is 1/3 of the way from min to max
rightThird = (min + 2 * max) / 3 // represents the point which is 2/3 of the way from min to max
if (f(leftThird) < f(rightThird))
{
return Algorithm(max,leftThird) // look for the answer in the interval between leftThird and max
}
else
{
return Algorithm(min, rightThird) // look for the answer in the interval between min and rightThird
}
}

Calculate the ticks of an axis for a chart with a stepsize

I've calculated a stepsize for an axis on a chart.
Also I have the Min and Max -Values. Now I need to calculate all ticks so that all values between my Min and Max can be displayed.
For Example:
Stepsize: 1000
Min: 213
Max: 4405
Expected ticks: 0,1000,2000,3000,4000,5000
Stepsize: 500
Min: -1213
Max: 1405
Expected ticks: -1500,-1000,-500,0,500,1000,1500
Until now I'm trying to calculate the first value with "try and error" like:
bool firstStepSet = false;
double firstStep = stepSize;
do
{
if (xValue >= (firstStep - (stepSize / 2)) && xValue <=
(firstStep + (stepSize / 2)))
{
firstStepSet = true;
this.myBarXValues.Add(firstStep, 0);
}
else if (xValue > stepSize)
{
firstStep += stepSize;
}
else
{
firstStep -= stepSize;
}
}
while (!firstStepSet);
And after that I'm adding steps to this list until all values fit.
This seems pretty dirty to me and I want to know if there is another solution.
So what I need is a solution which calculate the first tick that I need.
This function calculates first and last step values:
static void CalcSteps(int min, int max, int stepSize, out int firstStep, out int lastStep)
{
if (min >= 0)
{
firstStep = (min / stepSize) * stepSize;
}
else
{
firstStep = ((min - stepSize + 1) / stepSize) * stepSize;
}
if (max >= 0)
{
lastStep = ((max + stepSize - 1) / stepSize) * stepSize;
}
else
{
lastStep = (max / stepSize) * stepSize;
}
}
You can calculate axis limits using integer rounding to lower and higher values
low = stepsize * (min / stepsize) //integer division needed
high = stepsize * ((max + stepsize - 1) / stepsize)
Example Python code returns limits and number of ticks (one more than interval count)
def getminmax(minn, maxx, step):
low = (minn // step)
high = (maxx + step - 1) // step
ticks = high - low + 1
return low * step, high * step, ticks
print(getminmax(213, 4405, 1000))
print(getminmax(-1213,1405, 500))
(0, 5000, 6)
(-1500, 1500, 7)

Rounding integers to nearest multiple of 10 [duplicate]

This question already has answers here:
Returning the nearest multiple value of a number
(6 answers)
Closed 3 years ago.
I am trying to figure out how to round prices - both ways. For example:
Round down
43 becomes 40
143 becomes 140
1433 becomes 1430
Round up
43 becomes 50
143 becomes 150
1433 becomes 1440
I have the situation where I have a price range of say:
£143 - £193
of which I want to show as:
£140 - £200
as it looks a lot cleaner
Any ideas on how I can achieve this?
I would just create a couple methods;
int RoundUp(int toRound)
{
if (toRound % 10 == 0) return toRound;
return (10 - toRound % 10) + toRound;
}
int RoundDown(int toRound)
{
return toRound - toRound % 10;
}
Modulus gives us the remainder, in the case of rounding up 10 - r takes you to the nearest tenth, to round down you just subtract r. Pretty straight forward.
You don't need to use modulus (%) or floating point...
This works:
public static int RoundUp(int value)
{
return 10*((value + 9)/10);
}
public static int RoundDown(int value)
{
return 10*(value/10);
}
This code rounds to the nearest multiple of 10:
int RoundNum(int num)
{
int rem = num % 10;
return rem >= 5 ? (num - rem + 10) : (num - rem);
}
Very simple usage :
Console.WriteLine(RoundNum(143)); // prints 140
Console.WriteLine(RoundNum(193)); // prints 190
A general method to round a number to a multiple of another number, rounding away from zero.
For integer
int RoundNum(int num, int step)
{
if (num >= 0)
return ((num + (step / 2)) / step) * step;
else
return ((num - (step / 2)) / step) * step;
}
For float
float RoundNum(float num, float step)
{
if (num >= 0)
return floor((num + step / 2) / step) * step;
else
return ceil((num - step / 2) / step) * step;
}
I know some parts might seem counter-intuitive or not very optimized. I tried casting (num + step / 2) to an int, but this gave wrong results for negative floats ((int) -12.0000 = -11 and such). Anyways these are a few cases I tested:
any number rounded to step 1 should be itself
-3 rounded to step 2 = -4
-2 rounded to step 2 = -2
3 rounded to step 2 = 4
2 rounded to step 2 = 2
-2.3 rounded to step 0.2 = -2.4
-2.4 rounded to step 0.2 = -2.4
2.3 rounded to step 0.2 = 2.4
2.4 rounded to step 0.2 = 2.4
Divide the number by 10.
number = number / 10;
Math.Ceiling(number);//round up
Math.Round(number);//round down
Then multiply by 10.
number = number * 10;
public static int Round(int n)
{
// Smaller multiple
int a = (n / 10) * 10;
// Larger multiple
int b = a + 10;
// Return of closest of two
return (n - a > b - n) ? b : a;
}

Convert Degrees/Minutes/Seconds to Decimal Coordinates

In one part of my code I convert from decimal coordinates to degrees/minutes/seconds and I use this:
double coord = 59.345235;
int sec = (int)Math.Round(coord * 3600);
int deg = sec / 3600;
sec = Math.Abs(sec % 3600);
int min = sec / 60;
sec %= 60;
How would I convert back from degrees/minutes/seconds to decimal coordinates?
Try this:
public double ConvertDegreeAngleToDouble( double degrees, double minutes, double seconds )
{
//Decimal degrees =
// whole number of degrees,
// plus minutes divided by 60,
// plus seconds divided by 3600
return degrees + (minutes/60) + (seconds/3600);
}
Just to save others time, I wanted to add on to Byron's answer. If you have the point in string form (e.g. "17.21.18S"), you can use this method:
public double ConvertDegreeAngleToDouble(string point)
{
//Example: 17.21.18S
var multiplier = (point.Contains("S") || point.Contains("W")) ? -1 : 1; //handle south and west
point = Regex.Replace(point, "[^0-9.]", ""); //remove the characters
var pointArray = point.Split('.'); //split the string.
//Decimal degrees =
// whole number of degrees,
// plus minutes divided by 60,
// plus seconds divided by 3600
var degrees = Double.Parse(pointArray[0]);
var minutes = Double.Parse(pointArray[1]) / 60;
var seconds = Double.Parse(pointArray[2]) / 3600;
return (degrees + minutes + seconds) * multiplier;
}
Since degrees are each worth 1 coordinate total, and minutes are worth 1/60 of a coordinate total, and seconds are worth 1/3600 of a coordinate total, you should be able to put them back together with:
new_coord = deg + min/60 + sec/3600
Beware that it won't be the exact same as the original, though, due to floating-point rounding.
Often the western and southern hemispheres are expressed as negative degrees, and seconds contain decimals for accuracy: -86:44:52.892 Remember longitude is the X-coordinate and latitude is the Y-coordinate. This often gets mixed up because people often refer to them lat/lon and X/Y. I modified the code below for the above format.
private double ConvertDegreesToDecimal(string coordinate)
{
double decimalCoordinate;
string[] coordinateArray = coordinate.Split(':');
if (3 == coordinateArray.Length)
{
double degrees = Double.Parse(coordinateArray[0]);
double minutes = Double.Parse(coordinateArray[1]) / 60;
double seconds = Double.Parse(coordinateArray[2]) / 3600;
if (degrees > 0)
{
decimalCoordinate = (degrees + minutes + seconds);
}
else
{
decimalCoordinate = (degrees - minutes - seconds);
}
}
return decimalCoordinate;
}
CoordinateSharp is available as a Nuget package and can handle Coordinate conversions for you. It even does UTM/MGRS conversion and provides solar/lunar times relative to the input location. It's really easy to use!
Coordinate c = new Coordinate(40.465, -75.089);
//Display DMS Format
c.FormatOptions.Format = CoordinateFormatType.Degree_Minutes_Seconds;
c.ToString();//N 40º 27' 54" W 75º 5' 20.4"
c.Latitude.ToString();//N 40º 27' 54"
c.Latitude.ToDouble();//40.465
Coordinate properties are iObservable as as well. So if you change a latitude minute value for example, everything else will update.
The accepted answer to date is inaccurate and doesn't take into account what happens when you add negative numbers to positive numbers. The below code addresses the issue and will correctly convert.
public double ConvertDegreeAngleToDouble(double degrees, double minutes, double seconds)
{
var multiplier = (degrees < 0 ? -1 : 1);
var _deg = (double)Math.Abs(degrees);
var result = _deg + (minutes / 60) + (seconds / 3600);
return result * multiplier;
}
For those who prefer regular expression and to handle format like DDMMSS.dddS
This function could easily be updated to handle other format.
C#
Regex reg = new Regex(#"^((?<D>\d{1,2}(\.\d+)?)(?<W>[SN])|(?<D>\d{2})(?<M>\d{2}(\.\d+)?)(?<W>[SN])|(?<D>\d{2})(?<M>\d{2})(?<S>\d{2}(\.\d+)?)(?<W>[SN])|(?<D>\d{1,3}(\.\d+)?)(?<W>[WE])|(?<D>\d{3})(?<M>\d{2}(\.\d+)?)(?<W>[WE])|(?<D>\d{3})(?<M>\d{2})(?<S>\d{2}(\.\d+)?)(?<W>[WE]))$");
private double DMS2Decimal(string dms)
{
double result = double.NaN;
var match = reg.Match(dms);
if (match.Success)
{
var degrees = double.Parse("0" + match.Groups["D"]);
var minutes = double.Parse("0" + match.Groups["M"]);
var seconds = double.Parse("0" + match.Groups["S"]);
var direction = match.Groups["W"].ToString();
var dec = (Math.Abs(degrees) + minutes / 60d + seconds / 3600d) * (direction == "S" || direction == "W" ? -1 : 1);
var absDec = Math.Abs(dec);
if ((((direction == "W" || direction == "E") && degrees <= 180 & absDec <= 180) || (degrees <= 90 && absDec <= 90)) && minutes < 60 && seconds < 60)
{
result = dec;
}
}
return result;
}

How to implement this oscillation function

What would be a fast way to implent this osscilation function.
A signature would look like this:
public static double Calculate(UInt64 currentCounter, uint duration, uint inDuration, uint outDuration)
And the result should be a double that as currentCounter advances, ossciates between 0 and 1. The osscialtion speed is defines by the duration parameter (the number of ticks for a single osccilation). Similarily the ascent and descent speed is defines via inDUration and outDuration (inDUration + outDuration).
alt text http://img252.imageshack.us/img252/9457/graphuf.jpg
The x-Axis of this graph would of course be currentCounter.
As the commenter points out, you have to know the functions.
The program structure would be something like:
// Use modulo to get the counter within the range of the first duration
var phaseCounter = currentCounter % duration;
// Use the appropriate function
if( phaseCounter < inDuration )
{
return InFunction( phaseCounter, inDuration );
}
if( phaseCounter > duration - outDuration )
{
// Normalize the phaseCounter to the domain of definition for OutFunction()
var outDurationOffset = duration - outDuration;
return OutFuntion( phaseCounter - outDurationOffset, outDuration );
}
return 0;
As you can see, you have to fill out InFunction() and OutFunction().
They both get two parameters, the x position in their domain of definition and their domain of definition. This way it should be easy to implement the functions.
EDIT:
The quadratic function could be an example for your InFunction:
double InFunction( uint current, uint range )
{
return Math.Pow( ( current / range ) - 1, 2 );
}
By dividing current by range you get a value between 0 and 1 - which will make sure that the result is between 0 and 1, too (as you specified).
EDIT - Here's a new function that includes staying at 1.0 between outDuration and the the next inDuration. Note that I've changed your function signature - the input parameters are now inDuration, holdDuration, and outDuration. The function stays at 0 between inDuration and outDuration for holdDuration samples, then stays at 1.0 after outDuration for another holdDuration samples. The ramps are half-Hann functions again, you can change them as desired.
public static double Calculate(UInt64 currentCounter, uint inDuration, uint holdDuration, uint outDuration)
{
UInt64 curTime;
double ret;
curTime = currentCounter % (inDuration + 2*holdDuration + outDuration); //this wrapping should really be handled by the caller
if (curTime < inDuration)
{
ret = 0.5 * (1.0 - Math.Cos(2.0 * Math.PI * (inDuration - curTime) / (2.0 * inDuration)));
}
else if (curTime < inDuration + holdDuration)
{
ret = 0.0;
}
else if (curTime < inDuration + holdDuration + outDuration)
{
ret = 0.5 * (1.0 - Math.Cos(2.0 * Math.PI * (curTime - inDuration - holdDuration) / (2.0 * outDuration)));
}
else
{
ret = 1.0;
}
return ret;
}
This has the same periodicity features as the previous version.
Here's a graph showing two cycles of the function. The test loop was
for (ctr = 0; ctr < 20000; ctr++)
Calculate(ctr, 2500, 2250, 3000);
alt text http://img16.imageshack.us/img16/4443/oscfnxn2.png
First version
I'm a big fan of the Hann function for stuff like that. It's continuous and differentiable, if that's a concern. Here's a simple implementation:
public static double Calculate(UInt64 currentCounter, uint duration, uint inDuration, uint outDuration)
{
UInt64 curTime;
double ret;
//should check that inDuration + outDuration <= duration
curTime = currentCounter % duration; //this wrapping should really be handled by the caller
if (curTime < inDuration)
{
ret = 0.5 * (1.0 - Math.Cos(2.0 * Math.PI * (inDuration - curTime) / (2.0 * inDuration)));
}
else if (curTime >= (duration - outDuration))
{
ret = 0.5 * (1.0 - Math.Cos(2.0 * Math.PI * (outDuration + duration - curTime) / (2.0 * outDuration)));
}
else
{
ret = 1.0;
}
return ret;
}
Here's a sample graph. This was generated with the loop
for (ctr = 0; ctr < 10000; ctr++)
Calculate(ctr, 10000, 2500, 3000);
Graph with duration = 10000, in = 2500, out = 3000 http://img269.imageshack.us/img269/2969/oscfnxn.png
The function descends from 1.0 to 0 from index 0 to inDuration, stays at 0 until index duration-outDuration, then ascends to 1.0 at index duration, so it is exactly periodic in 'duration' samples.
I didn't understand your comment "Between out and in it is 1 for some time." Don't you need another parameter to specify the hold time?

Categories

Resources