C#: Do not show result in comand line when result is 0 - c#

I'm having a task for school in C#. I'm having this issue with the following code (example)
static void Main()
{
do
{
Console.Write("Amount of centimeters?: ");
double centimeters = double.Parse(Console.ReadLine());
double meters = centimeters / 100;
Console.WriteLine($"Amount of meters: {meters}");
int wholeMeters = (int)meters;
Console.WriteLine($"Amount of whole meters: {wholeMeters}");
}while (true);
}
Result:
Amount of centimeters?: 350
Amount of meters: 3,5
Amount of whole meters: 3
Amount of centimeters?: 50
Amount of meters: 0,5
Amount of whole meters: 0
If the result gives 0 for "Amount of whole meters", I don't want to show the line "Amount of whole meters:" in the console.
Like this:
Amount of centimeters?: 50
Amount of meters: 0,5
How can I achieve that, only using the 'System' namespace?

You will pretty sure learn about control structures in the very near future.
Just check the value of your wholeMeters field and act on the result
if(wholeMeters != 0)
Console.WriteLine($"Amount of whole meters: {wholeMeters}");

Actually this was my exercise, and I found the result by going true the code again step by step (Took me 1 day !!! :) )
static void Main()
{
do
{
Console.Write("Timespan in seconds?: ");
int timeInSeconds;
if (int.TryParse(Console.ReadLine(), out timeInSeconds))
{
Console.WriteLine("This is:");
double amountOfDays = timeInSeconds / 86400;
if (amountOfDays != 0)
Console.WriteLine($"- {(int)amountOfDays} days");
double amountOfHours = timeInSeconds / 3600 - ((int)amountOfDays * 24);
if (amountOfHours != 0)
Console.WriteLine($"- {(int)amountOfHours} hours");
double amountOfMinuts = timeInSeconds / 60 - ((int)amountOfHours * 60) - ((int)amountOfDays * 24 * 60);
if (amountOfMinuts != 0)
Console.WriteLine($"- {(int)amountOfMinuts} minuts");
double amountOfSeconds = timeInSeconds - ((int)amountOfMinuts * 60) - ((int)amountOfHours * 60 * 60) - ((int)amountOfDays * 24 * 60 * 60);
if (amountOfSeconds != 0)
Console.WriteLine($"- {(int)amountOfSeconds} seconds");
}
else
{
Console.WriteLine("Please enter a positive integer!");
}
} while (true);
}
}
Timespan in seconds?: 34567788
This is:
400 days
2 hours
9 minuts
48 seconds
Timespan in seconds?: 34567
This is:
9 hours
36 minuts
7 seconds Timespan in seconds?: 2345 This is:
39 minuts
5 seconds
Timespan in seconds?: 45
This is:
45 seconds
Timespan in seconds?: twenty
Please enter a positive integer!
I knew I had to use the if statement, but I had my (double) variables declared at the start of the code instead of right before each calculation.
Thanks for the help anyway!

Related

How to Fix Time String in c#

I have a situation where in I have time strings like
10:20:70
11:65:40
I need to convert them into proper time in hh:mm:ss format using c# console.
For eg : 10:20:70 will be 10:21:10 after fixing
26:12:20 will be 02:12:10 as 26hours to be considered as 2 hours
How to achieve this? Please help me out.
Any help would be appreciated
Split the input and and either use a TimeSpan to get the real representation of the input.
Or use modulo operator % to fix the overflow.
var split = date.Split(":").Select(int.Parse).ToArray();
if(split.Count() != 3) {Console.WriteLine("bad format"); continue;}
/// public TimeSpan (int hours, int minutes, int seconds);
var realTimeSpanRepresentation = new TimeSpan(split[0],split[1],split[2]);
var correctedTimeSpanRepresentation = new TimeSpan(split[0]%24,split[1]%60,split[2]%60);
Console.WriteLine(date+" => "+realTimeSpanRepresentation+" / "+correctedTimeSpanRepresentation);
/// public DateTime (int year, int month, int day, int hour, int minute, int second);
//var realDateTimeRepresentation = new DateTime(1,1,1,split[0],split[1],split[2]); // Will go boom cause overflow
var correctedDateTimeRepresentation = new DateTime(1,1,1,split[0]%24,split[1]%60,split[2]%60);
Console.WriteLine(date+" => "+correctedDateTimeRepresentation);
Result:
10:20:70 => 10:21:10 / 10:20:10
10:20:70 => 01/01/0001 10:20:10
11:65:40 => 12:05:40 / 11:05:40
11:65:40 => 01/01/0001 11:05:40
99:99:99 => 4.04:40:39 / 03:39:39
99:99:99 => 01/01/0001 03:39:39
demo: https://dotnetfiddle.net/Uwb4zc
NB: I nammed it real representation, cause Imo "00:60:00" is one Hour not "00:00:00"
Here is a method that takes a total amount of seconds and gives proper values for how many years, days, hours, minutes and seconds in there.
public static void GetTimeFromSeconds(float secondsTotal, out int s, out int m, out int h, out int d, out int y)
{
s = m = h = d = y = 0;
s = (int)(secondsTotal % 60);
// substruct the seconds remainder from the total amount (75 - 15 = 60, 125 - 5 = 120).
secondsTotal -= s;
// if nothing left then it was less than 1 minute (45 - 0 = 45).
if (secondsTotal < 60)
return;
// secondsTotal / 60 => how many minutes total
// % 60 => how many minutes remain after splitting to whole hours
m = (int)(secondsTotal / 60 % 60);
// substruct the minutes remainder from the total amount (every minute takes 60 secs from the total)
secondsTotal -= m * 60;
// if there's not enough seconds remain in the total to get at least 1 whole hour (3600 secs)
// then it means there was less than 1 hour.
if (secondsTotal < 3600)
return;
// secondsTotal / 3600 => how many hours total
// % 24 => what will remain after splitting to whole days (24 hours)
h = (int)(secondsTotal / 3600 % 24);
// every whole hour takes 3600 secs from the total
secondsTotal -= h * 3600;
// 24 hours = 86400 seconds.
// If there's less remaining than it was less than 24 hours.
if (secondsTotal < 86400)
return;
// secondsTotal/ 86400 => how many days total
// % 365 => how many will remain after splitting to years
d = (int)(secondsTotal / 86400 % 365);
// substruct whole days
secondsTotal -= d * 86400;
// 1 year = 31536000 secs.
// is there enough secs remaining to get a whole year?
if (secondsTotal < 31536000)
return;
y = (int)(secondsTotal / 31536000);
}
So, you could parse your time into separate values
26:70:20 => hours=26, minutes=70, seconds=20
then count the total amount of seconds:
secondsTotal = hours * 3600 + minutes * 60 + seconds
and then use the method above:
int years, days, hours, mins, secs;
GetTimeFromSeconds(secondsTotal, out secs, out mins, out hours, out days, out years);
For 26 hours, 70 mins, 20 secs the results will be days: 1, hours: 3, minutes: 10, secs: 20.
Then format it into the format you need. For example:
TimeSpan properTime = new TimeSpan(hours, mins, secs);
properTime.ToString(#"hh\:mm\:ss");

Edit timer number format

I have a code like this:
private IEnumerator RunTimer(float time, int kind_of_function)
{
var seconds = (int) time;
while (time > 0)
{
yield return null;
time -= Time.deltaTime;
if ((int) time != seconds)
{
// Update the text
seconds = (int) time;
timerText.text = string.Format("{0:00}:{1:00}", seconds / 60, seconds % 60);
}
if (seconds == 0)
{
}
}
}
How to change this output format: 0:00 In such a way that if the number of seconds was two-digit then it would look like 00, and if it was one-digit then 0?
As said use one of
#0 where
0 means: I definitely want this digit always
# means: I want this digit only if it is not 0 or is a significant 0
see Custom Numeric Format Strings
D
which basically means: Only show significant decimals digits.
Since you have int you could even also use N which usually includes digits after the comma
see Standard Numeric Format strings
Simply do not define a special format at all.
What you describe is what happens by default anyway if you simply used
string.Format("{0}:{1}", seconds / 60, seconds % 60)
Then I would prefer $ string interpolation which in my opinion is more flexible and better maintainable
timeText.text = $"{seconds / 60}:{seconds % 60}";
or with the formatter
timeText.text = $"{seconds / 60:#0}:{seconds % 60:#0}";
Though in my humble opinion you should stick to what you had. Doesn't it look way better?
Okey apparently what you actually wanted is not displaying the minutes at all if there are only seconds
var minutes = seconds / 60;
if(minutes > 0)
{
timeText.text = $"{minutes}:{seconds % 60:#0}";
}
else
{
timeText.text = $"{seconds:#0}";
}
private IEnumerator RunTimer(float time)
{
var seconds = (int) time;
while (time > 0)
{
yield return null;
time -= Time.deltaTime;
bool moreThanTenSec = time / 10 > 1;
if ((int) time != seconds)
{
// Update the text
seconds = (int) time;
if (moreThanTenSec)
timerText.text = string.Format("{0:00}:{1:00}", seconds / 60, seconds % 60);
else
timerText.text = string.Format("{0:00}:{1:0}", seconds / 60, seconds % 60);
}
if (seconds == 0)
{
}
}

Angle Normalization 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.

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;
}

Time divided by hours/minutes

How can I divide time by using intervals?
like 01:00 divided by 20 mins = 3?
06:00 divided by 2 hours = 3?
/M
I'd just use the TimeSpan object:
int hours = 1;
int minutes = 0;
int seconds = 0;
TimeSpan span = new TimeSpan(hours, minutes, seconds);
double result = span.TotalMinutes / 20; // 3
Don't bother manually doing any conversions, the TimeSpan object with it's TotalHours, TotalMinutes, TotalSeconds properties, etc, do it all for you.
Something like this should work well, I suppose:
public static double SplitTime(TimeSpan input, TimeSpan splitSize)
{
double msInput = input.TotalMilliseconds;
double msSplitSize = splitSize.TotalMilliseconds;
return msInput / msSplitSize;
}
Example; split 1 hour in 20 minute chunks:
double result = SplitTime(new TimeSpan(1,0,0), new TimeSpan(0,20,0));
I guess the method could fairly easily be reworked to return an array of TimeSpan objects containing the different "slices".
First convert everything to seconds.
01:00 => 3600 seconds, 20 mins => 1200 seconds
then you can divide
Convert to minutes and then do the divison.
h - hours
m - minutes
hd - divider hours
md - divider minutes
(h * 60 + m) / (hd * 60 + md)

Categories

Resources