5
\$\begingroup\$

Out of fun, I solved "Nice Angles" challenge on CodeEval in C# 4.0:

CHALLENGE DESCRIPTION:

Write a program that outputs the value of angle, reducing its fractional part to minutes and seconds.

INPUT SAMPLE:

The first argument is a path to a file that contains the values of angles with their decimal fractions:

330.39991833
0.001
14.64530319
0.25
254.16991217

OUTPUT SAMPLE:

Print to stdout values of angles with their fractional parts reduced to minutes and seconds.

The whole and fractional parts are separated by period, minutes are separated by apostrophe, seconds by double quotes. The values of minutes and seconds are shown as two numbers (with leading zeros if needed).

 330.23'59"
 0.00'03"
 14.38'43"
 0.15'00"
 254.10'11"

This is the code I used to solve the problem:

public static void ConvertToMinSec(string path)
 {
 using (StreamReader reader = File.OpenText(path))
 {
 while (!reader.EndOfStream)
 {
 var degreeValues = reader.ReadLine();
 if (!string.IsNullOrWhiteSpace(degreeValues))
 {
 var totalVal = degreeValues.Split('.');
 if (totalVal.Length == 1)
 {
 var temp = totalVal[0] + ".0";
 totalVal = temp.Split('.');
 }
 var intPart = totalVal[0];
 var decimalPart = "0." + totalVal[1];
 decimal minutes;
 decimal.TryParse(decimalPart, out minutes);
 minutes = decimal.Multiply(minutes, 60);
 var minutePart = (int)minutes;
 var remainingDecimal = minutes.ToString().Split('.');
 if (remainingDecimal.Length == 1)
 {
 var tempDecimal = remainingDecimal[0] + ".0";
 remainingDecimal = tempDecimal.Split('.');
 }
 decimal seconds;
 decimal.TryParse("0." + remainingDecimal[1], out seconds);
 seconds = seconds*60;
 var secondsPart = (int) seconds;
 var report = string.Format("{0}"+"."+"{1:00}"+"'"+"{2:00}"+'"', intPart,
 minutePart, secondsPart);
 Console.WriteLine(report);
 }
 }
 }
200_success
146k22 gold badges190 silver badges478 bronze badges
asked Sep 15, 2014 at 3:59
\$\endgroup\$
4
  • \$\begingroup\$ What about "180" without the decimal point? \$\endgroup\$ Commented Sep 15, 2014 at 4:22
  • \$\begingroup\$ I think that problem is not in decimal separators - they are clearly described in the task as dots, so I assume no problem here. However do check this line of yours: var report = string.Format("{0}" + "." + "{1:00}" + "'" + "{2:00}" + "''", intPart, minutePart, secondsPart); You used two apsothropes for seconds separator ("''") while they just used doublequete in description. Try changing this string into that - "\"". \$\endgroup\$ Commented Sep 15, 2014 at 12:05
  • \$\begingroup\$ @SebGruch thank you for your response. As I mentioned in the question, the error is due to IndexOutOfRange exception, which is happening for an input of 180.0 or 90.0 or such numbers on the CodeEval server. I contacted them, and they say that there might be a difference in their C# 4 compiler than my C# 4 compiler on my machine, which I am not convinced. I am working on another solution to this problem, which I will post it when it is completed. \$\endgroup\$ Commented Sep 15, 2014 at 16:51
  • \$\begingroup\$ On-topic Help Center Hints: To the best of my knowledge, does the code work? This looks like question from gray zone, where it seems that the code works for most cases, but may fail in other. I am not sure where this belongs. \$\endgroup\$ Commented Sep 16, 2014 at 10:48

2 Answers 2

10
\$\begingroup\$

At the heart of the solution, there should be a function that converts decimal degrees into a d°mm'ss" string. Assuming that the input is in a reasonable domain (between 0 and 360, for example), the conversion algorithm should be simple and regular. Above all, it should be purely mathematical at this point — you shouldn't be trying to do any string parsing.

Your format string had lots of unnecessary concatenation.

public static string ToDegMinSec(double dec)
{
 int degrees = (int)dec;
 dec = 60 * (dec - degrees);
 int minutes = (int)dec;
 dec = 60 * (dec - minutes);
 int seconds = (int)dec;
 return string.Format("{0}.{1:00}'{2:00}\"", degrees, minutes, seconds);
}
answered Sep 16, 2014 at 9:08
\$\endgroup\$
6
\$\begingroup\$
var minutes = Convert.ToDecimal("0." + totalVal[1])*60;
var remainingDecimal = minutes.ToString().Split('.');

I think the issue is that Decimal.ToString's formatting will depend on the current culture. A computer with different settings will produce different results. The settings on your computer is such that it produces 0.0 here. But it could produce 0,0, 0, or various other crazy things.

As a general practice, don't use the result of .ToString() in computations. It's almost always the wrong way.

answered Sep 15, 2014 at 4:27
\$\endgroup\$
1
  • \$\begingroup\$ ToString(InvariantCulture ), same with parsing. \$\endgroup\$ Commented Sep 16, 2014 at 10:40

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.